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