From efed5ef02e2d6b662aa2d5c7740bddf209791f40 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 6 Apr 2021 22:27:05 +0900 Subject: [PATCH 01/16] common paint: fix wrong fast clippath logic. it missed to check clippath's transform in fasttrack logic. now it additionally check it... --- src/lib/tvgPaint.h | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/lib/tvgPaint.h b/src/lib/tvgPaint.h index adb7cfe..2df21c7 100644 --- a/src/lib/tvgPaint.h +++ b/src/lib/tvgPaint.h @@ -31,7 +31,7 @@ static inline bool FLT_SAME(float a, float b) return (fabsf(a - b) < FLT_EPSILON); } -static bool _clipPathFastTrack(Paint* cmpTarget, const RenderTransform* transform, RenderRegion& viewport) +static bool _clipPathFastTrack(Paint* cmpTarget, const RenderTransform* pTransform, RenderTransform* rTransform, RenderRegion& viewport) { /* Access Shape class by Paint is bad... but it's ok still it's an internal usage. */ auto shape = static_cast(cmpTarget); @@ -40,10 +40,11 @@ static bool _clipPathFastTrack(Paint* cmpTarget, const RenderTransform* transfor const Point* pts; if (shape->pathCoords(&pts) != 4) return false; + if (rTransform) rTransform->update(); + //No Rotation? - if (transform) { - if (transform->m.e12 != 0 || transform->m.e21 != 0 || transform->m.e11 != transform->m.e22) return false; - } + if (pTransform && (pTransform->m.e12 != 0 || pTransform->m.e21 != 0 || pTransform->m.e11 != pTransform->m.e22)) return false; + if (rTransform && (rTransform->m.e12 != 0 || rTransform->m.e21 != 0 || rTransform->m.e11 != rTransform->m.e22)) return false; //Othogonal Rectangle? auto pt1 = pts + 0; @@ -59,11 +60,18 @@ static bool _clipPathFastTrack(Paint* cmpTarget, const RenderTransform* transfor auto x2 = pt3->x; auto y2 = pt3->y; - if (transform) { - x1 = x1 * transform->m.e11 + transform->m.e13; - y1 = y1 * transform->m.e22 + transform->m.e23; - x2 = x2 * transform->m.e11 + transform->m.e13; - y2 = y2 * transform->m.e22 + transform->m.e23; + if (rTransform) { + x1 = x1 * rTransform->m.e11 + rTransform->m.e13; + y1 = y1 * rTransform->m.e22 + rTransform->m.e23; + x2 = x2 * rTransform->m.e11 + rTransform->m.e13; + y2 = y2 * rTransform->m.e22 + rTransform->m.e23; + } + + if (pTransform) { + x1 = x1 * pTransform->m.e11 + pTransform->m.e13; + y1 = y1 * pTransform->m.e22 + pTransform->m.e23; + x2 = x2 * pTransform->m.e11 + pTransform->m.e13; + y2 = y2 * pTransform->m.e22 + pTransform->m.e23; } viewport.x = static_cast(x1); @@ -212,7 +220,7 @@ namespace tvg we can avoid regular ClipPath sequence but use viewport for performance */ if (cmpMethod == CompositeMethod::ClipPath) { RenderRegion viewport2; - if ((cmpFastTrack = _clipPathFastTrack(cmpTarget, pTransform, viewport2))) { + if ((cmpFastTrack = _clipPathFastTrack(cmpTarget, pTransform, cmpTarget->pImpl->rTransform, viewport2))) { viewport = renderer.viewport(); viewport2.merge(viewport); renderer.viewport(viewport2); -- 2.7.4 From fad1f5bb39abd0a293cfc0956145b6efbdc429fc Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Wed, 7 Apr 2021 21:13:29 +0900 Subject: [PATCH 02/16] binary optimization remove inlining to reduce size by 22kb. Change-Id: I1036e28cac2de5d42f8a7a08b09897c1fb3dc5a6 --- src/lib/tvgPaint.cpp | 214 ++++++++++++++++++++++++++++++++++++++++++++++++ src/lib/tvgPaint.h | 217 ++----------------------------------------------- src/lib/tvgSceneImpl.h | 1 + src/lib/tvgShape.cpp | 2 + 4 files changed, 224 insertions(+), 210 deletions(-) diff --git a/src/lib/tvgPaint.cpp b/src/lib/tvgPaint.cpp index be78d22..aca756f 100644 --- a/src/lib/tvgPaint.cpp +++ b/src/lib/tvgPaint.cpp @@ -19,12 +19,226 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ +#include +#include #include "tvgPaint.h" /************************************************************************/ /* Internal Class Implementation */ /************************************************************************/ +static inline bool FLT_SAME(float a, float b) +{ + return (fabsf(a - b) < FLT_EPSILON); +} + +static bool _clipPathFastTrack(Paint* cmpTarget, const RenderTransform* pTransform, RenderTransform* rTransform, RenderRegion& viewport) +{ + /* Access Shape class by Paint is bad... but it's ok still it's an internal usage. */ + auto shape = static_cast(cmpTarget); + + //Rectangle Candidates? + const Point* pts; + if (shape->pathCoords(&pts) != 4) return false; + + if (rTransform) rTransform->update(); + + //No Rotation? + if (pTransform && (pTransform->m.e12 != 0 || pTransform->m.e21 != 0 || pTransform->m.e11 != pTransform->m.e22)) return false; + if (rTransform && (rTransform->m.e12 != 0 || rTransform->m.e21 != 0 || rTransform->m.e11 != rTransform->m.e22)) return false; + + //Othogonal Rectangle? + auto pt1 = pts + 0; + auto pt2 = pts + 1; + auto pt3 = pts + 2; + auto pt4 = pts + 3; + + if ((FLT_SAME(pt1->x, pt2->x) && FLT_SAME(pt2->y, pt3->y) && FLT_SAME(pt3->x, pt4->x) && FLT_SAME(pt1->y, pt4->y)) || + (FLT_SAME(pt2->x, pt3->x) && FLT_SAME(pt1->y, pt2->y) && FLT_SAME(pt1->x, pt4->x) && FLT_SAME(pt3->y, pt4->y))) { + + auto x1 = pt1->x; + auto y1 = pt1->y; + auto x2 = pt3->x; + auto y2 = pt3->y; + + if (rTransform) { + x1 = x1 * rTransform->m.e11 + rTransform->m.e13; + y1 = y1 * rTransform->m.e22 + rTransform->m.e23; + x2 = x2 * rTransform->m.e11 + rTransform->m.e13; + y2 = y2 * rTransform->m.e22 + rTransform->m.e23; + } + + if (pTransform) { + x1 = x1 * pTransform->m.e11 + pTransform->m.e13; + y1 = y1 * pTransform->m.e22 + pTransform->m.e23; + x2 = x2 * pTransform->m.e11 + pTransform->m.e13; + y2 = y2 * pTransform->m.e22 + pTransform->m.e23; + } + + viewport.x = static_cast(x1); + viewport.y = static_cast(y1); + viewport.w = static_cast(roundf(x2 - x1 + 0.5f)); + viewport.h = static_cast(roundf(y2 - y1 + 0.5f)); + + return true; + } + + return false; +} + + +Paint* Paint::Impl::duplicate() +{ + auto ret = smethod->duplicate(); + if (!ret) return nullptr; + + //duplicate Transform + if (rTransform) { + ret->pImpl->rTransform = new RenderTransform(); + if (ret->pImpl->rTransform) { + *ret->pImpl->rTransform = *rTransform; + ret->pImpl->flag |= RenderUpdateFlag::Transform; + } + } + + ret->pImpl->opacity = opacity; + + if (cmpTarget) ret->pImpl->cmpTarget = cmpTarget->duplicate(); + + ret->pImpl->cmpMethod = cmpMethod; + + return ret; +} + + +bool Paint::Impl::rotate(float degree) +{ + if (rTransform) { + if (fabsf(degree - rTransform->degree) <= FLT_EPSILON) return true; + } else { + if (fabsf(degree) <= FLT_EPSILON) return true; + rTransform = new RenderTransform(); + if (!rTransform) return false; + } + rTransform->degree = degree; + if (!rTransform->overriding) flag |= RenderUpdateFlag::Transform; + + return true; +} + + +bool Paint::Impl::scale(float factor) +{ + if (rTransform) { + if (fabsf(factor - rTransform->scale) <= FLT_EPSILON) return true; + } else { + if (fabsf(factor) <= FLT_EPSILON) return true; + rTransform = new RenderTransform(); + if (!rTransform) return false; + } + rTransform->scale = factor; + if (!rTransform->overriding) flag |= RenderUpdateFlag::Transform; + + return true; +} + + +bool Paint::Impl::translate(float x, float y) +{ + if (rTransform) { + if (fabsf(x - rTransform->x) <= FLT_EPSILON && fabsf(y - rTransform->y) <= FLT_EPSILON) return true; + } else { + if (fabsf(x) <= FLT_EPSILON && fabsf(y) <= FLT_EPSILON) return true; + rTransform = new RenderTransform(); + if (!rTransform) return false; + } + rTransform->x = x; + rTransform->y = y; + if (!rTransform->overriding) flag |= RenderUpdateFlag::Transform; + + return true; +} + + +bool Paint::Impl::render(RenderMethod& renderer) +{ + Compositor* cmp = nullptr; + + /* Note: only ClipPath is processed in update() step. + Create a composition image. */ + if (cmpTarget && cmpMethod != CompositeMethod::ClipPath) { + auto region = cmpTarget->pImpl->bounds(renderer); + if (region.w == 0 || region.h == 0) return false; + cmp = renderer.target(region); + renderer.beginComposite(cmp, CompositeMethod::None, 255); + cmpTarget->pImpl->render(renderer); + } + + if (cmp) renderer.beginComposite(cmp, cmpMethod, cmpTarget->pImpl->opacity); + + auto ret = smethod->render(renderer); + + if (cmp) renderer.endComposite(cmp); + + return ret; +} + + +void* Paint::Impl::update(RenderMethod& renderer, const RenderTransform* pTransform, uint32_t opacity, Array& clips, uint32_t pFlag) +{ + if (flag & RenderUpdateFlag::Transform) { + if (!rTransform) return nullptr; + if (!rTransform->update()) { + delete(rTransform); + rTransform = nullptr; + } + } + + /* 1. Composition Pre Processing */ + void *cmpData = nullptr; + RenderRegion viewport; + bool cmpFastTrack = false; + + if (cmpTarget) { + /* If transform has no rotation factors && ClipPath is a simple rectangle, + we can avoid regular ClipPath sequence but use viewport for performance */ + if (cmpMethod == CompositeMethod::ClipPath) { + RenderRegion viewport2; + if ((cmpFastTrack = _clipPathFastTrack(cmpTarget, pTransform, cmpTarget->pImpl->rTransform, viewport2))) { + viewport = renderer.viewport(); + viewport2.merge(viewport); + renderer.viewport(viewport2); + } + } + + if (!cmpFastTrack) { + cmpData = cmpTarget->pImpl->update(renderer, pTransform, 255, clips, pFlag); + if (cmpMethod == CompositeMethod::ClipPath) clips.push(cmpData); + } + } + + /* 2. Main Update */ + void *edata = nullptr; + auto newFlag = static_cast(pFlag | flag); + flag = RenderUpdateFlag::None; + opacity = (opacity * this->opacity) / 255; + + if (rTransform && pTransform) { + RenderTransform outTransform(pTransform, rTransform); + edata = smethod->update(renderer, &outTransform, opacity, clips, newFlag); + } else { + auto outTransform = pTransform ? pTransform : rTransform; + edata = smethod->update(renderer, outTransform, opacity, clips, newFlag); + } + + /* 3. Composition Post Processing */ + if (cmpFastTrack) renderer.viewport(viewport); + else if (cmpData && cmpMethod == CompositeMethod::ClipPath) clips.pop(); + + return edata; +} + + Paint :: Paint() : pImpl(new Impl()) { } diff --git a/src/lib/tvgPaint.h b/src/lib/tvgPaint.h index 2df21c7..044c3aa 100644 --- a/src/lib/tvgPaint.h +++ b/src/lib/tvgPaint.h @@ -22,69 +22,8 @@ #ifndef _TVG_PAINT_H_ #define _TVG_PAINT_H_ -#include -#include #include "tvgRender.h" -static inline bool FLT_SAME(float a, float b) -{ - return (fabsf(a - b) < FLT_EPSILON); -} - -static bool _clipPathFastTrack(Paint* cmpTarget, const RenderTransform* pTransform, RenderTransform* rTransform, RenderRegion& viewport) -{ - /* Access Shape class by Paint is bad... but it's ok still it's an internal usage. */ - auto shape = static_cast(cmpTarget); - - //Rectangle Candidates? - const Point* pts; - if (shape->pathCoords(&pts) != 4) return false; - - if (rTransform) rTransform->update(); - - //No Rotation? - if (pTransform && (pTransform->m.e12 != 0 || pTransform->m.e21 != 0 || pTransform->m.e11 != pTransform->m.e22)) return false; - if (rTransform && (rTransform->m.e12 != 0 || rTransform->m.e21 != 0 || rTransform->m.e11 != rTransform->m.e22)) return false; - - //Othogonal Rectangle? - auto pt1 = pts + 0; - auto pt2 = pts + 1; - auto pt3 = pts + 2; - auto pt4 = pts + 3; - - if ((FLT_SAME(pt1->x, pt2->x) && FLT_SAME(pt2->y, pt3->y) && FLT_SAME(pt3->x, pt4->x) && FLT_SAME(pt1->y, pt4->y)) || - (FLT_SAME(pt2->x, pt3->x) && FLT_SAME(pt1->y, pt2->y) && FLT_SAME(pt1->x, pt4->x) && FLT_SAME(pt3->y, pt4->y))) { - - auto x1 = pt1->x; - auto y1 = pt1->y; - auto x2 = pt3->x; - auto y2 = pt3->y; - - if (rTransform) { - x1 = x1 * rTransform->m.e11 + rTransform->m.e13; - y1 = y1 * rTransform->m.e22 + rTransform->m.e23; - x2 = x2 * rTransform->m.e11 + rTransform->m.e13; - y2 = y2 * rTransform->m.e22 + rTransform->m.e23; - } - - if (pTransform) { - x1 = x1 * pTransform->m.e11 + pTransform->m.e13; - y1 = y1 * pTransform->m.e22 + pTransform->m.e23; - x2 = x2 * pTransform->m.e11 + pTransform->m.e13; - y2 = y2 * pTransform->m.e22 + pTransform->m.e23; - } - - viewport.x = static_cast(x1); - viewport.y = static_cast(y1); - viewport.w = static_cast(roundf(x2 - x1 + 0.5f)); - viewport.h = static_cast(roundf(y2 - y1 + 0.5f)); - - return true; - } - - return false; -} - namespace tvg { @@ -107,12 +46,9 @@ namespace tvg StrategyMethod* smethod = nullptr; RenderTransform *rTransform = nullptr; uint32_t flag = RenderUpdateFlag::None; - Paint* cmpTarget = nullptr; CompositeMethod cmpMethod = CompositeMethod::None; - uint8_t opacity = 255; - PaintType type; ~Impl() { @@ -126,52 +62,6 @@ namespace tvg smethod = method; } - bool rotate(float degree) - { - if (rTransform) { - if (fabsf(degree - rTransform->degree) <= FLT_EPSILON) return true; - } else { - if (fabsf(degree) <= FLT_EPSILON) return true; - rTransform = new RenderTransform(); - if (!rTransform) return false; - } - rTransform->degree = degree; - if (!rTransform->overriding) flag |= RenderUpdateFlag::Transform; - - return true; - } - - bool scale(float factor) - { - if (rTransform) { - if (fabsf(factor - rTransform->scale) <= FLT_EPSILON) return true; - } else { - if (fabsf(factor) <= FLT_EPSILON) return true; - rTransform = new RenderTransform(); - if (!rTransform) return false; - } - rTransform->scale = factor; - if (!rTransform->overriding) flag |= RenderUpdateFlag::Transform; - - return true; - } - - bool translate(float x, float y) - { - if (rTransform) { - if (fabsf(x - rTransform->x) <= FLT_EPSILON && fabsf(y - rTransform->y) <= FLT_EPSILON) return true; - } else { - if (fabsf(x) <= FLT_EPSILON && fabsf(y) <= FLT_EPSILON) return true; - rTransform = new RenderTransform(); - if (!rTransform) return false; - } - rTransform->x = x; - rTransform->y = y; - if (!rTransform->overriding) flag |= RenderUpdateFlag::Transform; - - return true; - } - bool transform(const Matrix& m) { if (!rTransform) { @@ -200,106 +90,6 @@ namespace tvg return smethod->dispose(renderer); } - void* update(RenderMethod& renderer, const RenderTransform* pTransform, uint32_t opacity, Array& clips, uint32_t pFlag) - { - if (flag & RenderUpdateFlag::Transform) { - if (!rTransform) return nullptr; - if (!rTransform->update()) { - delete(rTransform); - rTransform = nullptr; - } - } - - /* 1. Composition Pre Processing */ - void *cmpData = nullptr; - RenderRegion viewport; - bool cmpFastTrack = false; - - if (cmpTarget) { - /* If transform has no rotation factors && ClipPath is a simple rectangle, - we can avoid regular ClipPath sequence but use viewport for performance */ - if (cmpMethod == CompositeMethod::ClipPath) { - RenderRegion viewport2; - if ((cmpFastTrack = _clipPathFastTrack(cmpTarget, pTransform, cmpTarget->pImpl->rTransform, viewport2))) { - viewport = renderer.viewport(); - viewport2.merge(viewport); - renderer.viewport(viewport2); - } - } - - if (!cmpFastTrack) { - cmpData = cmpTarget->pImpl->update(renderer, pTransform, 255, clips, pFlag); - if (cmpMethod == CompositeMethod::ClipPath) clips.push(cmpData); - } - } - - /* 2. Main Update */ - void *edata = nullptr; - auto newFlag = static_cast(pFlag | flag); - flag = RenderUpdateFlag::None; - opacity = (opacity * this->opacity) / 255; - - if (rTransform && pTransform) { - RenderTransform outTransform(pTransform, rTransform); - edata = smethod->update(renderer, &outTransform, opacity, clips, newFlag); - } else { - auto outTransform = pTransform ? pTransform : rTransform; - edata = smethod->update(renderer, outTransform, opacity, clips, newFlag); - } - - /* 3. Composition Post Processing */ - if (cmpFastTrack) renderer.viewport(viewport); - else if (cmpData && cmpMethod == CompositeMethod::ClipPath) clips.pop(); - - return edata; - } - - bool render(RenderMethod& renderer) - { - Compositor* cmp = nullptr; - - /* Note: only ClipPath is processed in update() step. - Create a composition image. */ - if (cmpTarget && cmpMethod != CompositeMethod::ClipPath) { - auto region = cmpTarget->pImpl->bounds(renderer); - if (region.w == 0 || region.h == 0) return false; - cmp = renderer.target(region); - renderer.beginComposite(cmp, CompositeMethod::None, 255); - cmpTarget->pImpl->render(renderer); - } - - if (cmp) renderer.beginComposite(cmp, cmpMethod, cmpTarget->pImpl->opacity); - - auto ret = smethod->render(renderer); - - if (cmp) renderer.endComposite(cmp); - - return ret; - } - - Paint* duplicate() - { - auto ret = smethod->duplicate(); - if (!ret) return nullptr; - - //duplicate Transform - if (rTransform) { - ret->pImpl->rTransform = new RenderTransform(); - if (ret->pImpl->rTransform) { - *ret->pImpl->rTransform = *rTransform; - ret->pImpl->flag |= RenderUpdateFlag::Transform; - } - } - - ret->pImpl->opacity = opacity; - - if (cmpTarget) ret->pImpl->cmpTarget = cmpTarget->duplicate(); - - ret->pImpl->cmpMethod = cmpMethod; - - return ret; - } - bool composite(Paint* target, CompositeMethod method) { if ((!target && method != CompositeMethod::None) || (target && method == CompositeMethod::None)) return false; @@ -308,6 +98,13 @@ namespace tvg cmpMethod = method; return true; } + + bool rotate(float degree); + bool scale(float factor); + bool translate(float x, float y); + void* update(RenderMethod& renderer, const RenderTransform* pTransform, uint32_t opacity, Array& clips, uint32_t pFlag); + bool render(RenderMethod& renderer); + Paint* duplicate(); }; diff --git a/src/lib/tvgSceneImpl.h b/src/lib/tvgSceneImpl.h index b32c036..40f1e58 100644 --- a/src/lib/tvgSceneImpl.h +++ b/src/lib/tvgSceneImpl.h @@ -22,6 +22,7 @@ #ifndef _TVG_SCENE_IMPL_H_ #define _TVG_SCENE_IMPL_H_ +#include #include "tvgPaint.h" /************************************************************************/ diff --git a/src/lib/tvgShape.cpp b/src/lib/tvgShape.cpp index 0b1f870..68013ce 100644 --- a/src/lib/tvgShape.cpp +++ b/src/lib/tvgShape.cpp @@ -20,6 +20,8 @@ * SOFTWARE. */ #include +#include +#include #include "tvgShapeImpl.h" /************************************************************************/ -- 2.7.4 From a4908167da048ed31c2583f33367a88f30f92f88 Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Fri, 2 Apr 2021 01:41:51 +0200 Subject: [PATCH 03/16] sw_engine: removed unnecessary function parameter In the fillFetchLinear function the offset parameter was removed. The destination address may be shifted directly in the dst parameter, it doesn't need to be passed separately. --- src/lib/sw_engine/tvgSwCommon.h | 2 +- src/lib/sw_engine/tvgSwFill.cpp | 6 ++---- src/lib/sw_engine/tvgSwRaster.cpp | 18 +++++++++--------- 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index 32adfd6..47d7d6d 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -331,7 +331,7 @@ void imageFree(SwImage* image); bool fillGenColorTable(SwFill* fill, const Fill* fdata, const Matrix* transform, SwSurface* surface, uint32_t opacity, bool ctable); void fillReset(SwFill* fill); void fillFree(SwFill* fill); -void fillFetchLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t offset, uint32_t len); +void fillFetchLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len); void fillFetchRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len); SwRleData* rleRender(SwRleData* rle, const SwOutline* outline, const SwBBox& renderRegion, bool antiAlias); diff --git a/src/lib/sw_engine/tvgSwFill.cpp b/src/lib/sw_engine/tvgSwFill.cpp index 3214ffc..d8900f7 100644 --- a/src/lib/sw_engine/tvgSwFill.cpp +++ b/src/lib/sw_engine/tvgSwFill.cpp @@ -226,7 +226,7 @@ void fillFetchRadial(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, } -void fillFetchLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t offset, uint32_t len) +void fillFetchLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, uint32_t len) { //Rotation float rx = x + 0.5f; @@ -236,12 +236,10 @@ void fillFetchLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, if (abs(inc) < FLT_EPSILON) { auto color = _fixedPixel(fill, static_cast(t * FIXPT_SIZE)); - rasterRGBA32(dst, color, offset, len); + rasterRGBA32(dst, color, 0, len); return; } - dst += offset; - auto vMax = static_cast(INT32_MAX >> (FIXPT_BITS + 1)); auto vMin = -vMax; auto v = t + (inc * len); diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index b7878ea..5fe0b38 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -611,7 +611,7 @@ static bool _rasterLinearGradientRect(SwSurface* surface, const SwBBox& region, for (uint32_t y = 0; y < h; ++y) { auto dst = &buffer[y * surface->stride]; - fillFetchLinear(fill, tmpBuf, region.min.y + y, region.min.x, 0, w); + fillFetchLinear(fill, tmpBuf, region.min.y + y, region.min.x, w); for (uint32_t x = 0; x < w; ++x) { dst[x] = tmpBuf[x] + ALPHA_BLEND(dst[x], 255 - surface->blender.alpha(tmpBuf[x])); } @@ -626,7 +626,7 @@ static bool _rasterLinearGradientRect(SwSurface* surface, const SwBBox& region, if (method == CompositeMethod::AlphaMask) { for (uint32_t y = 0; y < h; ++y) { - fillFetchLinear(fill, sbuffer, region.min.y + y, region.min.x, 0, w); + fillFetchLinear(fill, sbuffer, region.min.y + y, region.min.x, w); auto dst = buffer; auto cmp = cbuffer; auto src = sbuffer; @@ -639,7 +639,7 @@ static bool _rasterLinearGradientRect(SwSurface* surface, const SwBBox& region, } } else if (method == CompositeMethod::InvAlphaMask) { for (uint32_t y = 0; y < h; ++y) { - fillFetchLinear(fill, sbuffer, region.min.y + y, region.min.x, 0, w); + fillFetchLinear(fill, sbuffer, region.min.y + y, region.min.x, w); auto dst = buffer; auto cmp = cbuffer; auto src = sbuffer; @@ -653,7 +653,7 @@ static bool _rasterLinearGradientRect(SwSurface* surface, const SwBBox& region, } } else { for (uint32_t y = 0; y < h; ++y) { - fillFetchLinear(fill, buffer + y * surface->stride, region.min.y + y, region.min.x, 0, w); + fillFetchLinear(fill, buffer + y * surface->stride, region.min.y + y, region.min.x, w); } } } @@ -706,7 +706,7 @@ static bool _rasterLinearGradientRle(SwSurface* surface, const SwRleData* rle, c if (fill->translucent) { for (uint32_t i = 0; i < rle->size; ++i) { auto dst = &surface->buffer[span->y * surface->stride + span->x]; - fillFetchLinear(fill, buf, span->y, span->x, 0, span->len); + fillFetchLinear(fill, buf, span->y, span->x, span->len); if (span->coverage == 255) { for (uint32_t i = 0; i < span->len; ++i) { dst[i] = buf[i] + ALPHA_BLEND(dst[i], 255 - surface->blender.alpha(buf[i])); @@ -727,7 +727,7 @@ static bool _rasterLinearGradientRle(SwSurface* surface, const SwRleData* rle, c if (method == CompositeMethod::AlphaMask) { for (uint32_t i = 0; i < rle->size; ++i, ++span) { - fillFetchLinear(fill, buf, span->y, span->x, 0, span->len); + fillFetchLinear(fill, buf, span->y, span->x, span->len); auto dst = &surface->buffer[span->y * surface->stride + span->x]; auto cmp = &cbuffer[span->y * surface->stride + span->x]; auto src = buf; @@ -738,7 +738,7 @@ static bool _rasterLinearGradientRle(SwSurface* surface, const SwRleData* rle, c } } else if (method == CompositeMethod::InvAlphaMask) { for (uint32_t i = 0; i < rle->size; ++i, ++span) { - fillFetchLinear(fill, buf, span->y, span->x, 0, span->len); + fillFetchLinear(fill, buf, span->y, span->x, span->len); auto dst = &surface->buffer[span->y * surface->stride + span->x]; auto cmp = &cbuffer[span->y * surface->stride + span->x]; auto src = buf; @@ -751,9 +751,9 @@ static bool _rasterLinearGradientRle(SwSurface* surface, const SwRleData* rle, c } else { for (uint32_t i = 0; i < rle->size; ++i) { if (span->coverage == 255) { - fillFetchLinear(fill, surface->buffer + span->y * surface->stride, span->y, span->x, span->x, span->len); + fillFetchLinear(fill, surface->buffer + span->y * surface->stride + span->x, span->y, span->x, span->len); } else { - fillFetchLinear(fill, buf, span->y, span->x, 0, span->len); + fillFetchLinear(fill, buf, span->y, span->x, span->len); auto ialpha = 255 - span->coverage; auto dst = &surface->buffer[span->y * surface->stride + span->x]; for (uint32_t i = 0; i < span->len; ++i) { -- 2.7.4 From d55a808beee33d323a0044bc5a1f8da3e5512360 Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Sun, 4 Apr 2021 17:09:00 +0200 Subject: [PATCH 04/16] sw_engine: rastering the opaque radial gradient with masking In the radial gradient rastering functions, the part supporting the (inverse) masking was added. --- src/lib/sw_engine/tvgSwRaster.cpp | 91 +++++++++++++++++++++++++++++++++------ 1 file changed, 77 insertions(+), 14 deletions(-) diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index 5fe0b38..632cb7d 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -671,7 +671,6 @@ static bool _rasterRadialGradientRect(SwSurface* surface, const SwBBox& region, //Translucent Gradient if (fill->translucent) { - auto tmpBuf = static_cast(alloca(surface->w * sizeof(uint32_t))); if (!tmpBuf) return false; @@ -684,9 +683,44 @@ static bool _rasterRadialGradientRect(SwSurface* surface, const SwBBox& region, } //Opaque Gradient } else { - for (uint32_t y = 0; y < h; ++y) { - auto dst = &buffer[y * surface->stride]; - fillFetchRadial(fill, dst, region.min.y + y, region.min.x, w); + if (surface->compositor) { + auto method = surface->compositor->method; + auto cbuffer = surface->compositor->image.data + (region.min.y * surface->stride) + region.min.x; + auto sbuffer = static_cast(alloca(w * sizeof(uint32_t))); + if (!sbuffer) return false; + + if (method == CompositeMethod::AlphaMask) { + for (uint32_t y = 0; y < h; ++y) { + fillFetchRadial(fill, sbuffer, region.min.y + y, region.min.x, w); + auto dst = buffer; + auto cmp = cbuffer; + auto src = sbuffer; + for (uint32_t x = 0; x < w; ++x, ++dst, ++cmp, ++src) { + auto tmp = ALPHA_BLEND(*src, surface->blender.alpha(*cmp)); + *dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp)); + } + buffer += surface->stride; + cbuffer += surface->stride; + } + } else if (method == CompositeMethod::InvAlphaMask) { + for (uint32_t y = 0; y < h; ++y) { + fillFetchRadial(fill, sbuffer, region.min.y + y, region.min.x, w); + auto dst = buffer; + auto cmp = cbuffer; + auto src = sbuffer; + for (uint32_t x = 0; x < w; ++x, ++dst, ++cmp, ++src) { + auto tmp = ALPHA_BLEND(*src, 255 - surface->blender.alpha(*cmp)); + *dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp)); + } + buffer += surface->stride; + cbuffer += surface->stride; + } + } + } else { + for (uint32_t y = 0; y < h; ++y) { + auto dst = &buffer[y * surface->stride]; + fillFetchRadial(fill, dst, region.min.y + y, region.min.x, w); + } } } return true; @@ -796,18 +830,47 @@ static bool _rasterRadialGradientRle(SwSurface* surface, const SwRleData* rle, c } //Opaque Gradient } else { - for (uint32_t i = 0; i < rle->size; ++i) { - auto dst = &surface->buffer[span->y * surface->stride + span->x]; - if (span->coverage == 255) { - fillFetchRadial(fill, dst, span->y, span->x, span->len); - } else { - fillFetchRadial(fill, buf, span->y, span->x, span->len); - auto ialpha = 255 - span->coverage; - for (uint32_t i = 0; i < span->len; ++i) { - dst[i] = ALPHA_BLEND(buf[i], span->coverage) + ALPHA_BLEND(dst[i], ialpha); + if (surface->compositor) { + auto method = surface->compositor->method; + auto cbuffer = surface->compositor->image.data; + + if (method == CompositeMethod::AlphaMask) { + for (uint32_t i = 0; i < rle->size; ++i, ++span) { + fillFetchRadial(fill, buf, span->y, span->x, span->len); + auto dst = &surface->buffer[span->y * surface->stride + span->x]; + auto cmp = &cbuffer[span->y * surface->stride + span->x]; + auto src = buf; + for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) { + auto tmp = ALPHA_BLEND(*src, surface->blender.alpha(*cmp)); + *dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp)); + } + } + } else if (method == CompositeMethod::InvAlphaMask) { + for (uint32_t i = 0; i < rle->size; ++i, ++span) { + fillFetchRadial(fill, buf, span->y, span->x, span->len); + auto dst = &surface->buffer[span->y * surface->stride + span->x]; + auto cmp = &cbuffer[span->y * surface->stride + span->x]; + auto src = buf; + for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) { + auto tmp = ALPHA_BLEND(*src, 255 - surface->blender.alpha(*cmp)); + *dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp)); + } } } - ++span; + } else { + for (uint32_t i = 0; i < rle->size; ++i) { + auto dst = &surface->buffer[span->y * surface->stride + span->x]; + if (span->coverage == 255) { + fillFetchRadial(fill, dst, span->y, span->x, span->len); + } else { + fillFetchRadial(fill, buf, span->y, span->x, span->len); + auto ialpha = 255 - span->coverage; + for (uint32_t i = 0; i < span->len; ++i) { + dst[i] = ALPHA_BLEND(buf[i], span->coverage) + ALPHA_BLEND(dst[i], ialpha); + } + } + ++span; + } } } return true; -- 2.7.4 From 3c1c128fded2ed58bc41da14efd8bb106e5a75e5 Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Wed, 7 Apr 2021 15:16:42 +0200 Subject: [PATCH 05/16] sw_engine raster: refactoring the gradient rastering functions The gradient rastering functions have been splitted into translucent and opaque. --- src/lib/sw_engine/tvgSwRaster.cpp | 448 +++++++++++++++++++++----------------- 1 file changed, 247 insertions(+), 201 deletions(-) diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index 632cb7d..2b15ba4 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -596,7 +596,7 @@ static bool _rasterImage(SwSurface* surface, const uint32_t *img, uint32_t w, ui /* Gradient */ /************************************************************************/ -static bool _rasterLinearGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill) +static bool _rasterTranslucentLinearGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill) { if (!fill || fill->linear.len < FLT_EPSILON) return false; @@ -604,64 +604,71 @@ static bool _rasterLinearGradientRect(SwSurface* surface, const SwBBox& region, auto h = static_cast(region.max.y - region.min.y); auto w = static_cast(region.max.x - region.min.x); - //Translucent Gradient - if (fill->translucent) { - auto tmpBuf = static_cast(alloca(surface->w * sizeof(uint32_t))); - if (!tmpBuf) return false; + auto tmpBuf = static_cast(alloca(surface->w * sizeof(uint32_t))); + if (!tmpBuf) return false; - for (uint32_t y = 0; y < h; ++y) { - auto dst = &buffer[y * surface->stride]; - fillFetchLinear(fill, tmpBuf, region.min.y + y, region.min.x, w); - for (uint32_t x = 0; x < w; ++x) { - dst[x] = tmpBuf[x] + ALPHA_BLEND(dst[x], 255 - surface->blender.alpha(tmpBuf[x])); - } + for (uint32_t y = 0; y < h; ++y) { + auto dst = &buffer[y * surface->stride]; + fillFetchLinear(fill, tmpBuf, region.min.y + y, region.min.x, w); + for (uint32_t x = 0; x < w; ++x) { + dst[x] = tmpBuf[x] + ALPHA_BLEND(dst[x], 255 - surface->blender.alpha(tmpBuf[x])); } - //Opaque Gradient - } else { - if (surface->compositor) { - auto method = surface->compositor->method; - auto cbuffer = surface->compositor->image.data + (region.min.y * surface->stride) + region.min.x; - auto sbuffer = static_cast(alloca(w * sizeof(uint32_t))); - if (!sbuffer) return false; - - if (method == CompositeMethod::AlphaMask) { - for (uint32_t y = 0; y < h; ++y) { - fillFetchLinear(fill, sbuffer, region.min.y + y, region.min.x, w); - auto dst = buffer; - auto cmp = cbuffer; - auto src = sbuffer; - for (uint32_t x = 0; x < w; ++x, ++dst, ++cmp, ++src) { - auto tmp = ALPHA_BLEND(*src, surface->blender.alpha(*cmp)); - *dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp)); - } - buffer += surface->stride; - cbuffer += surface->stride; - } - } else if (method == CompositeMethod::InvAlphaMask) { - for (uint32_t y = 0; y < h; ++y) { - fillFetchLinear(fill, sbuffer, region.min.y + y, region.min.x, w); - auto dst = buffer; - auto cmp = cbuffer; - auto src = sbuffer; - for (uint32_t x = 0; x < w; ++x, ++dst, ++cmp, ++src) { - auto tmp = ALPHA_BLEND(*src, 255 - surface->blender.alpha(*cmp)); - *dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp)); - } - buffer += surface->stride; - cbuffer += surface->stride; + } + return true; +} + + +static bool _rasterOpaqueLinearGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill) +{ + if (!fill || fill->linear.len < FLT_EPSILON) return false; + + auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x; + auto h = static_cast(region.max.y - region.min.y); + auto w = static_cast(region.max.x - region.min.x); + + if (surface->compositor) { + auto method = surface->compositor->method; + auto cbuffer = surface->compositor->image.data + (region.min.y * surface->stride) + region.min.x; + auto sbuffer = static_cast(alloca(w * sizeof(uint32_t))); + if (!sbuffer) return false; + + if (method == CompositeMethod::AlphaMask) { + for (uint32_t y = 0; y < h; ++y) { + fillFetchLinear(fill, sbuffer, region.min.y + y, region.min.x, w); + auto dst = buffer; + auto cmp = cbuffer; + auto src = sbuffer; + for (uint32_t x = 0; x < w; ++x, ++dst, ++cmp, ++src) { + auto tmp = ALPHA_BLEND(*src, surface->blender.alpha(*cmp)); + *dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp)); } + buffer += surface->stride; + cbuffer += surface->stride; } - } else { + } else if (method == CompositeMethod::InvAlphaMask) { for (uint32_t y = 0; y < h; ++y) { - fillFetchLinear(fill, buffer + y * surface->stride, region.min.y + y, region.min.x, w); + fillFetchLinear(fill, sbuffer, region.min.y + y, region.min.x, w); + auto dst = buffer; + auto cmp = cbuffer; + auto src = sbuffer; + for (uint32_t x = 0; x < w; ++x, ++dst, ++cmp, ++src) { + auto tmp = ALPHA_BLEND(*src, 255 - surface->blender.alpha(*cmp)); + *dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp)); + } + buffer += surface->stride; + cbuffer += surface->stride; } } + } else { + for (uint32_t y = 0; y < h; ++y) { + fillFetchLinear(fill, buffer + y * surface->stride, region.min.y + y, region.min.x, w); + } } return true; } -static bool _rasterRadialGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill) +static bool _rasterTranslucentRadialGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill) { if (!fill || fill->radial.a < FLT_EPSILON) return false; @@ -669,65 +676,101 @@ static bool _rasterRadialGradientRect(SwSurface* surface, const SwBBox& region, auto h = static_cast(region.max.y - region.min.y); auto w = static_cast(region.max.x - region.min.x); - //Translucent Gradient - if (fill->translucent) { - auto tmpBuf = static_cast(alloca(surface->w * sizeof(uint32_t))); - if (!tmpBuf) return false; + auto tmpBuf = static_cast(alloca(surface->w * sizeof(uint32_t))); + if (!tmpBuf) return false; - for (uint32_t y = 0; y < h; ++y) { - auto dst = &buffer[y * surface->stride]; - fillFetchRadial(fill, tmpBuf, region.min.y + y, region.min.x, w); - for (uint32_t x = 0; x < w; ++x) { - dst[x] = tmpBuf[x] + ALPHA_BLEND(dst[x], 255 - surface->blender.alpha(tmpBuf[x])); - } + for (uint32_t y = 0; y < h; ++y) { + auto dst = &buffer[y * surface->stride]; + fillFetchRadial(fill, tmpBuf, region.min.y + y, region.min.x, w); + for (uint32_t x = 0; x < w; ++x) { + dst[x] = tmpBuf[x] + ALPHA_BLEND(dst[x], 255 - surface->blender.alpha(tmpBuf[x])); } - //Opaque Gradient - } else { - if (surface->compositor) { - auto method = surface->compositor->method; - auto cbuffer = surface->compositor->image.data + (region.min.y * surface->stride) + region.min.x; - auto sbuffer = static_cast(alloca(w * sizeof(uint32_t))); - if (!sbuffer) return false; - - if (method == CompositeMethod::AlphaMask) { - for (uint32_t y = 0; y < h; ++y) { - fillFetchRadial(fill, sbuffer, region.min.y + y, region.min.x, w); - auto dst = buffer; - auto cmp = cbuffer; - auto src = sbuffer; - for (uint32_t x = 0; x < w; ++x, ++dst, ++cmp, ++src) { - auto tmp = ALPHA_BLEND(*src, surface->blender.alpha(*cmp)); - *dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp)); - } - buffer += surface->stride; - cbuffer += surface->stride; + } + return true; +} + + +static bool _rasterOpaqueRadialGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill) +{ + if (!fill || fill->radial.a < FLT_EPSILON) return false; + + auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x; + auto h = static_cast(region.max.y - region.min.y); + auto w = static_cast(region.max.x - region.min.x); + + if (surface->compositor) { + auto method = surface->compositor->method; + auto cbuffer = surface->compositor->image.data + (region.min.y * surface->stride) + region.min.x; + auto sbuffer = static_cast(alloca(w * sizeof(uint32_t))); + if (!sbuffer) return false; + + if (method == CompositeMethod::AlphaMask) { + for (uint32_t y = 0; y < h; ++y) { + fillFetchRadial(fill, sbuffer, region.min.y + y, region.min.x, w); + auto dst = buffer; + auto cmp = cbuffer; + auto src = sbuffer; + for (uint32_t x = 0; x < w; ++x, ++dst, ++cmp, ++src) { + auto tmp = ALPHA_BLEND(*src, surface->blender.alpha(*cmp)); + *dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp)); } - } else if (method == CompositeMethod::InvAlphaMask) { - for (uint32_t y = 0; y < h; ++y) { - fillFetchRadial(fill, sbuffer, region.min.y + y, region.min.x, w); - auto dst = buffer; - auto cmp = cbuffer; - auto src = sbuffer; - for (uint32_t x = 0; x < w; ++x, ++dst, ++cmp, ++src) { - auto tmp = ALPHA_BLEND(*src, 255 - surface->blender.alpha(*cmp)); - *dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp)); - } - buffer += surface->stride; - cbuffer += surface->stride; + buffer += surface->stride; + cbuffer += surface->stride; + } + } else if (method == CompositeMethod::InvAlphaMask) { + for (uint32_t y = 0; y < h; ++y) { + fillFetchRadial(fill, sbuffer, region.min.y + y, region.min.x, w); + auto dst = buffer; + auto cmp = cbuffer; + auto src = sbuffer; + for (uint32_t x = 0; x < w; ++x, ++dst, ++cmp, ++src) { + auto tmp = ALPHA_BLEND(*src, 255 - surface->blender.alpha(*cmp)); + *dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp)); } + buffer += surface->stride; + cbuffer += surface->stride; + } + } + } else { + for (uint32_t y = 0; y < h; ++y) { + auto dst = &buffer[y * surface->stride]; + fillFetchRadial(fill, dst, region.min.y + y, region.min.x, w); + } + } + + return true; +} + + +static bool _rasterTranslucentLinearGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill) +{ + if (!rle || !fill || fill->linear.len < FLT_EPSILON) return false; + + auto buf = static_cast(alloca(surface->w * sizeof(uint32_t))); + if (!buf) return false; + + auto span = rle->spans; + + for (uint32_t i = 0; i < rle->size; ++i) { + auto dst = &surface->buffer[span->y * surface->stride + span->x]; + fillFetchLinear(fill, buf, span->y, span->x, span->len); + if (span->coverage == 255) { + for (uint32_t i = 0; i < span->len; ++i) { + dst[i] = buf[i] + ALPHA_BLEND(dst[i], 255 - surface->blender.alpha(buf[i])); } } else { - for (uint32_t y = 0; y < h; ++y) { - auto dst = &buffer[y * surface->stride]; - fillFetchRadial(fill, dst, region.min.y + y, region.min.x, w); + for (uint32_t i = 0; i < span->len; ++i) { + auto tmp = ALPHA_BLEND(buf[i], span->coverage); + dst[i] = tmp + ALPHA_BLEND(dst[i], 255 - surface->blender.alpha(tmp)); } } + ++span; } return true; } -static bool _rasterLinearGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill) +static bool _rasterOpaqueLinearGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill) { if (!rle || !fill || fill->linear.len < FLT_EPSILON) return false; @@ -736,73 +779,81 @@ static bool _rasterLinearGradientRle(SwSurface* surface, const SwRleData* rle, c auto span = rle->spans; - //Translucent Gradient - if (fill->translucent) { + if (surface->compositor) { + auto method = surface->compositor->method; + auto cbuffer = surface->compositor->image.data; + + if (method == CompositeMethod::AlphaMask) { + for (uint32_t i = 0; i < rle->size; ++i, ++span) { + fillFetchLinear(fill, buf, span->y, span->x, span->len); + auto dst = &surface->buffer[span->y * surface->stride + span->x]; + auto cmp = &cbuffer[span->y * surface->stride + span->x]; + auto src = buf; + for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) { + auto tmp = ALPHA_BLEND(*src, surface->blender.alpha(*cmp)); + *dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp)); + } + } + } else if (method == CompositeMethod::InvAlphaMask) { + for (uint32_t i = 0; i < rle->size; ++i, ++span) { + fillFetchLinear(fill, buf, span->y, span->x, span->len); + auto dst = &surface->buffer[span->y * surface->stride + span->x]; + auto cmp = &cbuffer[span->y * surface->stride + span->x]; + auto src = buf; + for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) { + auto tmp = ALPHA_BLEND(*src, 255 - surface->blender.alpha(*cmp)); + *dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp)); + } + } + } + } else { for (uint32_t i = 0; i < rle->size; ++i) { - auto dst = &surface->buffer[span->y * surface->stride + span->x]; - fillFetchLinear(fill, buf, span->y, span->x, span->len); if (span->coverage == 255) { - for (uint32_t i = 0; i < span->len; ++i) { - dst[i] = buf[i] + ALPHA_BLEND(dst[i], 255 - surface->blender.alpha(buf[i])); - } + fillFetchLinear(fill, surface->buffer + span->y * surface->stride + span->x, span->y, span->x, span->len); } else { + fillFetchLinear(fill, buf, span->y, span->x, span->len); + auto ialpha = 255 - span->coverage; + auto dst = &surface->buffer[span->y * surface->stride + span->x]; for (uint32_t i = 0; i < span->len; ++i) { - auto tmp = ALPHA_BLEND(buf[i], span->coverage); - dst[i] = tmp + ALPHA_BLEND(dst[i], 255 - surface->blender.alpha(tmp)); + dst[i] = ALPHA_BLEND(buf[i], span->coverage) + ALPHA_BLEND(dst[i], ialpha); } } ++span; } - //Opaque Gradient - } else { - if (surface->compositor) { - auto method = surface->compositor->method; - auto cbuffer = surface->compositor->image.data; - - if (method == CompositeMethod::AlphaMask) { - for (uint32_t i = 0; i < rle->size; ++i, ++span) { - fillFetchLinear(fill, buf, span->y, span->x, span->len); - auto dst = &surface->buffer[span->y * surface->stride + span->x]; - auto cmp = &cbuffer[span->y * surface->stride + span->x]; - auto src = buf; - for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) { - auto tmp = ALPHA_BLEND(*src, surface->blender.alpha(*cmp)); - *dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp)); - } - } - } else if (method == CompositeMethod::InvAlphaMask) { - for (uint32_t i = 0; i < rle->size; ++i, ++span) { - fillFetchLinear(fill, buf, span->y, span->x, span->len); - auto dst = &surface->buffer[span->y * surface->stride + span->x]; - auto cmp = &cbuffer[span->y * surface->stride + span->x]; - auto src = buf; - for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) { - auto tmp = ALPHA_BLEND(*src, 255 - surface->blender.alpha(*cmp)); - *dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp)); - } - } + } + return true; +} + + +static bool _rasterTranslucentRadialGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill) +{ + if (!rle || !fill || fill->radial.a < FLT_EPSILON) return false; + + auto buf = static_cast(alloca(surface->w * sizeof(uint32_t))); + if (!buf) return false; + + auto span = rle->spans; + + for (uint32_t i = 0; i < rle->size; ++i) { + auto dst = &surface->buffer[span->y * surface->stride + span->x]; + fillFetchRadial(fill, buf, span->y, span->x, span->len); + if (span->coverage == 255) { + for (uint32_t i = 0; i < span->len; ++i) { + dst[i] = buf[i] + ALPHA_BLEND(dst[i], 255 - surface->blender.alpha(buf[i])); } } else { - for (uint32_t i = 0; i < rle->size; ++i) { - if (span->coverage == 255) { - fillFetchLinear(fill, surface->buffer + span->y * surface->stride + span->x, span->y, span->x, span->len); - } else { - fillFetchLinear(fill, buf, span->y, span->x, span->len); - auto ialpha = 255 - span->coverage; - auto dst = &surface->buffer[span->y * surface->stride + span->x]; - for (uint32_t i = 0; i < span->len; ++i) { - dst[i] = ALPHA_BLEND(buf[i], span->coverage) + ALPHA_BLEND(dst[i], ialpha); - } - } - ++span; + for (uint32_t i = 0; i < span->len; ++i) { + auto tmp = ALPHA_BLEND(buf[i], span->coverage); + dst[i] = tmp + ALPHA_BLEND(dst[i], 255 - surface->blender.alpha(tmp)); } } + ++span; } return true; } -static bool _rasterRadialGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill) +static bool _rasterOpaqueRadialGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill) { if (!rle || !fill || fill->radial.a < FLT_EPSILON) return false; @@ -811,67 +862,47 @@ static bool _rasterRadialGradientRle(SwSurface* surface, const SwRleData* rle, c auto span = rle->spans; - //Translucent Gradient - if (fill->translucent) { + if (surface->compositor) { + auto method = surface->compositor->method; + auto cbuffer = surface->compositor->image.data; + + if (method == CompositeMethod::AlphaMask) { + for (uint32_t i = 0; i < rle->size; ++i, ++span) { + fillFetchRadial(fill, buf, span->y, span->x, span->len); + auto dst = &surface->buffer[span->y * surface->stride + span->x]; + auto cmp = &cbuffer[span->y * surface->stride + span->x]; + auto src = buf; + for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) { + auto tmp = ALPHA_BLEND(*src, surface->blender.alpha(*cmp)); + *dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp)); + } + } + } else if (method == CompositeMethod::InvAlphaMask) { + for (uint32_t i = 0; i < rle->size; ++i, ++span) { + fillFetchRadial(fill, buf, span->y, span->x, span->len); + auto dst = &surface->buffer[span->y * surface->stride + span->x]; + auto cmp = &cbuffer[span->y * surface->stride + span->x]; + auto src = buf; + for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) { + auto tmp = ALPHA_BLEND(*src, 255 - surface->blender.alpha(*cmp)); + *dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp)); + } + } + } + } else { for (uint32_t i = 0; i < rle->size; ++i) { auto dst = &surface->buffer[span->y * surface->stride + span->x]; - fillFetchRadial(fill, buf, span->y, span->x, span->len); if (span->coverage == 255) { - for (uint32_t i = 0; i < span->len; ++i) { - dst[i] = buf[i] + ALPHA_BLEND(dst[i], 255 - surface->blender.alpha(buf[i])); - } + fillFetchRadial(fill, dst, span->y, span->x, span->len); } else { + fillFetchRadial(fill, buf, span->y, span->x, span->len); + auto ialpha = 255 - span->coverage; for (uint32_t i = 0; i < span->len; ++i) { - auto tmp = ALPHA_BLEND(buf[i], span->coverage); - dst[i] = tmp + ALPHA_BLEND(dst[i], 255 - surface->blender.alpha(tmp)); + dst[i] = ALPHA_BLEND(buf[i], span->coverage) + ALPHA_BLEND(dst[i], ialpha); } } ++span; } - //Opaque Gradient - } else { - if (surface->compositor) { - auto method = surface->compositor->method; - auto cbuffer = surface->compositor->image.data; - - if (method == CompositeMethod::AlphaMask) { - for (uint32_t i = 0; i < rle->size; ++i, ++span) { - fillFetchRadial(fill, buf, span->y, span->x, span->len); - auto dst = &surface->buffer[span->y * surface->stride + span->x]; - auto cmp = &cbuffer[span->y * surface->stride + span->x]; - auto src = buf; - for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) { - auto tmp = ALPHA_BLEND(*src, surface->blender.alpha(*cmp)); - *dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp)); - } - } - } else if (method == CompositeMethod::InvAlphaMask) { - for (uint32_t i = 0; i < rle->size; ++i, ++span) { - fillFetchRadial(fill, buf, span->y, span->x, span->len); - auto dst = &surface->buffer[span->y * surface->stride + span->x]; - auto cmp = &cbuffer[span->y * surface->stride + span->x]; - auto src = buf; - for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) { - auto tmp = ALPHA_BLEND(*src, 255 - surface->blender.alpha(*cmp)); - *dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp)); - } - } - } - } else { - for (uint32_t i = 0; i < rle->size; ++i) { - auto dst = &surface->buffer[span->y * surface->stride + span->x]; - if (span->coverage == 255) { - fillFetchRadial(fill, dst, span->y, span->x, span->len); - } else { - fillFetchRadial(fill, buf, span->y, span->x, span->len); - auto ialpha = 255 - span->coverage; - for (uint32_t i = 0; i < span->len; ++i) { - dst[i] = ALPHA_BLEND(buf[i], span->coverage) + ALPHA_BLEND(dst[i], ialpha); - } - } - ++span; - } - } } return true; } @@ -902,11 +933,21 @@ bool rasterGradientShape(SwSurface* surface, SwShape* shape, unsigned id) { //Fast Track if (shape->rect) { - if (id == FILL_ID_LINEAR) return _rasterLinearGradientRect(surface, shape->bbox, shape->fill); - return _rasterRadialGradientRect(surface, shape->bbox, shape->fill); + if (id == FILL_ID_LINEAR) { + if (shape->fill->translucent) return _rasterTranslucentLinearGradientRect(surface, shape->bbox, shape->fill); + return _rasterOpaqueLinearGradientRect(surface, shape->bbox, shape->fill); + } else { + if (shape->fill->translucent) return _rasterTranslucentRadialGradientRect(surface, shape->bbox, shape->fill); + return _rasterOpaqueRadialGradientRect(surface, shape->bbox, shape->fill); + } } else { - if (id == FILL_ID_LINEAR) return _rasterLinearGradientRle(surface, shape->rle, shape->fill); - return _rasterRadialGradientRle(surface, shape->rle, shape->fill); + if (id == FILL_ID_LINEAR) { + if (shape->fill->translucent) return _rasterTranslucentLinearGradientRle(surface, shape->rle, shape->fill); + return _rasterOpaqueLinearGradientRle(surface, shape->rle, shape->fill); + } else { + if (shape->fill->translucent) return _rasterTranslucentRadialGradientRle(surface, shape->rle, shape->fill); + return _rasterOpaqueRadialGradientRle(surface, shape->rle, shape->fill); + } } return false; } @@ -953,8 +994,13 @@ bool rasterStroke(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint bool rasterGradientStroke(SwSurface* surface, SwShape* shape, unsigned id) { - if (id == FILL_ID_LINEAR) return _rasterLinearGradientRle(surface, shape->strokeRle, shape->stroke->fill); - return _rasterRadialGradientRle(surface, shape->strokeRle, shape->stroke->fill); + if (id == FILL_ID_LINEAR) { + if (shape->fill->translucent) return _rasterTranslucentLinearGradientRle(surface, shape->strokeRle, shape->stroke->fill); + return _rasterOpaqueLinearGradientRle(surface, shape->strokeRle, shape->stroke->fill); + } else { + if (shape->fill->translucent) return _rasterTranslucentRadialGradientRle(surface, shape->strokeRle, shape->stroke->fill); + return _rasterOpaqueRadialGradientRle(surface, shape->strokeRle, shape->stroke->fill); + } return false; } -- 2.7.4 From 8e9067c8251f1a89e7b0b0f3cf98dd7e4a8cd218 Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Wed, 7 Apr 2021 15:29:22 +0200 Subject: [PATCH 06/16] sw_engine raster: adding antialiasing to the gradient rastering functions The gradient rastering functions with composition did not take antialiasing into account. The missing part has been added. --- src/lib/sw_engine/tvgSwRaster.cpp | 62 +++++++++++++++++++++++++++++++-------- 1 file changed, 49 insertions(+), 13 deletions(-) diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index 2b15ba4..4a0e71b 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -754,7 +754,7 @@ static bool _rasterTranslucentLinearGradientRle(SwSurface* surface, const SwRleD for (uint32_t i = 0; i < rle->size; ++i) { auto dst = &surface->buffer[span->y * surface->stride + span->x]; fillFetchLinear(fill, buf, span->y, span->x, span->len); - if (span->coverage == 255) { + if (span->coverage == 255) { for (uint32_t i = 0; i < span->len; ++i) { dst[i] = buf[i] + ALPHA_BLEND(dst[i], 255 - surface->blender.alpha(buf[i])); } @@ -789,9 +789,18 @@ static bool _rasterOpaqueLinearGradientRle(SwSurface* surface, const SwRleData* auto dst = &surface->buffer[span->y * surface->stride + span->x]; auto cmp = &cbuffer[span->y * surface->stride + span->x]; auto src = buf; - for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) { - auto tmp = ALPHA_BLEND(*src, surface->blender.alpha(*cmp)); - *dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp)); + if (span->coverage == 255) { + for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) { + auto tmp = ALPHA_BLEND(*src, surface->blender.alpha(*cmp)); + *dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp)); + } + } else { + auto ialpha = 255 - span->coverage; + for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) { + auto tmp = ALPHA_BLEND(*src, surface->blender.alpha(*cmp)); + tmp = ALPHA_BLEND(tmp, span->coverage) + ALPHA_BLEND(*dst, ialpha); + *dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp)); + } } } } else if (method == CompositeMethod::InvAlphaMask) { @@ -800,9 +809,18 @@ static bool _rasterOpaqueLinearGradientRle(SwSurface* surface, const SwRleData* auto dst = &surface->buffer[span->y * surface->stride + span->x]; auto cmp = &cbuffer[span->y * surface->stride + span->x]; auto src = buf; - for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) { - auto tmp = ALPHA_BLEND(*src, 255 - surface->blender.alpha(*cmp)); - *dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp)); + if (span->coverage == 255) { + for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) { + auto tmp = ALPHA_BLEND(*src, 255 - surface->blender.alpha(*cmp)); + *dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp)); + } + } else { + auto ialpha = 255 - span->coverage; + for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) { + auto tmp = ALPHA_BLEND(*src, 255 - surface->blender.alpha(*cmp)); + tmp = ALPHA_BLEND(tmp, span->coverage) + ALPHA_BLEND(*dst, ialpha); + *dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp)); + } } } } @@ -872,9 +890,18 @@ static bool _rasterOpaqueRadialGradientRle(SwSurface* surface, const SwRleData* auto dst = &surface->buffer[span->y * surface->stride + span->x]; auto cmp = &cbuffer[span->y * surface->stride + span->x]; auto src = buf; - for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) { - auto tmp = ALPHA_BLEND(*src, surface->blender.alpha(*cmp)); - *dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp)); + if (span->coverage == 255) { + for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) { + auto tmp = ALPHA_BLEND(*src, surface->blender.alpha(*cmp)); + *dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp)); + } + } else { + auto ialpha = 255 - span->coverage; + for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) { + auto tmp = ALPHA_BLEND(*src, surface->blender.alpha(*cmp)); + tmp = ALPHA_BLEND(tmp, span->coverage) + ALPHA_BLEND(*dst, ialpha); + *dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp)); + } } } } else if (method == CompositeMethod::InvAlphaMask) { @@ -883,9 +910,18 @@ static bool _rasterOpaqueRadialGradientRle(SwSurface* surface, const SwRleData* auto dst = &surface->buffer[span->y * surface->stride + span->x]; auto cmp = &cbuffer[span->y * surface->stride + span->x]; auto src = buf; - for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) { - auto tmp = ALPHA_BLEND(*src, 255 - surface->blender.alpha(*cmp)); - *dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp)); + if (span->coverage == 255) { + for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) { + auto tmp = ALPHA_BLEND(*src, 255 - surface->blender.alpha(*cmp)); + *dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp)); + } + } else { + auto ialpha = 255 - span->coverage; + for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp, ++src) { + auto tmp = ALPHA_BLEND(*src, 255 - surface->blender.alpha(*cmp)); + tmp = ALPHA_BLEND(tmp, span->coverage) + ALPHA_BLEND(*dst, ialpha); + *dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp)); + } } } } -- 2.7.4 From 2768d0284d7f649512c8f11b31fc48db38271bb2 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 8 Apr 2021 14:15:23 +0900 Subject: [PATCH 07/16] sw_engine: fix GradientStroke crash ++ strict null check. --- src/lib/sw_engine/tvgSwRaster.cpp | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index 4a0e71b..b9ab35c 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -598,7 +598,7 @@ static bool _rasterImage(SwSurface* surface, const uint32_t *img, uint32_t w, ui static bool _rasterTranslucentLinearGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill) { - if (!fill || fill->linear.len < FLT_EPSILON) return false; + if (fill->linear.len < FLT_EPSILON) return false; auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x; auto h = static_cast(region.max.y - region.min.y); @@ -620,7 +620,7 @@ static bool _rasterTranslucentLinearGradientRect(SwSurface* surface, const SwBBo static bool _rasterOpaqueLinearGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill) { - if (!fill || fill->linear.len < FLT_EPSILON) return false; + if (fill->linear.len < FLT_EPSILON) return false; auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x; auto h = static_cast(region.max.y - region.min.y); @@ -670,7 +670,7 @@ static bool _rasterOpaqueLinearGradientRect(SwSurface* surface, const SwBBox& re static bool _rasterTranslucentRadialGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill) { - if (!fill || fill->radial.a < FLT_EPSILON) return false; + if (fill->radial.a < FLT_EPSILON) return false; auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x; auto h = static_cast(region.max.y - region.min.y); @@ -692,7 +692,7 @@ static bool _rasterTranslucentRadialGradientRect(SwSurface* surface, const SwBBo static bool _rasterOpaqueRadialGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill) { - if (!fill || fill->radial.a < FLT_EPSILON) return false; + if (fill->radial.a < FLT_EPSILON) return false; auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x; auto h = static_cast(region.max.y - region.min.y); @@ -744,7 +744,7 @@ static bool _rasterOpaqueRadialGradientRect(SwSurface* surface, const SwBBox& re static bool _rasterTranslucentLinearGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill) { - if (!rle || !fill || fill->linear.len < FLT_EPSILON) return false; + if (fill->linear.len < FLT_EPSILON) return false; auto buf = static_cast(alloca(surface->w * sizeof(uint32_t))); if (!buf) return false; @@ -772,7 +772,7 @@ static bool _rasterTranslucentLinearGradientRle(SwSurface* surface, const SwRleD static bool _rasterOpaqueLinearGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill) { - if (!rle || !fill || fill->linear.len < FLT_EPSILON) return false; + if (fill->linear.len < FLT_EPSILON) return false; auto buf = static_cast(alloca(surface->w * sizeof(uint32_t))); if (!buf) return false; @@ -845,7 +845,7 @@ static bool _rasterOpaqueLinearGradientRle(SwSurface* surface, const SwRleData* static bool _rasterTranslucentRadialGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill) { - if (!rle || !fill || fill->radial.a < FLT_EPSILON) return false; + if (fill->radial.a < FLT_EPSILON) return false; auto buf = static_cast(alloca(surface->w * sizeof(uint32_t))); if (!buf) return false; @@ -873,7 +873,7 @@ static bool _rasterTranslucentRadialGradientRle(SwSurface* surface, const SwRleD static bool _rasterOpaqueRadialGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill) { - if (!rle || !fill || fill->radial.a < FLT_EPSILON) return false; + if (fill->radial.a < FLT_EPSILON) return false; auto buf = static_cast(alloca(surface->w * sizeof(uint32_t))); if (!buf) return false; @@ -967,6 +967,8 @@ bool rasterCompositor(SwSurface* surface) bool rasterGradientShape(SwSurface* surface, SwShape* shape, unsigned id) { + if (!shape->fill) return false; + //Fast Track if (shape->rect) { if (id == FILL_ID_LINEAR) { @@ -977,6 +979,7 @@ bool rasterGradientShape(SwSurface* surface, SwShape* shape, unsigned id) return _rasterOpaqueRadialGradientRect(surface, shape->bbox, shape->fill); } } else { + if (!shape->rle) return false; if (id == FILL_ID_LINEAR) { if (shape->fill->translucent) return _rasterTranslucentLinearGradientRle(surface, shape->rle, shape->fill); return _rasterOpaqueLinearGradientRle(surface, shape->rle, shape->fill); @@ -1030,11 +1033,13 @@ bool rasterStroke(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint bool rasterGradientStroke(SwSurface* surface, SwShape* shape, unsigned id) { + if (!shape->stroke->fill || !shape->strokeRle) return false; + if (id == FILL_ID_LINEAR) { - if (shape->fill->translucent) return _rasterTranslucentLinearGradientRle(surface, shape->strokeRle, shape->stroke->fill); + if (shape->fill && shape->fill->translucent) return _rasterTranslucentLinearGradientRle(surface, shape->strokeRle, shape->stroke->fill); return _rasterOpaqueLinearGradientRle(surface, shape->strokeRle, shape->stroke->fill); } else { - if (shape->fill->translucent) return _rasterTranslucentRadialGradientRle(surface, shape->strokeRle, shape->stroke->fill); + if (shape->fill && shape->fill->translucent) return _rasterTranslucentRadialGradientRle(surface, shape->strokeRle, shape->stroke->fill); return _rasterOpaqueRadialGradientRle(surface, shape->strokeRle, shape->stroke->fill); } -- 2.7.4 From 42281826df99a10ab424b580bb5cbbd55b55fa56 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 8 Apr 2021 17:39:51 +0900 Subject: [PATCH 08/16] loaders svg: fix invalid clip path result. tvg engine expects the valid clippath with valid colors, loaders set any colors values to enable it. this fixes invalid clippath behavior. --- src/loaders/svg/tvgSvgSceneBuilder.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/loaders/svg/tvgSvgSceneBuilder.cpp b/src/loaders/svg/tvgSvgSceneBuilder.cpp index 9c79c3b..a3299de 100644 --- a/src/loaders/svg/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg/tvgSvgSceneBuilder.cpp @@ -271,6 +271,7 @@ void _applyProperty(SvgNode* node, Shape* vg, float vx, float vy, float vw, floa auto comp = Shape::gen(); auto child = compNode->child.data; for (uint32_t i = 0; i < compNode->child.count; ++i, ++child) _appendChildShape(*child, comp.get(), vx, vy, vw, vh); + comp->fill(0, 0, 0, 255); vg->composite(move(comp), CompositeMethod::ClipPath); } } @@ -375,6 +376,7 @@ unique_ptr _sceneBuildHelper(const SvgNode* node, float vx, float vy, flo auto comp = Shape::gen(); auto child = compNode->child.data; for (uint32_t i = 0; i < compNode->child.count; ++i, ++child) _appendChildShape(*child, comp.get(), vx, vy, vw, vh); + comp->fill(0, 0, 0, 255); scene->composite(move(comp), CompositeMethod::ClipPath); } } -- 2.7.4 From b8200bebf8a33ae52a57113024f9bf9c25ec4ab9 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 8 Apr 2021 20:47:57 +0900 Subject: [PATCH 09/16] loaders svg: code refactoring ++ clean code. --- src/loaders/svg/tvgSvgLoader.cpp | 6 +-- src/loaders/svg/tvgSvgLoaderCommon.h | 7 +--- src/loaders/svg/tvgSvgSceneBuilder.cpp | 68 +++++++++++----------------------- 3 files changed, 25 insertions(+), 56 deletions(-) diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index 1a487a7..25c7a42 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -858,8 +858,7 @@ static void _handleTransformAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node static void _handleClipPathAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, const char* value) { SvgStyleProperty* style = node->style; - style->comp.flags = (SvgCompositeFlags)((int)style->comp.flags | (int)SvgCompositeFlags::ClipPath); - + style->comp.method = CompositeMethod::ClipPath; int len = strlen(value); if (len >= 3 && !strncmp(value, "url", 3)) style->comp.url = _idFromUrl((const char*)(value + 3)); } @@ -867,8 +866,7 @@ static void _handleClipPathAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, static void _handleMaskAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, const char* value) { SvgStyleProperty* style = node->style; - style->comp.flags = (SvgCompositeFlags)((int)style->comp.flags | (int)SvgCompositeFlags::AlphaMask); - + style->comp.method = CompositeMethod::AlphaMask; int len = strlen(value); if (len >= 3 && !strncmp(value, "url", 3)) style->comp.url = _idFromUrl((const char*)(value + 3)); } diff --git a/src/loaders/svg/tvgSvgLoaderCommon.h b/src/loaders/svg/tvgSvgLoaderCommon.h index f985b24..b639efe 100644 --- a/src/loaders/svg/tvgSvgLoaderCommon.h +++ b/src/loaders/svg/tvgSvgLoaderCommon.h @@ -62,11 +62,6 @@ enum class SvgLengthType In, }; -enum class SvgCompositeFlags -{ - ClipPath = 0x01, - AlphaMask = 0x02, -}; enum class SvgFillFlags { @@ -227,7 +222,7 @@ struct SvgGradientStop struct SvgComposite { - SvgCompositeFlags flags; + CompositeMethod method; //TODO: Currently support either one method string *url; SvgNode* node; }; diff --git a/src/loaders/svg/tvgSvgSceneBuilder.cpp b/src/loaders/svg/tvgSvgSceneBuilder.cpp index a3299de..aa45fab 100644 --- a/src/loaders/svg/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg/tvgSvgSceneBuilder.cpp @@ -203,6 +203,7 @@ void _appendChildShape(SvgNode* node, Shape* shape, float vx, float vy, float vw } } + void _applyProperty(SvgNode* node, Shape* vg, float vx, float vy, float vw, float vh) { SvgStyleProperty* style = node->style; @@ -243,8 +244,9 @@ void _applyProperty(SvgNode* node, Shape* vg, float vx, float vy, float vw, floa vg->stroke(style->stroke.width); vg->stroke(style->stroke.cap); vg->stroke(style->stroke.join); - if (style->stroke.dash.array.count > 0) + if (style->stroke.dash.array.count > 0) { vg->stroke(style->stroke.dash.array.data, style->stroke.dash.array.count); + } //If stroke property is nullptr then do nothing if (style->stroke.paint.none) { @@ -256,34 +258,20 @@ void _applyProperty(SvgNode* node, Shape* vg, float vx, float vy, float vw, floa } else if (style->stroke.paint.curColor) { //Apply the current style color vg->stroke(style->r, style->g, style->b, style->stroke.opacity); - } else { //Apply the stroke color vg->stroke(style->stroke.paint.r, style->stroke.paint.g, style->stroke.paint.b, style->stroke.opacity); } //Apply composite node - if (style->comp.node) { - //Composite ClipPath - if (((int)style->comp.flags & (int)SvgCompositeFlags::ClipPath)) { - auto compNode = style->comp.node; - if (compNode->child.count > 0) { - auto comp = Shape::gen(); - auto child = compNode->child.data; - for (uint32_t i = 0; i < compNode->child.count; ++i, ++child) _appendChildShape(*child, comp.get(), vx, vy, vw, vh); - comp->fill(0, 0, 0, 255); - vg->composite(move(comp), CompositeMethod::ClipPath); - } - } - //Composite Alpha Mask - if (((int)style->comp.flags & (int)SvgCompositeFlags::AlphaMask)) { - auto compNode = style->comp.node; - if (compNode->child.count > 0) { - auto comp = Shape::gen(); - auto child = compNode->child.data; - for (uint32_t i = 0; i < compNode->child.count; ++i, ++child) _appendChildShape(*child, comp.get(), vx, vy, vw, vh); - vg->composite(move(comp), CompositeMethod::AlphaMask); - } + if (style->comp.node && (style->comp.method != CompositeMethod::None)) { + auto compNode = style->comp.node; + if (compNode->child.count > 0) { + auto comp = Shape::gen(); + auto child = compNode->child.data; + for (uint32_t i = 0; i < compNode->child.count; ++i, ++child) _appendChildShape(*child, comp.get(), vx, vy, vw, vh); + if (style->comp.method == CompositeMethod::ClipPath) comp->fill(0, 0, 0, 255); + vg->composite(move(comp), style->comp.method); } } } @@ -303,8 +291,9 @@ bool _appendShape(SvgNode* node, Shape* shape, float vx, float vy, float vw, flo switch (node->type) { case SvgNodeType::Path: { if (node->node.path.path) { - if (svgPathToTvgPath(node->node.path.path->c_str(), cmds, pts)) + if (svgPathToTvgPath(node->node.path.path->c_str(), cmds, pts)) { shape->appendPath(cmds.data, cmds.count, pts.data, pts.count); + } } break; } @@ -368,27 +357,14 @@ unique_ptr _sceneBuildHelper(const SvgNode* node, float vx, float vy, flo } } //Apply composite node - if (node->style->comp.node) { - //Composite ClipPath - if (((int)node->style->comp.flags & (int)SvgCompositeFlags::ClipPath)) { - auto compNode = node->style->comp.node; - if (compNode->child.count > 0) { - auto comp = Shape::gen(); - auto child = compNode->child.data; - for (uint32_t i = 0; i < compNode->child.count; ++i, ++child) _appendChildShape(*child, comp.get(), vx, vy, vw, vh); - comp->fill(0, 0, 0, 255); - scene->composite(move(comp), CompositeMethod::ClipPath); - } - } - //Composite AlphaMask - if (((int)node->style->comp.flags & (int)SvgCompositeFlags::AlphaMask)) { - auto compNode = node->style->comp.node; - if (compNode->child.count > 0) { - auto comp = Shape::gen(); - auto child = compNode->child.data; - for (uint32_t i = 0; i < compNode->child.count; ++i, ++child) _appendChildShape(*child, comp.get(), vx, vy, vw, vh); - scene->composite(move(comp), CompositeMethod::AlphaMask); - } + if (node->style->comp.node && (node->style->comp.method != CompositeMethod::None)) { + auto compNode = node->style->comp.node; + if (compNode->child.count > 0) { + auto comp = Shape::gen(); + auto child = compNode->child.data; + for (uint32_t i = 0; i < compNode->child.count; ++i, ++child) _appendChildShape(*child, comp.get(), vx, vy, vw, vh); + if (node->style->comp.method == CompositeMethod::ClipPath) comp->fill(0, 0, 0, 255); + scene->composite(move(comp), node->style->comp.method); } } scene->opacity(node->style->opacity); @@ -412,7 +388,7 @@ unique_ptr _buildRoot(const SvgNode* node, float vx, float vy, float vw, viewBoxClip->fill(0, 0, 0, 255); auto compositeLayer = Scene::gen(); - compositeLayer->composite(move(viewBoxClip), tvg::CompositeMethod::ClipPath); + compositeLayer->composite(move(viewBoxClip), CompositeMethod::ClipPath); compositeLayer->push(move(docNode)); root = Scene::gen(); -- 2.7.4 From d7ce02941efa53f543d376667a0617f1df5f7add Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Fri, 9 Apr 2021 11:02:35 +0900 Subject: [PATCH 10/16] loaders svg: ++ log info for wrong situation. if either log is printed, we need to improve the composition method. --- src/loaders/svg/tvgSvgLoader.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index 25c7a42..dcb69d2 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -858,6 +858,9 @@ static void _handleTransformAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node static void _handleClipPathAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, const char* value) { SvgStyleProperty* style = node->style; +#ifdef THORVG_LOG_ENABLED + if (style->comp.method != CompositeMethod::None) printf("SVG: Multiple Composition Tried!\n"); +#endif style->comp.method = CompositeMethod::ClipPath; int len = strlen(value); if (len >= 3 && !strncmp(value, "url", 3)) style->comp.url = _idFromUrl((const char*)(value + 3)); @@ -866,6 +869,9 @@ static void _handleClipPathAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, static void _handleMaskAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, const char* value) { SvgStyleProperty* style = node->style; +#ifdef THORVG_LOG_ENABLED + if (style->comp.method != CompositeMethod::None) printf("SVG: Multiple Composition Tried!\n"); +#endif style->comp.method = CompositeMethod::AlphaMask; int len = strlen(value); if (len >= 3 && !strncmp(value, "url", 3)) style->comp.url = _idFromUrl((const char*)(value + 3)); -- 2.7.4 From d17b400e8f5542c9f88e81661343023425eea873 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Fri, 9 Apr 2021 15:34:34 +0900 Subject: [PATCH 11/16] loaders svg: code refactoring clean up code and remove unnecessary internal class. this also helps to reduce binary size by 5.5kb no logical changes. --- src/loaders/svg/tvgSvgLoader.cpp | 15 ++++---- src/loaders/svg/tvgSvgLoader.h | 3 +- src/loaders/svg/tvgSvgPath.cpp | 13 +++++-- src/loaders/svg/tvgSvgPath.h | 2 +- src/loaders/svg/tvgSvgSceneBuilder.cpp | 62 ++++++++++++++++++---------------- src/loaders/svg/tvgSvgSceneBuilder.h | 11 ++---- src/loaders/svg/tvgXmlParser.cpp | 10 ++++++ 7 files changed, 63 insertions(+), 53 deletions(-) diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index dcb69d2..1114413 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -19,14 +19,13 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#include #include -#include #include #include #include "tvgLoaderMgr.h" #include "tvgXmlParser.h" #include "tvgSvgLoader.h" +#include "tvgSvgSceneBuilder.h" /************************************************************************/ /* Internal Class Implementation */ @@ -855,6 +854,7 @@ static void _handleTransformAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node node->transform = _parseTransformationMatrix(value); } + static void _handleClipPathAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, const char* value) { SvgStyleProperty* style = node->style; @@ -866,6 +866,7 @@ static void _handleClipPathAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, if (len >= 3 && !strncmp(value, "url", 3)) style->comp.url = _idFromUrl((const char*)(value + 3)); } + static void _handleMaskAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, const char* value) { SvgStyleProperty* style = node->style; @@ -877,6 +878,7 @@ static void _handleMaskAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, con if (len >= 3 && !strncmp(value, "url", 3)) style->comp.url = _idFromUrl((const char*)(value + 3)); } + static void _handleDisplayAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, const char* value) { //TODO : The display attribute can have various values as well as "none". @@ -890,12 +892,7 @@ static void _handleDisplayAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, typedef void (*styleMethod)(SvgLoaderData* loader, SvgNode* node, const char* value); - -#define STYLE_DEF(Name, Name1) \ - { \ -#Name, sizeof(#Name), _handle##Name1##Attr \ - } - +#define STYLE_DEF(Name, Name1) { #Name, sizeof(#Name), _handle##Name1##Attr } static constexpr struct { @@ -2589,7 +2586,7 @@ void SvgLoader::run(unsigned tid) _updateComposite(loaderData.doc, loaderData.doc); if (defs) _updateComposite(loaderData.doc, defs); } - root = builder.build(loaderData.doc); + root = svgSceneBuild(loaderData.doc); }; diff --git a/src/loaders/svg/tvgSvgLoader.h b/src/loaders/svg/tvgSvgLoader.h index bd442bc..29ec944 100644 --- a/src/loaders/svg/tvgSvgLoader.h +++ b/src/loaders/svg/tvgSvgLoader.h @@ -23,7 +23,7 @@ #define _TVG_SVG_LOADER_H_ #include "tvgTaskScheduler.h" -#include "tvgSvgSceneBuilder.h" +#include "tvgSvgLoaderCommon.h" class SvgLoader : public Loader, public Task { @@ -33,7 +33,6 @@ public: uint32_t size = 0; SvgLoaderData loaderData; - SvgSceneBuilder builder; unique_ptr root; SvgLoader(); diff --git a/src/loaders/svg/tvgSvgPath.cpp b/src/loaders/svg/tvgSvgPath.cpp index d7eaefc..8993314 100644 --- a/src/loaders/svg/tvgSvgPath.cpp +++ b/src/loaders/svg/tvgSvgPath.cpp @@ -19,12 +19,14 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#include #include -#include -#include +#include "tvgSvgLoaderCommon.h" #include "tvgSvgPath.h" +/************************************************************************/ +/* Internal Class Implementation */ +/************************************************************************/ + static char* _skipComma(const char* content) { while (*content && isspace(*content)) { @@ -491,6 +493,11 @@ static char* _nextCommand(char* path, char* cmd, float* arr, int* count) } +/************************************************************************/ +/* External Class Implementation */ +/************************************************************************/ + + bool svgPathToTvgPath(const char* svgPath, Array& cmds, Array& pts) { float numberArray[7]; diff --git a/src/loaders/svg/tvgSvgPath.h b/src/loaders/svg/tvgSvgPath.h index a3391d8..7f26c4a 100644 --- a/src/loaders/svg/tvgSvgPath.h +++ b/src/loaders/svg/tvgSvgPath.h @@ -23,7 +23,7 @@ #ifndef _TVG_SVG_PATH_H_ #define _TVG_SVG_PATH_H_ -#include "tvgSvgLoaderCommon.h" +#include bool svgPathToTvgPath(const char* svgPath, Array& cmds, Array& pts); diff --git a/src/loaders/svg/tvgSvgSceneBuilder.cpp b/src/loaders/svg/tvgSvgSceneBuilder.cpp index aa45fab..a1c9835 100644 --- a/src/loaders/svg/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg/tvgSvgSceneBuilder.cpp @@ -20,19 +20,24 @@ * SOFTWARE. */ #include -#include +#include "tvgSvgLoaderCommon.h" #include "tvgSvgSceneBuilder.h" #include "tvgSvgPath.h" -bool _appendShape(SvgNode* node, Shape* shape, float vx, float vy, float vw, float vh); +static bool _appendShape(SvgNode* node, Shape* shape, float vx, float vy, float vw, float vh); -bool _isGroupType(SvgNodeType type) +/************************************************************************/ +/* Internal Class Implementation */ +/************************************************************************/ + +static inline bool _isGroupType(SvgNodeType type) { if (type == SvgNodeType::Doc || type == SvgNodeType::G || type == SvgNodeType::ClipPath) return true; return false; } -unique_ptr _applyLinearGradientProperty(SvgStyleGradient* g, const Shape* vg, float rx, float ry, float rw, float rh) + +static unique_ptr _applyLinearGradientProperty(SvgStyleGradient* g, const Shape* vg, float rx, float ry, float rw, float rh) { Fill::ColorStop* stops; int stopCount = 0; @@ -112,7 +117,7 @@ unique_ptr _applyLinearGradientProperty(SvgStyleGradient* g, con } -unique_ptr _applyRadialGradientProperty(SvgStyleGradient* g, const Shape* vg, float rx, float ry, float rw, float rh) +static unique_ptr _applyRadialGradientProperty(SvgStyleGradient* g, const Shape* vg, float rx, float ry, float rw, float rh) { Fill::ColorStop *stops; int stopCount = 0; @@ -194,7 +199,8 @@ unique_ptr _applyRadialGradientProperty(SvgStyleGradient* g, con return fillGrad; } -void _appendChildShape(SvgNode* node, Shape* shape, float vx, float vy, float vw, float vh) + +static void _appendChildShape(SvgNode* node, Shape* shape, float vx, float vy, float vw, float vh) { _appendShape(node, shape, vx, vy, vw, vh); if (node->child.count > 0) { @@ -204,7 +210,7 @@ void _appendChildShape(SvgNode* node, Shape* shape, float vx, float vy, float vw } -void _applyProperty(SvgNode* node, Shape* vg, float vx, float vy, float vw, float vh) +static void _applyProperty(SvgNode* node, Shape* vg, float vx, float vy, float vw, float vh) { SvgStyleProperty* style = node->style; @@ -276,14 +282,16 @@ void _applyProperty(SvgNode* node, Shape* vg, float vx, float vy, float vw, floa } } -unique_ptr _shapeBuildHelper(SvgNode* node, float vx, float vy, float vw, float vh) + +static unique_ptr _shapeBuildHelper(SvgNode* node, float vx, float vy, float vw, float vh) { auto shape = Shape::gen(); if (_appendShape(node, shape.get(), vx, vy, vw, vh)) return shape; else return nullptr; } -bool _appendShape(SvgNode* node, Shape* shape, float vx, float vy, float vw, float vh) + +static bool _appendShape(SvgNode* node, Shape* shape, float vx, float vy, float vw, float vh) { Array cmds; Array pts; @@ -340,7 +348,8 @@ bool _appendShape(SvgNode* node, Shape* shape, float vx, float vy, float vw, flo return true; } -unique_ptr _sceneBuildHelper(const SvgNode* node, float vx, float vy, float vw, float vh) + +static unique_ptr _sceneBuildHelper(const SvgNode* node, float vx, float vy, float vw, float vh) { if (_isGroupType(node->type)) { auto scene = Scene::gen(); @@ -374,8 +383,20 @@ unique_ptr _sceneBuildHelper(const SvgNode* node, float vx, float vy, flo return nullptr; } -unique_ptr _buildRoot(const SvgNode* node, float vx, float vy, float vw, float vh) + +/************************************************************************/ +/* External Class Implementation */ +/************************************************************************/ + +unique_ptr svgSceneBuild(SvgNode* node) { + if (!node || (node->type != SvgNodeType::Doc)) return nullptr; + + auto vx = node->node.doc.vx; + auto vy = node->node.doc.vy; + auto vw = node->node.doc.vw; + auto vh = node->node.doc.vh; + unique_ptr root; auto docNode = _sceneBuildHelper(node, vx, vy, vw, vh); float x, y, w, h; @@ -397,21 +418,4 @@ unique_ptr _buildRoot(const SvgNode* node, float vx, float vy, float vw, root = move(docNode); } return root; -} - -SvgSceneBuilder::SvgSceneBuilder() -{ -} - - -SvgSceneBuilder::~SvgSceneBuilder() -{ -} - - -unique_ptr SvgSceneBuilder::build(SvgNode* node) -{ - if (!node || (node->type != SvgNodeType::Doc)) return nullptr; - - return _buildRoot(node, node->node.doc.vx, node->node.doc.vy, node->node.doc.vw, node->node.doc.vh); -} +} \ No newline at end of file diff --git a/src/loaders/svg/tvgSvgSceneBuilder.h b/src/loaders/svg/tvgSvgSceneBuilder.h index 5456fa6..d1b8f8c 100644 --- a/src/loaders/svg/tvgSvgSceneBuilder.h +++ b/src/loaders/svg/tvgSvgSceneBuilder.h @@ -23,15 +23,8 @@ #ifndef _TVG_SVG_SCENE_BUILDER_H_ #define _TVG_SVG_SCENE_BUILDER_H_ -#include "tvgSvgLoaderCommon.h" +#include "tvgCommon.h" -class SvgSceneBuilder -{ -public: - SvgSceneBuilder(); - ~SvgSceneBuilder(); - - unique_ptr build(SvgNode* node); -}; +unique_ptr svgSceneBuild(SvgNode* node); #endif //_TVG_SVG_SCENE_BUILDER_H_ diff --git a/src/loaders/svg/tvgXmlParser.cpp b/src/loaders/svg/tvgXmlParser.cpp index c5c8e6a..1fe223a 100644 --- a/src/loaders/svg/tvgXmlParser.cpp +++ b/src/loaders/svg/tvgXmlParser.cpp @@ -22,6 +22,7 @@ #include #include + #ifdef _WIN32 #include #else @@ -30,6 +31,10 @@ #include "tvgXmlParser.h" +/************************************************************************/ +/* Internal Class Implementation */ +/************************************************************************/ + #ifdef THORVG_LOG_ENABLED #include @@ -199,6 +204,11 @@ static const char* _simpleXmlFindDoctypeChildEndTag(const char* itr, const char* } +/************************************************************************/ +/* External Class Implementation */ +/************************************************************************/ + + bool simpleXmlParseAttributes(const char* buf, unsigned bufLength, simpleXMLAttributeCb func, const void* data) { const char *itr = buf, *itrEnd = buf + bufLength; -- 2.7.4 From e89362505e945bb3934d4dd5ebf30356daf97ca9 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Fri, 9 Apr 2021 15:57:32 +0900 Subject: [PATCH 12/16] loaders svg: prevent composition setting if the result shape is invalid. Current loader could return invalid shapes -default, from _appendShape()- by a certain interpretation result, Though it's a wrong or exception case, we can prevent worse case by avoiding it. --- src/loaders/svg/tvgSvgSceneBuilder.cpp | 35 +++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/src/loaders/svg/tvgSvgSceneBuilder.cpp b/src/loaders/svg/tvgSvgSceneBuilder.cpp index a1c9835..f620596 100644 --- a/src/loaders/svg/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg/tvgSvgSceneBuilder.cpp @@ -200,13 +200,20 @@ static unique_ptr _applyRadialGradientProperty(SvgStyleGradient* } -static void _appendChildShape(SvgNode* node, Shape* shape, float vx, float vy, float vw, float vh) +static bool _appendChildShape(SvgNode* node, Shape* shape, float vx, float vy, float vw, float vh) { - _appendShape(node, shape, vx, vy, vw, vh); + auto valid = false; + + if (_appendShape(node, shape, vx, vy, vw, vh)) valid = true; + if (node->child.count > 0) { auto child = node->child.data; - for (uint32_t i = 0; i < node->child.count; ++i, ++child) _appendChildShape(*child, shape, vx, vy, vw, vh); + for (uint32_t i = 0; i < node->child.count; ++i, ++child) { + if (_appendChildShape(*child, shape, vx, vy, vw, vh)) valid = true; + } } + + return valid; } @@ -275,9 +282,14 @@ static void _applyProperty(SvgNode* node, Shape* vg, float vx, float vy, float v if (compNode->child.count > 0) { auto comp = Shape::gen(); auto child = compNode->child.data; - for (uint32_t i = 0; i < compNode->child.count; ++i, ++child) _appendChildShape(*child, comp.get(), vx, vy, vw, vh); - if (style->comp.method == CompositeMethod::ClipPath) comp->fill(0, 0, 0, 255); - vg->composite(move(comp), style->comp.method); + auto valid = false; //Composite only when valid shapes are existed + for (uint32_t i = 0; i < compNode->child.count; ++i, ++child) { + if (_appendChildShape(*child, comp.get(), vx, vy, vw, vh)) valid = true; + } + if (valid) { + if (style->comp.method == CompositeMethod::ClipPath) comp->fill(0, 0, 0, 255); + vg->composite(move(comp), style->comp.method); + } } } } @@ -371,9 +383,14 @@ static unique_ptr _sceneBuildHelper(const SvgNode* node, float vx, float if (compNode->child.count > 0) { auto comp = Shape::gen(); auto child = compNode->child.data; - for (uint32_t i = 0; i < compNode->child.count; ++i, ++child) _appendChildShape(*child, comp.get(), vx, vy, vw, vh); - if (node->style->comp.method == CompositeMethod::ClipPath) comp->fill(0, 0, 0, 255); - scene->composite(move(comp), node->style->comp.method); + auto valid = false; //Composite only when valid shapes are existed + for (uint32_t i = 0; i < compNode->child.count; ++i, ++child) { + if (_appendChildShape(*child, comp.get(), vx, vy, vw, vh)) valid = true; + } + if (valid) { + if (node->style->comp.method == CompositeMethod::ClipPath) comp->fill(0, 0, 0, 255); + scene->composite(move(comp), node->style->comp.method); + } } } scene->opacity(node->style->opacity); -- 2.7.4 From 5e918ee1666150ad8fdaa35aa6ca5b4907cbddcb Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Fri, 9 Apr 2021 16:44:46 +0900 Subject: [PATCH 13/16] loaders svg: set default color for composition paint. not only clippath but alpha compositions might also have any valid color. Set it default and let it override values while appending shapes if it's necessary. --- src/loaders/svg/tvgSvgSceneBuilder.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/loaders/svg/tvgSvgSceneBuilder.cpp b/src/loaders/svg/tvgSvgSceneBuilder.cpp index f620596..5e8da35 100644 --- a/src/loaders/svg/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg/tvgSvgSceneBuilder.cpp @@ -281,15 +281,13 @@ static void _applyProperty(SvgNode* node, Shape* vg, float vx, float vy, float v auto compNode = style->comp.node; if (compNode->child.count > 0) { auto comp = Shape::gen(); + comp->fill(255, 255, 255, 255); auto child = compNode->child.data; auto valid = false; //Composite only when valid shapes are existed for (uint32_t i = 0; i < compNode->child.count; ++i, ++child) { if (_appendChildShape(*child, comp.get(), vx, vy, vw, vh)) valid = true; } - if (valid) { - if (style->comp.method == CompositeMethod::ClipPath) comp->fill(0, 0, 0, 255); - vg->composite(move(comp), style->comp.method); - } + if (valid) vg->composite(move(comp), style->comp.method); } } } @@ -382,15 +380,13 @@ static unique_ptr _sceneBuildHelper(const SvgNode* node, float vx, float auto compNode = node->style->comp.node; if (compNode->child.count > 0) { auto comp = Shape::gen(); + comp->fill(255, 255, 255, 255); auto child = compNode->child.data; auto valid = false; //Composite only when valid shapes are existed for (uint32_t i = 0; i < compNode->child.count; ++i, ++child) { if (_appendChildShape(*child, comp.get(), vx, vy, vw, vh)) valid = true; } - if (valid) { - if (node->style->comp.method == CompositeMethod::ClipPath) comp->fill(0, 0, 0, 255); - scene->composite(move(comp), node->style->comp.method); - } + if (valid) scene->composite(move(comp), node->style->comp.method); } } scene->opacity(node->style->opacity); -- 2.7.4 From e4635d39ae0d2816aed48b1a2e6cdf8786b1262a Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Fri, 9 Apr 2021 12:34:56 +0200 Subject: [PATCH 14/16] sw_engine: fixing stroke gradient Instead of checking the stroke's fill, the shape's fill was checked. As a result the improper rastering function was called (or none). --- src/lib/sw_engine/tvgSwRaster.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index b9ab35c..b117412 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -1036,10 +1036,10 @@ bool rasterGradientStroke(SwSurface* surface, SwShape* shape, unsigned id) if (!shape->stroke->fill || !shape->strokeRle) return false; if (id == FILL_ID_LINEAR) { - if (shape->fill && shape->fill->translucent) return _rasterTranslucentLinearGradientRle(surface, shape->strokeRle, shape->stroke->fill); + if (shape->stroke->fill->translucent) return _rasterTranslucentLinearGradientRle(surface, shape->strokeRle, shape->stroke->fill); return _rasterOpaqueLinearGradientRle(surface, shape->strokeRle, shape->stroke->fill); } else { - if (shape->fill && shape->fill->translucent) return _rasterTranslucentRadialGradientRle(surface, shape->strokeRle, shape->stroke->fill); + if (shape->stroke->fill->translucent) return _rasterTranslucentRadialGradientRle(surface, shape->strokeRle, shape->stroke->fill); return _rasterOpaqueRadialGradientRle(surface, shape->strokeRle, shape->stroke->fill); } -- 2.7.4 From 709341fee3630598e68a74fc25e509f6cc7a6687 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Fri, 9 Apr 2021 20:50:01 +0900 Subject: [PATCH 15/16] loader svg: fix composition(mask/clip) issue. composition target missed transform of its source. That brings incorrect composition area. This fixes it. Change-Id: I7e1adc225af2c0177581b3505288de50d77cc411 --- src/loaders/svg/tvgSvgSceneBuilder.cpp | 52 ++++++++++++++++------------------ 1 file changed, 24 insertions(+), 28 deletions(-) diff --git a/src/loaders/svg/tvgSvgSceneBuilder.cpp b/src/loaders/svg/tvgSvgSceneBuilder.cpp index 5e8da35..3b37f31 100644 --- a/src/loaders/svg/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg/tvgSvgSceneBuilder.cpp @@ -217,6 +217,28 @@ static bool _appendChildShape(SvgNode* node, Shape* shape, float vx, float vy, f } +static void _applyComposition(Paint* paint, const SvgNode* node, float vx, float vy, float vw, float vh) +{ + if (node->style->comp.method == CompositeMethod::None) return; + + auto compNode = node->style->comp.node; + if (!compNode || compNode->child.count == 0) return; + + auto comp = Shape::gen(); + comp->fill(255, 255, 255, 255); + if (node->transform) comp->transform(*node->transform); + + auto child = compNode->child.data; + auto valid = false; //Composite only when valid shapes are existed + + for (uint32_t i = 0; i < compNode->child.count; ++i, ++child) { + if (_appendChildShape(*child, comp.get(), vx, vy, vw, vh)) valid = true; + } + + if (valid) paint->composite(move(comp), node->style->comp.method); +} + + static void _applyProperty(SvgNode* node, Shape* vg, float vx, float vy, float vw, float vh) { SvgStyleProperty* style = node->style; @@ -276,20 +298,7 @@ static void _applyProperty(SvgNode* node, Shape* vg, float vx, float vy, float v vg->stroke(style->stroke.paint.r, style->stroke.paint.g, style->stroke.paint.b, style->stroke.opacity); } - //Apply composite node - if (style->comp.node && (style->comp.method != CompositeMethod::None)) { - auto compNode = style->comp.node; - if (compNode->child.count > 0) { - auto comp = Shape::gen(); - comp->fill(255, 255, 255, 255); - auto child = compNode->child.data; - auto valid = false; //Composite only when valid shapes are existed - for (uint32_t i = 0; i < compNode->child.count; ++i, ++child) { - if (_appendChildShape(*child, comp.get(), vx, vy, vw, vh)) valid = true; - } - if (valid) vg->composite(move(comp), style->comp.method); - } - } + _applyComposition(vg, node, vx, vy, vw, vh); } @@ -375,20 +384,7 @@ static unique_ptr _sceneBuildHelper(const SvgNode* node, float vx, float if (shape) scene->push(move(shape)); } } - //Apply composite node - if (node->style->comp.node && (node->style->comp.method != CompositeMethod::None)) { - auto compNode = node->style->comp.node; - if (compNode->child.count > 0) { - auto comp = Shape::gen(); - comp->fill(255, 255, 255, 255); - auto child = compNode->child.data; - auto valid = false; //Composite only when valid shapes are existed - for (uint32_t i = 0; i < compNode->child.count; ++i, ++child) { - if (_appendChildShape(*child, comp.get(), vx, vy, vw, vh)) valid = true; - } - if (valid) scene->composite(move(comp), node->style->comp.method); - } - } + _applyComposition(scene.get(), node, vx, vy, vw, vh); scene->opacity(node->style->opacity); } return scene; -- 2.7.4 From 25c05b4be13eb01b382a56307dffcaf1115329de Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Fri, 9 Apr 2021 21:27:38 +0900 Subject: [PATCH 16/16] bump up v0.0.7 Change-Id: I3e8d10dc94f2931b2898a02c86d851a964f0acb6 --- packaging/thorvg.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/thorvg.spec b/packaging/thorvg.spec index 87ad72d..5feb7f2 100644 --- a/packaging/thorvg.spec +++ b/packaging/thorvg.spec @@ -1,6 +1,6 @@ Name: thorvg Summary: Thor Vector Graphics Library -Version: 0.0.6 +Version: 0.0.7 Release: 1 Group: Graphics System/Rendering Engine License: MIT -- 2.7.4