From 50342ec162f52dc305a223235068c5c43637d0e6 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Mon, 13 Dec 2021 19:26:56 +0900 Subject: [PATCH 01/16] common picture: remove unused variable. --- src/lib/tvgPicture.cpp | 2 +- src/lib/tvgPictureImpl.h | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/lib/tvgPicture.cpp b/src/lib/tvgPicture.cpp index 52f73cb..1d97763 100644 --- a/src/lib/tvgPicture.cpp +++ b/src/lib/tvgPicture.cpp @@ -26,7 +26,7 @@ /* External Class Implementation */ /************************************************************************/ -Picture::Picture() : pImpl(new Impl(this)) +Picture::Picture() : pImpl(new Impl) { Paint::pImpl->id = TVG_CLASS_ID_PICTURE; Paint::pImpl->method(new PaintMethod(pImpl)); diff --git a/src/lib/tvgPictureImpl.h b/src/lib/tvgPictureImpl.h index 794363f..2e27471 100644 --- a/src/lib/tvgPictureImpl.h +++ b/src/lib/tvgPictureImpl.h @@ -63,16 +63,10 @@ struct Picture::Impl Paint* paint = nullptr; //vector picture uses Surface* surface = nullptr; //bitmap picture uses - - Picture* picture = nullptr; void* rdata = nullptr; //engine data float w = 0, h = 0; bool resizing = false; - Impl(Picture* p) : picture(p) - { - } - ~Impl() { if (paint) delete(paint); -- 2.7.4 From 023556e46a16120591a3866275903b45e17e59cf Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Mon, 13 Dec 2021 20:34:43 +0900 Subject: [PATCH 02/16] common paint: code refactoring Grouping the composite data to add source paint necessarily. this refactoring is a prerequisite job for the texmap anti-aliasing. --- src/lib/tvgPaint.cpp | 53 +++++++++++++++++++++++++----------------------- src/lib/tvgPaint.h | 39 +++++++++++++++++++++++++++-------- src/lib/tvgPictureImpl.h | 1 - src/lib/tvgSceneImpl.h | 2 +- src/lib/tvgShapeImpl.h | 1 - 5 files changed, 60 insertions(+), 36 deletions(-) diff --git a/src/lib/tvgPaint.cpp b/src/lib/tvgPaint.cpp index d256ac0..909e6be 100644 --- a/src/lib/tvgPaint.cpp +++ b/src/lib/tvgPaint.cpp @@ -95,7 +95,6 @@ static bool _compFastTrack(Paint* cmpTarget, const RenderTransform* pTransform, Paint* Paint::Impl::duplicate() { auto ret = smethod->duplicate(); - if (!ret) return nullptr; //duplicate Transform if (rTransform) { @@ -106,9 +105,7 @@ Paint* Paint::Impl::duplicate() ret->pImpl->opacity = opacity; - if (cmpTarget) ret->pImpl->cmpTarget = cmpTarget->duplicate(); - - ret->pImpl->cmpMethod = cmpMethod; + if (compData) ret->pImpl->composite(ret, compData->target->duplicate(), compData->method); return ret; } @@ -168,15 +165,15 @@ bool Paint::Impl::render(RenderMethod& renderer) /* Note: only ClipPath is processed in update() step. Create a composition image. */ - if (cmpTarget && cmpMethod != CompositeMethod::ClipPath && !(cmpTarget->pImpl->ctxFlag & ContextFlag::FastTrack)) { + if (compData && compData->method != CompositeMethod::ClipPath && !(compData->target->pImpl->ctxFlag & ContextFlag::FastTrack)) { auto region = smethod->bounds(renderer); if (region.w == 0 || region.h == 0) return true; cmp = renderer.target(region); renderer.beginComposite(cmp, CompositeMethod::None, 255); - cmpTarget->pImpl->render(renderer); + compData->target->pImpl->render(renderer); } - if (cmp) renderer.beginComposite(cmp, cmpMethod, cmpTarget->pImpl->opacity); + if (cmp) renderer.beginComposite(cmp, compData->method, compData->target->pImpl->opacity); auto ret = smethod->render(renderer); @@ -197,35 +194,37 @@ void* Paint::Impl::update(RenderMethod& renderer, const RenderTransform* pTransf } /* 1. Composition Pre Processing */ - void *cmpData = nullptr; + void *tdata = nullptr; RenderRegion viewport; - bool cmpFastTrack = false; + bool compFastTrack = false; - if (cmpTarget) { - cmpTarget->pImpl->ctxFlag = ContextFlag::Invalid; //reset + if (compData) { + auto target = compData->target; + auto method = compData->method; + target->pImpl->ctxFlag = ContextFlag::Invalid; //reset /* If transform has no rotation factors && ClipPath / AlphaMasking is a simple rectangle, we can avoid regular ClipPath / AlphaMasking sequence but use viewport for performance */ auto tryFastTrack = false; - if (cmpMethod == CompositeMethod::ClipPath) tryFastTrack = true; - else if (cmpMethod == CompositeMethod::AlphaMask && cmpTarget->identifier() == TVG_CLASS_ID_SHAPE) { - auto shape = static_cast(cmpTarget); + if (method == CompositeMethod::ClipPath) tryFastTrack = true; + else if (method == CompositeMethod::AlphaMask && target->identifier() == TVG_CLASS_ID_SHAPE) { + auto shape = static_cast(target); uint8_t a; shape->fillColor(nullptr, nullptr, nullptr, &a); if (a == 255 && shape->opacity() == 255 && !shape->fill()) tryFastTrack = true; } if (tryFastTrack) { RenderRegion viewport2; - if ((cmpFastTrack = _compFastTrack(cmpTarget, pTransform, cmpTarget->pImpl->rTransform, viewport2))) { + if ((compFastTrack = _compFastTrack(target, pTransform, target->pImpl->rTransform, viewport2))) { viewport = renderer.viewport(); viewport2.intersect(viewport); renderer.viewport(viewport2); - cmpTarget->pImpl->ctxFlag |= ContextFlag::FastTrack; + target->pImpl->ctxFlag |= ContextFlag::FastTrack; } } - if (!cmpFastTrack) { - cmpData = cmpTarget->pImpl->update(renderer, pTransform, 255, clips, pFlag); - if (cmpMethod == CompositeMethod::ClipPath) clips.push(cmpData); + if (!compFastTrack) { + tdata = target->pImpl->update(renderer, pTransform, 255, clips, pFlag); + if (method == CompositeMethod::ClipPath) clips.push(tdata); } } @@ -244,8 +243,8 @@ void* Paint::Impl::update(RenderMethod& renderer, const RenderTransform* pTransf } /* 3. Composition Post Processing */ - if (cmpFastTrack) renderer.viewport(viewport); - else if (cmpData && cmpMethod == CompositeMethod::ClipPath) clips.pop(); + if (compFastTrack) renderer.viewport(viewport); + else if (tdata && compData->method == CompositeMethod::ClipPath) clips.pop(); return edata; } @@ -366,7 +365,7 @@ Paint* Paint::duplicate() const noexcept Result Paint::composite(std::unique_ptr target, CompositeMethod method) noexcept { auto p = target.release(); - if (pImpl->composite(p, method)) return Result::Success; + if (pImpl->composite(this, p, method)) return Result::Success; if (p) delete(p); return Result::InvalidArguments; } @@ -374,9 +373,13 @@ Result Paint::composite(std::unique_ptr target, CompositeMethod method) n CompositeMethod Paint::composite(const Paint** target) const noexcept { - if (target) *target = pImpl->cmpTarget; - - return pImpl->cmpMethod; + if (pImpl->compData) { + if (target) *target = pImpl->compData->target; + return pImpl->compData->method; + } else { + if (target) *target = nullptr; + return CompositeMethod::None; + } } diff --git a/src/lib/tvgPaint.h b/src/lib/tvgPaint.h index 8cfae71..1f36ec3 100644 --- a/src/lib/tvgPaint.h +++ b/src/lib/tvgPaint.h @@ -50,19 +50,28 @@ namespace tvg virtual Iterator* iterator() = 0; }; + struct Composite + { + Paint* target; + Paint* source; + CompositeMethod method; + }; + struct Paint::Impl { StrategyMethod* smethod = nullptr; RenderTransform* rTransform = nullptr; + Composite* compData = nullptr; uint32_t renderFlag = RenderUpdateFlag::None; - Paint* cmpTarget = nullptr; - CompositeMethod cmpMethod = CompositeMethod::None; uint32_t ctxFlag = ContextFlag::Invalid; uint32_t id; uint8_t opacity = 255; ~Impl() { - if (cmpTarget) delete(cmpTarget); + if (compData) { + delete(compData->target); + free(compData); + } if (smethod) delete(smethod); if (rTransform) delete(rTransform); } @@ -100,7 +109,7 @@ namespace tvg bool dispose(RenderMethod& renderer) { - if (cmpTarget) cmpTarget->pImpl->dispose(renderer); + if (compData) compData->target->pImpl->dispose(renderer); return smethod->dispose(renderer); } @@ -109,12 +118,26 @@ namespace tvg return smethod->iterator(); } - bool composite(Paint* target, CompositeMethod method) + bool composite(Paint* source, Paint* target, CompositeMethod method) { + //Invalid case if ((!target && method != CompositeMethod::None) || (target && method == CompositeMethod::None)) return false; - if (cmpTarget) delete(cmpTarget); - cmpTarget = target; - cmpMethod = method; + + if (compData) { + delete(compData->target); + //Reset scenario + if (!target && method == CompositeMethod::None) { + free(compData); + compData = nullptr; + return true; + } + } else { + if (!target && method == CompositeMethod::None) return true; + compData = static_cast(calloc(1, sizeof(Composite))); + } + compData->target = target; + compData->source = source; + compData->method = method; return true; } diff --git a/src/lib/tvgPictureImpl.h b/src/lib/tvgPictureImpl.h index 2e27471..00e8aa6 100644 --- a/src/lib/tvgPictureImpl.h +++ b/src/lib/tvgPictureImpl.h @@ -225,7 +225,6 @@ struct Picture::Impl reload(); auto ret = Picture::gen(); - if (!ret) return nullptr; auto dup = ret.get()->pImpl; if (paint) dup->paint = paint->duplicate(); diff --git a/src/lib/tvgSceneImpl.h b/src/lib/tvgSceneImpl.h index 5e8ce3d..de94a66 100644 --- a/src/lib/tvgSceneImpl.h +++ b/src/lib/tvgSceneImpl.h @@ -184,7 +184,7 @@ struct Scene::Impl Paint* duplicate() { auto ret = Scene::gen(); - if (!ret) return nullptr; + auto dup = ret.get()->pImpl; dup->paints.reserve(paints.count); diff --git a/src/lib/tvgShapeImpl.h b/src/lib/tvgShapeImpl.h index 32aa00a..dcf4e6e 100644 --- a/src/lib/tvgShapeImpl.h +++ b/src/lib/tvgShapeImpl.h @@ -352,7 +352,6 @@ struct Shape::Impl Paint* duplicate() { auto ret = Shape::gen(); - if (!ret) return nullptr; auto dup = ret.get()->pImpl; dup->rule = rule; -- 2.7.4 From 5234c376e818c44060c722ddde77fa6a13628d65 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 14 Dec 2021 16:33:17 +0900 Subject: [PATCH 03/16] png_loaders: fix the wrong premultiplying operations. It should not modify the alpha channel value while premultiplying that turned out with the wrong visual result. @Issue: https://github.com/Samsung/thorvg/issues/655 --- src/examples/PicturePng.cpp | 6 ++++++ src/loaders/external_png/tvgPngLoader.cpp | 8 ++++---- src/loaders/png/tvgPngLoader.cpp | 8 ++++---- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/examples/PicturePng.cpp b/src/examples/PicturePng.cpp index 1cccf69..3798ab1 100644 --- a/src/examples/PicturePng.cpp +++ b/src/examples/PicturePng.cpp @@ -31,6 +31,12 @@ void tvgDrawCmds(tvg::Canvas* canvas) { if (!canvas) return; + //Background + auto bg = tvg::Shape::gen(); + bg->appendRect(0, 0, WIDTH, HEIGHT, 0, 0); //x, y, w, h, rx, ry + bg->fill(255, 255, 255, 255); //r, g, b, a + canvas->push(move(bg)); + //Load png file from path auto opacity = 51; diff --git a/src/loaders/external_png/tvgPngLoader.cpp b/src/loaders/external_png/tvgPngLoader.cpp index 316f51d..c3d2814 100644 --- a/src/loaders/external_png/tvgPngLoader.cpp +++ b/src/loaders/external_png/tvgPngLoader.cpp @@ -23,10 +23,10 @@ #include "tvgLoader.h" #include "tvgPngLoader.h" -static inline uint32_t ALPHA_BLEND(uint32_t c, uint32_t a) +static inline uint32_t PREMULTIPLY(uint32_t c) { - return (((((c >> 8) & 0x00ff00ff) * a + 0x00ff00ff) & 0xff00ff00) + - ((((c & 0x00ff00ff) * a + 0x00ff00ff) >> 8) & 0x00ff00ff)); + auto a = (c >> 24); + return (c & 0xff000000) + ((((c >> 8) & 0xff) * a) & 0xff00) + ((((c & 0x00ff00ff) * a) >> 8) & 0x00ff00ff); } @@ -36,7 +36,7 @@ static void _premultiply(uint32_t* data, uint32_t w, uint32_t h) for (uint32_t y = 0; y < h; ++y, buffer += w) { auto src = buffer; for (uint32_t x = 0; x < w; ++x, ++src) { - *src = ALPHA_BLEND(*src, (*src >> 24)); + *src = PREMULTIPLY(*src); } } } diff --git a/src/loaders/png/tvgPngLoader.cpp b/src/loaders/png/tvgPngLoader.cpp index b938893..c6d95be 100644 --- a/src/loaders/png/tvgPngLoader.cpp +++ b/src/loaders/png/tvgPngLoader.cpp @@ -29,10 +29,10 @@ /************************************************************************/ -static inline uint32_t ALPHA_BLEND(uint32_t c, uint32_t a) +static inline uint32_t PREMULTIPLY(uint32_t c) { - return (((((c >> 8) & 0x00ff00ff) * a + 0x00ff00ff) & 0xff00ff00) + - ((((c & 0x00ff00ff) * a + 0x00ff00ff) >> 8) & 0x00ff00ff)); + auto a = (c >> 24); + return (c & 0xff000000) + ((((c >> 8) & 0xff) * a) & 0xff00) + ((((c & 0x00ff00ff) * a) >> 8) & 0x00ff00ff); } @@ -42,7 +42,7 @@ static void _premultiply(uint32_t* data, uint32_t w, uint32_t h) for (uint32_t y = 0; y < h; ++y, buffer += w) { auto src = buffer; for (uint32_t x = 0; x < w; ++x, ++src) { - *src = ALPHA_BLEND(*src, (*src >> 24)); + *src = PREMULTIPLY(*src); } } } -- 2.7.4 From f4292f4a9918a5e2694079e30a03758e66f204b4 Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Tue, 14 Dec 2021 20:19:14 -0800 Subject: [PATCH 04/16] sw_engine SwShape: Prevent null access strokeOutline returned strokeExportOutline() is the address of mpool->strokeOutline[idx]. Assuming this value is null, mpoolRetStrokeOutline on line 617 will access mpool->strokeOutline[idx]. Logically, the logic of the mpool* functions does not occur in this case. --- src/lib/sw_engine/tvgSwShape.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index 29f5590..ca5548c 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -594,10 +594,6 @@ bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, const Matrix* transfo } strokeOutline = strokeExportOutline(shape->stroke, mpool, tid); - if (!strokeOutline) { - ret = false; - goto fail; - } if (!mathUpdateOutlineBBox(strokeOutline, clipRegion, renderRegion, false)) { ret = false; -- 2.7.4 From c801447c6a971c8df943551e4214301d6b4fcea0 Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Tue, 14 Dec 2021 20:29:01 -0800 Subject: [PATCH 05/16] sw_engine SwShape: Fix coding style --- src/lib/sw_engine/tvgSwShape.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index ca5548c..7b49c23 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -297,7 +297,7 @@ static SwOutline* _genDashOutline(const Shape* sdata, const Matrix* transform) auto outlineCntrsCnt = 0; for (uint32_t i = 0; i < cmdCnt; ++i) { - switch(*(cmds + i)) { + switch (*(cmds + i)) { case PathCommand::Close: { ++outlinePtsCnt; break; @@ -326,7 +326,7 @@ static SwOutline* _genDashOutline(const Shape* sdata, const Matrix* transform) _growOutlineContour(*dash.outline, outlineCntrsCnt * 20); while (cmdCnt-- > 0) { - switch(*cmds) { + switch (*cmds) { case PathCommand::Close: { _dashLineTo(dash, &dash.ptStart, transform); break; @@ -397,7 +397,7 @@ static bool _genOutline(SwShape* shape, const Shape* sdata, const Matrix* transf auto closeCnt = 0; for (uint32_t i = 0; i < cmdCnt; ++i) { - switch(*(cmds + i)) { + switch (*(cmds + i)) { case PathCommand::Close: { ++outlinePtsCnt; ++closeCnt; @@ -440,7 +440,7 @@ static bool _genOutline(SwShape* shape, const Shape* sdata, const Matrix* transf //Generate Outlines while (cmdCnt-- > 0) { - switch(*cmds) { + switch (*cmds) { case PathCommand::Close: { _outlineClose(*outline); break; -- 2.7.4 From 5ef121f7c70759f3e89940955f308a96a4107b09 Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Tue, 21 Dec 2021 18:30:51 -0800 Subject: [PATCH 06/16] capi: rename tvg_paint_get_bounds Apply the changed code of 9db4a49 Change-Id: I101ec1b5ac3876a0cba76f4da97e953d0894e8f0 --- src/bindings/capi/thorvg_capi.h | 3 +-- src/bindings/capi/tvgCapi.cpp | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/bindings/capi/thorvg_capi.h b/src/bindings/capi/thorvg_capi.h index 0f99966..404f1ff 100644 --- a/src/bindings/capi/thorvg_capi.h +++ b/src/bindings/capi/thorvg_capi.h @@ -855,8 +855,7 @@ TVG_EXPORT Tvg_Paint* tvg_paint_duplicate(Tvg_Paint* paint); * * \note The bounding box doesn't indicate the actual drawing region. It's the smallest rectangle that encloses the object. */ -//TIZEN_ONLY: RENAME TO tvg_paint_get_bounds() AFTER DUPLICATED API IS REMOVED -TVG_EXPORT Tvg_Result _tvg_paint_get_bounds(const Tvg_Paint* paint, float* x, float* y, float* w, float* h, bool transformed); +TVG_EXPORT Tvg_Result tvg_paint_get_bounds(const Tvg_Paint* paint, float* x, float* y, float* w, float* h, bool transformed); /*! * \brief Sets the composition target object and the composition method. diff --git a/src/bindings/capi/tvgCapi.cpp b/src/bindings/capi/tvgCapi.cpp index 4ae221e..7c2fd12 100644 --- a/src/bindings/capi/tvgCapi.cpp +++ b/src/bindings/capi/tvgCapi.cpp @@ -199,8 +199,7 @@ TVG_EXPORT Tvg_Result tvg_paint_get_opacity(const Tvg_Paint* paint, uint8_t* opa } -//TIZEN_ONLY: RENAME TO tvg_paint_get_bounds() AFTER DUPLICATED API IS REMOVED -TVG_EXPORT Tvg_Result _tvg_paint_get_bounds(const Tvg_Paint* paint, float* x, float* y, float* w, float* h, bool transformed) +TVG_EXPORT Tvg_Result tvg_paint_get_bounds(const Tvg_Paint* paint, float* x, float* y, float* w, float* h, bool transformed) { if (!paint) return TVG_RESULT_INVALID_ARGUMENT; return (Tvg_Result) reinterpret_cast(paint)->bounds(x, y, w, h, transformed); -- 2.7.4 From d8aa8aab516b602bbdb61a447eca49dc2a8f85ef Mon Sep 17 00:00:00 2001 From: jykeon Date: Mon, 27 Dec 2021 10:36:22 +0900 Subject: [PATCH 07/16] bump up 0.6.5 Change-Id: I8431f13558ce30db255650ab2f52f794729e7c57 Signed-off-by: jykeon --- packaging/thorvg.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/thorvg.spec b/packaging/thorvg.spec index 16eba8a..84db581 100644 --- a/packaging/thorvg.spec +++ b/packaging/thorvg.spec @@ -1,6 +1,6 @@ Name: thorvg Summary: Thor Vector Graphics Library -Version: 0.6.4 +Version: 0.6.5 Release: 1 Group: Graphics System/Rendering Engine License: MIT -- 2.7.4 From eac74b661ad55c5eaf6c23b15ec205f99773bf39 Mon Sep 17 00:00:00 2001 From: JunsuChoi Date: Tue, 4 Jan 2022 17:42:41 -0800 Subject: [PATCH 08/16] sw_engine SwRaster: Initialize uninitialized transform value Change-Id: I7aac462c6d6e481655c35a10b237970de7dbea76 --- src/lib/sw_engine/tvgSwRaster.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index 28b1e59..6602998 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -907,7 +907,9 @@ static bool _rasterScaledRleRGBAImage(SwSurface* surface, const SwImage* image, static bool _scaledRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* transform, const SwBBox& region, uint32_t opacity) { Matrix itransform; + if (transform && !mathInverse(transform, &itransform)) return false; + else mathIdentity(&itransform); auto halfScale = _halfScale(image->scale); @@ -1226,7 +1228,9 @@ static bool _rasterScaledRGBAImage(SwSurface* surface, const SwImage* image, con static bool _scaledRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* transform, const SwBBox& region, uint32_t opacity) { Matrix itransform; + if (transform && !mathInverse(transform, &itransform)) return false; + else mathIdentity(&itransform); auto halfScale = _halfScale(image->scale); -- 2.7.4 From 6e9c82d505f44b81c66691824e089ca86fdd3837 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 6 Jan 2022 12:32:16 +0900 Subject: [PATCH 09/16] sw_engine raster: fix a regression bug. Picture example were broken by 90fa26b7bb75cb938290170882e65da8d9fc5d9e the correct condition must be like this change. Change-Id: Ie3af07bca9d44872073b111874c60575fa4b38f4 --- src/lib/sw_engine/tvgSwRaster.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index 6602998..07a8561 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -908,8 +908,9 @@ static bool _scaledRleRGBAImage(SwSurface* surface, const SwImage* image, const { Matrix itransform; - if (transform && !mathInverse(transform, &itransform)) return false; - else mathIdentity(&itransform); + if (transform) { + if (!mathInverse(transform, &itransform)) return false; + } else mathIdentity(&itransform); auto halfScale = _halfScale(image->scale); @@ -1229,8 +1230,9 @@ static bool _scaledRGBAImage(SwSurface* surface, const SwImage* image, const Mat { Matrix itransform; - if (transform && !mathInverse(transform, &itransform)) return false; - else mathIdentity(&itransform); + if (transform) { + if (!mathInverse(transform, &itransform)) return false; + } else mathIdentity(&itransform); auto halfScale = _halfScale(image->scale); -- 2.7.4 From 5c959b1fb7362741143d781b55681a37d0783821 Mon Sep 17 00:00:00 2001 From: jykeon Date: Fri, 7 Jan 2022 10:41:57 +0900 Subject: [PATCH 10/16] bump up 0.6.6 Change-Id: I1106ae0d6d5623ca397232964f06bc99aeaadd42 Signed-off-by: jykeon --- packaging/thorvg.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/thorvg.spec b/packaging/thorvg.spec index 84db581..c13d829 100644 --- a/packaging/thorvg.spec +++ b/packaging/thorvg.spec @@ -1,6 +1,6 @@ Name: thorvg Summary: Thor Vector Graphics Library -Version: 0.6.5 +Version: 0.6.6 Release: 1 Group: Graphics System/Rendering Engine License: MIT -- 2.7.4 From 758d8661f557c4db2beb8dacae7b7d8665e9652f Mon Sep 17 00:00:00 2001 From: Michal Maciola Date: Fri, 14 Jan 2022 14:06:39 +0100 Subject: [PATCH 11/16] sw_engine: fixed declaration of 'i' shadows a previous local Some gcc versions and configurations was giving an error: error: "declaration of 'i' shadows a previous local" This patch should fix these errors Change-Id: Ic33bc0095a7ddfd78dd530a7dd4712c000ddd2eb --- src/lib/sw_engine/tvgSwRaster.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index 07a8561..7ef47b2 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -1530,12 +1530,12 @@ static bool _rasterTranslucentLinearGradientRle(SwSurface* surface, const SwRleD auto dst = &surface->buffer[span->y * surface->stride + span->x]; fillFetchLinear(fill, buffer, span->y, span->x, span->len); if (span->coverage == 255) { - for (uint32_t i = 0; i < span->len; ++i, ++dst) { - *dst = buffer[i] + ALPHA_BLEND(*dst, _ialpha(buffer[i])); + for (uint32_t x = 0; x < span->len; ++x, ++dst) { + *dst = buffer[x] + ALPHA_BLEND(*dst, _ialpha(buffer[x])); } } else { - for (uint32_t i = 0; i < span->len; ++i, ++dst) { - auto tmp = ALPHA_BLEND(buffer[i], span->coverage); + for (uint32_t x = 0; x < span->len; ++x, ++dst) { + auto tmp = ALPHA_BLEND(buffer[x], span->coverage); *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp)); } } @@ -1559,8 +1559,8 @@ static bool _rasterSolidLinearGradientRle(SwSurface* surface, const SwRleData* r } else { fillFetchLinear(fill, buf, span->y, span->x, span->len); auto dst = &surface->buffer[span->y * surface->stride + span->x]; - for (uint32_t i = 0; i < span->len; ++i) { - dst[i] = INTERPOLATE(span->coverage, buf[i], dst[i]); + for (uint32_t x = 0; x < span->len; ++x) { + dst[x] = INTERPOLATE(span->coverage, buf[x], dst[x]); } } } @@ -1719,12 +1719,12 @@ static bool _rasterTranslucentRadialGradientRle(SwSurface* surface, const SwRleD auto dst = &surface->buffer[span->y * surface->stride + span->x]; fillFetchRadial(fill, buffer, span->y, span->x, span->len); if (span->coverage == 255) { - for (uint32_t i = 0; i < span->len; ++i, ++dst) { - *dst = buffer[i] + ALPHA_BLEND(*dst, _ialpha(buffer[i])); + for (uint32_t x = 0; x < span->len; ++x, ++dst) { + *dst = buffer[x] + ALPHA_BLEND(*dst, _ialpha(buffer[x])); } } else { - for (uint32_t i = 0; i < span->len; ++i, ++dst) { - auto tmp = ALPHA_BLEND(buffer[i], span->coverage); + for (uint32_t x = 0; x < span->len; ++x, ++dst) { + auto tmp = ALPHA_BLEND(buffer[x], span->coverage); *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp)); } } @@ -1749,8 +1749,8 @@ static bool _rasterSolidRadialGradientRle(SwSurface* surface, const SwRleData* r } 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) { - *dst = ALPHA_BLEND(buf[i], span->coverage) + ALPHA_BLEND(*dst, ialpha); + for (uint32_t x = 0; x < span->len; ++x, ++dst) { + *dst = ALPHA_BLEND(buf[x], span->coverage) + ALPHA_BLEND(*dst, ialpha); } } } -- 2.7.4 From 35bff319244b0847febb9dc6c6e2ba757318834c Mon Sep 17 00:00:00 2001 From: Michal Maciola Date: Fri, 14 Jan 2022 14:19:55 +0100 Subject: [PATCH 12/16] sw_engine: fix comparison of integer expressions of different signedness Some gcc versions and configurations was giving an error: error: "comparison of integer expressions of different signedness: 'const SwCoord' {aka 'const long int'} and 'uint32_t' {aka 'unsigned int'} [-Werror=sign-compare]" This patch should fix the error Change-Id: Ie683f35220b130b3548d0059ffe130fa4fc53fdc --- src/lib/sw_engine/tvgSwRaster.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index 7ef47b2..9987aeb 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -1904,7 +1904,7 @@ bool rasterStroke(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint bool rasterImage(SwSurface* surface, SwImage* image, const Matrix* transform, const SwBBox& bbox, uint32_t opacity) { //Verify Boundary - if (bbox.max.x < 0 || bbox.max.y < 0 || bbox.min.x >= surface->w || bbox.min.y >= surface->h) return false; + if (bbox.max.x < 0 || bbox.max.y < 0 || bbox.min.x >= static_cast(surface->w) || bbox.min.y >= static_cast(surface->h)) return false; //TOOD: switch (image->format) //TODO: case: _rasterRGBImage() -- 2.7.4 From 32fabcb8e90c963fb7752e6caf111e4f6018de62 Mon Sep 17 00:00:00 2001 From: jykeon Date: Wed, 19 Jan 2022 17:16:29 +0900 Subject: [PATCH 13/16] bump up 0.6.7 Change-Id: Ib07f04d7c74b5f3be2ec6aaf6b76e3a88f2dbe2f Signed-off-by: jykeon --- packaging/thorvg.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/thorvg.spec b/packaging/thorvg.spec index c13d829..b58cec2 100644 --- a/packaging/thorvg.spec +++ b/packaging/thorvg.spec @@ -1,6 +1,6 @@ Name: thorvg Summary: Thor Vector Graphics Library -Version: 0.6.6 +Version: 0.6.7 Release: 1 Group: Graphics System/Rendering Engine License: MIT -- 2.7.4 From 2111930048843b2373907f4e9813f97a3b2d6206 Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Mon, 22 Aug 2022 15:53:37 +0200 Subject: [PATCH 14/16] svg_loader: the preserveAspectRatio attrib handled The preserveAspectRatio attribute handled according to the svg standard. Change-Id: Ie7292ba47341994cf703b3634016c267292a22d2 --- src/lib/tvgLoadModule.h | 1 - src/loaders/svg/tvgSvgLoader.cpp | 80 ++++++++++++++++--------- src/loaders/svg/tvgSvgLoader.h | 2 + src/loaders/svg/tvgSvgLoaderCommon.h | 23 +++++++- src/loaders/svg/tvgSvgSceneBuilder.cpp | 104 ++++++++++++++++++++++++--------- src/loaders/svg/tvgSvgSceneBuilder.h | 2 +- 6 files changed, 154 insertions(+), 58 deletions(-) diff --git a/src/lib/tvgLoadModule.h b/src/lib/tvgLoadModule.h index 0c34ecb..a496b09 100644 --- a/src/lib/tvgLoadModule.h +++ b/src/lib/tvgLoadModule.h @@ -36,7 +36,6 @@ public: float vw = 0; float vh = 0; float w = 0, h = 0; //default image size - bool preserveAspect = true; //keep aspect ratio by default. virtual ~LoadModule() {} diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index def8ae1..050611f 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -116,6 +116,49 @@ static bool _parseNumber(const char** content, float* number) return true; } + +static constexpr struct +{ + AspectRatioAlign align; + const char* tag; +} alignTags[] = { + { AspectRatioAlign::XMinYMin, "xMinYMin" }, + { AspectRatioAlign::XMidYMin, "xMidYMin" }, + { AspectRatioAlign::XMaxYMin, "xMaxYMin" }, + { AspectRatioAlign::XMinYMid, "xMinYMid" }, + { AspectRatioAlign::XMidYMid, "xMidYMid" }, + { AspectRatioAlign::XMaxYMid, "xMaxYMid" }, + { AspectRatioAlign::XMinYMax, "xMinYMax" }, + { AspectRatioAlign::XMidYMax, "xMidYMax" }, + { AspectRatioAlign::XMaxYMax, "xMaxYMax" }, +}; + + +static void _parseAspectRatio(const char** content, AspectRatioAlign* align, AspectRatioMeetOrSlice* meetOrSlice) +{ + if (!strcmp(*content, "none")) { + *align = AspectRatioAlign::None; + return; + } + + for (unsigned int i = 0; i < sizeof(alignTags) / sizeof(alignTags[0]); i++) { + if (!strncmp(*content, alignTags[i].tag, 8)) { + *align = alignTags[i].align; + *content += 8; + *content = _skipSpace(*content, nullptr); + break; + } + } + + if (!strcmp(*content, "meet")) + *meetOrSlice = AspectRatioMeetOrSlice::Meet; + else if (!strcmp(*content, "slice")) + *meetOrSlice = AspectRatioMeetOrSlice::Slice; + + return; +} + + /** * According to https://www.w3.org/TR/SVG/coords.html#Units */ @@ -783,7 +826,7 @@ static bool _attrParseSvgNode(void* data, const char* key, const char* value) } loader->svgParse->global.x = (int)doc->vx; } else if (!strcmp(key, "preserveAspectRatio")) { - if (!strcmp(value, "none")) doc->preserveAspect = false; + _parseAspectRatio(&value, &doc->align, &doc->meetOrSlice); } else if (!strcmp(key, "style")) { return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader); } @@ -1150,7 +1193,9 @@ static SvgNode* _createSvgNode(SvgLoaderData* loader, SvgNode* parent, const cha loader->svgParse->global.w = 0; loader->svgParse->global.h = 0; - doc->preserveAspect = true; + doc->align = AspectRatioAlign::XMidYMid; + doc->meetOrSlice = AspectRatioMeetOrSlice::Meet; + simpleXmlParseAttributes(buf, bufLength, _attrParseSvgNode, loader); if (loader->svgParse->global.w == 0) { @@ -2846,7 +2891,7 @@ void SvgLoader::run(unsigned tid) if (loaderData.cloneNodes.count > 0) _clonePostponedNodes(&loaderData.cloneNodes); } - root = svgSceneBuild(loaderData.doc, vx, vy, vw, vh, w, h, preserveAspect, svgPath); + root = svgSceneBuild(loaderData.doc, vx, vy, vw, vh, w, h, align, meetOrSlice, svgPath); } @@ -2879,7 +2924,8 @@ bool SvgLoader::header() if (vh < FLT_EPSILON) vh = h; } - preserveAspect = loaderData.doc->node.doc.preserveAspect; + align = loaderData.doc->node.doc.align; + meetOrSlice = loaderData.doc->node.doc.meetOrSlice; } else { TVGLOG("SVG", "No SVG File. There is no "); return false; @@ -2934,31 +2980,9 @@ bool SvgLoader::resize(Paint* paint, float w, float h) auto sx = w / this->w; auto sy = h / this->h; + Matrix m = {sx, 0, 0, 0, sy, 0, 0, 0, 1}; + paint->transform(m); - if (preserveAspect) { - //Scale - auto scale = sx < sy ? sx : sy; - paint->scale(scale); - //Align - auto tx = 0.0f; - auto ty = 0.0f; - auto tw = this->w * scale; - auto th = this->h * scale; - if (tw > th) ty -= (h - th) * 0.5f; - else tx -= (w - tw) * 0.5f; - paint->translate(-tx, -ty); - } else { - //Align - auto tx = 0.0f; - auto ty = 0.0f; - auto tw = this->w * sx; - auto th = this->h * sy; - if (tw > th) ty -= (h - th) * 0.5f; - else tx -= (w - tw) * 0.5f; - - Matrix m = {sx, 0, -tx, 0, sy, -ty, 0, 0, 1}; - paint->transform(m); - } return true; } diff --git a/src/loaders/svg/tvgSvgLoader.h b/src/loaders/svg/tvgSvgLoader.h index 468f058..8c5b233 100644 --- a/src/loaders/svg/tvgSvgLoader.h +++ b/src/loaders/svg/tvgSvgLoader.h @@ -32,6 +32,8 @@ public: string svgPath = ""; const char* content = nullptr; uint32_t size = 0; + AspectRatioAlign align = AspectRatioAlign::XMidYMid; + AspectRatioMeetOrSlice meetOrSlice = AspectRatioMeetOrSlice::Meet; SvgLoaderData loaderData; unique_ptr root; diff --git a/src/loaders/svg/tvgSvgLoaderCommon.h b/src/loaders/svg/tvgSvgLoaderCommon.h index cceef91..0a6f019 100644 --- a/src/loaders/svg/tvgSvgLoaderCommon.h +++ b/src/loaders/svg/tvgSvgLoaderCommon.h @@ -136,6 +136,26 @@ enum class SvgParserLengthType Other }; +enum class AspectRatioAlign +{ + None, + XMinYMin, + XMidYMin, + XMaxYMin, + XMinYMid, + XMidYMid, + XMaxYMid, + XMinYMax, + XMidYMax, + XMaxYMax +}; + +enum class AspectRatioMeetOrSlice +{ + Meet, + Slice +}; + struct SvgDocNode { float w; @@ -145,7 +165,8 @@ struct SvgDocNode float vw; float vh; SvgNode* defs; - bool preserveAspect; + AspectRatioAlign align; + AspectRatioMeetOrSlice meetOrSlice; }; struct SvgGNode diff --git a/src/loaders/svg/tvgSvgSceneBuilder.cpp b/src/loaders/svg/tvgSvgSceneBuilder.cpp index 8701fe3..243fe7b 100644 --- a/src/loaders/svg/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg/tvgSvgSceneBuilder.cpp @@ -595,11 +595,85 @@ static unique_ptr _sceneBuildHelper(const SvgNode* node, const Box& vBox, } +static Matrix _calculateAspectRatioMatrix(AspectRatioAlign align, AspectRatioMeetOrSlice meetOrSlice, float width, float height, const Box& box) +{ + auto sx = width / box.w; + auto sy = height / box.h; + auto tvx = box.x * sx; + auto tvy = box.y * sy; + + if (align == AspectRatioAlign::None) + return {sx, 0, -tvx, 0, sy, -tvy, 0, 0, 1}; + + //Scale + if (meetOrSlice == AspectRatioMeetOrSlice::Meet) { + if (sx < sy) sy = sx; + else sx = sy; + } else { + if (sx < sy) sx = sy; + else sy = sx; + } + + //Align + tvx = box.x * sx; + tvy = box.y * sy; + auto tvw = box.w * sx; + auto tvh = box.h * sy; + + switch (align) { + case AspectRatioAlign::XMinYMin: { + break; + } + case AspectRatioAlign::XMidYMin: { + tvx -= (width - tvw) * 0.5f; + break; + } + case AspectRatioAlign::XMaxYMin: { + tvx -= width - tvw; + break; + } + case AspectRatioAlign::XMinYMid: { + tvy -= (height - tvh) * 0.5f; + break; + } + case AspectRatioAlign::XMidYMid: { + tvx -= (width - tvw) * 0.5f; + tvy -= (height - tvh) * 0.5f; + break; + } + case AspectRatioAlign::XMaxYMid: { + tvx -= width - tvw; + tvy -= (height - tvh) * 0.5f; + break; + } + case AspectRatioAlign::XMinYMax: { + tvy -= height - tvh; + break; + } + case AspectRatioAlign::XMidYMax: { + tvx -= (width - tvw) * 0.5f; + tvy -= height - tvh; + break; + } + case AspectRatioAlign::XMaxYMax: { + tvx -= width - tvw; + tvy -= height - tvh; + break; + } + default: { + break; + } + } + + return {sx, 0, -tvx, 0, sy, -tvy, 0, 0, 1}; +} + + /************************************************************************/ /* External Class Implementation */ /************************************************************************/ -unique_ptr svgSceneBuild(SvgNode* node, float vx, float vy, float vw, float vh, float w, float h, bool preserveAspect, const string& svgPath) +unique_ptr svgSceneBuild(SvgNode* node, float vx, float vy, float vw, float vh, float w, float h, AspectRatioAlign align, AspectRatioMeetOrSlice meetOrSlice, const string& svgPath) { if (!node || (node->type != SvgNodeType::Doc)) return nullptr; @@ -607,32 +681,8 @@ unique_ptr svgSceneBuild(SvgNode* node, float vx, float vy, float vw, flo auto docNode = _sceneBuildHelper(node, vBox, svgPath, false); if (!mathEqual(w, vw) || !mathEqual(h, vh)) { - auto sx = w / vw; - auto sy = h / vh; - - if (preserveAspect) { - //Scale - auto scale = sx < sy ? sx : sy; - docNode->scale(scale); - //Align - auto tvx = vx * scale; - auto tvy = vy * scale; - auto tvw = vw * scale; - auto tvh = vh * scale; - if (vw > vh) tvy -= (h - tvh) * 0.5f; - else tvx -= (w - tvw) * 0.5f; - docNode->translate(-tvx, -tvy); - } else { - //Align - auto tvx = vx * sx; - auto tvy = vy * sy; - auto tvw = vw * sx; - auto tvh = vh * sy; - if (tvw > tvh) tvy -= (h - tvh) * 0.5f; - else tvx -= (w - tvw) * 0.5f; - Matrix m = {sx, 0, -tvx, 0, sy, -tvy, 0, 0, 1}; - docNode->transform(m); - } + Matrix m = _calculateAspectRatioMatrix(align, meetOrSlice, w, h, vBox); + docNode->transform(m); } else if (!mathZero(vx) || !mathZero(vy)) { docNode->translate(-vx, -vy); } diff --git a/src/loaders/svg/tvgSvgSceneBuilder.h b/src/loaders/svg/tvgSvgSceneBuilder.h index 4232aca..20b6b2b 100644 --- a/src/loaders/svg/tvgSvgSceneBuilder.h +++ b/src/loaders/svg/tvgSvgSceneBuilder.h @@ -25,6 +25,6 @@ #include "tvgCommon.h" -unique_ptr svgSceneBuild(SvgNode* node, float vx, float vy, float vw, float vh, float w, float h, bool preserveAspect, const string& svgPath); +unique_ptr svgSceneBuild(SvgNode* node, float vx, float vy, float vw, float vh, float w, float h, AspectRatioAlign align, AspectRatioMeetOrSlice meetOrSlice, const string& svgPath); #endif //_TVG_SVG_SCENE_BUILDER_H_ -- 2.7.4 From f85123c6506371a6fe50879ace0cef3996dc1d10 Mon Sep 17 00:00:00 2001 From: Chun Date: Mon, 14 Nov 2022 01:23:09 +0000 Subject: [PATCH 15/16] Revert "svg_loader: the preserveAspectRatio attrib handled" This reverts commit 2111930048843b2373907f4e9813f97a3b2d6206. Change-Id: I608f73c16e8bb9c6caf2a3fb40254e6eca056dcf --- src/lib/tvgLoadModule.h | 1 + src/loaders/svg/tvgSvgLoader.cpp | 80 +++++++++---------------- src/loaders/svg/tvgSvgLoader.h | 2 - src/loaders/svg/tvgSvgLoaderCommon.h | 23 +------- src/loaders/svg/tvgSvgSceneBuilder.cpp | 104 +++++++++------------------------ src/loaders/svg/tvgSvgSceneBuilder.h | 2 +- 6 files changed, 58 insertions(+), 154 deletions(-) diff --git a/src/lib/tvgLoadModule.h b/src/lib/tvgLoadModule.h index a496b09..0c34ecb 100644 --- a/src/lib/tvgLoadModule.h +++ b/src/lib/tvgLoadModule.h @@ -36,6 +36,7 @@ public: float vw = 0; float vh = 0; float w = 0, h = 0; //default image size + bool preserveAspect = true; //keep aspect ratio by default. virtual ~LoadModule() {} diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index 050611f..def8ae1 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -116,49 +116,6 @@ static bool _parseNumber(const char** content, float* number) return true; } - -static constexpr struct -{ - AspectRatioAlign align; - const char* tag; -} alignTags[] = { - { AspectRatioAlign::XMinYMin, "xMinYMin" }, - { AspectRatioAlign::XMidYMin, "xMidYMin" }, - { AspectRatioAlign::XMaxYMin, "xMaxYMin" }, - { AspectRatioAlign::XMinYMid, "xMinYMid" }, - { AspectRatioAlign::XMidYMid, "xMidYMid" }, - { AspectRatioAlign::XMaxYMid, "xMaxYMid" }, - { AspectRatioAlign::XMinYMax, "xMinYMax" }, - { AspectRatioAlign::XMidYMax, "xMidYMax" }, - { AspectRatioAlign::XMaxYMax, "xMaxYMax" }, -}; - - -static void _parseAspectRatio(const char** content, AspectRatioAlign* align, AspectRatioMeetOrSlice* meetOrSlice) -{ - if (!strcmp(*content, "none")) { - *align = AspectRatioAlign::None; - return; - } - - for (unsigned int i = 0; i < sizeof(alignTags) / sizeof(alignTags[0]); i++) { - if (!strncmp(*content, alignTags[i].tag, 8)) { - *align = alignTags[i].align; - *content += 8; - *content = _skipSpace(*content, nullptr); - break; - } - } - - if (!strcmp(*content, "meet")) - *meetOrSlice = AspectRatioMeetOrSlice::Meet; - else if (!strcmp(*content, "slice")) - *meetOrSlice = AspectRatioMeetOrSlice::Slice; - - return; -} - - /** * According to https://www.w3.org/TR/SVG/coords.html#Units */ @@ -826,7 +783,7 @@ static bool _attrParseSvgNode(void* data, const char* key, const char* value) } loader->svgParse->global.x = (int)doc->vx; } else if (!strcmp(key, "preserveAspectRatio")) { - _parseAspectRatio(&value, &doc->align, &doc->meetOrSlice); + if (!strcmp(value, "none")) doc->preserveAspect = false; } else if (!strcmp(key, "style")) { return simpleXmlParseW3CAttribute(value, _parseStyleAttr, loader); } @@ -1193,9 +1150,7 @@ static SvgNode* _createSvgNode(SvgLoaderData* loader, SvgNode* parent, const cha loader->svgParse->global.w = 0; loader->svgParse->global.h = 0; - doc->align = AspectRatioAlign::XMidYMid; - doc->meetOrSlice = AspectRatioMeetOrSlice::Meet; - + doc->preserveAspect = true; simpleXmlParseAttributes(buf, bufLength, _attrParseSvgNode, loader); if (loader->svgParse->global.w == 0) { @@ -2891,7 +2846,7 @@ void SvgLoader::run(unsigned tid) if (loaderData.cloneNodes.count > 0) _clonePostponedNodes(&loaderData.cloneNodes); } - root = svgSceneBuild(loaderData.doc, vx, vy, vw, vh, w, h, align, meetOrSlice, svgPath); + root = svgSceneBuild(loaderData.doc, vx, vy, vw, vh, w, h, preserveAspect, svgPath); } @@ -2924,8 +2879,7 @@ bool SvgLoader::header() if (vh < FLT_EPSILON) vh = h; } - align = loaderData.doc->node.doc.align; - meetOrSlice = loaderData.doc->node.doc.meetOrSlice; + preserveAspect = loaderData.doc->node.doc.preserveAspect; } else { TVGLOG("SVG", "No SVG File. There is no "); return false; @@ -2980,9 +2934,31 @@ bool SvgLoader::resize(Paint* paint, float w, float h) auto sx = w / this->w; auto sy = h / this->h; - Matrix m = {sx, 0, 0, 0, sy, 0, 0, 0, 1}; - paint->transform(m); + if (preserveAspect) { + //Scale + auto scale = sx < sy ? sx : sy; + paint->scale(scale); + //Align + auto tx = 0.0f; + auto ty = 0.0f; + auto tw = this->w * scale; + auto th = this->h * scale; + if (tw > th) ty -= (h - th) * 0.5f; + else tx -= (w - tw) * 0.5f; + paint->translate(-tx, -ty); + } else { + //Align + auto tx = 0.0f; + auto ty = 0.0f; + auto tw = this->w * sx; + auto th = this->h * sy; + if (tw > th) ty -= (h - th) * 0.5f; + else tx -= (w - tw) * 0.5f; + + Matrix m = {sx, 0, -tx, 0, sy, -ty, 0, 0, 1}; + paint->transform(m); + } return true; } diff --git a/src/loaders/svg/tvgSvgLoader.h b/src/loaders/svg/tvgSvgLoader.h index 8c5b233..468f058 100644 --- a/src/loaders/svg/tvgSvgLoader.h +++ b/src/loaders/svg/tvgSvgLoader.h @@ -32,8 +32,6 @@ public: string svgPath = ""; const char* content = nullptr; uint32_t size = 0; - AspectRatioAlign align = AspectRatioAlign::XMidYMid; - AspectRatioMeetOrSlice meetOrSlice = AspectRatioMeetOrSlice::Meet; SvgLoaderData loaderData; unique_ptr root; diff --git a/src/loaders/svg/tvgSvgLoaderCommon.h b/src/loaders/svg/tvgSvgLoaderCommon.h index 0a6f019..cceef91 100644 --- a/src/loaders/svg/tvgSvgLoaderCommon.h +++ b/src/loaders/svg/tvgSvgLoaderCommon.h @@ -136,26 +136,6 @@ enum class SvgParserLengthType Other }; -enum class AspectRatioAlign -{ - None, - XMinYMin, - XMidYMin, - XMaxYMin, - XMinYMid, - XMidYMid, - XMaxYMid, - XMinYMax, - XMidYMax, - XMaxYMax -}; - -enum class AspectRatioMeetOrSlice -{ - Meet, - Slice -}; - struct SvgDocNode { float w; @@ -165,8 +145,7 @@ struct SvgDocNode float vw; float vh; SvgNode* defs; - AspectRatioAlign align; - AspectRatioMeetOrSlice meetOrSlice; + bool preserveAspect; }; struct SvgGNode diff --git a/src/loaders/svg/tvgSvgSceneBuilder.cpp b/src/loaders/svg/tvgSvgSceneBuilder.cpp index 243fe7b..8701fe3 100644 --- a/src/loaders/svg/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg/tvgSvgSceneBuilder.cpp @@ -595,85 +595,11 @@ static unique_ptr _sceneBuildHelper(const SvgNode* node, const Box& vBox, } -static Matrix _calculateAspectRatioMatrix(AspectRatioAlign align, AspectRatioMeetOrSlice meetOrSlice, float width, float height, const Box& box) -{ - auto sx = width / box.w; - auto sy = height / box.h; - auto tvx = box.x * sx; - auto tvy = box.y * sy; - - if (align == AspectRatioAlign::None) - return {sx, 0, -tvx, 0, sy, -tvy, 0, 0, 1}; - - //Scale - if (meetOrSlice == AspectRatioMeetOrSlice::Meet) { - if (sx < sy) sy = sx; - else sx = sy; - } else { - if (sx < sy) sx = sy; - else sy = sx; - } - - //Align - tvx = box.x * sx; - tvy = box.y * sy; - auto tvw = box.w * sx; - auto tvh = box.h * sy; - - switch (align) { - case AspectRatioAlign::XMinYMin: { - break; - } - case AspectRatioAlign::XMidYMin: { - tvx -= (width - tvw) * 0.5f; - break; - } - case AspectRatioAlign::XMaxYMin: { - tvx -= width - tvw; - break; - } - case AspectRatioAlign::XMinYMid: { - tvy -= (height - tvh) * 0.5f; - break; - } - case AspectRatioAlign::XMidYMid: { - tvx -= (width - tvw) * 0.5f; - tvy -= (height - tvh) * 0.5f; - break; - } - case AspectRatioAlign::XMaxYMid: { - tvx -= width - tvw; - tvy -= (height - tvh) * 0.5f; - break; - } - case AspectRatioAlign::XMinYMax: { - tvy -= height - tvh; - break; - } - case AspectRatioAlign::XMidYMax: { - tvx -= (width - tvw) * 0.5f; - tvy -= height - tvh; - break; - } - case AspectRatioAlign::XMaxYMax: { - tvx -= width - tvw; - tvy -= height - tvh; - break; - } - default: { - break; - } - } - - return {sx, 0, -tvx, 0, sy, -tvy, 0, 0, 1}; -} - - /************************************************************************/ /* External Class Implementation */ /************************************************************************/ -unique_ptr svgSceneBuild(SvgNode* node, float vx, float vy, float vw, float vh, float w, float h, AspectRatioAlign align, AspectRatioMeetOrSlice meetOrSlice, const string& svgPath) +unique_ptr svgSceneBuild(SvgNode* node, float vx, float vy, float vw, float vh, float w, float h, bool preserveAspect, const string& svgPath) { if (!node || (node->type != SvgNodeType::Doc)) return nullptr; @@ -681,8 +607,32 @@ unique_ptr svgSceneBuild(SvgNode* node, float vx, float vy, float vw, flo auto docNode = _sceneBuildHelper(node, vBox, svgPath, false); if (!mathEqual(w, vw) || !mathEqual(h, vh)) { - Matrix m = _calculateAspectRatioMatrix(align, meetOrSlice, w, h, vBox); - docNode->transform(m); + auto sx = w / vw; + auto sy = h / vh; + + if (preserveAspect) { + //Scale + auto scale = sx < sy ? sx : sy; + docNode->scale(scale); + //Align + auto tvx = vx * scale; + auto tvy = vy * scale; + auto tvw = vw * scale; + auto tvh = vh * scale; + if (vw > vh) tvy -= (h - tvh) * 0.5f; + else tvx -= (w - tvw) * 0.5f; + docNode->translate(-tvx, -tvy); + } else { + //Align + auto tvx = vx * sx; + auto tvy = vy * sy; + auto tvw = vw * sx; + auto tvh = vh * sy; + if (tvw > tvh) tvy -= (h - tvh) * 0.5f; + else tvx -= (w - tvw) * 0.5f; + Matrix m = {sx, 0, -tvx, 0, sy, -tvy, 0, 0, 1}; + docNode->transform(m); + } } else if (!mathZero(vx) || !mathZero(vy)) { docNode->translate(-vx, -vy); } diff --git a/src/loaders/svg/tvgSvgSceneBuilder.h b/src/loaders/svg/tvgSvgSceneBuilder.h index 20b6b2b..4232aca 100644 --- a/src/loaders/svg/tvgSvgSceneBuilder.h +++ b/src/loaders/svg/tvgSvgSceneBuilder.h @@ -25,6 +25,6 @@ #include "tvgCommon.h" -unique_ptr svgSceneBuild(SvgNode* node, float vx, float vy, float vw, float vh, float w, float h, AspectRatioAlign align, AspectRatioMeetOrSlice meetOrSlice, const string& svgPath); +unique_ptr svgSceneBuild(SvgNode* node, float vx, float vy, float vw, float vh, float w, float h, bool preserveAspect, const string& svgPath); #endif //_TVG_SVG_SCENE_BUILDER_H_ -- 2.7.4 From eb9b7dc59640ddceeecacedb60edac1fb6c78510 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Fri, 26 Nov 2021 12:10:23 +0900 Subject: [PATCH 16/16] sw_engine raster: improve the transformed rle image rasterizer. replace the transformed rle rgba image with the texmap raster. this patch removes the several scattered transformed image rasterizer, reuse the unified one texmap method instead. yay, it's much clean and optimal. Change-Id: Ie5c1a99b28c5242639618e1f4e41f8912c443b4c --- src/lib/sw_engine/tvgSwRaster.cpp | 446 +------------------------- src/lib/sw_engine/tvgSwRasterTexmap.h | 29 +- src/lib/sw_engine/tvgSwRasterTexmapInternal.h | 49 ++- src/lib/sw_engine/tvgSwRenderer.cpp | 5 +- src/lib/tvgPaint.cpp | 13 +- src/lib/tvgPaint.h | 3 +- src/lib/tvgRender.h | 2 +- 7 files changed, 81 insertions(+), 466 deletions(-) diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index 9987aeb..9ef4cc0 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -265,445 +265,16 @@ static bool _rasterRle(SwSurface* surface, SwRleData* rle, uint32_t color, uint8 /* RLE Transformed RGBA Image */ /************************************************************************/ -static bool _rasterTransformedMaskedTranslucentRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, uint32_t opacity, uint32_t (*blendMethod)(uint32_t)) -{ - TVGLOG("SW_ENGINE", "Transformed Masked Translucent Rle Image"); - - auto span = image->rle->spans; - auto img = image->data; - auto w = image->w; - auto h = image->h; - auto cbuffer = surface->compositor->image.data; - - for (uint32_t i = 0; i < image->rle->size; ++i, ++span) { - auto ey1 = span->y * itransform->e12 + itransform->e13; - auto ey2 = span->y * itransform->e22 + itransform->e23; - auto dst = &surface->buffer[span->y * surface->stride + span->x]; - auto cmp = &cbuffer[span->y * surface->compositor->image.stride + span->x]; - auto alpha = _multiplyAlpha(span->coverage, opacity); - for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp) { - auto rX = static_cast(roundf((span->x + x) * itransform->e11 + ey1)); - auto rY = static_cast(roundf((span->x + x) * itransform->e21 + ey2)); - if (rX >= w || rY >= h) continue; - auto src = ALPHA_BLEND(img[rY * image->stride + rX], alpha); - auto tmp = ALPHA_BLEND(src, blendMethod(*cmp)); - *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp)); - } - } - return true; -} - - -static bool _rasterTransformedMaskedRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, uint32_t (*blendMethod)(uint32_t)) -{ - TVGLOG("SW_ENGINE", "Transformed Masked Rle Image"); - - auto span = image->rle->spans; - auto img = image->data; - auto w = image->w; - auto h = image->h; - auto cbuffer = surface->compositor->image.data; - - for (uint32_t i = 0; i < image->rle->size; ++i, ++span) { - auto ey1 = span->y * itransform->e12 + itransform->e13; - auto ey2 = span->y * itransform->e22 + itransform->e23; - auto dst = &surface->buffer[span->y * surface->stride + span->x]; - auto cmp = &cbuffer[span->y * surface->compositor->image.stride + span->x]; - if (span->coverage == 255) { - for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp) { - auto rX = static_cast(roundf((span->x + x) * itransform->e11 + ey1)); - auto rY = static_cast(roundf((span->x + x) * itransform->e21 + ey2)); - if (rX >= w || rY >= h) continue; - auto tmp = ALPHA_BLEND(img[rY * image->stride + rX], blendMethod(*cmp)); - *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp)); - } - } else { - for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp) { - auto rX = static_cast(roundf((span->x + x) * itransform->e11 + ey1)); - auto rY = static_cast(roundf((span->x + x) * itransform->e21 + ey2)); - if (rX >= w || rY >= h) continue; - auto src = ALPHA_BLEND(img[rY * image->stride + rX], span->coverage); - auto tmp = ALPHA_BLEND(src, blendMethod(*cmp)); - *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp)); - } - } - } - return true; -} - - -static bool _rasterTransformedTranslucentRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, uint32_t opacity) -{ - auto span = image->rle->spans; - auto img = image->data; - auto w = image->w; - auto h = image->h; - - for (uint32_t i = 0; i < image->rle->size; ++i, ++span) { - auto ey1 = span->y * itransform->e12 + itransform->e13; - auto ey2 = span->y * itransform->e22 + itransform->e23; - auto dst = &surface->buffer[span->y * surface->stride + span->x]; - auto alpha = _multiplyAlpha(span->coverage, opacity); - for (uint32_t x = 0; x < span->len; ++x, ++dst) { - auto rX = static_cast(roundf((span->x + x) * itransform->e11 + ey1)); - auto rY = static_cast(roundf((span->x + x) * itransform->e21 + ey2)); - if (rX >= w || rY >= h) continue; - auto src = ALPHA_BLEND(img[rY * image->stride + rX], alpha); - *dst = src + ALPHA_BLEND(*dst, _ialpha(src)); - } - } - return true; -} - - -static bool _rasterDownScaledMaskedTranslucentRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, uint32_t opacity, uint32_t halfScale, uint32_t (*blendMethod)(uint32_t)) -{ - TVGLOG("SW_ENGINE", "Down Scaled Masked Translucent Rle Image"); - - auto span = image->rle->spans; - auto img = image->data; - auto w = image->w; - auto h = image->h; - auto cbuffer = surface->compositor->image.data; - - for (uint32_t i = 0; i < image->rle->size; ++i, ++span) { - auto ey1 = span->y * itransform->e12 + itransform->e13; - auto ey2 = span->y * itransform->e22 + itransform->e23; - auto dst = &surface->buffer[span->y * surface->stride + span->x]; - auto cmp = &cbuffer[span->y * surface->compositor->image.stride + span->x]; - auto alpha = _multiplyAlpha(span->coverage, opacity); - for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp) { - auto rX = static_cast(roundf((span->x + x) * itransform->e11 + ey1)); - auto rY = static_cast(roundf((span->x + x) * itransform->e21 + ey2)); - if (rX >= w || rY >= h) continue; - uint32_t src; - if (rX < halfScale || rY < halfScale || rX >= w - halfScale || rY >= h - halfScale) src = ALPHA_BLEND(img[rY * image->stride + rX], alpha); - else src = ALPHA_BLEND(_interpDownScaler(img, image->stride, h, rX, rY, halfScale), alpha); - auto tmp = ALPHA_BLEND(src, _multiplyAlpha(alpha, blendMethod(*cmp))); - *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp)); - } - } - return true; -} - - -static bool _rasterDownScaledMaskedRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, uint32_t halfScale, uint32_t (*blendMethod)(uint32_t)) -{ - TVGLOG("SW_ENGINE", "Down Scaled Masked Rle Image"); - - auto span = image->rle->spans; - auto img = image->data; - auto w = image->w; - auto h = image->h; - auto cbuffer = surface->compositor->image.data; - - for (uint32_t i = 0; i < image->rle->size; ++i, ++span) { - auto ey1 = span->y * itransform->e12 + itransform->e13; - auto ey2 = span->y * itransform->e22 + itransform->e23; - auto dst = &surface->buffer[span->y * surface->stride + span->x]; - auto cmp = &cbuffer[span->y * surface->compositor->image.stride + span->x]; - if (span->coverage == 255) { - for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp) { - auto rX = static_cast(roundf((span->x + x) * itransform->e11 + ey1)); - auto rY = static_cast(roundf((span->x + x) * itransform->e21 + ey2)); - if (rX >= w || rY >= h) continue; - uint32_t src; - if (rX < halfScale || rY < halfScale || rX >= w - halfScale || rY >= h - halfScale) src = img[rY * image->stride + rX]; - else src = _interpDownScaler(img, image->stride, h, rX, rY, halfScale); - auto tmp = ALPHA_BLEND(src, blendMethod(*cmp)); - *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp)); - } - } else { - for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp) { - auto rX = static_cast(roundf((span->x + x) * itransform->e11 + ey1)); - auto rY = static_cast(roundf((span->x + x) * itransform->e21 + ey2)); - if (rX >= w || rY >= h) continue; - uint32_t src; - if (rX < halfScale || rY < halfScale || rX >= w - halfScale || rY >= h - halfScale) src = ALPHA_BLEND(img[rY * image->stride + rX], span->coverage); - else src = ALPHA_BLEND(_interpDownScaler(img, image->stride, h, rX, rY, halfScale), span->coverage); - auto tmp = ALPHA_BLEND(src, _multiplyAlpha(span->coverage, blendMethod(*cmp))); - *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp)); - } - } - } - return true; -} - - -static bool _rasterDownScaledTranslucentRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, uint32_t opacity, uint32_t halfScale) -{ - auto span = image->rle->spans; - auto img = image->data; - auto w = image->w; - auto h = image->h; - - for (uint32_t i = 0; i < image->rle->size; ++i, ++span) { - auto ey1 = span->y * itransform->e12 + itransform->e13; - auto ey2 = span->y * itransform->e22 + itransform->e23; - auto dst = &surface->buffer[span->y * surface->stride + span->x]; - auto alpha = _multiplyAlpha(span->coverage, opacity); - for (uint32_t x = 0; x < span->len; ++x, ++dst) { - auto rX = static_cast(roundf((span->x + x) * itransform->e11 + ey1)); - auto rY = static_cast(roundf((span->x + x) * itransform->e21 + ey2)); - if (rX >= w || rY >= h) continue; - uint32_t src; - if (rX < halfScale || rY < halfScale || rX >= w - halfScale || rY >= h - halfScale) src = ALPHA_BLEND(img[rY * image->stride + rX], alpha); - else src = ALPHA_BLEND(_interpDownScaler(img, image->stride, h, rX, rY, halfScale), alpha); - *dst = src + ALPHA_BLEND(*dst, _ialpha(src)); - } - } - return true; -} - - -static bool _rasterUpScaledMaskedTranslucentRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, uint32_t opacity, uint32_t (*blendMethod)(uint32_t)) -{ - TVGLOG("SW_ENGINE", "Up Scaled Masked Translucent Rle Image"); - - auto span = image->rle->spans; - auto img = image->data; - auto w = image->w; - auto h = image->h; - auto cbuffer = surface->compositor->image.data; - - for (uint32_t i = 0; i < image->rle->size; ++i, ++span) { - auto ey1 = span->y * itransform->e12 + itransform->e13; - auto ey2 = span->y * itransform->e22 + itransform->e23; - auto dst = &surface->buffer[span->y * surface->stride + span->x]; - auto cmp = &cbuffer[span->y * surface->compositor->image.stride + span->x]; - auto alpha = _multiplyAlpha(span->coverage, opacity); - for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp) { - auto fX = (span->x + x) * itransform->e11 + ey1; - auto fY = (span->x + x) * itransform->e21 + ey2; - auto rX = static_cast(roundf(fX)); - auto rY = static_cast(roundf(fY)); - if (rX >= w || rY >= h) continue; - uint32_t src; - if (rX == w - 1 || rY == h - 1) src = ALPHA_BLEND(img[rY * image->stride + rX], alpha); - else src = ALPHA_BLEND(_interpUpScaler(img, image->stride, h, fX, fY), alpha); - auto tmp = ALPHA_BLEND(src, _multiplyAlpha(alpha, blendMethod(*cmp))); - *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp)); - } - } - return true; -} - - -static bool _rasterUpScaledMaskedRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, uint32_t (*blendMethod)(uint32_t)) -{ - TVGLOG("SW_ENGINE", "Up Scaled Masked Rle Image"); - - auto span = image->rle->spans; - auto img = image->data; - auto w = image->w; - auto h = image->h; - auto cbuffer = surface->compositor->image.data; - - for (uint32_t i = 0; i < image->rle->size; ++i, ++span) { - auto ey1 = span->y * itransform->e12 + itransform->e13; - auto ey2 = span->y * itransform->e22 + itransform->e23; - auto dst = &surface->buffer[span->y * surface->stride + span->x]; - auto cmp = &cbuffer[span->y * surface->compositor->image.stride + span->x]; - if (span->coverage == 255) { - for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp) { - auto fX = (span->x + x) * itransform->e11 + ey1; - auto fY = (span->x + x) * itransform->e21 + ey2; - auto rX = static_cast(roundf(fX)); - auto rY = static_cast(roundf(fY)); - if (rX >= w || rY >= h) continue; - uint32_t src; - if (rX == w - 1 || rY == h - 1) src = img[rY * image->stride + rX]; - else src = _interpUpScaler(img, image->stride, h, fX, fY); - auto tmp = ALPHA_BLEND(src, blendMethod(*cmp)); - *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp)); - } - } else { - for (uint32_t x = 0; x < span->len; ++x, ++dst, ++cmp) { - auto fX = (span->x + x) * itransform->e11 + ey1; - auto fY = (span->x + x) * itransform->e21 + ey2; - auto rX = static_cast(roundf(fX)); - auto rY = static_cast(roundf(fY)); - if (rX >= w || rY >= h) continue; - uint32_t src; - if (rX == w - 1 || rY == h - 1) src = ALPHA_BLEND(img[rY * image->stride + rX], span->coverage); - else src = ALPHA_BLEND(_interpUpScaler(img, image->stride, h, fX, fY), span->coverage); - auto tmp = ALPHA_BLEND(src, _multiplyAlpha(span->coverage, blendMethod(*cmp))); - *dst = tmp + ALPHA_BLEND(*dst, _ialpha(tmp)); - } - } - } - return true; -} - - -static bool _rasterUpScaledTranslucentRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, uint32_t opacity) -{ - auto span = image->rle->spans; - auto img = image->data; - auto w = image->w; - auto h = image->h; - - for (uint32_t i = 0; i < image->rle->size; ++i, ++span) { - auto ey1 = span->y * itransform->e12 + itransform->e13; - auto ey2 = span->y * itransform->e22 + itransform->e23; - auto dst = &surface->buffer[span->y * surface->stride + span->x]; - auto alpha = _multiplyAlpha(span->coverage, opacity); - for (uint32_t x = 0; x < span->len; ++x, ++dst) { - auto fX = (span->x + x) * itransform->e11 + ey1; - auto fY = (span->x + x) * itransform->e21 + ey2; - auto rX = static_cast(roundf(fX)); - auto rY = static_cast(roundf(fY)); - if (rX >= w || rY >= h) continue; - uint32_t src; - if (rX == w - 1 || rY == h - 1) src = ALPHA_BLEND(img[rY * image->stride + rX], alpha); - else src = ALPHA_BLEND(_interpUpScaler(img, image->stride, h, fX, fY), alpha); - *dst = src + ALPHA_BLEND(*dst, _ialpha(src)); - } - } - return true; -} - - -static bool _rasterTransformedRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform) -{ - auto span = image->rle->spans; - - for (uint32_t i = 0; i < image->rle->size; ++i, ++span) { - auto ey1 = span->y * itransform->e12 + itransform->e13; - auto ey2 = span->y * itransform->e22 + itransform->e23; - auto dst = &surface->buffer[span->y * surface->stride + span->x]; - - for (uint32_t x = 0; x < span->len; ++x, ++dst) { - auto rX = static_cast(roundf((span->x + x) * itransform->e11 + ey1)); - auto rY = static_cast(roundf((span->x + x) * itransform->e21 + ey2)); - if (rX >= image->w || rY >= image->h) continue; - auto src = ALPHA_BLEND(image->data[rY * image->stride + rX], span->coverage); - *dst = src + ALPHA_BLEND(*dst, _ialpha(src)); - } - } - return true; -} - - -static bool _rasterDownScaledRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, uint32_t halfScale) -{ - auto span = image->rle->spans; - auto img = image->data; - auto w = image->w; - auto h = image->h; - - for (uint32_t i = 0; i < image->rle->size; ++i, ++span) { - auto ey1 = span->y * itransform->e12 + itransform->e13; - auto ey2 = span->y * itransform->e22 + itransform->e23; - auto dst = &surface->buffer[span->y * surface->stride + span->x]; - for (uint32_t x = static_cast(span->x); x < static_cast(span->x) + span->len; ++x, ++dst) { - auto rX = static_cast(roundf(x * itransform->e11 + ey1)); - auto rY = static_cast(roundf(x * itransform->e21 + ey2)); - if (rX >= w || rY >= h) continue; - - uint32_t src; - if (rX < halfScale || rY < halfScale || rX >= w - halfScale || rY >= h - halfScale) src = ALPHA_BLEND(img[rY * image->stride + rX], span->coverage); - else src = ALPHA_BLEND(_interpDownScaler(img, image->stride, h, rX, rY, halfScale), span->coverage); - *dst = src + ALPHA_BLEND(*dst, _ialpha(src)); - } - } - return true; -} - - -static bool _rasterUpScaledRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* itransform) -{ - auto span = image->rle->spans; - auto img = image->data; - auto w = image->w; - auto h = image->h; - - for (uint32_t i = 0; i < image->rle->size; ++i, ++span) { - auto ey1 = span->y * itransform->e12 + itransform->e13; - auto ey2 = span->y * itransform->e22 + itransform->e23; - auto dst = &surface->buffer[span->y * surface->stride + span->x]; - for (uint32_t x = static_cast(span->x); x < static_cast(span->x) + span->len; ++x, ++dst) { - auto fX = x * itransform->e11 + ey1; - auto fY = x * itransform->e21 + ey2; - auto rX = static_cast(roundf(fX)); - auto rY = static_cast(roundf(fY)); - if (rX >= w || rY >= h) continue; - uint32_t src; - if (rX == w - 1 || rY == h - 1) src = ALPHA_BLEND(img[rY * image->stride + rX], span->coverage); - else src = ALPHA_BLEND(_interpUpScaler(img, image->stride, h, fX, fY), span->coverage); - *dst = src + ALPHA_BLEND(*dst, _ialpha(src)); - } - } - return true; -} - - static bool _transformedRleRGBAImage(SwSurface* surface, const SwImage* image, const Matrix* transform, uint32_t opacity) { - Matrix itransform; - mathIdentity(&itransform); - if (transform && !mathInverse(transform, &itransform)) return false; - - auto halfScale = _halfScale(image->scale); - if (_compositing(surface)) { - if (opacity == 255) { - //Transformed - if (mathEqual(image->scale, 1.0f)) { - if (surface->compositor->method == CompositeMethod::AlphaMask) { - return _rasterTransformedMaskedRleRGBAImage(surface, image, &itransform, _alpha); - } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) { - return _rasterTransformedMaskedRleRGBAImage(surface, image, &itransform, _ialpha); - } - //Transformed + Down Scaled - } else if (image->scale < DOWN_SCALE_TOLERANCE) { - if (surface->compositor->method == CompositeMethod::AlphaMask) { - return _rasterDownScaledMaskedRleRGBAImage(surface, image, &itransform, halfScale, _alpha); - } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) { - return _rasterDownScaledMaskedRleRGBAImage(surface, image, &itransform, halfScale, _ialpha); - } - //Transformed + Up Scaled - } else { - if (surface->compositor->method == CompositeMethod::AlphaMask) { - return _rasterUpScaledMaskedRleRGBAImage(surface, image, &itransform, _alpha); - } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) { - return _rasterUpScaledMaskedRleRGBAImage(surface, image, &itransform, _ialpha); - } - } - } else { - //Transformed - if (mathEqual(image->scale, 1.0f)) { - if (surface->compositor->method == CompositeMethod::AlphaMask) { - return _rasterTransformedMaskedTranslucentRleRGBAImage(surface, image, &itransform, opacity, _alpha); - } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) { - return _rasterTransformedMaskedTranslucentRleRGBAImage(surface, image, &itransform, opacity, _ialpha); - } - //Transformed + Down Scaled - } else if (image->scale < DOWN_SCALE_TOLERANCE) { - if (surface->compositor->method == CompositeMethod::AlphaMask) { - return _rasterDownScaledMaskedTranslucentRleRGBAImage(surface, image, &itransform, opacity, halfScale, _alpha); - } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) { - return _rasterDownScaledMaskedTranslucentRleRGBAImage(surface, image, &itransform, opacity, halfScale, _ialpha); - } - //Transformed + Up Scaled - } else { - if (surface->compositor->method == CompositeMethod::AlphaMask) { - return _rasterUpScaledMaskedTranslucentRleRGBAImage(surface, image, &itransform, opacity, _alpha); - } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) { - return _rasterUpScaledMaskedTranslucentRleRGBAImage(surface, image, &itransform, opacity, _ialpha); - } - } + if (surface->compositor->method == CompositeMethod::AlphaMask) { + return _rasterTexmapPolygon(surface, image, transform, nullptr, opacity, _alpha); + } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) { + return _rasterTexmapPolygon(surface, image, transform, nullptr, opacity, _ialpha); } } else { - if (opacity == 255) { - if (mathEqual(image->scale, 1.0f)) return _rasterTransformedRleRGBAImage(surface, image, &itransform); - else if (image->scale < DOWN_SCALE_TOLERANCE) return _rasterDownScaledRleRGBAImage(surface, image, &itransform, halfScale); - else return _rasterUpScaledRleRGBAImage(surface, image, &itransform); - } else { - if (mathEqual(image->scale, 1.0f)) return _rasterTransformedTranslucentRleRGBAImage(surface, image, &itransform, opacity); - else if (image->scale < DOWN_SCALE_TOLERANCE) return _rasterDownScaledTranslucentRleRGBAImage(surface, image, &itransform, opacity, halfScale); - else return _rasterUpScaledTranslucentRleRGBAImage(surface, image, &itransform, opacity); - } + return _rasterTexmapPolygon(surface, image, transform, nullptr, opacity, nullptr); } return false; } @@ -1066,12 +637,12 @@ static bool _transformedRGBAImage(SwSurface* surface, const SwImage* image, cons { if (_compositing(surface)) { if (surface->compositor->method == CompositeMethod::AlphaMask) { - return _rasterTexmapPolygon(surface, image, transform, region, opacity, _alpha); + return _rasterTexmapPolygon(surface, image, transform, ®ion, opacity, _alpha); } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) { - return _rasterTexmapPolygon(surface, image, transform, region, opacity, _ialpha); + return _rasterTexmapPolygon(surface, image, transform, ®ion, opacity, _ialpha); } } else { - return _rasterTexmapPolygon(surface, image, transform, region, opacity, nullptr); + return _rasterTexmapPolygon(surface, image, transform, ®ion, opacity, nullptr); } return false; } @@ -1385,7 +956,6 @@ static bool _rasterRGBAImage(SwSurface* surface, SwImage* image, const Matrix* t if (image->rle) { if (image->direct) return _directRleRGBAImage(surface, image, opacity); else if (image->scaled) return _scaledRleRGBAImage(surface, image, transform, region, opacity); - //OPTIMIZE_ME: Replace with the TexMap Rasterizer else return _transformedRleRGBAImage(surface, image, transform, opacity); //Whole Image } else { diff --git a/src/lib/sw_engine/tvgSwRasterTexmap.h b/src/lib/sw_engine/tvgSwRasterTexmap.h index ca4e303..c7d225d 100644 --- a/src/lib/sw_engine/tvgSwRasterTexmap.h +++ b/src/lib/sw_engine/tvgSwRasterTexmap.h @@ -31,6 +31,7 @@ struct Polygon Vertex vertex[3]; }; + static inline void _swap(float& a, float& b, float& tmp) { tmp = a; @@ -44,7 +45,7 @@ static float dxdya, dxdyb, dudya, dvdya; static float xa, xb, ua, va; -static void _rasterPolygonImageSegment(SwSurface* surface, const SwImage* image, const SwBBox& region, int ystart, int yend, uint32_t opacity, uint32_t (*blendMethod)(uint32_t)) +static void _rasterPolygonImageSegment(SwSurface* surface, const SwImage* image, const SwBBox* region, int yStart, int yEnd, uint32_t opacity, uint32_t (*blendMethod)(uint32_t)) { #define TEXMAP_TRANSLUCENT #define TEXMAP_MASKING @@ -54,7 +55,7 @@ static void _rasterPolygonImageSegment(SwSurface* surface, const SwImage* image, } -static void _rasterPolygonImageSegment(SwSurface* surface, const SwImage* image, const SwBBox& region, int ystart, int yend, uint32_t (*blendMethod)(uint32_t)) +static void _rasterPolygonImageSegment(SwSurface* surface, const SwImage* image, const SwBBox* region, int yStart, int yEnd, uint32_t (*blendMethod)(uint32_t)) { #define TEXMAP_MASKING #include "tvgSwRasterTexmapInternal.h" @@ -62,7 +63,7 @@ static void _rasterPolygonImageSegment(SwSurface* surface, const SwImage* image, } -static void _rasterPolygonImageSegment(SwSurface* surface, const SwImage* image, const SwBBox& region, int ystart, int yend, uint32_t opacity) +static void _rasterPolygonImageSegment(SwSurface* surface, const SwImage* image, const SwBBox* region, int yStart, int yEnd, uint32_t opacity) { #define TEXMAP_TRANSLUCENT #include "tvgSwRasterTexmapInternal.h" @@ -70,14 +71,15 @@ static void _rasterPolygonImageSegment(SwSurface* surface, const SwImage* image, } -static void _rasterPolygonImageSegment(SwSurface* surface, const SwImage* image, const SwBBox& region, int ystart, int yend) +static void _rasterPolygonImageSegment(SwSurface* surface, const SwImage* image, const SwBBox* region, int yStart, int yEnd) { #include "tvgSwRasterTexmapInternal.h" } + /* This mapping algorithm is based on Mikael Kalms's. */ -static void _rasterPolygonImage(SwSurface* surface, const SwImage* image, const SwBBox& region, uint32_t opacity, Polygon& polygon, uint32_t (*blendMethod)(uint32_t)) +static void _rasterPolygonImage(SwSurface* surface, const SwImage* image, const SwBBox* region, uint32_t opacity, Polygon& polygon, uint32_t (*blendMethod)(uint32_t)) { float x[3] = {polygon.vertex[0].pt.x, polygon.vertex[1].pt.x, polygon.vertex[2].pt.x}; float y[3] = {polygon.vertex[0].pt.y, polygon.vertex[1].pt.y, polygon.vertex[2].pt.y}; @@ -139,6 +141,8 @@ static void _rasterPolygonImage(SwSurface* surface, const SwImage* image, const if (mathEqual(y[0], y[1])) side = x[0] > x[1]; if (mathEqual(y[1], y[2])) side = x[2] > x[1]; + auto regionTop = region ? region->min.y : image->rle->spans->y; //Normal Image or Rle Image? + //Longer edge is on the left side if (!side) { //Calculate slopes along left edge @@ -154,7 +158,7 @@ static void _rasterPolygonImage(SwSurface* surface, const SwImage* image, const //Draw upper segment if possibly visible if (yi[0] < yi[1]) { - off_y = y[0] < region.min.y ? (region.min.y - y[0]) : 0; + off_y = y[0] < regionTop ? (regionTop - y[0]) : 0; xa += (off_y * dxdya); ua += (off_y * dudya); va += (off_y * dvdya); @@ -175,7 +179,7 @@ static void _rasterPolygonImage(SwSurface* surface, const SwImage* image, const } //Draw lower segment if possibly visible if (yi[1] < yi[2]) { - off_y = y[1] < region.min.y ? (region.min.y - y[1]) : 0; + off_y = y[1] < regionTop ? (regionTop - y[1]) : 0; if (!upper) { xa += (off_y * dxdya); ua += (off_y * dudya); @@ -201,7 +205,7 @@ static void _rasterPolygonImage(SwSurface* surface, const SwImage* image, const //Draw upper segment if possibly visible if (yi[0] < yi[1]) { - off_y = y[0] < region.min.y ? (region.min.y - y[0]) : 0; + off_y = y[0] < regionTop ? (regionTop - y[0]) : 0; xb += (off_y *dxdyb); // Set slopes along left edge and perform subpixel pre-stepping @@ -225,7 +229,7 @@ static void _rasterPolygonImage(SwSurface* surface, const SwImage* image, const } //Draw lower segment if possibly visible if (yi[1] < yi[2]) { - off_y = y[1] < region.min.y ? (region.min.y - y[1]) : 0; + off_y = y[1] < regionTop ? (regionTop - y[1]) : 0; if (!upper) xb += (off_y *dxdyb); // Set slopes along left edge and perform subpixel pre-stepping @@ -259,8 +263,11 @@ static void _rasterPolygonImage(SwSurface* surface, const SwImage* image, const | / | 3 -- 2 */ -static bool _rasterTexmapPolygon(SwSurface* surface, const SwImage* image, const Matrix* transform, const SwBBox& region, uint32_t opacity, uint32_t (*blendMethod)(uint32_t)) +static bool _rasterTexmapPolygon(SwSurface* surface, const SwImage* image, const Matrix* transform, const SwBBox* region, uint32_t opacity, uint32_t (*blendMethod)(uint32_t)) { + //Exceptions: No dedicated drawing area? + if (!region && image->rle->size == 0) return false; + /* Prepare vertices. shift XY coordinates to match the sub-pixeling technique. */ Vertex vertices[4]; @@ -286,6 +293,6 @@ static bool _rasterTexmapPolygon(SwSurface* surface, const SwImage* image, const polygon.vertex[2] = vertices[3]; _rasterPolygonImage(surface, image, region, opacity, polygon, blendMethod); - + return true; } \ No newline at end of file diff --git a/src/lib/sw_engine/tvgSwRasterTexmapInternal.h b/src/lib/sw_engine/tvgSwRasterTexmapInternal.h index ce234cf..0a93530 100644 --- a/src/lib/sw_engine/tvgSwRasterTexmapInternal.h +++ b/src/lib/sw_engine/tvgSwRasterTexmapInternal.h @@ -33,28 +33,48 @@ int uu = 0; float dx, u, v, iptr; uint32_t* buf; + int regionTop; + int regionBottom; + SwSpan* span = nullptr; //used only when rle based. + #ifdef TEXMAP_MASKING uint32_t* cmp; #endif + if (region) { + regionTop = region->min.y; + regionBottom = region->max.y; + } else { + regionTop = image->rle->spans->y; + regionBottom = image->rle->spans[image->rle->size - 1].y; + } + //Range exception handling - if (ystart >= region.max.y) return; - if (ystart < region.min.y) ystart = region.min.y; - if (yend > region.max.y) yend = region.max.y; + if (yStart >= regionBottom) return; + if (yStart < regionTop) yStart = regionTop; + if (yEnd > regionBottom) yEnd = regionBottom; //Loop through all lines in the segment - y = ystart; + y = yStart; + + if (!region) span = image->rle->spans + (yStart - regionTop); - while (y < yend) { + while (y < yEnd) { x1 = _xa; x2 = _xb; //Range exception handling - if (x1 < region.min.x) x1 = region.min.x; - if (x2 > region.max.x) x2 = region.max.x; - - if ((x2 - x1) < 1) goto next; - if ((x1 >= region.max.x) || (x2 <= region.min.x)) goto next; + if (region) { + if (x1 < region->min.x) x1 = region->min.x; + if (x2 > region->max.x) x2 = region->max.x; + if ((x2 - x1) < 1) goto next; + if ((x1 >= region->max.x) || (x2 <= region->min.x)) goto next; + } else { + if (x1 < span->x) x1 = span->x; + if (x2 > span->x + span->len) x2 = (span->x + span->len); + if ((x2 - x1) < 1) goto next; + if ((x1 >= (span->x + span->len)) || (x2 <= span->x)) goto next; + } //Perform subtexel pre-stepping on UV dx = 1 - (_xa - x1); @@ -105,7 +125,7 @@ #elif defined(TEXMAP_TRANSLUCENT) auto src = ALPHA_BLEND(px, opacity); #else - auto src = px; + auto src = px; #endif *buf = src + ALPHA_BLEND(*buf, _ialpha(src)); ++buf; @@ -123,7 +143,12 @@ next: _ua += _dudya; _va += _dvdya; - y++; + if (span) { + ++span; + y = span->y; + } else { + y++; + } } xa = _xa; xb = _xb; diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index 1c0c3c2..672b938 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -111,11 +111,14 @@ struct SwShapeTask : SwTask //Fill if (flags & (RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform | RenderUpdateFlag::Color)) { if (visibleFill) { + auto antiAlias = (flags & RenderUpdateFlag::IgnoreAliasing) ? false : true; + /* We assume that if stroke width is bigger than 2, shape outline below stroke could be full covered by stroke drawing. Thus it turns off antialising in that condition. Also, it shouldn't be dash style. */ - auto antiAlias = (strokeAlpha == 255 && sdata->strokeWidth() > 2 && sdata->strokeDash(nullptr) == 0) ? false : true; + if (strokeAlpha == 255 && sdata->strokeWidth() > 2 && sdata->strokeDash(nullptr) == 0) antiAlias = false; + if (!shapeGenRle(&shape, sdata, antiAlias)) goto err; } if (auto fill = sdata->fill()) { diff --git a/src/lib/tvgPaint.cpp b/src/lib/tvgPaint.cpp index 909e6be..d258dd5 100644 --- a/src/lib/tvgPaint.cpp +++ b/src/lib/tvgPaint.cpp @@ -201,7 +201,7 @@ void* Paint::Impl::update(RenderMethod& renderer, const RenderTransform* pTransf if (compData) { auto target = compData->target; auto method = compData->method; - target->pImpl->ctxFlag = ContextFlag::Invalid; //reset + target->pImpl->ctxFlag &= ~ContextFlag::FastTrack; //reset /* If transform has no rotation factors && ClipPath / AlphaMasking is a simple rectangle, we can avoid regular ClipPath / AlphaMasking sequence but use viewport for performance */ @@ -223,7 +223,15 @@ void* Paint::Impl::update(RenderMethod& renderer, const RenderTransform* pTransf } } if (!compFastTrack) { - tdata = target->pImpl->update(renderer, pTransform, 255, clips, pFlag); + //Bad design!: ignore anti-aliasing if the bitmap image is the source of the clip-path! + auto tempFlag = pFlag; + + if (id == TVG_CLASS_ID_PICTURE) { + auto picture = static_cast(compData->source); + if (picture->data(nullptr, nullptr)) tempFlag |= RenderUpdateFlag::IgnoreAliasing; + } + + tdata = target->pImpl->update(renderer, pTransform, 255, clips, tempFlag); if (method == CompositeMethod::ClipPath) clips.push(tdata); } } @@ -249,6 +257,7 @@ void* Paint::Impl::update(RenderMethod& renderer, const RenderTransform* pTransf return edata; } + bool Paint::Impl::bounds(float* x, float* y, float* w, float* h, bool transformed) { Matrix* m = nullptr; diff --git a/src/lib/tvgPaint.h b/src/lib/tvgPaint.h index 1f36ec3..4003bdb 100644 --- a/src/lib/tvgPaint.h +++ b/src/lib/tvgPaint.h @@ -67,7 +67,8 @@ namespace tvg uint32_t id; uint8_t opacity = 255; - ~Impl() { + ~Impl() + { if (compData) { delete(compData->target); free(compData); diff --git a/src/lib/tvgRender.h b/src/lib/tvgRender.h index 955816e..7621fe2 100644 --- a/src/lib/tvgRender.h +++ b/src/lib/tvgRender.h @@ -28,7 +28,7 @@ namespace tvg { -enum RenderUpdateFlag {None = 0, Path = 1, Color = 2, Gradient = 4, Stroke = 8, Transform = 16, Image = 32, GradientStroke = 64, All = 127}; +enum RenderUpdateFlag {None = 0, Path = 1, Color = 2, Gradient = 4, Stroke = 8, Transform = 16, Image = 32, GradientStroke = 64, All = 255, IgnoreAliasing = 256}; struct Surface { -- 2.7.4