summaryrefslogtreecommitdiff
path: root/Source/WebCore/platform/graphics/filters/FEBlend.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/platform/graphics/filters/FEBlend.cpp')
-rw-r--r--Source/WebCore/platform/graphics/filters/FEBlend.cpp144
1 files changed, 88 insertions, 56 deletions
diff --git a/Source/WebCore/platform/graphics/filters/FEBlend.cpp b/Source/WebCore/platform/graphics/filters/FEBlend.cpp
index 363a75b7f..f6dcf6396 100644
--- a/Source/WebCore/platform/graphics/filters/FEBlend.cpp
+++ b/Source/WebCore/platform/graphics/filters/FEBlend.cpp
@@ -3,6 +3,7 @@
* Copyright (C) 2004, 2005 Rob Buis <buis@kde.org>
* Copyright (C) 2005 Eric Seidel <eric@webkit.org>
* Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
+ * Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -62,71 +63,102 @@ bool FEBlend::setBlendMode(BlendModeType mode)
return true;
}
-static inline unsigned char normal(unsigned char colorA, unsigned char colorB, unsigned char alphaA, unsigned char)
+static inline unsigned char fastDivideBy255(uint16_t value)
{
- return (((255 - alphaA) * colorB + colorA * 255) / 255);
+ // This is an approximate algorithm for division by 255, but it gives accurate results for 16bit values.
+ uint16_t quotient = value >> 8;
+ uint16_t remainder = value - (quotient * 255) + 1;
+ return quotient + (remainder >> 8);
}
-static inline unsigned char multiply(unsigned char colorA, unsigned char colorB, unsigned char alphaA, unsigned char alphaB)
-{
- return (((255 - alphaA) * colorB + (255 - alphaB + colorB) * colorA) / 255);
-}
+class BlendNormal {
+public:
+ static unsigned char apply(unsigned char colorA, unsigned char colorB, unsigned char alphaA, unsigned char)
+ {
+ return fastDivideBy255((255 - alphaA) * colorB + colorA * 255);
+ }
+};
-static inline unsigned char screen(unsigned char colorA, unsigned char colorB, unsigned char, unsigned char)
-{
- return (((colorB + colorA) * 255 - colorA * colorB) / 255);
-}
+class BlendMultiply {
+public:
+ static unsigned char apply(unsigned char colorA, unsigned char colorB, unsigned char alphaA, unsigned char alphaB)
+ {
+ return fastDivideBy255((255 - alphaA) * colorB + (255 - alphaB + colorB) * colorA);
+ }
+};
-static inline unsigned char darken(unsigned char colorA, unsigned char colorB, unsigned char alphaA, unsigned char alphaB)
-{
- return ((std::min((255 - alphaA) * colorB + colorA * 255, (255 - alphaB) * colorA + colorB * 255)) / 255);
-}
+class BlendScreen {
+public:
+ static unsigned char apply(unsigned char colorA, unsigned char colorB, unsigned char, unsigned char)
+ {
+ return fastDivideBy255((colorB + colorA) * 255 - colorA * colorB);
+ }
+};
+
+class BlendDarken {
+public:
+ static unsigned char apply(unsigned char colorA, unsigned char colorB, unsigned char alphaA, unsigned char alphaB)
+ {
+ return fastDivideBy255(std::min((255 - alphaA) * colorB + colorA * 255, (255 - alphaB) * colorA + colorB * 255));
+ }
+};
+
+class BlendLighten {
+public:
+ static unsigned char apply(unsigned char colorA, unsigned char colorB, unsigned char alphaA, unsigned char alphaB)
+ {
+ return fastDivideBy255(std::max((255 - alphaA) * colorB + colorA * 255, (255 - alphaB) * colorA + colorB * 255));
+ }
+};
+
+class BlendUnknown {
+public:
+ static unsigned char apply(unsigned char, unsigned char, unsigned char, unsigned char)
+ {
+ return 0;
+ }
+};
-static inline unsigned char lighten(unsigned char colorA, unsigned char colorB, unsigned char alphaA, unsigned char alphaB)
+template<typename BlendFunctor>
+static void platformApply(unsigned char* sourcePixelA, unsigned char* sourcePixelB,
+ unsigned char* destinationPixel, unsigned pixelArrayLength)
{
- return ((std::max((255 - alphaA) * colorB + colorA * 255, (255 - alphaB) * colorA + colorB * 255)) / 255);
+ unsigned len = pixelArrayLength / 4;
+ for (unsigned pixelOffset = 0; pixelOffset < len; pixelOffset++) {
+ unsigned char alphaA = sourcePixelA[3];
+ unsigned char alphaB = sourcePixelB[3];
+ destinationPixel[0] = BlendFunctor::apply(sourcePixelA[0], sourcePixelB[0], alphaA, alphaB);
+ destinationPixel[1] = BlendFunctor::apply(sourcePixelA[1], sourcePixelB[1], alphaA, alphaB);
+ destinationPixel[2] = BlendFunctor::apply(sourcePixelA[2], sourcePixelB[2], alphaA, alphaB);
+ destinationPixel[3] = 255 - fastDivideBy255((255 - alphaA) * (255 - alphaB));
+ sourcePixelA += 4;
+ sourcePixelB += 4;
+ destinationPixel += 4;
+ }
}
-void FEBlend::platformApplyGeneric(PassRefPtr<Uint8ClampedArray> pixelArrayA, PassRefPtr<Uint8ClampedArray> pixelArrayB,
- Uint8ClampedArray* dstPixelArray, unsigned pixelArrayLength)
+void FEBlend::platformApplyGeneric(unsigned char* sourcePixelA, unsigned char* sourcePixelB,
+ unsigned char* destinationPixel, unsigned pixelArrayLength)
{
- RefPtr<Uint8ClampedArray> srcPixelArrayA = pixelArrayA;
- RefPtr<Uint8ClampedArray> srcPixelArrayB = pixelArrayB;
-
- for (unsigned pixelOffset = 0; pixelOffset < pixelArrayLength; pixelOffset += 4) {
- unsigned char alphaA = srcPixelArrayA->item(pixelOffset + 3);
- unsigned char alphaB = srcPixelArrayB->item(pixelOffset + 3);
- for (unsigned channel = 0; channel < 3; ++channel) {
- unsigned char colorA = srcPixelArrayA->item(pixelOffset + channel);
- unsigned char colorB = srcPixelArrayB->item(pixelOffset + channel);
- unsigned char result;
-
- switch (m_mode) {
- case FEBLEND_MODE_NORMAL:
- result = normal(colorA, colorB, alphaA, alphaB);
- break;
- case FEBLEND_MODE_MULTIPLY:
- result = multiply(colorA, colorB, alphaA, alphaB);
- break;
- case FEBLEND_MODE_SCREEN:
- result = screen(colorA, colorB, alphaA, alphaB);
- break;
- case FEBLEND_MODE_DARKEN:
- result = darken(colorA, colorB, alphaA, alphaB);
- break;
- case FEBLEND_MODE_LIGHTEN:
- result = lighten(colorA, colorB, alphaA, alphaB);
- break;
- case FEBLEND_MODE_UNKNOWN:
- default:
- result = 0;
- break;
- }
-
- dstPixelArray->set(pixelOffset + channel, result);
- }
- unsigned char alphaR = 255 - ((255 - alphaA) * (255 - alphaB)) / 255;
- dstPixelArray->set(pixelOffset + 3, alphaR);
+ switch (m_mode) {
+ case FEBLEND_MODE_NORMAL:
+ platformApply<BlendNormal>(sourcePixelA, sourcePixelB, destinationPixel, pixelArrayLength);
+ break;
+ case FEBLEND_MODE_MULTIPLY:
+ platformApply<BlendMultiply>(sourcePixelA, sourcePixelB, destinationPixel, pixelArrayLength);
+ break;
+ case FEBLEND_MODE_SCREEN:
+ platformApply<BlendScreen>(sourcePixelA, sourcePixelB, destinationPixel, pixelArrayLength);
+ break;
+ case FEBLEND_MODE_DARKEN:
+ platformApply<BlendDarken>(sourcePixelA, sourcePixelB, destinationPixel, pixelArrayLength);
+ break;
+ case FEBLEND_MODE_LIGHTEN:
+ platformApply<BlendLighten>(sourcePixelA, sourcePixelB, destinationPixel, pixelArrayLength);
+ break;
+ case FEBLEND_MODE_UNKNOWN:
+ platformApply<BlendUnknown>(sourcePixelA, sourcePixelB, destinationPixel, pixelArrayLength);
+ break;
}
}
@@ -165,7 +197,7 @@ void FEBlend::platformApplySoftware()
reinterpret_cast<uint32_t*>(dstPixelArray->data())[0] = sourceBAndDest[0];
}
#else
- platformApplyGeneric(srcPixelArrayA, srcPixelArrayB, dstPixelArray, pixelArrayLength);
+ platformApplyGeneric(srcPixelArrayA->data(), srcPixelArrayB->data(), dstPixelArray->data(), pixelArrayLength);
#endif
}