#include "config.h"
#if ENABLE(FILTERS)
#include "FEBlend.h"
#include "Filter.h"
#include "FloatPoint.h"
#include "GraphicsContext.h"
#include "RenderTreeAsText.h"
#include "TextStream.h"
#include <wtf/Uint8ClampedArray.h>
typedef unsigned char (*BlendType)(unsigned char colorA, unsigned char colorB, unsigned char alphaA, unsigned char alphaB);
namespace WebCore {
FEBlend::FEBlend(Filter* filter, BlendModeType mode)
: FilterEffect(filter)
, m_mode(mode)
{
}
PassRefPtr<FEBlend> FEBlend::create(Filter* filter, BlendModeType mode)
{
return adoptRef(new FEBlend(filter, mode));
}
BlendModeType FEBlend::blendMode() const
{
return m_mode;
}
bool FEBlend::setBlendMode(BlendModeType mode)
{
if (m_mode == mode)
return false;
m_mode = mode;
return true;
}
static inline unsigned char normal(unsigned char colorA, unsigned char colorB, unsigned char alphaA, unsigned char)
{
return (((255 - alphaA) * colorB + colorA * 255) / 255);
}
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);
}
static inline unsigned char screen(unsigned char colorA, unsigned char colorB, unsigned char, unsigned char)
{
return (((colorB + colorA) * 255 - colorA * colorB) / 255);
}
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);
}
static inline unsigned char lighten(unsigned char colorA, unsigned char colorB, unsigned char alphaA, unsigned char alphaB)
{
return ((std::max((255 - alphaA) * colorB + colorA * 255, (255 - alphaB) * colorA + colorB * 255)) / 255);
}
void FEBlend::platformApplySoftware()
{
FilterEffect* in = inputEffect(0);
FilterEffect* in2 = inputEffect(1);
ASSERT(m_mode > FEBLEND_MODE_UNKNOWN);
ASSERT(m_mode <= FEBLEND_MODE_LIGHTEN);
Uint8ClampedArray* dstPixelArray = createPremultipliedImageResult();
if (!dstPixelArray)
return;
IntRect effectADrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect());
RefPtr<Uint8ClampedArray> srcPixelArrayA = in->asPremultipliedImage(effectADrawingRect);
IntRect effectBDrawingRect = requestedRegionOfInputImageData(in2->absolutePaintRect());
RefPtr<Uint8ClampedArray> srcPixelArrayB = in2->asPremultipliedImage(effectBDrawingRect);
unsigned pixelArrayLength = srcPixelArrayA->length();
ASSERT(pixelArrayLength == srcPixelArrayB->length());
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);
}
}
void FEBlend::dump()
{
}
static TextStream& operator<<(TextStream& ts, const BlendModeType& type)
{
switch (type) {
case FEBLEND_MODE_UNKNOWN:
ts << "UNKNOWN";
break;
case FEBLEND_MODE_NORMAL:
ts << "NORMAL";
break;
case FEBLEND_MODE_MULTIPLY:
ts << "MULTIPLY";
break;
case FEBLEND_MODE_SCREEN:
ts << "SCREEN";
break;
case FEBLEND_MODE_DARKEN:
ts << "DARKEN";
break;
case FEBLEND_MODE_LIGHTEN:
ts << "LIGHTEN";
break;
}
return ts;
}
TextStream& FEBlend::externalRepresentation(TextStream& ts, int indent) const
{
writeIndent(ts, indent);
ts << "[feBlend";
FilterEffect::externalRepresentation(ts);
ts << " mode=\"" << m_mode << "\"]\n";
inputEffect(0)->externalRepresentation(ts, indent + 1);
inputEffect(1)->externalRepresentation(ts, indent + 1);
return ts;
}
}
#endif // ENABLE(FILTERS)