sw_engine: convert colorspace ARGB -> RGBA in default. 12/241112/5
authorHermet Park <chuneon.park@samsung.com>
Sat, 15 Aug 2020 07:29:46 +0000 (16:29 +0900)
committerHermet Park <chuneon.park@samsung.com>
Sat, 15 Aug 2020 09:22:43 +0000 (18:22 +0900)
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

34 files changed:
inc/thorvg.h
inc/thorvg_capi.h
src/bindings/capi/tvgCapi.cpp
src/lib/sw_engine/tvgSwCommon.h
src/lib/sw_engine/tvgSwFill.cpp
src/lib/sw_engine/tvgSwRaster.cpp
src/lib/sw_engine/tvgSwRenderer.cpp
src/lib/sw_engine/tvgSwRenderer.h
src/lib/sw_engine/tvgSwShape.cpp
src/lib/tvgGlCanvas.cpp
src/lib/tvgRender.h
src/lib/tvgSwCanvas.cpp
test/testArc.cpp
test/testAsync.cpp
test/testBlending.cpp
test/testBoundary.cpp
test/testCapi.c
test/testCustomTransform.cpp
test/testDirectUpdate.cpp
test/testGradientTransform.cpp
test/testLinearGradient.cpp
test/testMultiShapes.cpp
test/testPath.cpp
test/testPathCopy.cpp
test/testRadialGradient.cpp
test/testScene.cpp
test/testSceneTransform.cpp
test/testShape.cpp
test/testStroke.cpp
test/testStrokeLine.cpp
test/testSvg.cpp
test/testSvg2.cpp
test/testTransform.cpp
test/testUpdate.cpp

index 3f43a2f..9ed5498 100644 (file)
@@ -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<SwCanvas> gen() noexcept;
 
index 763d71b..2f1bf96 100644 (file)
@@ -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);
 
 
 /************************************************************************/
index e05435a..ac8cdcb 100644 (file)
@@ -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<SwCanvas*>(canvas)->target(buffer, stride, w, h);
+    return (Tvg_Result) reinterpret_cast<SwCanvas*>(canvas)->target(buffer, stride, w, h, static_cast<SwCanvas::Colorspace>(cs));
 }
 
 
index 295f11a..e5d4719 100644 (file)
@@ -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;
index ae938fd..cd68d0f 100644 (file)
@@ -34,7 +34,7 @@
 #define FIXPT_SIZE (1<<FIXPT_BITS)
 
 
-static bool _updateColorTable(SwFill* fill, const Fill* fdata)
+static bool _updateColorTable(SwFill* fill, const Fill* fdata, uint32_t cs)
 {
     assert(fill && fdata);
 
@@ -51,11 +51,11 @@ static bool _updateColorTable(SwFill* fill, const Fill* fdata)
 
     if (pColors->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<float>(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<int32_t>(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<int32_t>(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) {
index 46ef4ac..d07d7eb 100644 (file)
@@ -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<uint32_t>(region.max.y - region.min.y);
     auto w = static_cast<uint32_t>(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<uint32_t>(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);
+
+    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_ARGB_JOIN(r, g, b, a));
-    return _rasterTranslucentRle(surface, shape->strokeRle, COLOR_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;
index eb2f199..66608f5 100644 (file)
@@ -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);
             }
index 9a41902..5657602 100644 (file)
@@ -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;
 
index f9537d1..3704a2c 100644 (file)
@@ -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);
 }
 
 
index 7f2c04b..1ac5732 100644 (file)
@@ -70,7 +70,7 @@ Result GlCanvas::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t
     auto renderer = static_cast<GlRenderer*>(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
index 60c76d5..3535bf4 100644 (file)
@@ -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};
index e958ea2..755d422 100644 (file)
@@ -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<SwRenderer*>(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
index b02196e..1f15812 100644 (file)
@@ -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
index edc6dde..608cefb 100644 (file)
@@ -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)
index 59a4fad..743b1e0 100644 (file)
@@ -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
index 57a3d6c..3830687 100644 (file)
@@ -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
index 90c4e1d..c6df396 100644 (file)
@@ -16,7 +16,7 @@ void testCapi()
     tvg_engine_init(TVG_ENGINE_SW | TVG_ENGINE_GL);\r
 \r
     Tvg_Canvas* canvas = tvg_swcanvas_create();\r
-    tvg_swcanvas_set_target(canvas, buffer, WIDTH, WIDTH, HEIGHT);\r
+    tvg_swcanvas_set_target(canvas, buffer, WIDTH, WIDTH, HEIGHT, TVG_COLORSPACE_ARGB8888);\r
 \r
     Tvg_Paint* shape = tvg_shape_new();\r
     tvg_shape_append_rect(shape, 0, 0, 200, 200, 0, 0);\r
index 4803ef1..9daa6fc 100644 (file)
@@ -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
index 3c275b6..8dcc474 100644 (file)
@@ -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
index 4fa426b..77d5f6a 100644 (file)
@@ -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
index f98fc97..db11682 100644 (file)
@@ -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
index 5a6d34f..12009bc 100644 (file)
@@ -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
index 52c56ef..de6ef60 100644 (file)
@@ -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
index 0ae364b..fb1080b 100644 (file)
@@ -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
index a6c10ba..6e77291 100644 (file)
@@ -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
index 5b12020..daa5d86 100644 (file)
@@ -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
index 49558fb..e64fa9a 100644 (file)
@@ -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
index 88519d0..af4d0c4 100644 (file)
@@ -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
index 9174872..778d7c7 100644 (file)
@@ -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
index 445f840..1205bb1 100644 (file)
@@ -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
index e16f19b..06fe350 100644 (file)
@@ -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
index 171db91..2300f21 100644 (file)
@@ -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
index 7529d14..5ef33f4 100644 (file)
@@ -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
index 9c21343..3ff6c24 100644 (file)
@@ -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