sw_engine composition: enhance image masking
authorHermet Park <chuneon.park@samsung.com>
Sun, 10 Jan 2021 11:37:20 +0000 (20:37 +0900)
committerJunsuChoi <jsuya.choi@samsung.com>
Mon, 11 Jan 2021 01:33:19 +0000 (10:33 +0900)
composition alpha masking supports scene/paints targets.

@Examples: Masking

@Issues: 31

Change-Id: I7aed18172fab54a2e31ccf8894fcb6fb6925a8a8

src/examples/Masking.cpp
src/lib/sw_engine/tvgSwRaster.cpp

index 624ea6f..8d517ef 100644 (file)
@@ -26,6 +26,7 @@ void tvgDrawCmds(tvg::Canvas* canvas)
     //SVG
     auto svg = tvg::Picture::gen();
     if (svg->load(EXAMPLE_DIR"/cartman.svg") != tvg::Result::Success) return;
+    svg->opacity(100);
     svg->scale(3);
     svg->translate(50, 400);
 
@@ -35,53 +36,59 @@ void tvgDrawCmds(tvg::Canvas* canvas)
     mask2->appendRect(150, 500, 200, 200, 30, 30);
     mask2->fill(255, 255, 255, 255);
     svg->composite(move(mask2), tvg::CompositeMethod::AlphaMask);
-    canvas->push(move(svg));
+    if (canvas->push(move(svg)) != tvg::Result::Success) return;
 
     //Star
-
-#if 0
-    //Appends Paths
-    shape->moveTo(199, 34);
-    shape->lineTo(253, 143);
-    shape->lineTo(374, 160);
-    shape->lineTo(287, 244);
-    shape->lineTo(307, 365);
-    shape->lineTo(199, 309);
-    shape->lineTo(97, 365);
-    shape->lineTo(112, 245);
-    shape->lineTo(26, 161);
-    shape->lineTo(146, 143);
-    shape->close();
-#endif
-
-    //shape->opacity(127);
-
-//    scene->push(move(shape));
-
-#if 0
-    scene->composite(move(mask2), tvg::CompositeMethod::AlphaMask);
-    if (canvas->push(move(scene)) != tvg::Result::Success) return;
-
-
+    auto star = tvg::Shape::gen();
+    star->fill(80, 80, 80, 255);
+    star->moveTo(599, 34);
+    star->lineTo(653, 143);
+    star->lineTo(774, 160);
+    star->lineTo(687, 244);
+    star->lineTo(707, 365);
+    star->lineTo(599, 309);
+    star->lineTo(497, 365);
+    star->lineTo(512, 245);
+    star->lineTo(426, 161);
+    star->lineTo(546, 143);
+    star->close();
+    star->stroke(10);
+    star->stroke(255, 255, 255, 255);
+
+    //Mask3
+    auto mask3 = tvg::Shape::gen();
+    mask3->appendCircle(600, 200, 125, 125);
+    mask3->fill(255, 255, 255, 255);
+    star->composite(move(mask3), tvg::CompositeMethod::AlphaMask);
+    if (canvas->push(move(star)) != tvg::Result::Success) return;
+
+    //Image
     ifstream file(EXAMPLE_DIR"/rawimage_200x300.raw");
     if (!file.is_open()) return;
     data = (uint32_t*) malloc(sizeof(uint32_t) * (200 * 300));
     file.read(reinterpret_cast<char *>(data), sizeof (data) * 200 * 300);
     file.close();
 
-    //Mask Target 1
-    auto picture = tvg::Picture::gen();
-    if (picture->load(data, 200, 300, true) != tvg::Result::Success) return;
-    picture->translate(500, 400);
-
-    //Alpha Mask
-    auto mask = tvg::Shape::gen();
-    mask->appendCircle(500, 500, 125, 125);
-    mask->fill(255, 255, 255, 100);
-
-    picture->composite(move(mask), tvg::CompositeMethod::AlphaMask);
-    if (canvas->push(move(picture)) != tvg::Result::Success) return;
-#endif
+    auto image = tvg::Picture::gen();
+    if (image->load(data, 200, 300, true) != tvg::Result::Success) return;
+    image->translate(500, 400);
+
+    //Mask4
+    auto mask4 = tvg::Shape::gen();
+    mask4->moveTo(599, 384);
+    mask4->lineTo(653, 493);
+    mask4->lineTo(774, 510);
+    mask4->lineTo(687, 594);
+    mask4->lineTo(707, 715);
+    mask4->lineTo(599, 659);
+    mask4->lineTo(497, 715);
+    mask4->lineTo(512, 595);
+    mask4->lineTo(426, 511);
+    mask4->lineTo(546, 493);
+    mask4->close();
+    mask4->fill(255, 255, 255, 70);
+    image->composite(move(mask4), tvg::CompositeMethod::AlphaMask);
+    if (canvas->push(move(image)) != tvg::Result::Success) return;
 }
 
 
