Extended Color: Streamline SimpleColor premulitply/unpremultiply code
authorweinig@apple.com <weinig@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 9 Jun 2020 21:05:09 +0000 (21:05 +0000)
committerweinig@apple.com <weinig@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 9 Jun 2020 21:05:09 +0000 (21:05 +0000)
https://bugs.webkit.org/show_bug.cgi?id=212945

Reviewed by Darin Adler.

Simplify / streamline the premulitply/unpremultiply code by:
- Removing the overloads that didn't take individual components, keeping
  only the ones taking a SimpleColor.
- Replacing the "ceiling" bool in makePremultipliedSimpleColor and converting
  it into two functions.
- Simplifying the names from makePremultipliedSimpleColor/makeUnpremultipliedSimpleColor
  to premultiplyFlooring/premultiplyCeiling/unpremultiply.
- Where component order is important, use valueAsARGB() explicitly to
  show what the resulting value's format will be.

* platform/graphics/Color.cpp:
(WebCore::blend):
Update to call premultiplyCeiling/unpremultiply.

* platform/graphics/ImageBackingStore.h:
(WebCore::ImageBackingStore::blendPixel):
(WebCore::ImageBackingStore::pixelValue const):
Update to call premultiplyFlooring/unpremultiply and valueAsARGB().

* platform/graphics/SimpleColor.h:
* platform/graphics/SimpleColor.cpp:
(WebCore::premultiplyFlooring):
(WebCore::premultiplyCeiling):
(WebCore::unpremultiplyChannel):
(WebCore::unpremultiply):
(WebCore::premultipliedChannel): Deleted.
(WebCore::unpremultipliedChannel): Deleted.
(WebCore::makePremultipliedSimpleColor): Deleted.
(WebCore::makeUnpremultipliedSimpleColor): Deleted.
Simplify premulitply/unpremultiply interfaces. Use structured bindings to make
the code a bit easier to follow as well.

* platform/graphics/cairo/ImageBufferCairoImageSurfaceBackend.cpp:
(WebCore::ImageBufferCairoImageSurfaceBackend::platformTransformColorSpace):
Update to call premultiplyFlooring/unpremultiply and valueAsARGB().

* platform/graphics/cairo/NativeImageCairo.cpp:
(WebCore::nativeImageSinglePixelSolidColor):
Update to call premultiplyFlooring/unpremultiply and valueAsARGB(). Also removes
reinterpret cast to SimpleColor, instead following the model in ImageBufferCairoImageSurfaceBackend
and casting to unsigned, and building the SimpleColor from that. This will allow
SimpleColor to change its underlying representation in the future without breaking things.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@262810 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/platform/graphics/Color.cpp
Source/WebCore/platform/graphics/ImageBackingStore.h
Source/WebCore/platform/graphics/SimpleColor.cpp
Source/WebCore/platform/graphics/SimpleColor.h
Source/WebCore/platform/graphics/cairo/ImageBufferCairoImageSurfaceBackend.cpp
Source/WebCore/platform/graphics/cairo/NativeImageCairo.cpp

