common: changed premultiplied color policy. 95/240395/2
authorHermet Park <chuneon.park@samsung.com>
Thu, 6 Aug 2020 04:53:00 +0000 (13:53 +0900)
committerHermet Park <chuneon.park@samsung.com>
Thu, 6 Aug 2020 04:54:51 +0000 (13:54 +0900)
Some user have no idea of premultiplied alpha concept,
We suggest more user-friendly interfaces so that they don't confuse it.

Now, this pre-multipying is acommplished by backend engines.

Change-Id: Ifd84d56361cb56a8b98240bbd16690accf370bad

src/lib/sw_engine/tvgSwCommon.h
src/lib/sw_engine/tvgSwFill.cpp
src/lib/sw_engine/tvgSwRaster.cpp
test/testBlending.cpp
test/testSceneTransform.cpp

index 469ce0f..b653a93 100644 (file)
@@ -244,6 +244,12 @@ static inline uint32_t COLOR_ARGB_JOIN(uint8_t r, uint8_t g, uint8_t b, uint8_t
 }
 
 
+static inline uint8_t COLOR_ALPHA_MULTIPLY(uint32_t c, uint32_t a)
+{
+    return (c * a) >> 8;
+}
+
+
 int64_t mathMultiply(int64_t a, int64_t b);
 int64_t mathDivide(int64_t a, int64_t b);
 int64_t mathMulDiv(int64_t a, int64_t b, int64_t c);
@@ -290,7 +296,8 @@ 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);
 bool rasterClear(Surface& surface);
 
-inline void rasterARGB32(uint32_t *dst, uint32_t val, uint32_t offset, int32_t len)
+
+static inline void rasterARGB32(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 266acaa..80540cc 100644 (file)
@@ -46,7 +46,11 @@ static bool _updateColorTable(SwFill* fill, const Fill* fdata)
 
     if (pColors->a < 255) fill->translucent = true;
 
-    auto rgba = COLOR_ARGB_JOIN(pColors->r, pColors->g, pColors->b, pColors->a);
+    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 rgba = COLOR_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;
@@ -65,7 +69,12 @@ static bool _updateColorTable(SwFill* fill, const Fill* fdata)
         assert(curr && next);
         auto delta = 1.0f / (next->offset - curr->offset);
         if (next->a < 255) fill->translucent = true;
-        auto rgba2 = COLOR_ARGB_JOIN(next->r, next->g, next->b, next->a);
+
+        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 rgba2 = COLOR_ARGB_JOIN(r, g, b, next->a);
 
         while (pos < next->offset && i < GRADIENT_STOP_SIZE) {
             auto t = (pos - curr->offset) * delta;
index 5819bb8..ce2dc15 100644 (file)
@@ -285,6 +285,10 @@ 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);
+
     //Fast Track
     if (shape.rect) {
         auto region = _clipRegion(surface, shape.bbox);
@@ -300,6 +304,10 @@ 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);
+
     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));
 }
index 5477b3b..59a4fad 100644 (file)
@@ -19,13 +19,13 @@ void tvgDrawCmds(tvg::Canvas* canvas)
     //Prepare Circle
     auto shape2 = tvg::Shape::gen();
     shape2->appendCircle(400, 400, 200, 200);    //cx, cy, radiusW, radiusH
-    shape2->fill(170, 170, 0, 170);              //r, g, b, a
+    shape2->fill(255, 255, 0, 170);              //r, g, b, a
     if (canvas->push(move(shape2)) != tvg::Result::Success) return;
 
     //Prepare Ellipse
     auto shape3 = tvg::Shape::gen();
     shape3->appendCircle(400, 400, 250, 100);    //cx, cy, radiusW, radiusH
-    shape3->fill(100, 100, 100, 100);            //r, g, b, a
+    shape3->fill(255, 255, 255, 100);            //r, g, b, a
     if (canvas->push(move(shape3)) != tvg::Result::Success) return;
 
     //Prepare Star
@@ -41,7 +41,7 @@ void tvgDrawCmds(tvg::Canvas* canvas)
     shape4->lineTo(26, 361);
     shape4->lineTo(146, 343);
     shape4->close();
-    shape4->fill(200, 0, 200, 200);
+    shape4->fill(255, 0, 200, 200);
     if (canvas->push(move(shape4)) != tvg::Result::Success) return;
 
     //Prepare Opaque Ellipse
index 0d0be8e..49558fb 100644 (file)
@@ -58,7 +58,7 @@ void tvgDrawCmds(tvg::Canvas* canvas)
     shape4->lineTo(-173, 12.5);
     shape4->lineTo(-53, -5.5);
     shape4->close();
-    shape4->fill(0, 0, 127, 127);
+    shape4->fill(0, 0, 255, 127);
     shape4->stroke(3);                             //width
     shape4->stroke(0, 0, 255, 255);                //r, g, b, a
     scene2->push(move(shape4));
@@ -78,7 +78,7 @@ void tvgDrawCmds(tvg::Canvas* canvas)
     shape5->cubicTo(cx - halfRadius, cy + radius, cx - radius, cy + halfRadius, cx - radius, cy);
     shape5->cubicTo(cx - radius, cy - halfRadius, cx - halfRadius, cy - radius, cx, cy - radius);
     shape5->close();
-    shape5->fill(127, 0, 0, 127);
+    shape5->fill(255, 0, 0, 127);
     scene2->push(move(shape5));
 
     scene2->translate(500, 350);