sw_engine: gradient shapes with opacity < 255 rastered properly
authorMira Grudzinska <m.grudzinska@samsung.com>
Tue, 18 May 2021 11:30:28 +0000 (13:30 +0200)
committerJunsuChoi <jsuya.choi@samsung.com>
Tue, 25 May 2021 08:48:29 +0000 (17:48 +0900)
The cases with gradient shapes with composition are handled
in the same function as gradint shapes with opacity < 255.
Parts of the code from _rasterOpaque... grad functions moved to
_rasterTranslucent... grad functions.

src/lib/sw_engine/tvgSwRaster.cpp

index 872bd8a82379d176c45813ccb486347c6dac2b5a..916ea49d12dabb97e60586a22efa8029aea894a2 100644 (file)
@@ -604,33 +604,12 @@ static bool _rasterTranslucentLinearGradientRect(SwSurface* surface, const SwBBo
     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 tmpBuf = static_cast<uint32_t*>(alloca(surface->w * sizeof(uint32_t)));
-    if (!tmpBuf) return false;
-
-    for (uint32_t y = 0; y < h; ++y) {
-        auto dst = &buffer[y * surface->stride];
-        fillFetchLinear(fill, tmpBuf, region.min.y + y, region.min.x, w);
-        for (uint32_t x = 0; x < w; ++x) {
-            dst[x] = tmpBuf[x] + ALPHA_BLEND(dst[x], 255 - surface->blender.alpha(tmpBuf[x]));
-        }
-    }
-    return true;
-}
-
-
-static bool _rasterOpaqueLinearGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
-{
-    if (fill->linear.len < FLT_EPSILON) return false;
-
-    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 sbuffer = static_cast<uint32_t*>(alloca(w * sizeof(uint32_t)));
+    if (!sbuffer) return false;
 
     if (surface->compositor) {
         auto method = surface->compositor->method;
         auto cbuffer = surface->compositor->image.data + (region.min.y * surface->stride) + region.min.x;
-        auto sbuffer = static_cast<uint32_t*>(alloca(w * sizeof(uint32_t)));
-        if (!sbuffer) return false;
 
         if (method == CompositeMethod::AlphaMask) {
             for (uint32_t y = 0; y < h; ++y) {
@@ -664,35 +643,32 @@ static bool _rasterOpaqueLinearGradientRect(SwSurface* surface, const SwBBox& re
     }
 
     for (uint32_t y = 0; y < h; ++y) {
-        fillFetchLinear(fill, buffer + y * surface->stride, region.min.y + y, region.min.x, w);
+        auto dst = &buffer[y * surface->stride];
+        fillFetchLinear(fill, sbuffer, region.min.y + y, region.min.x, w);
+        for (uint32_t x = 0; x < w; ++x) {
+            dst[x] = sbuffer[x] + ALPHA_BLEND(dst[x], 255 - surface->blender.alpha(sbuffer[x]));
+        }
     }
     return true;
 }
 
 
-static bool _rasterTranslucentRadialGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
+static bool _rasterOpaqueLinearGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
 {
-    if (fill->radial.a < FLT_EPSILON) return false;
+    if (fill->linear.len < FLT_EPSILON) return false;
 
     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 tmpBuf = static_cast<uint32_t*>(alloca(surface->w * sizeof(uint32_t)));
-    if (!tmpBuf) return false;
-
     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] + ALPHA_BLEND(dst[x], 255 - surface->blender.alpha(tmpBuf[x]));
-        }
+        fillFetchLinear(fill, buffer + y * surface->stride, region.min.y + y, region.min.x, w);
     }
     return true;
 }
 
 