index 7c85fa2..4270213 100644 (file)
@@ -1,3 +1,53 @@
+2020-06-09  Sam Weinig  <weinig@apple.com>
+
+        Extended Color: Streamline SimpleColor premulitply/unpremultiply code
+        https://bugs.webkit.org/show_bug.cgi?id=212945
+
+        Reviewed by Darin Adler.
+
+        Simplify / streamline the premulitply/unpremultiply code by:
+        - Removing the overloads that didn't take individual components, keeping 
+          only the ones taking a SimpleColor.
+        - Replacing the "ceiling" bool in makePremultipliedSimpleColor and converting
+          it into two functions.
+        - Simplifying the names from makePremultipliedSimpleColor/makeUnpremultipliedSimpleColor
+          to premultiplyFlooring/premultiplyCeiling/unpremultiply.
+        - Where component order is important, use valueAsARGB() explicitly to
+          show what the resulting value's format will be.
+
+        * platform/graphics/Color.cpp:
+        (WebCore::blend):
+        Update to call premultiplyCeiling/unpremultiply.
+
+        * platform/graphics/ImageBackingStore.h:
+        (WebCore::ImageBackingStore::blendPixel):
+        (WebCore::ImageBackingStore::pixelValue const):
+        Update to call premultiplyFlooring/unpremultiply and valueAsARGB().
+
+        * platform/graphics/SimpleColor.h:
+        * platform/graphics/SimpleColor.cpp:
+        (WebCore::premultiplyFlooring):
+        (WebCore::premultiplyCeiling):
+        (WebCore::unpremultiplyChannel):
+        (WebCore::unpremultiply):
+        (WebCore::premultipliedChannel): Deleted.
+        (WebCore::unpremultipliedChannel): Deleted.
+        (WebCore::makePremultipliedSimpleColor): Deleted.
+        (WebCore::makeUnpremultipliedSimpleColor): Deleted.
+        Simplify premulitply/unpremultiply interfaces. Use structured bindings to make
+        the code a bit easier to follow as well.
+        
+        * platform/graphics/cairo/ImageBufferCairoImageSurfaceBackend.cpp:
+        (WebCore::ImageBufferCairoImageSurfaceBackend::platformTransformColorSpace):
+        Update to call premultiplyFlooring/unpremultiply and valueAsARGB().
+
+        * platform/graphics/cairo/NativeImageCairo.cpp:
+        (WebCore::nativeImageSinglePixelSolidColor):
+        Update to call premultiplyFlooring/unpremultiply and valueAsARGB(). Also removes
+        reinterpret cast to SimpleColor, instead following the model in ImageBufferCairoImageSurfaceBackend
+        and casting to unsigned, and building the SimpleColor from that. This will allow 
+        SimpleColor to change its underlying representation in the future without breaking things.
+
 2020-06-09  Commit Queue  <commit-queue@webkit.org>
 
         Unreviewed, reverting r261841.
index 96472ea..f9e056d 100644 (file)
@@ -266,18 +266,18 @@ Color blend(const Color& from, const Color& to, double progress)
     if (progress == 1 && !to.isValid())
         return { };
 
-    // Since makePremultipliedSimpleColor() bails on zero alpha, special-case that.
-    auto premultFrom = from.alpha() ? makePremultipliedSimpleColor(from.toSRGBASimpleColorLossy()) : Color::transparent;
-    auto premultTo = to.alpha() ? makePremultipliedSimpleColor(to.toSRGBASimpleColorLossy()) : Color::transparent;
+    // Since premultiplyCeiling() bails on zero alpha, special-case that.
+    auto premultipliedFrom = from.alpha() ? premultiplyCeiling(from.toSRGBASimpleColorLossy()) : Color::transparent;
+    auto premultipliedTo = to.alpha() ? premultiplyCeiling(to.toSRGBASimpleColorLossy()) : Color::transparent;
 
     SimpleColor premultBlended = makeSimpleColor(
-        WebCore::blend(premultFrom.redComponent(), premultTo.redComponent(), progress),
-        WebCore::blend(premultFrom.greenComponent(), premultTo.greenComponent(), progress),
-        WebCore::blend(premultFrom.blueComponent(), premultTo.blueComponent(), progress),
-        WebCore::blend(premultFrom.alphaComponent(), premultTo.alphaComponent(), progress)
+        WebCore::blend(premultipliedFrom.redComponent(), premultipliedTo.redComponent(), progress),
+        WebCore::blend(premultipliedFrom.greenComponent(), premultipliedTo.greenComponent(), progress),
+        WebCore::blend(premultipliedFrom.blueComponent(), premultipliedTo.blueComponent(), progress),
+        WebCore::blend(premultipliedFrom.alphaComponent(), premultipliedTo.alphaComponent(), progress)
     );
 
