1 /*
2 * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
3 * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org>
4 * Copyright (C) 2005 Eric Seidel <eric@webkit.org>
5 * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public License
18 * along with this library; see the file COPYING.LIB. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 */
22
23 #include "config.h"
24
25 #if ENABLE(FILTERS)
26 #include "FEBlend.h"
27
28 #include "Filter.h"
29 #include "FloatPoint.h"
30 #include "GraphicsContext.h"
31 #include "RenderTreeAsText.h"
32 #include "TextStream.h"
33
34 #include <wtf/ByteArray.h>
35
36 typedef unsigned char (*BlendType)(unsigned char colorA, unsigned char colorB, unsigned char alphaA, unsigned char alphaB);
37
38 namespace WebCore {
39
FEBlend(Filter * filter,BlendModeType mode)40 FEBlend::FEBlend(Filter* filter, BlendModeType mode)
41 : FilterEffect(filter)
42 , m_mode(mode)
43 {
44 }
45
create(Filter * filter,BlendModeType mode)46 PassRefPtr<FEBlend> FEBlend::create(Filter* filter, BlendModeType mode)
47 {
48 return adoptRef(new FEBlend(filter, mode));
49 }
50
blendMode() const51 BlendModeType FEBlend::blendMode() const
52 {
53 return m_mode;
54 }
55
setBlendMode(BlendModeType mode)56 bool FEBlend::setBlendMode(BlendModeType mode)
57 {
58 if (m_mode == mode)
59 return false;
60 m_mode = mode;
61 return true;
62 }
63
unknown(unsigned char,unsigned char,unsigned char,unsigned char)64 static unsigned char unknown(unsigned char, unsigned char, unsigned char, unsigned char)
65 {
66 return 0;
67 }
68
normal(unsigned char colorA,unsigned char colorB,unsigned char alphaA,unsigned char)69 static unsigned char normal(unsigned char colorA, unsigned char colorB, unsigned char alphaA, unsigned char)
70 {
71 return (((255 - alphaA) * colorB + colorA * 255) / 255);
72 }
73
multiply(unsigned char colorA,unsigned char colorB,unsigned char alphaA,unsigned char alphaB)74 static unsigned char multiply(unsigned char colorA, unsigned char colorB, unsigned char alphaA, unsigned char alphaB)
75 {
76 return (((255 - alphaA) * colorB + (255 - alphaB + colorB) * colorA) / 255);
77 }
78
screen(unsigned char colorA,unsigned char colorB,unsigned char,unsigned char)79 static unsigned char screen(unsigned char colorA, unsigned char colorB, unsigned char, unsigned char)
80 {
81 return (((colorB + colorA) * 255 - colorA * colorB) / 255);
82 }
83
darken(unsigned char colorA,unsigned char colorB,unsigned char alphaA,unsigned char alphaB)84 static unsigned char darken(unsigned char colorA, unsigned char colorB, unsigned char alphaA, unsigned char alphaB)
85 {
86 return ((std::min((255 - alphaA) * colorB + colorA * 255, (255 - alphaB) * colorA + colorB * 255)) / 255);
87 }
88
lighten(unsigned char colorA,unsigned char colorB,unsigned char alphaA,unsigned char alphaB)89 static unsigned char lighten(unsigned char colorA, unsigned char colorB, unsigned char alphaA, unsigned char alphaB)
90 {
91 return ((std::max((255 - alphaA) * colorB + colorA * 255, (255 - alphaB) * colorA + colorB * 255)) / 255);
92 }
93
apply()94 void FEBlend::apply()
95 {
96 if (hasResult())
97 return;
98 FilterEffect* in = inputEffect(0);
99 FilterEffect* in2 = inputEffect(1);
100 in->apply();
101 in2->apply();
102 if (!in->hasResult() || !in2->hasResult())
103 return;
104
105 if (m_mode <= FEBLEND_MODE_UNKNOWN || m_mode > FEBLEND_MODE_LIGHTEN)
106 return;
107
108 ByteArray* dstPixelArray = createPremultipliedImageResult();
109 if (!dstPixelArray)
110 return;
111
112 IntRect effectADrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect());
113 RefPtr<ByteArray> srcPixelArrayA = in->asPremultipliedImage(effectADrawingRect);
114
115 IntRect effectBDrawingRect = requestedRegionOfInputImageData(in2->absolutePaintRect());
116 RefPtr<ByteArray> srcPixelArrayB = in2->asPremultipliedImage(effectBDrawingRect);
117
118 // Keep synchronized with BlendModeType
119 static const BlendType callEffect[] = {unknown, normal, multiply, screen, darken, lighten};
120
121 unsigned pixelArrayLength = srcPixelArrayA->length();
122 ASSERT(pixelArrayLength == srcPixelArrayB->length());
123 for (unsigned pixelOffset = 0; pixelOffset < pixelArrayLength; pixelOffset += 4) {
124 unsigned char alphaA = srcPixelArrayA->get(pixelOffset + 3);
125 unsigned char alphaB = srcPixelArrayB->get(pixelOffset + 3);
126 for (unsigned channel = 0; channel < 3; ++channel) {
127 unsigned char colorA = srcPixelArrayA->get(pixelOffset + channel);
128 unsigned char colorB = srcPixelArrayB->get(pixelOffset + channel);
129
130 unsigned char result = (*callEffect[m_mode])(colorA, colorB, alphaA, alphaB);
131 dstPixelArray->set(pixelOffset + channel, result);
132 }
133 unsigned char alphaR = 255 - ((255 - alphaA) * (255 - alphaB)) / 255;
134 dstPixelArray->set(pixelOffset + 3, alphaR);
135 }
136 }
137
dump()138 void FEBlend::dump()
139 {
140 }
141
operator <<(TextStream & ts,const BlendModeType & type)142 static TextStream& operator<<(TextStream& ts, const BlendModeType& type)
143 {
144 switch (type) {
145 case FEBLEND_MODE_UNKNOWN:
146 ts << "UNKNOWN";
147 break;
148 case FEBLEND_MODE_NORMAL:
149 ts << "NORMAL";
150 break;
151 case FEBLEND_MODE_MULTIPLY:
152 ts << "MULTIPLY";
153 break;
154 case FEBLEND_MODE_SCREEN:
155 ts << "SCREEN";
156 break;
157 case FEBLEND_MODE_DARKEN:
158 ts << "DARKEN";
159 break;
160 case FEBLEND_MODE_LIGHTEN:
161 ts << "LIGHTEN";
162 break;
163 }
164 return ts;
165 }
166
externalRepresentation(TextStream & ts,int indent) const167 TextStream& FEBlend::externalRepresentation(TextStream& ts, int indent) const
168 {
169 writeIndent(ts, indent);
170 ts << "[feBlend";
171 FilterEffect::externalRepresentation(ts);
172 ts << " mode=\"" << m_mode << "\"]\n";
173 inputEffect(0)->externalRepresentation(ts, indent + 1);
174 inputEffect(1)->externalRepresentation(ts, indent + 1);
175 return ts;
176 }
177
178 } // namespace WebCore
179
180 #endif // ENABLE(FILTERS)
181