index d33dba2..e0f86bc 100644 (file)
@@ -101,6 +101,11 @@ static bool _translucent(SwSurface* surface, uint8_t a)
     return true;
 }
 
+
+/************************************************************************/
+/* Rect                                                                 */
+/************************************************************************/
+
 static bool _translucentRect(SwSurface* surface, const SwBBox& region, uint32_t color)
 {
     auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
@@ -129,17 +134,13 @@ static bool _translucentRectAlphaMask(SwSurface* surface, const SwBBox& region,
 #endif
 
     auto cbuffer = surface->compositor->image.data + (region.min.y * surface->stride) + region.min.x;   //compositor buffer
-    auto tbuffer = static_cast<uint32_t*>(alloca(sizeof(uint32_t) * w));                                //temp buffer for intermediate processing
 
     for (uint32_t y = 0; y < h; ++y) {
         auto dst = &buffer[y * surface->stride];
         auto cmp = &cbuffer[y * surface->stride];
-        auto tmp = tbuffer;
-        //Composition
         for (uint32_t x = 0; x < w; ++x) {
-            *tmp = ALPHA_BLEND(color, surface->blender.alpha(*cmp));
-            dst[x] = *tmp + ALPHA_BLEND(dst[x], 255 - surface->blender.alpha(*tmp));
-            ++tmp;
+            auto tmp = ALPHA_BLEND(color, surface->blender.alpha(*cmp));
+            dst[x] = tmp + ALPHA_BLEND(dst[x], 255 - surface->blender.alpha(tmp));
             ++cmp;
         }
     }
@@ -171,6 +172,11 @@ static bool _rasterSolidRect(SwSurface* surface, const SwBBox& region, uint32_t
 }
 
 
+/************************************************************************/
+/* Rle                                                                  */
+/************************************************************************/
+
+
 static bool _translucentRle(SwSurface* surface, SwRleData* rle, uint32_t color)
 {
     auto span = rle->spans;
@@ -231,6 +237,34 @@ static bool _rasterTranslucentRle(SwSurface* surface, SwRleData* rle, uint32_t c
 }
 
 
+static bool _rasterSolidRle(SwSurface* surface, SwRleData* rle, uint32_t color)
+{
+    if (!rle) return false;
+
+    auto span = rle->spans;
+
+    for (uint32_t i = 0; i < rle->size; ++i) {
+        if (span->coverage == 255) {
+            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 = ALPHA_BLEND(color, span->coverage);
+            auto ialpha = 255 - span->coverage;
+            for (uint32_t i = 0; i < span->len; ++i) {
+                dst[i] = src + ALPHA_BLEND(dst[i], ialpha);
+            }
+        }
+        ++span;
+    }
+    return true;
+}
+
+
+/************************************************************************/
+/* Image                                                                */
+/************************************************************************/
+
+
 static bool _rasterTranslucentImageRle(SwSurface* surface, SwRleData* rle, uint32_t *img, uint32_t w, uint32_t h, uint32_t opacity, const Matrix* invTransform)
 {
     auto span = rle->spans;
@@ -274,7 +308,7 @@ static bool _rasterImageRle(SwSurface* surface, SwRleData* rle, uint32_t *img, u
 }
 
 
-static bool _rasterTranslucentImage(SwSurface* surface, uint32_t *img, uint32_t w, uint32_t h, uint32_t opacity, const SwBBox& region, const Matrix* invTransform)
+static bool _translucentImage(SwSurface* surface, uint32_t *img, uint32_t w, uint32_t h, uint32_t opacity, const SwBBox& region, const Matrix* invTransform)
 {
     for (auto y = region.min.y; y < region.max.y; ++y) {
         auto dst = &surface->buffer[y * surface->stride + region.min.x];
@@ -292,12 +326,45 @@ static bool _rasterTranslucentImage(SwSurface* surface, uint32_t *img, uint32_t
 }
 
 
-static bool _rasterTranslucentImage(SwSurface* surface, uint32_t *img, uint32_t w, uint32_t h, uint32_t opacity, const SwBBox& region)
+static bool _translucentImageAlphaMask(SwSurface* surface, uint32_t *img, uint32_t w, uint32_t h, uint32_t opacity, const SwBBox& region, const Matrix* invTransform)
+{
+#ifdef THORVG_LOG_ENABLED
+    printf("SW_ENGINE: Transformed Image Alpha Mask Composition\n");
+#endif
+    for (auto y = region.min.y; y < region.max.y; ++y) {
+        auto dst = &surface->buffer[y * surface->stride + region.min.x];
+        auto cmp = &surface->compositor->image.data[y * surface->stride + region.min.x];
+        float ey1 = y * invTransform->e12 + invTransform->e13;
+        float ey2 = y * invTransform->e22 + invTransform->e23;
+        for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++cmp) {
+            auto rX = static_cast<uint32_t>(roundf(x * invTransform->e11 + ey1));
+            auto rY = static_cast<uint32_t>(roundf(x * invTransform->e21 + ey2));
+            if (rX >= w || rY >= h) continue;
+            auto tmp = ALPHA_BLEND(img[rX + (rY * w)], ALPHA_MULTIPLY(opacity, surface->blender.alpha(*cmp)));  //TODO: need to use image's stride
+            *dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp));
+        }
+    }
+    return true;
+}
+
+
+static bool _rasterTranslucentImage(SwSurface* surface, uint32_t *img, uint32_t w, uint32_t h, uint32_t opacity, const SwBBox& region, const Matrix* invTransform)
+{
+    if (surface->compositor) {
+        if (surface->compositor->method == CompositeMethod::AlphaMask) {
+            return _translucentImageAlphaMask(surface, img, w, h, opacity, region, invTransform);
+        }
+    }
+    return _translucentImage(surface, img, w, h, opacity, region, invTransform);
+}
+
+
+static bool _translucentImage(SwSurface* surface, uint32_t *img, uint32_t w, uint32_t h, uint32_t opacity, const SwBBox& region)
 {
     for (auto y = region.min.y; y < region.max.y; ++y) {
         auto dst = &surface->buffer[y * surface->stride + region.min.x];
         auto src = img + region.min.x + (y * w);    //TODO: need to use image's stride
-        for (auto x = region.min.x; x < region.max.x; x++, dst++, src++) {
+        for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++src) {
             auto p = ALPHA_BLEND(*src, opacity);
             *dst = p + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(p));
         }
@@ -306,6 +373,43 @@ static bool _rasterTranslucentImage(SwSurface* surface, uint32_t *img, uint32_t
 }
 
 
+static bool _translucentImageAlphaMask(SwSurface* surface, uint32_t *img, uint32_t w, uint32_t h, uint32_t opacity, const SwBBox& region)
+{
+    auto buffer = surface->buffer + (region.min.y * surface->stride) + region.min.x;
+    auto h2 = static_cast<uint32_t>(region.max.y - region.min.y);
+    auto w2 = static_cast<uint32_t>(region.max.x - region.min.x);
+
+#ifdef THORVG_LOG_ENABLED
+    printf("SW_ENGINE: Image Alpha Mask Composition\n");
+#endif
+
+    auto sbuffer = img + (region.min.y * w) + region.min.x;
+    auto cbuffer = surface->compositor->image.data + (region.min.y * surface->stride) + region.min.x;   //compositor buffer
+
+    for (uint32_t y = 0; y < h2; ++y) {
+        auto dst = &buffer[y * surface->stride];
+        auto cmp = &cbuffer[y * surface->stride];
+        auto src = &sbuffer[y * w];   //TODO: need to use image's stride
+        for (uint32_t x = 0; x < w2; ++x, ++dst, ++src, ++cmp) {
+            auto tmp = ALPHA_BLEND(*src, ALPHA_MULTIPLY(opacity, surface->blender.alpha(*cmp)));
+            *dst = tmp + ALPHA_BLEND(*dst, 255 - surface->blender.alpha(tmp));
+        }
+    }
+    return true;
+}
+
+
+static bool _rasterTranslucentImage(SwSurface* surface, uint32_t *img, uint32_t w, uint32_t h, uint32_t opacity, const SwBBox& region)
+{
+    if (surface->compositor) {
+        if (surface->compositor->method == CompositeMethod::AlphaMask) {
+            return _translucentImageAlphaMask(surface, img, w, h, opacity, region);
+        }
+    }
+    return _translucentImage(surface, img, w, h, opacity, region);
+}
+
+
 static bool _rasterImage(SwSurface* surface, uint32_t *img, uint32_t w, uint32_t h, const SwBBox& region)
 {
     for (auto y = region.min.y; y < region.max.y; ++y) {
@@ -337,28 +441,9 @@ static bool _rasterImage(SwSurface* surface, uint32_t *img, uint32_t w, uint32_t
 }
 
 
-static bool _rasterSolidRle(SwSurface* surface, SwRleData* rle, uint32_t color)
-{
-    if (!rle) return false;
-
-    auto span = rle->spans;
-
-    for (uint32_t i = 0; i < rle->size; ++i) {
-        if (span->coverage == 255) {
-            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 = ALPHA_BLEND(color, span->coverage);
-            auto ialpha = 255 - span->coverage;
-            for (uint32_t i = 0; i < span->len; ++i) {
-                dst[i] = src + ALPHA_BLEND(dst[i], ialpha);
-            }
-        }
-        ++span;
-    }
-    return true;
-}
-
+/************************************************************************/
+/* Gradient                                                             */
+/************************************************************************/
 
 static bool _rasterLinearGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
 {
@@ -609,6 +694,8 @@ bool rasterImage(SwSurface* surface, SwImage* image, const Matrix* transform, Sw
     if (transform) _inverse(transform, &invTransform);
     else invTransform = {1, 0, 0, 0, 1, 0, 0, 0, 1};
 
+    auto translucent = _translucent(surface, opacity);
+
     if (image->rle) {
         //Fast track
         if (_identify(transform)) {
@@ -616,11 +703,11 @@ bool rasterImage(SwSurface* surface, SwImage* image, const Matrix* transform, Sw
 #ifdef THORVG_LOG_ENABLED
             printf("SW_ENGINE: implementation is missing!\n");
 #endif
-            //if (opacity < 255) return _rasterTranslucentImageRle(surface, image->rle, image->data, image->w, image->h, opacity);
+            //if (translucent) return _rasterTranslucentImageRle(surface, image->rle, image->data, image->w, image->h, opacity);
             //return _rasterImageRle(surface, image->rle, image->data, image->w, image->h);
             return false;
         } else {
-            if (opacity < 255) return _rasterTranslucentImageRle(surface, image->rle, image->data, image->w, image->h, opacity, &invTransform);
+            if (translucent) return _rasterTranslucentImageRle(surface, image->rle, image->data, image->w, image->h, opacity, &invTransform);
             return _rasterImageRle(surface, image->rle, image->data, image->w, image->h, &invTransform);
         }
     }
@@ -628,10 +715,10 @@ bool rasterImage(SwSurface* surface, SwImage* image, const Matrix* transform, Sw
         //Fast track
         if (_identify(transform)) {
             //OPTIMIZE ME: Support non transformed image. Only shifted image can use these routines.
-            if (opacity < 255) return _rasterTranslucentImage(surface, image->data, image->w, image->h, opacity, bbox);
+            if (translucent) return _rasterTranslucentImage(surface, image->data, image->w, image->h, opacity, bbox);
             else return _rasterImage(surface, image->data, image->w, image->h, bbox);
         } else {
-            if (opacity < 255) return _rasterTranslucentImage(surface, image->data, image->w, image->h, opacity, bbox, &invTransform);
+            if (translucent) return _rasterTranslucentImage(surface, image->data, image->w, image->h, opacity, bbox, &invTransform);
             else return _rasterImage(surface, image->data, image->w, image->h, bbox, &invTransform);
         }
     }