-    return makeUnpremultipliedSimpleColor(premultBlended);
+    return unpremultiply(premultBlended);
 }
 
 Color blendWithoutPremultiply(const Color& from, const Color& to, double progress)
index 61c6030..4b9b5f2 100644 (file)
@@ -160,7 +160,7 @@ public:
         }
 
         if (!m_premultiplyAlpha)
-            pixel = makePremultipliedSimpleColor(pixel.redComponent(), pixel.greenComponent(), pixel.blueComponent(), pixel.alphaComponent(), false);
+            pixel = premultiplyFlooring(pixel);
 
         unsigned d = 255 - a;
 
@@ -169,10 +169,12 @@ public:
         b = fastDivideBy255(b * a + pixel.blueComponent() * d);
         a += fastDivideBy255(d * pixel.alphaComponent());
 
-        if (m_premultiplyAlpha)
-            *dest = makeSimpleColor(r, g, b, a).value();
-        else
-            *dest = makeUnpremultipliedSimpleColor(r, g, b, a).value();
+        auto result = makeSimpleColor(r, g, b, a);
+
+        if (!m_premultiplyAlpha)
+            result = unpremultiply(result);
+
+        *dest = result.valueAsARGB();
     }
 
     static bool isOverSize(const IntSize& size)
@@ -224,10 +226,12 @@ private:
         if (m_premultiplyAlpha && !a)
             return 0;
 
+        auto result = makeSimpleColor(r, g, b, a);
+
         if (m_premultiplyAlpha && a < 255)
-            return makePremultipliedSimpleColor(r, g, b, a, false).value();
+            result = premultiplyFlooring(result);
 
-        return makeSimpleColor(r, g, b, a).value();
+        return result.valueAsARGB();
     }
 
     RefPtr<SharedBuffer::DataSegment> m_pixels;
