From f4d1065d5247abfd074aaff08a2db28343288357 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Sat, 15 Aug 2020 16:29:46 +0900 Subject: [PATCH] sw_engine: convert colorspace ARGB -> RGBA in default. We can use RGBA colorspace rather ARGB for pixel data. This would be better for many rendering system, since it's more widely preferred than ARGB including opengl. Change-Id: Ibbfe6a511d77bf0ef30ce261995467c11164d306 --- inc/thorvg.h | 4 +- inc/thorvg_capi.h | 4 +- src/bindings/capi/tvgCapi.cpp | 4 +- src/lib/sw_engine/tvgSwCommon.h | 30 +++++-- src/lib/sw_engine/tvgSwFill.cpp | 26 +++--- src/lib/sw_engine/tvgSwRaster.cpp | 124 +++++++++++++++++++--------- src/lib/sw_engine/tvgSwRenderer.cpp | 5 +- src/lib/sw_engine/tvgSwRenderer.h | 2 +- src/lib/sw_engine/tvgSwShape.cpp | 4 +- src/lib/tvgGlCanvas.cpp | 2 +- src/lib/tvgRender.h | 1 + src/lib/tvgSwCanvas.cpp | 4 +- test/testArc.cpp | 2 +- test/testAsync.cpp | 2 +- test/testBlending.cpp | 2 +- test/testBoundary.cpp | 2 +- test/testCapi.c | 2 +- test/testCustomTransform.cpp | 2 +- test/testDirectUpdate.cpp | 2 +- test/testGradientTransform.cpp | 2 +- test/testLinearGradient.cpp | 2 +- test/testMultiShapes.cpp | 2 +- test/testPath.cpp | 2 +- test/testPathCopy.cpp | 2 +- test/testRadialGradient.cpp | 2 +- test/testScene.cpp | 2 +- test/testSceneTransform.cpp | 2 +- test/testShape.cpp | 2 +- test/testStroke.cpp | 2 +- test/testStrokeLine.cpp | 2 +- test/testSvg.cpp | 2 +- test/testSvg2.cpp | 2 +- test/testTransform.cpp | 2 +- test/testUpdate.cpp | 2 +- 34 files changed, 157 insertions(+), 97 deletions(-) diff --git a/inc/thorvg.h b/inc/thorvg.h index 3f43a2fc..9ed54988 100644 --- a/inc/thorvg.h +++ b/inc/thorvg.h @@ -311,7 +311,9 @@ class TVG_EXPORT SwCanvas final : public Canvas public: ~SwCanvas(); - Result target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) noexcept; + enum Colorspace { RGBA8888 = 0, ARGB8888 }; + + Result target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, Colorspace cs) noexcept; static std::unique_ptr gen() noexcept; diff --git a/inc/thorvg_capi.h b/inc/thorvg_capi.h index 763d71b2..2f1bf967 100644 --- a/inc/thorvg_capi.h +++ b/inc/thorvg_capi.h @@ -23,6 +23,8 @@ typedef struct _Tvg_Gradient Tvg_Gradient; #define TVG_ENGINE_SW (1 << 1) #define TVG_ENGINE_GL (1 << 2) +#define TVG_COLORSPACE_RGBA8888 0 +#define TVG_COLORSPACE_ARGB8888 1 typedef enum { TVG_RESULT_SUCCESS = 0, @@ -94,7 +96,7 @@ TVG_EXPORT Tvg_Result tvg_engine_term(unsigned engine_method); /* SwCanvas API */ /************************************************************************/ TVG_EXPORT Tvg_Canvas* tvg_swcanvas_create(); -TVG_EXPORT Tvg_Result tvg_swcanvas_set_target(Tvg_Canvas* canvas, uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h); +TVG_EXPORT Tvg_Result tvg_swcanvas_set_target(Tvg_Canvas* canvas, uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, uint32_t cs); /************************************************************************/ diff --git a/src/bindings/capi/tvgCapi.cpp b/src/bindings/capi/tvgCapi.cpp index e05435a5..ac8cdcb1 100644 --- a/src/bindings/capi/tvgCapi.cpp +++ b/src/bindings/capi/tvgCapi.cpp @@ -88,9 +88,9 @@ TVG_EXPORT Tvg_Result tvg_canvas_destroy(Tvg_Canvas* canvas) } -TVG_EXPORT Tvg_Result tvg_swcanvas_set_target(Tvg_Canvas* canvas, uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) +TVG_EXPORT Tvg_Result tvg_swcanvas_set_target(Tvg_Canvas* canvas, uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, uint32_t cs) { - return (Tvg_Result) reinterpret_cast(canvas)->target(buffer, stride, w, h); + return (Tvg_Result) reinterpret_cast(canvas)->target(buffer, stride, w, h, static_cast(cs)); } diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index 295f11a5..e5d4719f 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -222,20 +222,26 @@ static inline SwCoord TO_SWCOORD(float val) } -static inline uint32_t COLOR_ALPHA(uint32_t rgba) +static inline uint32_t RGBA_ALPHA(uint32_t rgba) { - return (rgba >> 24) & 0xff; + return rgba & 0x000000ff; } -static inline uint32_t COLOR_ALPHA_BLEND(uint32_t rgba, uint32_t alpha) +static inline uint32_t ARGB_ALPHA(uint32_t argb) +{ + return (argb >> 24) & 0xff; +} + + +static inline uint32_t RGBA_ALPHA_BLEND(uint32_t rgba, uint32_t alpha) { return (((((rgba >> 8) & 0x00ff00ff) * alpha) & 0xff00ff00) + ((((rgba & 0x00ff00ff) * alpha) >> 8) & 0x00ff00ff)); } -static inline uint32_t COLOR_INTERPOLATE(uint32_t rgba1, uint32_t a, uint32_t rgba2, uint32_t b) +static inline uint32_t RGBA_INTERPOLATE(uint32_t rgba1, uint32_t a, uint32_t rgba2, uint32_t b) { auto t = (((rgba1 & 0xff00ff) * a + (rgba2 & 0xff00ff) * b) >> 8) & 0xff00ff; rgba1 = (((rgba1 >> 8) & 0xff00ff) * a + ((rgba2 >> 8) & 0xff00ff) * b) & 0xff00ff00; @@ -243,13 +249,19 @@ static inline uint32_t COLOR_INTERPOLATE(uint32_t rgba1, uint32_t a, uint32_t rg } -static inline uint32_t COLOR_ARGB_JOIN(uint8_t r, uint8_t g, uint8_t b, uint8_t a) +static inline uint32_t RGBA_JOIN(uint8_t r, uint8_t g, uint8_t b, uint8_t a) +{ + return (r << 24 | g << 16 | b << 8 | a); +} + + +static inline uint32_t ARGB_JOIN(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { return (a << 24 | r << 16 | g << 8 | b); } -static inline uint8_t COLOR_ALPHA_MULTIPLY(uint32_t c, uint32_t a) +static inline uint8_t ALPHA_MULTIPLY(uint32_t c, uint32_t a) { return (c * a) >> 8; } @@ -278,7 +290,7 @@ void shapeResetStroke(SwShape* shape, const Shape* sdata, const Matrix* transfor bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, const Matrix* transform, const SwSize& clip); void shapeFree(SwShape* shape); void shapeDelStroke(SwShape* shape); -bool shapeGenFillColors(SwShape* shape, const Fill* fill, const Matrix* transform, bool ctable); +bool shapeGenFillColors(SwShape* shape, const Fill* fill, const Matrix* transform, uint32_t cs, bool ctable); void shapeResetFill(SwShape* shape); void shapeDelFill(SwShape* shape); @@ -287,7 +299,7 @@ bool strokeParseOutline(SwStroke* stroke, const SwOutline& outline); SwOutline* strokeExportOutline(SwStroke* stroke); void strokeFree(SwStroke* stroke); -bool fillGenColorTable(SwFill* fill, const Fill* fdata, const Matrix* transform, bool ctable); +bool fillGenColorTable(SwFill* fill, const Fill* fdata, const Matrix* transform, uint32_t cs, 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); @@ -302,7 +314,7 @@ bool rasterStroke(Surface& surface, SwShape* shape, uint8_t r, uint8_t g, uint8_ bool rasterClear(Surface& surface); -static inline void rasterARGB32(uint32_t *dst, uint32_t val, uint32_t offset, int32_t len) +static inline void rasterRGBA32(uint32_t *dst, uint32_t val, uint32_t offset, int32_t len) { #ifdef THORVG_AVX_VECTOR_SUPPORT int32_t align = (8 - (offset % 8)) % 8; diff --git a/src/lib/sw_engine/tvgSwFill.cpp b/src/lib/sw_engine/tvgSwFill.cpp index ae938fd3..cd68d0f1 100644 --- a/src/lib/sw_engine/tvgSwFill.cpp +++ b/src/lib/sw_engine/tvgSwFill.cpp @@ -34,7 +34,7 @@ #define FIXPT_SIZE (1<a < 255) fill->translucent = true; - auto r = COLOR_ALPHA_MULTIPLY(pColors->r, pColors->a); - auto g = COLOR_ALPHA_MULTIPLY(pColors->g, pColors->a); - auto b = COLOR_ALPHA_MULTIPLY(pColors->b, pColors->a); + auto r = ALPHA_MULTIPLY(pColors->r, pColors->a); + auto g = ALPHA_MULTIPLY(pColors->g, pColors->a); + auto b = ALPHA_MULTIPLY(pColors->b, pColors->a); - auto rgba = COLOR_ARGB_JOIN(r, g, b, pColors->a); + auto rgba = (cs == SwCanvas::RGBA8888) ? RGBA_JOIN(r, g, b, pColors->a) : ARGB_JOIN(r, g, b, pColors->a); auto inc = 1.0f / static_cast(GRADIENT_STOP_SIZE); auto pos = 1.5f * inc; uint32_t i = 0; @@ -75,17 +75,17 @@ static bool _updateColorTable(SwFill* fill, const Fill* fdata) auto delta = 1.0f / (next->offset - curr->offset); if (next->a < 255) fill->translucent = true; - auto r = COLOR_ALPHA_MULTIPLY(next->r, next->a); - auto g = COLOR_ALPHA_MULTIPLY(next->g, next->a); - auto b = COLOR_ALPHA_MULTIPLY(next->b, next->a); + auto r = ALPHA_MULTIPLY(next->r, next->a); + auto g = ALPHA_MULTIPLY(next->g, next->a); + auto b = ALPHA_MULTIPLY(next->b, next->a); - auto rgba2 = COLOR_ARGB_JOIN(r, g, b, next->a); + auto rgba2 = (cs == SwCanvas::RGBA8888) ? RGBA_JOIN(r, g, b, next->a) : ARGB_JOIN(r, g, b, next->a); while (pos < next->offset && i < GRADIENT_STOP_SIZE) { auto t = (pos - curr->offset) * delta; auto dist = static_cast(256 * t); auto dist2 = 256 - dist; - fill->ctable[i] = COLOR_INTERPOLATE(rgba, dist2, rgba2, dist); + fill->ctable[i] = RGBA_INTERPOLATE(rgba, dist2, rgba2, dist); ++i; pos += inc; } @@ -252,7 +252,7 @@ void fillFetchLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, if (fabsf(inc) < FLT_EPSILON) { auto color = _fixedPixel(fill, static_cast(t * FIXPT_SIZE)); - rasterARGB32(dst, color, offset, len); + rasterRGBA32(dst, color, offset, len); return; } @@ -282,7 +282,7 @@ void fillFetchLinear(const SwFill* fill, uint32_t* dst, uint32_t y, uint32_t x, } -bool fillGenColorTable(SwFill* fill, const Fill* fdata, const Matrix* transform, bool ctable) +bool fillGenColorTable(SwFill* fill, const Fill* fdata, const Matrix* transform, uint32_t cs, bool ctable) { if (!fill) return false; @@ -291,7 +291,7 @@ bool fillGenColorTable(SwFill* fill, const Fill* fdata, const Matrix* transform, fill->spread = fdata->spread(); if (ctable) { - if (!_updateColorTable(fill, fdata)) return false; + if (!_updateColorTable(fill, fdata, cs)) return false; } if (fdata->id() == FILL_ID_LINEAR) { diff --git a/src/lib/sw_engine/tvgSwRaster.cpp b/src/lib/sw_engine/tvgSwRaster.cpp index 46ef4ac0..d07d7eb1 100644 --- a/src/lib/sw_engine/tvgSwRaster.cpp +++ b/src/lib/sw_engine/tvgSwRaster.cpp @@ -45,12 +45,12 @@ static bool _rasterTranslucentRect(Surface& surface, const SwBBox& region, uint3 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); - auto ialpha = 255 - COLOR_ALPHA(color); + auto ialpha = 255 - (surface.cs == SwCanvas::RGBA8888)? RGBA_ALPHA(color) : ARGB_ALPHA(color); for (uint32_t y = 0; y < h; ++y) { auto dst = &buffer[y * surface.stride]; for (uint32_t x = 0; x < w; ++x) { - dst[x] = color + COLOR_ALPHA_BLEND(dst[x], ialpha); + dst[x] = color + RGBA_ALPHA_BLEND(dst[x], ialpha); } } return true; @@ -64,7 +64,7 @@ static bool _rasterSolidRect(Surface& surface, const SwBBox& region, uint32_t co auto h = static_cast(region.max.y - region.min.y); for (uint32_t y = 0; y < h; ++y) { - rasterARGB32(buffer + y * surface.stride, color, region.min.x, w); + rasterRGBA32(buffer + y * surface.stride, color, region.min.x, w); } return true; } @@ -79,11 +79,11 @@ static bool _rasterTranslucentRle(Surface& surface, SwRleData* rle, uint32_t col for (uint32_t i = 0; i < rle->size; ++i) { auto dst = &surface.buffer[span->y * surface.stride + span->x]; - if (span->coverage < 255) src = COLOR_ALPHA_BLEND(color, span->coverage); + if (span->coverage < 255) src = RGBA_ALPHA_BLEND(color, span->coverage); else src = color; - auto ialpha = 255 - COLOR_ALPHA(src); + auto ialpha = 255 - ((surface.cs == SwCanvas::RGBA8888)? RGBA_ALPHA(src) : ARGB_ALPHA(src)); for (uint32_t i = 0; i < span->len; ++i) { - dst[i] = src + COLOR_ALPHA_BLEND(dst[i], ialpha); + dst[i] = src + RGBA_ALPHA_BLEND(dst[i], ialpha); } ++span; } @@ -99,13 +99,13 @@ static bool _rasterSolidRle(Surface& surface, SwRleData* rle, uint32_t color) for (uint32_t i = 0; i < rle->size; ++i) { if (span->coverage == 255) { - rasterARGB32(surface.buffer + span->y * surface.stride, color, span->x, span->len); + rasterRGBA32(surface.buffer + span->y * surface.stride, color, span->x, span->len); } else { auto dst = &surface.buffer[span->y * surface.stride + span->x]; - auto src = COLOR_ALPHA_BLEND(color, span->coverage); + auto src = RGBA_ALPHA_BLEND(color, span->coverage); auto ialpha = 255 - span->coverage; for (uint32_t i = 0; i < span->len; ++i) { - dst[i] = src + COLOR_ALPHA_BLEND(dst[i], ialpha); + dst[i] = src + RGBA_ALPHA_BLEND(dst[i], ialpha); } } ++span; @@ -131,8 +131,14 @@ static bool _rasterLinearGradientRect(Surface& surface, const SwBBox& region, co 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); - for (uint32_t x = 0; x < w; ++x) { - dst[x] = tmpBuf[x] + COLOR_ALPHA_BLEND(dst[x], 255 - COLOR_ALPHA(tmpBuf[x])); + if (surface.cs == SwCanvas::RGBA8888) { + for (uint32_t x = 0; x < w; ++x) { + dst[x] = tmpBuf[x] + RGBA_ALPHA_BLEND(dst[x], 255 - RGBA_ALPHA(tmpBuf[x])); + } + } else { + for (uint32_t x = 0; x < w; ++x) { + dst[x] = tmpBuf[x] + RGBA_ALPHA_BLEND(dst[x], 255 - ARGB_ALPHA(tmpBuf[x])); + } } } //Opaque Gradient @@ -162,8 +168,14 @@ static bool _rasterRadialGradientRect(Surface& surface, const SwBBox& region, co 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] + COLOR_ALPHA_BLEND(dst[x], 255 - COLOR_ALPHA(tmpBuf[x])); + if (surface.cs == SwCanvas::RGBA8888) { + for (uint32_t x = 0; x < w; ++x) { + dst[x] = tmpBuf[x] + RGBA_ALPHA_BLEND(dst[x], 255 - RGBA_ALPHA(tmpBuf[x])); + } + } else { + for (uint32_t x = 0; x < w; ++x) { + dst[x] = tmpBuf[x] + RGBA_ALPHA_BLEND(dst[x], 255 - ARGB_ALPHA(tmpBuf[x])); + } } } //Opaque Gradient @@ -191,14 +203,27 @@ static bool _rasterLinearGradientRle(Surface& surface, SwRleData* rle, const SwF 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); - if (span->coverage == 255) { - for (uint32_t i = 0; i < span->len; ++i) { - dst[i] = buf[i] + COLOR_ALPHA_BLEND(dst[i], 255 - COLOR_ALPHA(buf[i])); + if (surface.cs == SwCanvas::RGBA8888) { + if (span->coverage == 255) { + for (uint32_t i = 0; i < span->len; ++i) { + dst[i] = buf[i] + RGBA_ALPHA_BLEND(dst[i], 255 - RGBA_ALPHA(buf[i])); + } + } else { + for (uint32_t i = 0; i < span->len; ++i) { + auto tmp = RGBA_ALPHA_BLEND(buf[i], span->coverage); + dst[i] = tmp + RGBA_ALPHA_BLEND(dst[i], 255 - RGBA_ALPHA(tmp)); + } } } else { - for (uint32_t i = 0; i < span->len; ++i) { - auto tmp = COLOR_ALPHA_BLEND(buf[i], span->coverage); - dst[i] = tmp + COLOR_ALPHA_BLEND(dst[i], 255 - COLOR_ALPHA(tmp)); + if (span->coverage == 255) { + for (uint32_t i = 0; i < span->len; ++i) { + dst[i] = buf[i] + RGBA_ALPHA_BLEND(dst[i], 255 - ARGB_ALPHA(buf[i])); + } + } else { + for (uint32_t i = 0; i < span->len; ++i) { + auto tmp = RGBA_ALPHA_BLEND(buf[i], span->coverage); + dst[i] = tmp + RGBA_ALPHA_BLEND(dst[i], 255 - ARGB_ALPHA(tmp)); + } } } ++span; @@ -213,7 +238,7 @@ static bool _rasterLinearGradientRle(Surface& surface, SwRleData* rle, const SwF fillFetchLinear(fill, buf, span->y, span->x, 0, span->len); auto ialpha = 255 - span->coverage; for (uint32_t i = 0; i < span->len; ++i) { - dst[i] = COLOR_ALPHA_BLEND(buf[i], span->coverage) + COLOR_ALPHA_BLEND(dst[i], ialpha); + dst[i] = RGBA_ALPHA_BLEND(buf[i], span->coverage) + RGBA_ALPHA_BLEND(dst[i], ialpha); } } ++span; @@ -237,14 +262,27 @@ static bool _rasterRadialGradientRle(Surface& surface, SwRleData* rle, const SwF 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] + COLOR_ALPHA_BLEND(dst[i], 255 - COLOR_ALPHA(buf[i])); + if (surface.cs == SwCanvas::RGBA8888) { + if (span->coverage == 255) { + for (uint32_t i = 0; i < span->len; ++i) { + dst[i] = buf[i] + RGBA_ALPHA_BLEND(dst[i], 255 - RGBA_ALPHA(buf[i])); + } + } else { + for (uint32_t i = 0; i < span->len; ++i) { + auto tmp = RGBA_ALPHA_BLEND(buf[i], span->coverage); + dst[i] = tmp + RGBA_ALPHA_BLEND(dst[i], 255 - RGBA_ALPHA(tmp)); + } } } else { - for (uint32_t i = 0; i < span->len; ++i) { - auto tmp = COLOR_ALPHA_BLEND(buf[i], span->coverage); - dst[i] = tmp + COLOR_ALPHA_BLEND(dst[i], 255 - COLOR_ALPHA(tmp)); + if (span->coverage == 255) { + for (uint32_t i = 0; i < span->len; ++i) { + dst[i] = buf[i] + RGBA_ALPHA_BLEND(dst[i], 255 - ARGB_ALPHA(buf[i])); + } + } else { + for (uint32_t i = 0; i < span->len; ++i) { + auto tmp = RGBA_ALPHA_BLEND(buf[i], span->coverage); + dst[i] = tmp + RGBA_ALPHA_BLEND(dst[i], 255 - ARGB_ALPHA(tmp)); + } } } ++span; @@ -259,7 +297,7 @@ static bool _rasterRadialGradientRle(Surface& surface, SwRleData* rle, const SwF 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] = COLOR_ALPHA_BLEND(buf[i], span->coverage) + COLOR_ALPHA_BLEND(dst[i], ialpha); + dst[i] = RGBA_ALPHA_BLEND(buf[i], span->coverage) + RGBA_ALPHA_BLEND(dst[i], ialpha); } } ++span; @@ -290,18 +328,20 @@ bool rasterGradientShape(Surface& surface, SwShape* shape, unsigned id) bool rasterSolidShape(Surface& surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a) { - r = COLOR_ALPHA_MULTIPLY(r, a); - g = COLOR_ALPHA_MULTIPLY(g, a); - b = COLOR_ALPHA_MULTIPLY(b, a); + r = ALPHA_MULTIPLY(r, a); + g = ALPHA_MULTIPLY(g, a); + b = ALPHA_MULTIPLY(b, a); + + auto color = (surface.cs == SwCanvas::RGBA8888) ? RGBA_JOIN(r, g, b, a) : ARGB_JOIN(r, g, b, a); //Fast Track if (shape->rect) { auto region = _clipRegion(surface, shape->bbox); - if (a == 255) return _rasterSolidRect(surface, region, COLOR_ARGB_JOIN(r, g, b, a)); - return _rasterTranslucentRect(surface, region, COLOR_ARGB_JOIN(r, g, b, a)); + if (a == 255) return _rasterSolidRect(surface, region, color); + return _rasterTranslucentRect(surface, region, color); } else{ - if (a == 255) return _rasterSolidRle(surface, shape->rle, COLOR_ARGB_JOIN(r, g, b, a)); - return _rasterTranslucentRle(surface, shape->rle, COLOR_ARGB_JOIN(r, g, b, a)); + if (a == 255) return _rasterSolidRle(surface, shape->rle, color); + return _rasterTranslucentRle(surface, shape->rle, color); } return false; } @@ -309,12 +349,14 @@ bool rasterSolidShape(Surface& surface, SwShape* shape, uint8_t r, uint8_t g, ui bool rasterStroke(Surface& surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a) { - r = COLOR_ALPHA_MULTIPLY(r, a); - g = COLOR_ALPHA_MULTIPLY(g, a); - b = COLOR_ALPHA_MULTIPLY(b, a); + r = ALPHA_MULTIPLY(r, a); + g = ALPHA_MULTIPLY(g, a); + b = ALPHA_MULTIPLY(b, a); - if (a == 255) return _rasterSolidRle(surface, shape->strokeRle, COLOR_ARGB_JOIN(r, g, b, a)); - return _rasterTranslucentRle(surface, shape->strokeRle, COLOR_ARGB_JOIN(r, g, b, a)); + auto color = (surface.cs == SwCanvas::RGBA8888) ? RGBA_JOIN(r, g, b, a) : ARGB_JOIN(r, g, b, a); + + if (a == 255) return _rasterSolidRle(surface, shape->strokeRle, color); + return _rasterTranslucentRle(surface, shape->strokeRle, color); } @@ -323,10 +365,10 @@ bool rasterClear(Surface& surface) if (!surface.buffer || surface.stride <= 0 || surface.w <= 0 || surface.h <= 0) return false; if (surface.w == surface.stride) { - rasterARGB32(surface.buffer, 0x00000000, 0, surface.w * surface.h); + rasterRGBA32(surface.buffer, 0x00000000, 0, surface.w * surface.h); } else { for (uint32_t i = 0; i < surface.h; i++) { - rasterARGB32(surface.buffer + surface.stride * i, 0x00000000, 0, surface.w); + rasterRGBA32(surface.buffer + surface.stride * i, 0x00000000, 0, surface.w); } } return true; diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index eb2f199e..66608f54 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -40,7 +40,7 @@ SwRenderer::~SwRenderer() } -bool SwRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) +bool SwRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, uint32_t cs) { if (!buffer || stride == 0 || w == 0 || h == 0) return false; @@ -48,6 +48,7 @@ bool SwRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t surface.stride = stride; surface.w = w; surface.h = h; + surface.cs = cs; return true; } @@ -129,7 +130,7 @@ void* SwRenderer::prepare(const Shape& sdata, void* data, const RenderTransform* if (fill) { auto ctable = (flags & RenderUpdateFlag::Gradient) ? true : false; if (ctable) shapeResetFill(shape); - if (!shapeGenFillColors(shape, fill, matrix, ctable)) return shape; + if (!shapeGenFillColors(shape, fill, matrix, surface.cs, ctable)) return shape; } else { shapeDelFill(shape); } diff --git a/src/lib/sw_engine/tvgSwRenderer.h b/src/lib/sw_engine/tvgSwRenderer.h index 9a419028..5657602b 100644 --- a/src/lib/sw_engine/tvgSwRenderer.h +++ b/src/lib/sw_engine/tvgSwRenderer.h @@ -34,7 +34,7 @@ public: bool dispose(const Shape& shape, void *data) override; bool preRender() override; bool render(const Shape& shape, void *data) override; - bool target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h); + bool target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, uint32_t cs); uint32_t ref() override; uint32_t unref() override; diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index f9537d1b..3704a2cb 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -672,9 +672,9 @@ bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, const Matrix* transfo } -bool shapeGenFillColors(SwShape* shape, const Fill* fill, const Matrix* transform, bool ctable) +bool shapeGenFillColors(SwShape* shape, const Fill* fill, const Matrix* transform, uint32_t cs, bool ctable) { - return fillGenColorTable(shape->fill, fill, transform, ctable); + return fillGenColorTable(shape->fill, fill, transform, cs, ctable); } diff --git a/src/lib/tvgGlCanvas.cpp b/src/lib/tvgGlCanvas.cpp index 7f2c04b7..1ac57329 100644 --- a/src/lib/tvgGlCanvas.cpp +++ b/src/lib/tvgGlCanvas.cpp @@ -70,7 +70,7 @@ Result GlCanvas::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t auto renderer = static_cast(Canvas::pImpl.get()->renderer); if (!renderer) return Result::MemoryCorruption; - if (!renderer->target(buffer, stride, w, h)) return Result::Unknown; + if (!renderer->target(buffer, stride, w, h, 0)) return Result::Unknown; return Result::Success; #endif diff --git a/src/lib/tvgRender.h b/src/lib/tvgRender.h index 60c76d50..3535bf43 100644 --- a/src/lib/tvgRender.h +++ b/src/lib/tvgRender.h @@ -31,6 +31,7 @@ struct Surface uint32_t* buffer; uint32_t stride; uint32_t w, h; + uint32_t cs; }; enum RenderUpdateFlag {None = 0, Path = 1, Color = 2, Gradient = 4, Stroke = 8, Transform = 16, All = 32}; diff --git a/src/lib/tvgSwCanvas.cpp b/src/lib/tvgSwCanvas.cpp index e958ea26..755d422d 100644 --- a/src/lib/tvgSwCanvas.cpp +++ b/src/lib/tvgSwCanvas.cpp @@ -62,14 +62,14 @@ SwCanvas::~SwCanvas() } -Result SwCanvas::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) noexcept +Result SwCanvas::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, Colorspace cs) noexcept { #ifdef THORVG_SW_RASTER_SUPPORT //We know renderer type, avoid dynamic_cast for performance. auto renderer = static_cast(Canvas::pImpl.get()->renderer); if (!renderer) return Result::MemoryCorruption; - if (!renderer->target(buffer, stride, w, h)) return Result::InvalidArguments; + if (!renderer->target(buffer, stride, w, h, cs)) return Result::InvalidArguments; return Result::Success; #endif diff --git a/test/testArc.cpp b/test/testArc.cpp index b02196ef..1f158122 100644 --- a/test/testArc.cpp +++ b/test/testArc.cpp @@ -79,7 +79,7 @@ void tvgSwTest(uint32_t* buffer) { //Create a Canvas swCanvas = tvg::SwCanvas::gen(); - swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); + swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888); /* Push the shape into the Canvas drawing list When this shape is into the canvas list, the shape could update & prepare diff --git a/test/testAsync.cpp b/test/testAsync.cpp index edc6dde7..608cefb2 100644 --- a/test/testAsync.cpp +++ b/test/testAsync.cpp @@ -68,7 +68,7 @@ void tvgSwTest(uint32_t* buffer) { //Create a Canvas swCanvas = tvg::SwCanvas::gen(); - swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); + swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888); } Eina_Bool animSwCb(void* data) diff --git a/test/testBlending.cpp b/test/testBlending.cpp index 59a4fad7..743b1e09 100644 --- a/test/testBlending.cpp +++ b/test/testBlending.cpp @@ -62,7 +62,7 @@ void tvgSwTest(uint32_t* buffer) { //Create a Canvas swCanvas = tvg::SwCanvas::gen(); - swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); + swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888); /* Push the shape into the Canvas drawing list When this shape is into the canvas list, the shape could update & prepare diff --git a/test/testBoundary.cpp b/test/testBoundary.cpp index 57a3d6c6..38306877 100644 --- a/test/testBoundary.cpp +++ b/test/testBoundary.cpp @@ -51,7 +51,7 @@ void tvgSwTest(uint32_t* buffer) { //Create a Canvas swCanvas = tvg::SwCanvas::gen(); - swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); + swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888); /* Push the shape into the Canvas drawing list When this shape is into the canvas list, the shape could update & prepare diff --git a/test/testCapi.c b/test/testCapi.c index 90c4e1d7..c6df3968 100644 --- a/test/testCapi.c +++ b/test/testCapi.c @@ -16,7 +16,7 @@ void testCapi() tvg_engine_init(TVG_ENGINE_SW | TVG_ENGINE_GL); Tvg_Canvas* canvas = tvg_swcanvas_create(); - tvg_swcanvas_set_target(canvas, buffer, WIDTH, WIDTH, HEIGHT); + tvg_swcanvas_set_target(canvas, buffer, WIDTH, WIDTH, HEIGHT, TVG_COLORSPACE_ARGB8888); Tvg_Paint* shape = tvg_shape_new(); tvg_shape_append_rect(shape, 0, 0, 200, 200, 0, 0); diff --git a/test/testCustomTransform.cpp b/test/testCustomTransform.cpp index 4803ef16..9daa6fc1 100644 --- a/test/testCustomTransform.cpp +++ b/test/testCustomTransform.cpp @@ -92,7 +92,7 @@ void tvgSwTest(uint32_t* buffer) { //Create a Canvas swCanvas = tvg::SwCanvas::gen(); - swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); + swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888); /* Push the shape into the Canvas drawing list When this shape is into the canvas list, the shape could update & prepare diff --git a/test/testDirectUpdate.cpp b/test/testDirectUpdate.cpp index 3c275b62..8dcc474a 100644 --- a/test/testDirectUpdate.cpp +++ b/test/testDirectUpdate.cpp @@ -55,7 +55,7 @@ void tvgSwTest(uint32_t* buffer) { //Create a Canvas swCanvas = tvg::SwCanvas::gen(); - swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); + swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888); /* Push the shape into the Canvas drawing list When this shape is into the canvas list, the shape could update & prepare diff --git a/test/testGradientTransform.cpp b/test/testGradientTransform.cpp index 4fa426be..77d5f6af 100644 --- a/test/testGradientTransform.cpp +++ b/test/testGradientTransform.cpp @@ -120,7 +120,7 @@ void tvgSwTest(uint32_t* buffer) { //Create a Canvas swCanvas = tvg::SwCanvas::gen(); - swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); + swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888); /* Push the shape into the Canvas drawing list When this shape is into the canvas list, the shape could update & prepare diff --git a/test/testLinearGradient.cpp b/test/testLinearGradient.cpp index f98fc970..db11682a 100644 --- a/test/testLinearGradient.cpp +++ b/test/testLinearGradient.cpp @@ -80,7 +80,7 @@ void tvgSwTest(uint32_t* buffer) { //Create a Canvas swCanvas = tvg::SwCanvas::gen(); - swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); + swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888); /* Push the shape into the Canvas drawing list When this shape is into the canvas list, the shape could update & prepare diff --git a/test/testMultiShapes.cpp b/test/testMultiShapes.cpp index 5a6d34f9..12009bc2 100644 --- a/test/testMultiShapes.cpp +++ b/test/testMultiShapes.cpp @@ -40,7 +40,7 @@ void tvgSwTest(uint32_t* buffer) { //Create a Canvas swCanvas = tvg::SwCanvas::gen(); - swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); + swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888); /* Push the shape into the Canvas drawing list When this shape is into the canvas list, the shape could update & prepare diff --git a/test/testPath.cpp b/test/testPath.cpp index 52c56efb..de6ef60e 100644 --- a/test/testPath.cpp +++ b/test/testPath.cpp @@ -57,7 +57,7 @@ void tvgSwTest(uint32_t* buffer) { //Create a Canvas swCanvas = tvg::SwCanvas::gen(); - swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); + swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888); /* Push the shape into the Canvas drawing list When this shape is into the canvas list, the shape could update & prepare diff --git a/test/testPathCopy.cpp b/test/testPathCopy.cpp index 0ae364b7..fb1080b3 100644 --- a/test/testPathCopy.cpp +++ b/test/testPathCopy.cpp @@ -94,7 +94,7 @@ void tvgSwTest(uint32_t* buffer) { //Create a Canvas swCanvas = tvg::SwCanvas::gen(); - swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); + swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888); /* Push the shape into the Canvas drawing list When this shape is into the canvas list, the shape could update & prepare diff --git a/test/testRadialGradient.cpp b/test/testRadialGradient.cpp index a6c10ba1..6e772915 100644 --- a/test/testRadialGradient.cpp +++ b/test/testRadialGradient.cpp @@ -80,7 +80,7 @@ void tvgSwTest(uint32_t* buffer) { //Create a Canvas swCanvas = tvg::SwCanvas::gen(); - swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); + swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888); /* Push the shape into the Canvas drawing list When this shape is into the canvas list, the shape could update & prepare diff --git a/test/testScene.cpp b/test/testScene.cpp index 5b12020e..daa5d868 100644 --- a/test/testScene.cpp +++ b/test/testScene.cpp @@ -87,7 +87,7 @@ void tvgSwTest(uint32_t* buffer) { //Create a Canvas swCanvas = tvg::SwCanvas::gen(); - swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); + swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888); /* Push the shape into the Canvas drawing list When this shape is into the canvas list, the shape could update & prepare diff --git a/test/testSceneTransform.cpp b/test/testSceneTransform.cpp index 49558fb7..e64fa9aa 100644 --- a/test/testSceneTransform.cpp +++ b/test/testSceneTransform.cpp @@ -116,7 +116,7 @@ void tvgSwTest(uint32_t* buffer) { //Create a Canvas swCanvas = tvg::SwCanvas::gen(); - swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); + swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888); /* Push the shape into the Canvas drawing list When this shape is into the canvas list, the shape could update & prepare diff --git a/test/testShape.cpp b/test/testShape.cpp index 88519d05..af4d0c47 100644 --- a/test/testShape.cpp +++ b/test/testShape.cpp @@ -30,7 +30,7 @@ void tvgSwTest(uint32_t* buffer) { //Create a Canvas swCanvas = tvg::SwCanvas::gen(); - swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); + swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888); /* Push the shape into the Canvas drawing list When this shape is into the canvas list, the shape could update & prepare diff --git a/test/testStroke.cpp b/test/testStroke.cpp index 91748727..778d7c7b 100644 --- a/test/testStroke.cpp +++ b/test/testStroke.cpp @@ -77,7 +77,7 @@ void tvgSwTest(uint32_t* buffer) { //Create a Canvas swCanvas = tvg::SwCanvas::gen(); - swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); + swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888); /* Push the shape into the Canvas drawing list When this shape is into the canvas list, the shape could update & prepare diff --git a/test/testStrokeLine.cpp b/test/testStrokeLine.cpp index 445f8406..1205bb14 100644 --- a/test/testStrokeLine.cpp +++ b/test/testStrokeLine.cpp @@ -114,7 +114,7 @@ void tvgSwTest(uint32_t* buffer) { //Create a Canvas swCanvas = tvg::SwCanvas::gen(); - swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); + swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888); /* Push the shape into the Canvas drawing list When this shape is into the canvas list, the shape could update & prepare diff --git a/test/testSvg.cpp b/test/testSvg.cpp index e16f19b1..06fe3501 100644 --- a/test/testSvg.cpp +++ b/test/testSvg.cpp @@ -72,7 +72,7 @@ void tvgSwTest(uint32_t* buffer) { //Create a Canvas swCanvas = tvg::SwCanvas::gen(); - swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); + swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888); /* Push the shape into the Canvas drawing list When this shape is into the canvas list, the shape could update & prepare diff --git a/test/testSvg2.cpp b/test/testSvg2.cpp index 171db919..2300f217 100644 --- a/test/testSvg2.cpp +++ b/test/testSvg2.cpp @@ -55,7 +55,7 @@ void tvgSwTest(uint32_t* buffer) { //Create a Canvas swCanvas = tvg::SwCanvas::gen(); - swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); + swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888); /* Push the shape into the Canvas drawing list When this shape is into the canvas list, the shape could update & prepare diff --git a/test/testTransform.cpp b/test/testTransform.cpp index 7529d140..5ef33f44 100644 --- a/test/testTransform.cpp +++ b/test/testTransform.cpp @@ -83,7 +83,7 @@ void tvgSwTest(uint32_t* buffer) { //Create a Canvas swCanvas = tvg::SwCanvas::gen(); - swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); + swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888); /* Push the shape into the Canvas drawing list When this shape is into the canvas list, the shape could update & prepare diff --git a/test/testUpdate.cpp b/test/testUpdate.cpp index 9c213436..3ff6c246 100644 --- a/test/testUpdate.cpp +++ b/test/testUpdate.cpp @@ -44,7 +44,7 @@ void tvgSwTest(uint32_t* buffer) { //Create a Canvas swCanvas = tvg::SwCanvas::gen(); - swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT); + swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888); /* Push the shape into the Canvas drawing list When this shape is into the canvas list, the shape could update & prepare