Stop using PassRefPtr in platform/graphics
[WebKit-https.git] / Source / WebCore / css / CSSCrossfadeValue.cpp
1 /*
2  * Copyright (C) 2011 Apple Inc.  All rights reserved.
3  * Copyright (C) 2013 Adobe Systems Incorporated. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include "config.h"
28 #include "CSSCrossfadeValue.h"
29
30 #include "AnimationUtilities.h"
31 #include "CSSImageValue.h"
32 #include "CachedImage.h"
33 #include "CachedResourceLoader.h"
34 #include "CrossfadeGeneratedImage.h"
35 #include "ImageBuffer.h"
36 #include "RenderElement.h"
37 #include "StyleCachedImage.h"
38 #include "StyleGeneratedImage.h"
39 #include <wtf/text/StringBuilder.h>
40
41 namespace WebCore {
42
43 static inline double blendFunc(double from, double to, double progress)
44 {
45     return blend(from, to, progress);
46 }
47
48 static bool subimageKnownToBeOpaque(const CSSValue& value, const RenderElement& renderer)
49 {
50     if (is<CSSImageValue>(value))
51         return downcast<CSSImageValue>(value).knownToBeOpaque(&renderer);
52
53     if (is<CSSImageGeneratorValue>(value))
54         return downcast<CSSImageGeneratorValue>(value).knownToBeOpaque(renderer);
55
56     ASSERT_NOT_REACHED();
57
58     return false;
59 }
60
61 inline CSSCrossfadeValue::SubimageObserver::SubimageObserver(CSSCrossfadeValue& owner)
62     : m_owner(owner)
63 {
64 }
65
66 void CSSCrossfadeValue::SubimageObserver::imageChanged(CachedImage*, const IntRect*)
67 {
68     m_owner.crossfadeChanged();
69 }
70
71 inline CSSCrossfadeValue::CSSCrossfadeValue(Ref<CSSValue>&& fromValue, Ref<CSSValue>&& toValue, Ref<CSSPrimitiveValue>&& percentageValue, bool prefixed)
72     : CSSImageGeneratorValue(CrossfadeClass)
73     , m_fromValue(WTFMove(fromValue))
74     , m_toValue(WTFMove(toValue))
75     , m_percentageValue(WTFMove(percentageValue))
76     , m_subimageObserver(*this)
77     , m_isPrefixed(prefixed)
78 {
79 }
80
81 Ref<CSSCrossfadeValue> CSSCrossfadeValue::create(Ref<CSSValue>&& fromValue, Ref<CSSValue>&& toValue, Ref<CSSPrimitiveValue>&& percentageValue, bool prefixed)
82 {
83     return adoptRef(*new CSSCrossfadeValue(WTFMove(fromValue), WTFMove(toValue), WTFMove(percentageValue), prefixed));
84 }
85
86 CSSCrossfadeValue::~CSSCrossfadeValue()
87 {
88     if (m_cachedFromImage)
89         m_cachedFromImage->removeClient(m_subimageObserver);
90     if (m_cachedToImage)
91         m_cachedToImage->removeClient(m_subimageObserver);
92 }
93
94 String CSSCrossfadeValue::customCSSText() const
95 {
96     StringBuilder result;
97     if (m_isPrefixed)
98         result.appendLiteral("-webkit-cross-fade(");
99     else
100         result.appendLiteral("cross-fade(");
101     result.append(m_fromValue->cssText());
102     result.appendLiteral(", ");
103     result.append(m_toValue->cssText());
104     result.appendLiteral(", ");
105     result.append(m_percentageValue->cssText());
106     result.append(')');
107     return result.toString();
108 }
109
110 FloatSize CSSCrossfadeValue::fixedSize(const RenderElement& renderer)
111 {
112     float percentage = m_percentageValue->floatValue();
113     float inversePercentage = 1 - percentage;
114
115     // FIXME: Skip Content Security Policy check when cross fade is applied to an element in a user agent shadow tree.
116     // See <https://bugs.webkit.org/show_bug.cgi?id=146663>.
117     auto options = CachedResourceLoader::defaultCachedResourceOptions();
118
119     auto& cachedResourceLoader = renderer.document().cachedResourceLoader();
120     auto* cachedFromImage = cachedImageForCSSValue(m_fromValue, cachedResourceLoader, options);
121     auto* cachedToImage = cachedImageForCSSValue(m_toValue, cachedResourceLoader, options);
122
123     if (!cachedFromImage || !cachedToImage)
124         return FloatSize();
125
126     FloatSize fromImageSize = cachedFromImage->imageForRenderer(&renderer)->size();
127     FloatSize toImageSize = cachedToImage->imageForRenderer(&renderer)->size();
128
129     // Rounding issues can cause transitions between images of equal size to return
130     // a different fixed size; avoid performing the interpolation if the images are the same size.
131     if (fromImageSize == toImageSize)
132         return fromImageSize;
133
134     return fromImageSize * inversePercentage + toImageSize * percentage;
135 }
136
137 bool CSSCrossfadeValue::isPending() const
138 {
139     return CSSImageGeneratorValue::subimageIsPending(m_fromValue)
140         || CSSImageGeneratorValue::subimageIsPending(m_toValue);
141 }
142
143 bool CSSCrossfadeValue::knownToBeOpaque(const RenderElement& renderer) const
144 {
145     return subimageKnownToBeOpaque(m_fromValue, renderer)
146         && subimageKnownToBeOpaque(m_toValue, renderer);
147 }
148
149 void CSSCrossfadeValue::loadSubimages(CachedResourceLoader& cachedResourceLoader, const ResourceLoaderOptions& options)
150 {
151     auto oldCachedFromImage = m_cachedFromImage;
152     auto oldCachedToImage = m_cachedToImage;
153
154     m_cachedFromImage = CSSImageGeneratorValue::cachedImageForCSSValue(m_fromValue, cachedResourceLoader, options);
155     m_cachedToImage = CSSImageGeneratorValue::cachedImageForCSSValue(m_toValue, cachedResourceLoader, options);
156
157     if (m_cachedFromImage != oldCachedFromImage) {
158         if (oldCachedFromImage)
159             oldCachedFromImage->removeClient(m_subimageObserver);
160         if (m_cachedFromImage)
161             m_cachedFromImage->addClient(m_subimageObserver);
162     }
163
164     if (m_cachedToImage != oldCachedToImage) {
165         if (oldCachedToImage)
166             oldCachedToImage->removeClient(m_subimageObserver);
167         if (m_cachedToImage)
168             m_cachedToImage->addClient(m_subimageObserver);
169     }
170
171     // FIXME: Unclear why this boolean adds any value; for now keeping it around to avoid changing semantics.
172     m_subimagesAreReady = true;
173 }
174
175 Image* CSSCrossfadeValue::image(RenderElement& renderer, const FloatSize& size)
176 {
177     if (size.isEmpty())
178         return nullptr;
179
180     // FIXME: Skip Content Security Policy check when cross fade is applied to an element in a user agent shadow tree.
181     // See <https://bugs.webkit.org/show_bug.cgi?id=146663>.
182     auto options = CachedResourceLoader::defaultCachedResourceOptions();
183
184     auto& cachedResourceLoader = renderer.document().cachedResourceLoader();
185     auto* cachedFromImage = cachedImageForCSSValue(m_fromValue, cachedResourceLoader, options);
186     auto* cachedToImage = cachedImageForCSSValue(m_toValue, cachedResourceLoader, options);
187
188     if (!cachedFromImage || !cachedToImage)
189         return &Image::nullImage();
190
191     auto* fromImage = cachedFromImage->imageForRenderer(&renderer);
192     auto* toImage = cachedToImage->imageForRenderer(&renderer);
193
194     if (!fromImage || !toImage)
195         return &Image::nullImage();
196
197     m_generatedImage = CrossfadeGeneratedImage::create(*fromImage, *toImage, m_percentageValue->floatValue(), fixedSize(renderer), size);
198     return m_generatedImage.get();
199 }
200
201 inline void CSSCrossfadeValue::crossfadeChanged()
202 {
203     if (!m_subimagesAreReady)
204         return;
205     for (auto& client : clients())
206         client.key->imageChanged(this);
207 }
208
209 bool CSSCrossfadeValue::traverseSubresources(const std::function<bool (const CachedResource&)>& handler) const
210 {
211     if (m_cachedFromImage && handler(*m_cachedFromImage))
212         return true;
213     if (m_cachedToImage && handler(*m_cachedToImage))
214         return true;
215     return false;
216 }
217
218 RefPtr<CSSCrossfadeValue> CSSCrossfadeValue::blend(const CSSCrossfadeValue& from, double progress) const
219 {
220     ASSERT(equalInputImages(from));
221
222     if (!m_cachedToImage || !m_cachedFromImage)
223         return nullptr;
224
225     auto fromImageValue = CSSImageValue::create(*m_cachedFromImage);
226     auto toImageValue = CSSImageValue::create(*m_cachedToImage);
227
228     double fromPercentage = from.m_percentageValue->doubleValue();
229     if (from.m_percentageValue->isPercentage())
230         fromPercentage /= 100.0;
231     double toPercentage = m_percentageValue->doubleValue();
232     if (m_percentageValue->isPercentage())
233         toPercentage /= 100.0;
234     auto percentageValue = CSSPrimitiveValue::create(blendFunc(fromPercentage, toPercentage, progress), CSSPrimitiveValue::CSS_NUMBER);
235
236     return CSSCrossfadeValue::create(WTFMove(fromImageValue), WTFMove(toImageValue), WTFMove(percentageValue), from.isPrefixed() && isPrefixed());
237 }
238
239 bool CSSCrossfadeValue::equals(const CSSCrossfadeValue& other) const
240 {
241     return equalInputImages(other) && compareCSSValue(m_percentageValue, other.m_percentageValue);
242 }
243
244
245 bool CSSCrossfadeValue::equalInputImages(const CSSCrossfadeValue& other) const
246 {
247     return compareCSSValue(m_fromValue, other.m_fromValue) && compareCSSValue(m_toValue, other.m_toValue);
248 }
249
250 } // namespace WebCore