index cc9bdfd..ee29bb8 100644 (file)
 
 namespace WebCore {
 
-static inline unsigned premultipliedChannel(unsigned c, unsigned a, bool ceiling = true)
+SimpleColor premultiplyFlooring(SimpleColor color)
 {
-    return fastDivideBy255(ceiling ? c * a + 254 : c * a);
+    auto [r, g, b, a] = color;
+    if (!a || a == 255)
+        return color;
+    return makeSimpleColor(fastDivideBy255(r * a), fastDivideBy255(g * a), fastDivideBy255(b * a), a);
 }
 
-static inline unsigned unpremultipliedChannel(unsigned c, unsigned a)
+SimpleColor premultiplyCeiling(SimpleColor color)
 {
-    return (fastMultiplyBy255(c) + a - 1) / a;
-}
-
-SimpleColor makePremultipliedSimpleColor(int r, int g, int b, int a, bool ceiling)
-{
-    return makeSimpleColor(premultipliedChannel(r, a, ceiling), premultipliedChannel(g, a, ceiling), premultipliedChannel(b, a, ceiling), a);
+    auto [r, g, b, a] = color;
+    if (!a || a == 255)
+        return color;
+    return makeSimpleColor(fastDivideBy255(r * a + 254), fastDivideBy255(g * a + 254), fastDivideBy255(b * a + 254), a);
 }
 
-SimpleColor makePremultipliedSimpleColor(SimpleColor pixelColor)
+static inline uint16_t unpremultiplyChannel(uint8_t c, uint8_t a)
 {
-    if (pixelColor.isOpaque())
-        return pixelColor;
-    return makePremultipliedSimpleColor(pixelColor.redComponent(), pixelColor.greenComponent(), pixelColor.blueComponent(), pixelColor.alphaComponent());
-}
-
-SimpleColor makeUnpremultipliedSimpleColor(int r, int g, int b, int a)
-{
-    return makeSimpleColor(unpremultipliedChannel(r, a), unpremultipliedChannel(g, a), unpremultipliedChannel(b, a), a);
+    return (fastMultiplyBy255(c) + a - 1) / a;
 }
 
-SimpleColor makeUnpremultipliedSimpleColor(SimpleColor pixelColor)
+SimpleColor unpremultiply(SimpleColor color)
 {
-    if (pixelColor.isVisible() && !pixelColor.isOpaque())
-        return makeUnpremultipliedSimpleColor(pixelColor.redComponent(), pixelColor.greenComponent(), pixelColor.blueComponent(), pixelColor.alphaComponent());
-    return pixelColor;
+    auto [r, g, b, a] = color;
+    if (!a || a == 255)
+        return color;
+    return makeSimpleColor(unpremultiplyChannel(r, a), unpremultiplyChannel(g, a), unpremultiplyChannel(b, a), a);
 }
 
 SimpleColor makeSimpleColorFromCMYKA(float c, float m, float y, float k, float a)
index 8ec651a..42a22f3 100644 (file)
@@ -98,10 +98,9 @@ SimpleColor makeSimpleColor(const ColorComponents<float>& sRGBComponents);
 SimpleColor makeSimpleColorFromFloats(float r, float g, float b, float a);
 SimpleColor makeSimpleColorFromCMYKA(float c, float m, float y, float k, float a);
 
-SimpleColor makePremultipliedSimpleColor(int r, int g, int b, int a, bool ceiling = true);
-SimpleColor makePremultipliedSimpleColor(SimpleColor);
-SimpleColor makeUnpremultipliedSimpleColor(int r, int g, int b, int a);
-SimpleColor makeUnpremultipliedSimpleColor(SimpleColor);
+SimpleColor premultiplyFlooring(SimpleColor);
+SimpleColor premultiplyCeiling(SimpleColor);
+SimpleColor unpremultiply(SimpleColor);
 
 inline bool operator==(SimpleColor a, SimpleColor b)
 {
index 8ee4af9..d00060c 100644 (file)
@@ -80,9 +80,9 @@ void ImageBufferCairoImageSurfaceBackend::platformTransformColorSpace(const std:
         unsigned* row = reinterpret_cast_ptr<unsigned*>(dataSrc + stride * y);
         for (int x = 0; x < m_logicalSize.width(); x++) {
             unsigned* pixel = row + x;
-            auto pixelColor = makeUnpremultipliedSimpleColor(*pixel);
+            auto pixelColor = unpremultiply(SimpleColor { *pixel });
             pixelColor = makeSimpleColor(lookUpTable[pixelColor.redComponent()], lookUpTable[pixelColor.greenComponent()], lookUpTable[pixelColor.blueComponent()], pixelColor.alphaComponent());
-            *pixel = makePremultipliedSimpleColor(pixelColor).value();
+            *pixel = premultiplyCeiling(pixelColor).valueAsARGB();
         }
     }
     cairo_surface_mark_dirty_rectangle(m_surface.get(), 0, 0, m_logicalSize.width(), m_logicalSize.height());
index 81dc89e..e5d0d09 100644 (file)
@@ -53,8 +53,8 @@ Color nativeImageSinglePixelSolidColor(const NativeImagePtr& image)
     if (cairo_surface_get_type(image.get()) != CAIRO_SURFACE_TYPE_IMAGE)
         return Color();
 
-    SimpleColor* pixel = reinterpret_cast_ptr<SimpleColor*>(cairo_image_surface_get_data(image.get()));
-    return makeUnpremultipliedSimpleColor(*pixel);
+    unsigned* pixel = reinterpret_cast_ptr<unsigned*>(cairo_image_surface_get_data(image.get()));
+    return unpremultiply(SimpleColor { *pixel });
 }
 
 void drawNativeImage(const NativeImagePtr& image, GraphicsContext& context, const FloatRect& destRect, const FloatRect& srcRect, const IntSize& imageSize, const ImagePaintingOptions& options)