compositeMethod: introduced LumaMask 01/288801/1
authorMichal Maciola <m.maciola@samsung.com>
Thu, 30 Dec 2021 08:28:27 +0000 (09:28 +0100)
committerMichal Szczecinski <mihashco89@gmail.com>
Thu, 23 Feb 2023 08:18:27 +0000 (09:18 +0100)
Introduced CompositeMethod::LumaMask that converts the source pixels to the
grayscale (luma value) before alpha blending. Thanks to it, mask works more like
typical mask in graphics editor software.
Grayscale is calculated with  weighted method:
(0.0721*B + 0.7154*G + 0.2125*R) * A
Introduced surface->blender.lumaValue function

Change-Id: Ia0258e2f374aa27acaef9b2f4161af5b04400422

inc/thorvg.h
src/lib/sw_engine/tvgSwCommon.h
src/lib/sw_engine/tvgSwRaster.cpp

index e542d36..b08356d 100644 (file)
@@ -145,8 +145,9 @@ enum class TVG_EXPORT CompositeMethod
 {
     None = 0,     ///< No composition is applied.
     ClipPath,     ///< The intersection of the source and the target is determined and only the resulting pixels from the source are rendered.
-    AlphaMask,    ///< The pixels of the source and the target are alpha blended. As a result, only the part of the source, which intersects with the target is visible.
-    InvAlphaMask  ///< The pixels of the source and the complement to the target's pixels are alpha blended. As a result, only the part of the source which is not covered by the target is visible.
+    AlphaMask,    ///< The pixels of the source and the target are alpha blended. As a result, only the part of the source, which alpha intersects with the target is visible.
+    InvAlphaMask, ///< The pixels of the source and the complement to the target's pixels are alpha blended. As a result, only the part of the source which alpha is not covered by the target is visible.
+    LumaMask      ///< @BETA_API The source pixels are converted to the grayscale (luma value) and alpha blended with the target. As a result, only the part of the source, which intersects with the target is visible.
 };
 
 /**
index e0ffc1f..4d940eb 100644 (file)
@@ -235,6 +235,7 @@ struct SwImage
 struct SwBlender
 {
     uint32_t (*join)(uint8_t r, uint8_t g, uint8_t b, uint8_t a);
+    uint32_t (*lumaValue)(uint32_t c);
 };
 
 struct SwCompositor;
index 56bc2f7..6b5e00a 100644 (file)
@@ -47,6 +47,18 @@ static inline uint32_t _ialpha(uint32_t c)
 }
 
 
+static inline uint32_t _abgrLumaValue(uint32_t c)
+{
+    return ((((c&0xff)*54) + (((c>>8)&0xff)*183) + (((c>>16)&0xff)*19))) >> 8; //0.2125*R + 0.7154*G + 0.0721*B
+}
+
+
+static inline uint32_t _argbLumaValue(uint32_t c)
+{
+    return ((((c&0xff)*19) + (((c>>8)&0xff)*183) + (((c>>16)&0xff)*54))) >> 8; //0.0721*B + 0.7154*G + 0.2125*R
+}
+
+
 static inline uint32_t _abgrJoin(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
 {
     return (a << 24 | b << 16 | g << 8 | r);
@@ -139,7 +151,7 @@ static bool _rasterMaskedRect(SwSurface* surface, const SwBBox& region, uint32_t
     auto w = static_cast<uint32_t>(region.max.x - region.min.x);
     auto h = static_cast<uint32_t>(region.max.y - region.min.y);
 
-    auto cbuffer = surface->compositor->image.data + (region.min.y * surface->compositor->image.stride) + region.min.x;   //compositor buffer
+    auto cbuffer = surface->compositor->image.data + (region.min.y * surface->compositor->image.stride) + region.min.x; //compositor buffer
 
     for (uint32_t y = 0; y < h; ++y) {
         auto dst = &buffer[y * surface->stride];
@@ -173,6 +185,8 @@ static bool _rasterRect(SwSurface* surface, const SwBBox& region, uint32_t color
             return _rasterMaskedRect(surface, region, color, _alpha);
         } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
             return _rasterMaskedRect(surface, region, color, _ialpha);
+        } else if (surface->compositor->method == CompositeMethod::LumaMask) {
+            return _rasterMaskedRect(surface, region, color, surface->blender.lumaValue);
         }
     } else {
         if (opacity == 255) {
@@ -246,6 +260,8 @@ static bool _rasterRle(SwSurface* surface, SwRleData* rle, uint32_t color, uint8
             return _rasterMaskedRle(surface, rle, color, _alpha);
         } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
             return _rasterMaskedRle(surface, rle, color, _ialpha);
+        } else if (surface->compositor->method == CompositeMethod::LumaMask) {
+            return _rasterMaskedRle(surface, rle, color, surface->blender.lumaValue);
         }
     } else {
         if (opacity == 255) {
@@ -275,6 +291,8 @@ static bool _transformedRleRGBAImage(SwSurface* surface, const SwImage* image, c
             return _rasterTexmapPolygon(surface, image, transform, nullptr, opacity, _alpha);
         } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
             return _rasterTexmapPolygon(surface, image, transform, nullptr, opacity, _ialpha);
+        } else if (surface->compositor->method == CompositeMethod::LumaMask) {
+            return _rasterTexmapPolygon(surface, image, transform, nullptr, opacity, surface->blender.lumaValue);
         }
     } else {
         return _rasterTexmapPolygon(surface, image, transform, nullptr, opacity, nullptr);
@@ -494,12 +512,16 @@ static bool _scaledRleRGBAImage(SwSurface* surface, const SwImage* image, const
                 return _rasterScaledMaskedRleRGBAImage(surface, image, &itransform, region, halfScale, _alpha);
             } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
                 return _rasterScaledMaskedRleRGBAImage(surface, image, &itransform, region, halfScale, _ialpha);
+            } else if (surface->compositor->method == CompositeMethod::LumaMask) {
+                return _rasterScaledMaskedRleRGBAImage(surface, image, &itransform, region, halfScale, surface->blender.lumaValue);
             }
         } else {
             if (surface->compositor->method == CompositeMethod::AlphaMask) {
                 return _rasterScaledMaskedTranslucentRleRGBAImage(surface, image, &itransform, region, opacity, halfScale, _alpha);
             } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
                 return _rasterScaledMaskedTranslucentRleRGBAImage(surface, image, &itransform, region, opacity, halfScale, _ialpha);
+            } else if (surface->compositor->method == CompositeMethod::LumaMask) {
+                return _rasterScaledMaskedTranslucentRleRGBAImage(surface, image, &itransform, region, opacity, halfScale, surface->blender.lumaValue);
             }
         }
     } else {
@@ -616,12 +638,16 @@ static bool _directRleRGBAImage(SwSurface* surface, const SwImage* image, uint32
                 return _rasterDirectMaskedRleRGBAImage(surface, image, _alpha);
             } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
                 return _rasterDirectMaskedRleRGBAImage(surface, image, _ialpha);
+            } else if (surface->compositor->method == CompositeMethod::LumaMask) {
+                return _rasterDirectMaskedRleRGBAImage(surface, image, surface->blender.lumaValue);
             }
         } else {
             if (surface->compositor->method == CompositeMethod::AlphaMask) {
                 return _rasterDirectMaskedTranslucentRleRGBAImage(surface, image, opacity, _alpha);
             } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
                 return _rasterDirectMaskedTranslucentRleRGBAImage(surface, image, opacity, _ialpha);
+            } else if (surface->compositor->method == CompositeMethod::LumaMask) {
+                return _rasterDirectMaskedTranslucentRleRGBAImage(surface, image, opacity, surface->blender.lumaValue);
             }
         }
     } else {
@@ -643,6 +669,8 @@ static bool _transformedRGBAImage(SwSurface* surface, const SwImage* image, cons
             return _rasterTexmapPolygon(surface, image, transform, &region, opacity, _alpha);
         } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
             return _rasterTexmapPolygon(surface, image, transform, &region, opacity, _ialpha);
+        } else if (surface->compositor->method == CompositeMethod::LumaMask) {
+            return _rasterTexmapPolygon(surface, image, transform, &region, opacity, surface->blender.lumaValue);
         }
     } else {
         return _rasterTexmapPolygon(surface, image, transform, &region, opacity, nullptr);
@@ -832,12 +860,16 @@ static bool _scaledRGBAImage(SwSurface* surface, const SwImage* image, const Mat
                 return _rasterScaledMaskedRGBAImage(surface, image, &itransform, region, halfScale, _alpha);
             } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
                 return _rasterScaledMaskedRGBAImage(surface, image, &itransform, region, halfScale, _ialpha);
+            } else if (surface->compositor->method == CompositeMethod::LumaMask) {
+                return _rasterScaledMaskedRGBAImage(surface, image, &itransform, region, halfScale, surface->blender.lumaValue);
             }
         } else {
             if (surface->compositor->method == CompositeMethod::AlphaMask) {
                 return _rasterScaledMaskedTranslucentRGBAImage(surface, image, &itransform, region, opacity, halfScale, _alpha);
             } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
                 return _rasterScaledMaskedTranslucentRGBAImage(surface, image, &itransform, region, opacity, halfScale, _ialpha);
+            } else if (surface->compositor->method == CompositeMethod::LumaMask) {
+                return _rasterScaledMaskedTranslucentRGBAImage(surface, image, &itransform, region, opacity, halfScale, surface->blender.lumaValue);
             }
         }
     } else {
@@ -861,7 +893,7 @@ static bool _rasterDirectMaskedRGBAImage(SwSurface* surface, const SwImage* imag
     auto w2 = static_cast<uint32_t>(region.max.x - region.min.x);
 
     auto sbuffer = image->data + (region.min.y + image->oy) * image->stride + (region.min.x + image->ox);
-    auto cbuffer = surface->compositor->image.data + (region.min.y * surface->compositor->image.stride) + region.min.x;   //compositor buffer
+    auto cbuffer = surface->compositor->image.data + (region.min.y * surface->compositor->image.stride) + region.min.x; //compositor buffer
 
     for (uint32_t y = 0; y < h2; ++y) {
         auto dst = buffer;
@@ -888,7 +920,7 @@ static bool _rasterDirectMaskedTranslucentRGBAImage(SwSurface* surface, const Sw
     auto w2 = static_cast<uint32_t>(region.max.x - region.min.x);
 
     auto sbuffer = image->data + (region.min.y + image->oy) * image->stride + (region.min.x + image->ox);
-    auto cbuffer = surface->compositor->image.data + (region.min.y * surface->compositor->image.stride) + region.min.x;   //compositor buffer
+    auto cbuffer = surface->compositor->image.data + (region.min.y * surface->compositor->image.stride) + region.min.x; //compositor buffer
 
     for (uint32_t y = 0; y < h2; ++y) {
         auto dst = buffer;
@@ -952,12 +984,16 @@ static bool _directRGBAImage(SwSurface* surface, const SwImage* image, const SwB
                 return _rasterDirectMaskedRGBAImage(surface, image, region, _alpha);
             } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
                 return _rasterDirectMaskedRGBAImage(surface, image, region, _ialpha);
+            } else if (surface->compositor->method == CompositeMethod::LumaMask) {
+                return _rasterDirectMaskedRGBAImage(surface, image, region, surface->blender.lumaValue);
             }
         } else {
             if (surface->compositor->method == CompositeMethod::AlphaMask) {
                 return _rasterDirectMaskedTranslucentRGBAImage(surface, image, region, opacity, _alpha);
             } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
                 return _rasterDirectMaskedTranslucentRGBAImage(surface, image, region, opacity, _ialpha);
+            } else if (surface->compositor->method == CompositeMethod::LumaMask) {
+                return _rasterDirectMaskedTranslucentRGBAImage(surface, image, region, opacity, surface->blender.lumaValue);
             }
         }
     } else {
@@ -1062,6 +1098,8 @@ static bool _rasterLinearGradientRect(SwSurface* surface, const SwBBox& region,
             return _rasterLinearGradientMaskedRect(surface, region, fill, _alpha);
         } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
             return _rasterLinearGradientMaskedRect(surface, region, fill, _ialpha);
+        } else if (surface->compositor->method == CompositeMethod::LumaMask) {
+            return _rasterLinearGradientMaskedRect(surface, region, fill, surface->blender.lumaValue);
         }
     } else {
         if (fill->translucent) return _rasterTranslucentLinearGradientRect(surface, region, fill);
@@ -1166,6 +1204,8 @@ static bool _rasterLinearGradientRle(SwSurface* surface, const SwRleData* rle, c
             return _rasterLinearGradientMaskedRle(surface, rle, fill, _alpha);
         } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
             return _rasterLinearGradientMaskedRle(surface, rle, fill, _ialpha);
+        } else if (surface->compositor->method == CompositeMethod::LumaMask) {
+            return _rasterLinearGradientMaskedRle(surface, rle, fill, surface->blender.lumaValue);
         }
     } else {
         if (fill->translucent) return _rasterTranslucentLinearGradientRle(surface, rle, fill);
@@ -1253,6 +1293,8 @@ static bool _rasterRadialGradientRect(SwSurface* surface, const SwBBox& region,
             return _rasterRadialGradientMaskedRect(surface, region, fill, _alpha);
         } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
             return _rasterRadialGradientMaskedRect(surface, region, fill, _ialpha);
+        } else if (surface->compositor->method == CompositeMethod::LumaMask) {
+            return _rasterRadialGradientMaskedRect(surface, region, fill, surface->blender.lumaValue);
         }
     } else {
         if (fill->translucent) return _rasterTranslucentRadialGradientRect(surface, region, fill);
@@ -1356,6 +1398,8 @@ static bool _rasterRadialGradientRle(SwSurface* surface, const SwRleData* rle, c
             return _rasterRadialGradientMaskedRle(surface, rle, fill, _alpha);
         } else if (surface->compositor->method == CompositeMethod::InvAlphaMask) {
             return _rasterRadialGradientMaskedRle(surface, rle, fill, _ialpha);
+        } else if (surface->compositor->method == CompositeMethod::LumaMask) {
+            return _rasterRadialGradientMaskedRle(surface, rle, fill, surface->blender.lumaValue);
         }
     } else {
         if (fill->translucent) _rasterTranslucentRadialGradientRle(surface, rle, fill);
@@ -1385,8 +1429,10 @@ bool rasterCompositor(SwSurface* surface)
 {
     if (surface->cs == SwCanvas::ABGR8888 || surface->cs == SwCanvas::ABGR8888_STRAIGHT) {
         surface->blender.join = _abgrJoin;
+        surface->blender.lumaValue = _abgrLumaValue;
     } else if (surface->cs == SwCanvas::ARGB8888 || surface->cs == SwCanvas::ARGB8888_STRAIGHT) {
         surface->blender.join = _argbJoin;
+        surface->blender.lumaValue = _argbLumaValue;
     } else {
         //What Color Space ???
         return false;
@@ -1500,4 +1546,4 @@ bool rasterImage(SwSurface* surface, SwImage* image, const Matrix* transform, co
     //TODO: case: _rasterGrayscaleImage()
     //TODO: case: _rasterAlphaImage()
     return _rasterRGBAImage(surface, image, transform, bbox, opacity);
-}
\ No newline at end of file
+}