-static bool _rasterOpaqueRadialGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
+static bool _rasterTranslucentRadialGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
 {
     if (fill->radial.a < FLT_EPSILON) return false;
 
@@ -700,11 +676,12 @@ static bool _rasterOpaqueRadialGradientRect(SwSurface* surface, const SwBBox& re
     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 sbuffer = static_cast<uint32_t*>(alloca(w * sizeof(uint32_t)));
+    if (!sbuffer) return false;
+
     if (surface->compositor) {
         auto method = surface->compositor->method;
         auto cbuffer = surface->compositor->image.data + (region.min.y * surface->stride) + region.min.x;
-        auto sbuffer = static_cast<uint32_t*>(alloca(w * sizeof(uint32_t)));
-        if (!sbuffer) return false;
 
         if (method == CompositeMethod::AlphaMask) {
             for (uint32_t y = 0; y < h; ++y) {
@@ -739,41 +716,32 @@ static bool _rasterOpaqueRadialGradientRect(SwSurface* surface, const SwBBox& re
 
     for (uint32_t y = 0; y < h; ++y) {
         auto dst = &buffer[y * surface->stride];
-        fillFetchRadial(fill, dst, region.min.y + y, region.min.x, w);
+        fillFetchRadial(fill, sbuffer, region.min.y + y, region.min.x, w);
+        for (uint32_t x = 0; x < w; ++x) {
+            dst[x] = sbuffer[x] + ALPHA_BLEND(dst[x], 255 - surface->blender.alpha(sbuffer[x]));
+        }
     }
     return true;
 }
 
 
-static bool _rasterTranslucentLinearGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
+static bool _rasterOpaqueRadialGradientRect(SwSurface* surface, const SwBBox& region, const SwFill* fill)
 {
-    if (fill->linear.len < FLT_EPSILON) return false;
-
-    auto buf = static_cast<uint32_t*>(alloca(surface->w * sizeof(uint32_t)));
-    if (!buf) return false;
+    if (fill->radial.a < FLT_EPSILON) return false;
 
-    auto span = rle->spans;
+    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);
 
-    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, span->len);
-        if (span->coverage == 255) {
-            for (uint32_t i = 0; i < span->len; ++i) {
-                dst[i] = buf[i] + ALPHA_BLEND(dst[i], 255 - surface->blender.alpha(buf[i]));
-            }
-        } else {
-            for (uint32_t i = 0; i < span->len; ++i) {
-                auto tmp = ALPHA_BLEND(buf[i], span->coverage);
-                dst[i] = tmp + ALPHA_BLEND(dst[i], 255 - surface->blender.alpha(tmp));
-            }
-        }
-        ++span;
+    for (uint32_t y = 0; y < h; ++y) {
+        auto dst = &buffer[y * surface->stride];
+        fillFetchRadial(fill, dst, region.min.y + y, region.min.x, w);
     }
     return true;
 }
 
 
-static bool _rasterOpaqueLinearGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
+static bool _rasterTranslucentLinearGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
 {
     if (fill->linear.len < FLT_EPSILON) return false;
 
@@ -832,14 +800,16 @@ static bool _rasterOpaqueLinearGradientRle(SwSurface* surface, const SwRleData*
     }
 
     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, span->len);
         if (span->coverage == 255) {
-            fillFetchLinear(fill, surface->buffer + span->y * surface->stride + span->x, span->y, span->x, span->len);
+            for (uint32_t i = 0; i < span->len; ++i) {
+                dst[i] = buf[i] + ALPHA_BLEND(dst[i], 255 - surface->blender.alpha(buf[i]));
+            }
         } else {
-            fillFetchLinear(fill, buf, span->y, span->x, span->len);
-            auto ialpha = 255 - span->coverage;
-            auto dst = &surface->buffer[span->y * surface->stride + span->x];
             for (uint32_t i = 0; i < span->len; ++i) {
-                dst[i] = ALPHA_BLEND(buf[i], span->coverage) + ALPHA_BLEND(dst[i], ialpha);
+                auto tmp = ALPHA_BLEND(buf[i], span->coverage);
+                dst[i] = tmp + ALPHA_BLEND(dst[i], 255 - surface->blender.alpha(tmp));
             }
         }
         ++span;
@@ -848,9 +818,9 @@ static bool _rasterOpaqueLinearGradientRle(SwSurface* surface, const SwRleData*
 }
 
 
-static bool _rasterTranslucentRadialGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
+static bool _rasterOpaqueLinearGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
 {
-    if (fill->radial.a < FLT_EPSILON) return false;
+    if (fill->linear.len < FLT_EPSILON) return false;
 
     auto buf = static_cast<uint32_t*>(alloca(surface->w * sizeof(uint32_t)));
     if (!buf) return false;
@@ -858,16 +828,14 @@ static bool _rasterTranslucentRadialGradientRle(SwSurface* surface, const SwRleD
     auto span = rle->spans;
 
     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] + ALPHA_BLEND(dst[i], 255 - surface->blender.alpha(buf[i]));
-            }
+            fillFetchLinear(fill, surface->buffer + span->y * surface->stride + span->x, span->y, span->x, span->len);
         } else {
+            fillFetchLinear(fill, buf, span->y, span->x, span->len);
+            auto ialpha = 255 - span->coverage;
+            auto dst = &surface->buffer[span->y * surface->stride + span->x];
             for (uint32_t i = 0; i < span->len; ++i) {
-                auto tmp = ALPHA_BLEND(buf[i], span->coverage);
-                dst[i] = tmp + ALPHA_BLEND(dst[i], 255 - surface->blender.alpha(tmp));
+                dst[i] = ALPHA_BLEND(buf[i], span->coverage) + ALPHA_BLEND(dst[i], ialpha);
             }
         }
         ++span;
@@ -876,7 +844,7 @@ static bool _rasterTranslucentRadialGradientRle(SwSurface* surface, const SwRleD
 }
 
 
-static bool _rasterOpaqueRadialGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
+static bool _rasterTranslucentRadialGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
 {
     if (fill->radial.a < FLT_EPSILON) return false;
 
@@ -934,6 +902,34 @@ static bool _rasterOpaqueRadialGradientRle(SwSurface* surface, const SwRleData*
         }
     }
 
+    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] + ALPHA_BLEND(dst[i], 255 - surface->blender.alpha(buf[i]));
+            }
+        } else {
+            for (uint32_t i = 0; i < span->len; ++i) {
+                auto tmp = ALPHA_BLEND(buf[i], span->coverage);
+                dst[i] = tmp + ALPHA_BLEND(dst[i], 255 - surface->blender.alpha(tmp));
+            }
+        }
+        ++span;
+    }
+    return true;
+}
+
+
+static bool _rasterOpaqueRadialGradientRle(SwSurface* surface, const SwRleData* rle, const SwFill* fill)
+{
+    if (fill->radial.a < FLT_EPSILON) return false;
+
+    auto buf = static_cast<uint32_t*>(alloca(surface->w * sizeof(uint32_t)));
+    if (!buf) return false;
+
+    auto span = rle->spans;
+
     for (uint32_t i = 0; i < rle->size; ++i) {
         auto dst = &surface->buffer[span->y * surface->stride + span->x];
         if (span->coverage == 255) {
@@ -976,22 +972,24 @@ bool rasterGradientShape(SwSurface* surface, SwShape* shape, unsigned id)
 {
     if (!shape->fill) return false;
 
+    auto translucent = shape->fill->translucent || (surface->compositor && surface->compositor->method != CompositeMethod::None);
+
     //Fast Track
     if (shape->rect) {
         if (id == FILL_ID_LINEAR) {
-            if (shape->fill->translucent) return _rasterTranslucentLinearGradientRect(surface, shape->bbox, shape->fill);
+            if (translucent) return _rasterTranslucentLinearGradientRect(surface, shape->bbox, shape->fill);
             return _rasterOpaqueLinearGradientRect(surface, shape->bbox, shape->fill);
         } else {
-            if (shape->fill->translucent) return _rasterTranslucentRadialGradientRect(surface, shape->bbox, shape->fill);
+            if (translucent) return _rasterTranslucentRadialGradientRect(surface, shape->bbox, shape->fill);
             return _rasterOpaqueRadialGradientRect(surface, shape->bbox, shape->fill);
         }
     } else {
         if (!shape->rle) return false;
         if (id == FILL_ID_LINEAR) {
-            if (shape->fill->translucent) return _rasterTranslucentLinearGradientRle(surface, shape->rle, shape->fill);
+            if (translucent) return _rasterTranslucentLinearGradientRle(surface, shape->rle, shape->fill);
             return _rasterOpaqueLinearGradientRle(surface, shape->rle, shape->fill);
         } else {
-            if (shape->fill->translucent) return _rasterTranslucentRadialGradientRle(surface, shape->rle, shape->fill);
+            if (translucent) return _rasterTranslucentRadialGradientRle(surface, shape->rle, shape->fill);
             return _rasterOpaqueRadialGradientRle(surface, shape->rle, shape->fill);
         }
     }
@@ -1042,11 +1040,13 @@ bool rasterGradientStroke(SwSurface* surface, SwShape* shape, unsigned id)
 {
     if (!shape->stroke || !shape->stroke->fill || !shape->strokeRle) return false;
 
+    auto translucent = shape->stroke->fill->translucent || (surface->compositor && surface->compositor->method != CompositeMethod::None);
+
     if (id == FILL_ID_LINEAR) {
-        if (shape->stroke->fill->translucent) return _rasterTranslucentLinearGradientRle(surface, shape->strokeRle, shape->stroke->fill);
+        if (translucent) return _rasterTranslucentLinearGradientRle(surface, shape->strokeRle, shape->stroke->fill);
         return _rasterOpaqueLinearGradientRle(surface, shape->strokeRle, shape->stroke->fill);
     } else {
-        if (shape->stroke->fill->translucent) return _rasterTranslucentRadialGradientRle(surface, shape->strokeRle, shape->stroke->fill);
+        if (translucent) return _rasterTranslucentRadialGradientRle(surface, shape->strokeRle, shape->stroke->fill);
         return _rasterOpaqueRadialGradientRle(surface, shape->strokeRle, shape->stroke->fill);
     }