Implement rendering support for the color-filter CSS property
[WebKit-https.git] / Source / WebCore / platform / graphics / filters / FilterOperation.cpp
1 /*
2  * Copyright (C) 2011 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #include "config.h"
27 #include "FilterOperation.h"
28
29 #include "AnimationUtilities.h"
30 #include "CachedResourceLoader.h"
31 #include "CachedSVGDocumentReference.h"
32 #include "ColorUtilities.h"
33 #include "FilterEffect.h"
34 #include "SVGURIReference.h"
35 #include <wtf/text/TextStream.h>
36
37 namespace WebCore {
38     
39 bool DefaultFilterOperation::operator==(const FilterOperation& operation) const
40 {
41     if (!isSameType(operation))
42         return false;
43     
44     return representedType() == downcast<DefaultFilterOperation>(operation).representedType();
45 }
46
47 ReferenceFilterOperation::ReferenceFilterOperation(const String& url, const String& fragment)
48     : FilterOperation(REFERENCE)
49     , m_url(url)
50     , m_fragment(fragment)
51 {
52 }
53
54 ReferenceFilterOperation::~ReferenceFilterOperation() = default;
55     
56 bool ReferenceFilterOperation::operator==(const FilterOperation& operation) const
57 {
58     if (!isSameType(operation))
59         return false;
60     
61     return m_url == downcast<ReferenceFilterOperation>(operation).m_url;
62 }
63
64 void ReferenceFilterOperation::loadExternalDocumentIfNeeded(CachedResourceLoader& cachedResourceLoader, const ResourceLoaderOptions& options)
65 {
66     if (m_cachedSVGDocumentReference)
67         return;
68     if (!SVGURIReference::isExternalURIReference(m_url, *cachedResourceLoader.document()))
69         return;
70     m_cachedSVGDocumentReference = std::make_unique<CachedSVGDocumentReference>(m_url);
71     m_cachedSVGDocumentReference->load(cachedResourceLoader, options);
72 }
73
74 void ReferenceFilterOperation::setFilterEffect(RefPtr<FilterEffect>&& filterEffect)
75 {
76     m_filterEffect = WTFMove(filterEffect);
77 }
78
79 RefPtr<FilterOperation> BasicColorMatrixFilterOperation::blend(const FilterOperation* from, double progress, bool blendToPassthrough)
80 {
81     if (from && !from->isSameType(*this))
82         return this;
83     
84     if (blendToPassthrough)
85         return BasicColorMatrixFilterOperation::create(WebCore::blend(m_amount, passthroughAmount(), progress), m_type);
86         
87     const BasicColorMatrixFilterOperation* fromOperation = downcast<BasicColorMatrixFilterOperation>(from);
88     double fromAmount = fromOperation ? fromOperation->amount() : passthroughAmount();
89     return BasicColorMatrixFilterOperation::create(WebCore::blend(fromAmount, m_amount, progress), m_type);
90 }
91
92 bool BasicColorMatrixFilterOperation::transformColor(FloatComponents& colorComponents) const
93 {
94     switch (m_type) {
95     case GRAYSCALE: {
96         ColorMatrix matrix = ColorMatrix::grayscaleMatrix(m_amount);
97         matrix.transformColorComponents(colorComponents);
98         return true;
99     }
100     case SEPIA: {
101         ColorMatrix matrix = ColorMatrix::sepiaMatrix(m_amount);
102         matrix.transformColorComponents(colorComponents);
103         return true;
104     }
105     case HUE_ROTATE: {
106         ColorMatrix matrix = ColorMatrix::hueRotateMatrix(m_amount);
107         matrix.transformColorComponents(colorComponents);
108         return true;
109     }
110     case SATURATE: {
111         ColorMatrix matrix = ColorMatrix::saturationMatrix(m_amount);
112         matrix.transformColorComponents(colorComponents);
113         return true;
114     }
115     default:
116         ASSERT_NOT_REACHED();
117         return false;
118     }
119
120     return false;
121 }
122
123 inline bool BasicColorMatrixFilterOperation::operator==(const FilterOperation& operation) const
124 {
125     if (!isSameType(operation))
126         return false;
127     const BasicColorMatrixFilterOperation& other = downcast<BasicColorMatrixFilterOperation>(operation);
128     return m_amount == other.m_amount;
129 }
130
131 double BasicColorMatrixFilterOperation::passthroughAmount() const
132 {
133     switch (m_type) {
134     case GRAYSCALE:
135     case SEPIA:
136     case HUE_ROTATE:
137         return 0;
138     case SATURATE:
139         return 1;
140     default:
141         ASSERT_NOT_REACHED();
142         return 0;
143     }
144 }
145
146 RefPtr<FilterOperation> BasicComponentTransferFilterOperation::blend(const FilterOperation* from, double progress, bool blendToPassthrough)
147 {
148     if (from && !from->isSameType(*this))
149         return this;
150     
151     if (blendToPassthrough)
152         return BasicComponentTransferFilterOperation::create(WebCore::blend(m_amount, passthroughAmount(), progress), m_type);
153         
154     const BasicComponentTransferFilterOperation* fromOperation = downcast<BasicComponentTransferFilterOperation>(from);
155     double fromAmount = fromOperation ? fromOperation->amount() : passthroughAmount();
156     return BasicComponentTransferFilterOperation::create(WebCore::blend(fromAmount, m_amount, progress), m_type);
157 }
158
159 bool BasicComponentTransferFilterOperation::transformColor(FloatComponents& colorComponents) const
160 {
161     switch (m_type) {
162     case OPACITY:
163         colorComponents.components[3] *= m_amount;
164         return true;
165     case INVERT: {
166         float oneMinusAmount = 1.f - m_amount;
167         colorComponents.components[0] = 1 - (oneMinusAmount + colorComponents.components[0] * (m_amount - oneMinusAmount));
168         colorComponents.components[1] = 1 - (oneMinusAmount + colorComponents.components[1] * (m_amount - oneMinusAmount));
169         colorComponents.components[2] = 1 - (oneMinusAmount + colorComponents.components[2] * (m_amount - oneMinusAmount));
170         return true;
171     }
172     case CONTRAST: {
173         float intercept = -(0.5f * m_amount) + 0.5f;
174         colorComponents.components[0] = clampTo<float>(intercept + m_amount * colorComponents.components[0], 0, 1);
175         colorComponents.components[1] = clampTo<float>(intercept + m_amount * colorComponents.components[1], 0, 1);
176         colorComponents.components[2] = clampTo<float>(intercept + m_amount * colorComponents.components[2], 0, 1);
177         return true;
178     }
179     case BRIGHTNESS:
180         colorComponents.components[0] = std::max<float>(m_amount * colorComponents.components[0], 0);
181         colorComponents.components[1] = std::max<float>(m_amount * colorComponents.components[1], 0);
182         colorComponents.components[2] = std::max<float>(m_amount * colorComponents.components[2], 0);
183         return true;
184     default:
185         ASSERT_NOT_REACHED();
186         return false;
187     }
188     return false;
189 }
190
191 inline bool BasicComponentTransferFilterOperation::operator==(const FilterOperation& operation) const
192 {
193     if (!isSameType(operation))
194         return false;
195     const BasicComponentTransferFilterOperation& other = downcast<BasicComponentTransferFilterOperation>(operation);
196     return m_amount == other.m_amount;
197 }
198
199 double BasicComponentTransferFilterOperation::passthroughAmount() const
200 {
201     switch (m_type) {
202     case OPACITY:
203         return 1;
204     case INVERT:
205         return 0;
206     case CONTRAST:
207         return 1;
208     case BRIGHTNESS:
209         return 1;
210     default:
211         ASSERT_NOT_REACHED();
212         return 0;
213     }
214 }
215     
216 bool BlurFilterOperation::operator==(const FilterOperation& operation) const
217 {
218     if (!isSameType(operation))
219         return false;
220     
221     return m_stdDeviation == downcast<BlurFilterOperation>(operation).stdDeviation();
222 }
223     
224 RefPtr<FilterOperation> BlurFilterOperation::blend(const FilterOperation* from, double progress, bool blendToPassthrough)
225 {
226     if (from && !from->isSameType(*this))
227         return this;
228
229     LengthType lengthType = m_stdDeviation.type();
230
231     if (blendToPassthrough)
232         return BlurFilterOperation::create(WebCore::blend(m_stdDeviation, Length(lengthType), progress));
233
234     const BlurFilterOperation* fromOperation = downcast<BlurFilterOperation>(from);
235     Length fromLength = fromOperation ? fromOperation->m_stdDeviation : Length(lengthType);
236     return BlurFilterOperation::create(WebCore::blend(fromLength, m_stdDeviation, progress));
237 }
238     
239 bool DropShadowFilterOperation::operator==(const FilterOperation& operation) const
240 {
241     if (!isSameType(operation))
242         return false;
243     const DropShadowFilterOperation& other = downcast<DropShadowFilterOperation>(operation);
244     return m_location == other.m_location && m_stdDeviation == other.m_stdDeviation && m_color == other.m_color;
245 }
246     
247 RefPtr<FilterOperation> DropShadowFilterOperation::blend(const FilterOperation* from, double progress, bool blendToPassthrough)
248 {
249     if (from && !from->isSameType(*this))
250         return this;
251
252     if (blendToPassthrough)
253         return DropShadowFilterOperation::create(
254             WebCore::blend(m_location, IntPoint(), progress),
255             WebCore::blend(m_stdDeviation, 0, progress),
256             WebCore::blend(m_color, Color(Color::transparent), progress));
257
258     const DropShadowFilterOperation* fromOperation = downcast<DropShadowFilterOperation>(from);
259     IntPoint fromLocation = fromOperation ? fromOperation->location() : IntPoint();
260     int fromStdDeviation = fromOperation ? fromOperation->stdDeviation() : 0;
261     Color fromColor = fromOperation ? fromOperation->color() : Color(Color::transparent);
262     
263     return DropShadowFilterOperation::create(
264         WebCore::blend(fromLocation, m_location, progress),
265         WebCore::blend(fromStdDeviation, m_stdDeviation, progress),
266         WebCore::blend(fromColor, m_color, progress));
267 }
268
269 TextStream& operator<<(TextStream& ts, const FilterOperation& filter)
270 {
271     switch (filter.type()) {
272     case FilterOperation::REFERENCE:
273         ts << "reference";
274         break;
275     case FilterOperation::GRAYSCALE: {
276         const auto& colorMatrixFilter = downcast<BasicColorMatrixFilterOperation>(filter);
277         ts << "grayscale(" << colorMatrixFilter.amount() << ")";
278         break;
279     }
280     case FilterOperation::SEPIA: {
281         const auto& colorMatrixFilter = downcast<BasicColorMatrixFilterOperation>(filter);
282         ts << "sepia(" << colorMatrixFilter.amount() << ")";
283         break;
284     }
285     case FilterOperation::SATURATE: {
286         const auto& colorMatrixFilter = downcast<BasicColorMatrixFilterOperation>(filter);
287         ts << "saturate(" << colorMatrixFilter.amount() << ")";
288         break;
289     }
290     case FilterOperation::HUE_ROTATE: {
291         const auto& colorMatrixFilter = downcast<BasicColorMatrixFilterOperation>(filter);
292         ts << "hue-rotate(" << colorMatrixFilter.amount() << ")";
293         break;
294     }
295     case FilterOperation::INVERT: {
296         const auto& componentTransferFilter = downcast<BasicComponentTransferFilterOperation>(filter);
297         ts << "invert(" << componentTransferFilter.amount() << ")";
298         break;
299     }
300     case FilterOperation::OPACITY: {
301         const auto& componentTransferFilter = downcast<BasicComponentTransferFilterOperation>(filter);
302         ts << "opacity(" << componentTransferFilter.amount() << ")";
303         break;
304     }
305     case FilterOperation::BRIGHTNESS: {
306         const auto& componentTransferFilter = downcast<BasicComponentTransferFilterOperation>(filter);
307         ts << "brightness(" << componentTransferFilter.amount() << ")";
308         break;
309     }
310     case FilterOperation::CONTRAST: {
311         const auto& componentTransferFilter = downcast<BasicComponentTransferFilterOperation>(filter);
312         ts << "contrast(" << componentTransferFilter.amount() << ")";
313         break;
314     }
315     case FilterOperation::BLUR: {
316         const auto& blurFilter = downcast<BlurFilterOperation>(filter);
317         ts << "blur(" << blurFilter.stdDeviation().value() << ")"; // FIXME: should call floatValueForLength() but that's outisde of platform/.
318         break;
319     }
320     case FilterOperation::DROP_SHADOW: {
321         const auto& dropShadowFilter = downcast<DropShadowFilterOperation>(filter);
322         ts << "drop-shadow(" << dropShadowFilter.x() << " " << dropShadowFilter.y() << " " << dropShadowFilter.location() << " ";
323         ts << dropShadowFilter.color() << ")";
324         break;
325     }
326     case FilterOperation::PASSTHROUGH:
327         ts << "passthrough";
328         break;
329     case FilterOperation::DEFAULT: {
330         const auto& defaultFilter = downcast<DefaultFilterOperation>(filter);
331         ts << "default type=" << (int)defaultFilter.representedType();
332         break;
333     }
334     case FilterOperation::NONE:
335         ts << "none";
336         break;
337     }
338     return ts;
339 }
340
341 } // namespace WebCore