f4b696a6b16f02a9cbc33050ffa44204f7c47048
[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 "ColorMatrix.h"
33 #include "ColorUtilities.h"
34 #include "FilterEffect.h"
35 #include "SVGURIReference.h"
36 #include <wtf/text/TextStream.h>
37
38 namespace WebCore {
39     
40 bool DefaultFilterOperation::operator==(const FilterOperation& operation) const
41 {
42     if (!isSameType(operation))
43         return false;
44     
45     return representedType() == downcast<DefaultFilterOperation>(operation).representedType();
46 }
47
48 ReferenceFilterOperation::ReferenceFilterOperation(const String& url, const String& fragment)
49     : FilterOperation(REFERENCE)
50     , m_url(url)
51     , m_fragment(fragment)
52 {
53 }
54
55 ReferenceFilterOperation::~ReferenceFilterOperation() = default;
56     
57 bool ReferenceFilterOperation::operator==(const FilterOperation& operation) const
58 {
59     if (!isSameType(operation))
60         return false;
61     
62     return m_url == downcast<ReferenceFilterOperation>(operation).m_url;
63 }
64
65 void ReferenceFilterOperation::loadExternalDocumentIfNeeded(CachedResourceLoader& cachedResourceLoader, const ResourceLoaderOptions& options)
66 {
67     if (m_cachedSVGDocumentReference)
68         return;
69     if (!SVGURIReference::isExternalURIReference(m_url, *cachedResourceLoader.document()))
70         return;
71     m_cachedSVGDocumentReference = makeUnique<CachedSVGDocumentReference>(m_url);
72     m_cachedSVGDocumentReference->load(cachedResourceLoader, options);
73 }
74
75 RefPtr<FilterOperation> BasicColorMatrixFilterOperation::blend(const FilterOperation* from, double progress, bool blendToPassthrough)
76 {
77     if (from && !from->isSameType(*this))
78         return this;
79     
80     if (blendToPassthrough)
81         return BasicColorMatrixFilterOperation::create(WebCore::blend(m_amount, passthroughAmount(), progress), m_type);
82         
83     const BasicColorMatrixFilterOperation* fromOperation = downcast<BasicColorMatrixFilterOperation>(from);
84     double fromAmount = fromOperation ? fromOperation->amount() : passthroughAmount();
85     return BasicColorMatrixFilterOperation::create(WebCore::blend(fromAmount, m_amount, progress), m_type);
86 }
87
88 bool BasicColorMatrixFilterOperation::transformColor(ColorComponents<float>& colorComponents) const
89 {
90     switch (m_type) {
91     case GRAYSCALE: {
92         ColorMatrix matrix = ColorMatrix::grayscaleMatrix(m_amount);
93         matrix.transformColorComponents(colorComponents);
94         return true;
95     }
96     case SEPIA: {
97         ColorMatrix matrix = ColorMatrix::sepiaMatrix(m_amount);
98         matrix.transformColorComponents(colorComponents);
99         return true;
100     }
101     case HUE_ROTATE: {
102         ColorMatrix matrix = ColorMatrix::hueRotateMatrix(m_amount);
103         matrix.transformColorComponents(colorComponents);
104         return true;
105     }
106     case SATURATE: {
107         ColorMatrix matrix = ColorMatrix::saturationMatrix(m_amount);
108         matrix.transformColorComponents(colorComponents);
109         return true;
110     }
111     default:
112         ASSERT_NOT_REACHED();
113         return false;
114     }
115
116     return false;
117 }
118
119 inline bool BasicColorMatrixFilterOperation::operator==(const FilterOperation& operation) const
120 {
121     if (!isSameType(operation))
122         return false;
123     const BasicColorMatrixFilterOperation& other = downcast<BasicColorMatrixFilterOperation>(operation);
124     return m_amount == other.m_amount;
125 }
126
127 double BasicColorMatrixFilterOperation::passthroughAmount() const
128 {
129     switch (m_type) {
130     case GRAYSCALE:
131     case SEPIA:
132     case HUE_ROTATE:
133         return 0;
134     case SATURATE:
135         return 1;
136     default:
137         ASSERT_NOT_REACHED();
138         return 0;
139     }
140 }
141
142 RefPtr<FilterOperation> BasicComponentTransferFilterOperation::blend(const FilterOperation* from, double progress, bool blendToPassthrough)
143 {
144     if (from && !from->isSameType(*this))
145         return this;
146     
147     if (blendToPassthrough)
148         return BasicComponentTransferFilterOperation::create(WebCore::blend(m_amount, passthroughAmount(), progress), m_type);
149         
150     const BasicComponentTransferFilterOperation* fromOperation = downcast<BasicComponentTransferFilterOperation>(from);
151     double fromAmount = fromOperation ? fromOperation->amount() : passthroughAmount();
152     return BasicComponentTransferFilterOperation::create(WebCore::blend(fromAmount, m_amount, progress), m_type);
153 }
154
155 bool BasicComponentTransferFilterOperation::transformColor(ColorComponents<float>& colorComponents) const
156 {
157     switch (m_type) {
158     case OPACITY:
159         colorComponents.components[3] *= m_amount;
160         return true;
161     case INVERT: {
162         float oneMinusAmount = 1.f - m_amount;
163         colorComponents.components[0] = 1 - (oneMinusAmount + colorComponents.components[0] * (m_amount - oneMinusAmount));
164         colorComponents.components[1] = 1 - (oneMinusAmount + colorComponents.components[1] * (m_amount - oneMinusAmount));
165         colorComponents.components[2] = 1 - (oneMinusAmount + colorComponents.components[2] * (m_amount - oneMinusAmount));
166         return true;
167     }
168     case CONTRAST: {
169         float intercept = -(0.5f * m_amount) + 0.5f;
170         colorComponents.components[0] = clampTo<float>(intercept + m_amount * colorComponents.components[0], 0, 1);
171         colorComponents.components[1] = clampTo<float>(intercept + m_amount * colorComponents.components[1], 0, 1);
172         colorComponents.components[2] = clampTo<float>(intercept + m_amount * colorComponents.components[2], 0, 1);
173         return true;
174     }
175     case BRIGHTNESS:
176         colorComponents.components[0] = std::max<float>(m_amount * colorComponents.components[0], 0);
177         colorComponents.components[1] = std::max<float>(m_amount * colorComponents.components[1], 0);
178         colorComponents.components[2] = std::max<float>(m_amount * colorComponents.components[2], 0);
179         return true;
180     default:
181         ASSERT_NOT_REACHED();
182         return false;
183     }
184     return false;
185 }
186
187 inline bool BasicComponentTransferFilterOperation::operator==(const FilterOperation& operation) const
188 {
189     if (!isSameType(operation))
190         return false;
191     const BasicComponentTransferFilterOperation& other = downcast<BasicComponentTransferFilterOperation>(operation);
192     return m_amount == other.m_amount;
193 }
194
195 double BasicComponentTransferFilterOperation::passthroughAmount() const
196 {
197     switch (m_type) {
198     case OPACITY:
199         return 1;
200     case INVERT:
201         return 0;
202     case CONTRAST:
203         return 1;
204     case BRIGHTNESS:
205         return 1;
206     default:
207         ASSERT_NOT_REACHED();
208         return 0;
209     }
210 }
211     
212 bool InvertLightnessFilterOperation::operator==(const FilterOperation& operation) const
213 {
214     if (!isSameType(operation))
215         return false;
216
217     return true;
218 }
219     
220 RefPtr<FilterOperation> InvertLightnessFilterOperation::blend(const FilterOperation* from, double, bool)
221 {
222     if (from && !from->isSameType(*this))
223         return this;
224
225     // This filter is not currently blendable.
226     return InvertLightnessFilterOperation::create();
227 }
228
229 bool InvertLightnessFilterOperation::transformColor(ColorComponents<float>& sRGBColorComponents) const
230 {
231     auto hslComponents = sRGBToHSL(sRGBColorComponents);
232     
233     // Rotate the hue 180deg.
234     hslComponents.components[0] = fmod(hslComponents.components[0] + 0.5f, 1.0f);
235     
236     // Convert back to RGB.
237     sRGBColorComponents = hslToSRGB(hslComponents);
238     
239     // Apply the matrix. See rdar://problem/41146650 for how this matrix was derived.
240     const float matrixValues[20] = {
241        -0.770,  0.059, -0.089, 0, 1,
242         0.030, -0.741, -0.089, 0, 1,
243         0.030,  0.059, -0.890, 0, 1,
244         0,      0,      0,     1, 0
245     };
246
247     ColorMatrix toDarkModeMatrix(matrixValues);
248     toDarkModeMatrix.transformColorComponents(sRGBColorComponents);
249     return true;
250 }
251
252 bool InvertLightnessFilterOperation::inverseTransformColor(ColorComponents<float>& sRGBColorComponents) const
253 {
254     auto rgbComponents = sRGBColorComponents;
255
256     // Apply the matrix.
257     const float matrixValues[20] = {
258         -1.300, -0.097,  0.147, 0, 1.25,
259         -0.049, -1.347,  0.146, 0, 1.25,
260         -0.049, -0.097, -1.104, 0, 1.25,
261          0,      0,      0,     1, 0
262     };
263     ColorMatrix toLightModeMatrix(matrixValues);
264     toLightModeMatrix.transformColorComponents(rgbComponents);
265
266     // Convert to HSL.
267     auto hslComponents = sRGBToHSL(rgbComponents);
268     // Hue rotate by 180deg.
269     hslComponents.components[0] = fmod(hslComponents.components[0] + 0.5f, 1.0f);
270     // And return RGB.
271     sRGBColorComponents = hslToSRGB(hslComponents);
272     return true;
273 }
274
275 bool BlurFilterOperation::operator==(const FilterOperation& operation) const
276 {
277     if (!isSameType(operation))
278         return false;
279     
280     return m_stdDeviation == downcast<BlurFilterOperation>(operation).stdDeviation();
281 }
282     
283 RefPtr<FilterOperation> BlurFilterOperation::blend(const FilterOperation* from, double progress, bool blendToPassthrough)
284 {
285     if (from && !from->isSameType(*this))
286         return this;
287
288     LengthType lengthType = m_stdDeviation.type();
289
290     if (blendToPassthrough)
291         return BlurFilterOperation::create(WebCore::blend(m_stdDeviation, Length(lengthType), progress));
292
293     const BlurFilterOperation* fromOperation = downcast<BlurFilterOperation>(from);
294     Length fromLength = fromOperation ? fromOperation->m_stdDeviation : Length(lengthType);
295     return BlurFilterOperation::create(WebCore::blend(fromLength, m_stdDeviation, progress));
296 }
297     
298 bool DropShadowFilterOperation::operator==(const FilterOperation& operation) const
299 {
300     if (!isSameType(operation))
301         return false;
302     const DropShadowFilterOperation& other = downcast<DropShadowFilterOperation>(operation);
303     return m_location == other.m_location && m_stdDeviation == other.m_stdDeviation && m_color == other.m_color;
304 }
305     
306 RefPtr<FilterOperation> DropShadowFilterOperation::blend(const FilterOperation* from, double progress, bool blendToPassthrough)
307 {
308     if (from && !from->isSameType(*this))
309         return this;
310
311     if (blendToPassthrough)
312         return DropShadowFilterOperation::create(
313             WebCore::blend(m_location, IntPoint(), progress),
314             WebCore::blend(m_stdDeviation, 0, progress),
315             WebCore::blend(m_color, Color(Color::transparent), progress));
316
317     const DropShadowFilterOperation* fromOperation = downcast<DropShadowFilterOperation>(from);
318     IntPoint fromLocation = fromOperation ? fromOperation->location() : IntPoint();
319     int fromStdDeviation = fromOperation ? fromOperation->stdDeviation() : 0;
320     Color fromColor = fromOperation ? fromOperation->color() : Color(Color::transparent);
321     
322     return DropShadowFilterOperation::create(
323         WebCore::blend(fromLocation, m_location, progress),
324         WebCore::blend(fromStdDeviation, m_stdDeviation, progress),
325         WebCore::blend(fromColor, m_color, progress));
326 }
327
328 TextStream& operator<<(TextStream& ts, const FilterOperation& filter)
329 {
330     switch (filter.type()) {
331     case FilterOperation::REFERENCE:
332         ts << "reference";
333         break;
334     case FilterOperation::GRAYSCALE: {
335         const auto& colorMatrixFilter = downcast<BasicColorMatrixFilterOperation>(filter);
336         ts << "grayscale(" << colorMatrixFilter.amount() << ")";
337         break;
338     }
339     case FilterOperation::SEPIA: {
340         const auto& colorMatrixFilter = downcast<BasicColorMatrixFilterOperation>(filter);
341         ts << "sepia(" << colorMatrixFilter.amount() << ")";
342         break;
343     }
344     case FilterOperation::SATURATE: {
345         const auto& colorMatrixFilter = downcast<BasicColorMatrixFilterOperation>(filter);
346         ts << "saturate(" << colorMatrixFilter.amount() << ")";
347         break;
348     }
349     case FilterOperation::HUE_ROTATE: {
350         const auto& colorMatrixFilter = downcast<BasicColorMatrixFilterOperation>(filter);
351         ts << "hue-rotate(" << colorMatrixFilter.amount() << ")";
352         break;
353     }
354     case FilterOperation::INVERT: {
355         const auto& componentTransferFilter = downcast<BasicComponentTransferFilterOperation>(filter);
356         ts << "invert(" << componentTransferFilter.amount() << ")";
357         break;
358     }
359     case FilterOperation::APPLE_INVERT_LIGHTNESS: {
360         ts << "apple-invert-lightness()";
361         break;
362     }
363     case FilterOperation::OPACITY: {
364         const auto& componentTransferFilter = downcast<BasicComponentTransferFilterOperation>(filter);
365         ts << "opacity(" << componentTransferFilter.amount() << ")";
366         break;
367     }
368     case FilterOperation::BRIGHTNESS: {
369         const auto& componentTransferFilter = downcast<BasicComponentTransferFilterOperation>(filter);
370         ts << "brightness(" << componentTransferFilter.amount() << ")";
371         break;
372     }
373     case FilterOperation::CONTRAST: {
374         const auto& componentTransferFilter = downcast<BasicComponentTransferFilterOperation>(filter);
375         ts << "contrast(" << componentTransferFilter.amount() << ")";
376         break;
377     }
378     case FilterOperation::BLUR: {
379         const auto& blurFilter = downcast<BlurFilterOperation>(filter);
380         ts << "blur(" << blurFilter.stdDeviation().value() << ")"; // FIXME: should call floatValueForLength() but that's outisde of platform/.
381         break;
382     }
383     case FilterOperation::DROP_SHADOW: {
384         const auto& dropShadowFilter = downcast<DropShadowFilterOperation>(filter);
385         ts << "drop-shadow(" << dropShadowFilter.x() << " " << dropShadowFilter.y() << " " << dropShadowFilter.location() << " ";
386         ts << dropShadowFilter.color() << ")";
387         break;
388     }
389     case FilterOperation::PASSTHROUGH:
390         ts << "passthrough";
391         break;
392     case FilterOperation::DEFAULT: {
393         const auto& defaultFilter = downcast<DefaultFilterOperation>(filter);
394         ts << "default type=" << (int)defaultFilter.representedType();
395         break;
396     }
397     case FilterOperation::NONE:
398         ts << "none";
399         break;
400     }
401     return ts;
402 }
403
404 } // namespace WebCore