[WTF] Add makeUnique<T>, which ensures T is fast-allocated, makeUnique / makeUniqueWi...
[WebKit-https.git] / Source / WebCore / css / CSSImageGeneratorValue.cpp
1 /*
2  * Copyright (C) 2008, 2011, 2012, 2013 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 "CSSImageGeneratorValue.h"
29
30 #include "CSSCanvasValue.h"
31 #include "CSSCrossfadeValue.h"
32 #include "CSSFilterImageValue.h"
33 #include "CSSGradientValue.h"
34 #include "CSSImageValue.h"
35 #include "CSSNamedImageValue.h"
36 #include "CSSPaintImageValue.h"
37 #include "GeneratedImage.h"
38 #include "HTMLCanvasElement.h"
39 #include "InspectorInstrumentation.h"
40 #include "RenderElement.h"
41
42 namespace WebCore {
43
44 static const Seconds timeToKeepCachedGeneratedImages { 3_s };
45
46 class CSSImageGeneratorValue::CachedGeneratedImage {
47     WTF_MAKE_FAST_ALLOCATED;
48 public:
49     CachedGeneratedImage(CSSImageGeneratorValue&, FloatSize, GeneratedImage&);
50     GeneratedImage& image() const { return m_image; }
51     void puntEvictionTimer() { m_evictionTimer.restart(); }
52
53 private:
54     void evictionTimerFired();
55
56     CSSImageGeneratorValue& m_owner;
57     const FloatSize m_size;
58     const Ref<GeneratedImage> m_image;
59     DeferrableOneShotTimer m_evictionTimer;
60 };
61
62 CSSImageGeneratorValue::CSSImageGeneratorValue(ClassType classType)
63     : CSSValue(classType)
64 {
65 }
66
67 CSSImageGeneratorValue::~CSSImageGeneratorValue() = default;
68
69 void CSSImageGeneratorValue::addClient(RenderElement& renderer)
70 {
71     if (m_clients.isEmpty())
72         ref();
73
74     m_clients.add(&renderer);
75
76     if (is<CSSCanvasValue>(this)) {
77         if (HTMLCanvasElement* canvasElement = downcast<CSSCanvasValue>(this)->element())
78             InspectorInstrumentation::didChangeCSSCanvasClientNodes(*canvasElement);
79     }
80 }
81
82 void CSSImageGeneratorValue::removeClient(RenderElement& renderer)
83 {
84     ASSERT(m_clients.contains(&renderer));
85     if (!m_clients.remove(&renderer))
86         return;
87
88     if (is<CSSCanvasValue>(this)) {
89         if (HTMLCanvasElement* canvasElement = downcast<CSSCanvasValue>(this)->element())
90             InspectorInstrumentation::didChangeCSSCanvasClientNodes(*canvasElement);
91     }
92
93     if (m_clients.isEmpty())
94         deref();
95 }
96
97 GeneratedImage* CSSImageGeneratorValue::cachedImageForSize(FloatSize size)
98 {
99     if (size.isEmpty())
100         return nullptr;
101
102     auto* cachedGeneratedImage = m_images.get(size);
103     if (!cachedGeneratedImage)
104         return nullptr;
105
106     cachedGeneratedImage->puntEvictionTimer();
107     return &cachedGeneratedImage->image();
108 }
109
110 void CSSImageGeneratorValue::saveCachedImageForSize(FloatSize size, GeneratedImage& image)
111 {
112     ASSERT(!m_images.contains(size));
113     m_images.add(size, makeUnique<CachedGeneratedImage>(*this, size, image));
114 }
115
116 void CSSImageGeneratorValue::evictCachedGeneratedImage(FloatSize size)
117 {
118     ASSERT(m_images.contains(size));
119     m_images.remove(size);
120 }
121
122 inline CSSImageGeneratorValue::CachedGeneratedImage::CachedGeneratedImage(CSSImageGeneratorValue& owner, FloatSize size, GeneratedImage& image)
123     : m_owner(owner)
124     , m_size(size)
125     , m_image(image)
126     , m_evictionTimer(*this, &CSSImageGeneratorValue::CachedGeneratedImage::evictionTimerFired, timeToKeepCachedGeneratedImages)
127 {
128     m_evictionTimer.restart();
129 }
130
131 void CSSImageGeneratorValue::CachedGeneratedImage::evictionTimerFired()
132 {
133     // NOTE: This is essentially a "delete this", the object is no longer valid after this line.
134     m_owner.evictCachedGeneratedImage(m_size);
135 }
136
137 RefPtr<Image> CSSImageGeneratorValue::image(RenderElement& renderer, const FloatSize& size)
138 {
139     switch (classType()) {
140     case CanvasClass:
141         return downcast<CSSCanvasValue>(*this).image(&renderer, size);
142     case NamedImageClass:
143         return downcast<CSSNamedImageValue>(*this).image(&renderer, size);
144     case CrossfadeClass:
145         return downcast<CSSCrossfadeValue>(*this).image(renderer, size);
146     case FilterImageClass:
147         return downcast<CSSFilterImageValue>(*this).image(&renderer, size);
148     case LinearGradientClass:
149         return downcast<CSSLinearGradientValue>(*this).image(renderer, size);
150     case RadialGradientClass:
151         return downcast<CSSRadialGradientValue>(*this).image(renderer, size);
152     case ConicGradientClass:
153         return downcast<CSSConicGradientValue>(*this).image(renderer, size);
154 #if ENABLE(CSS_PAINTING_API)
155     case PaintImageClass:
156         return downcast<CSSPaintImageValue>(*this).image(renderer, size);
157 #endif
158     default:
159         ASSERT_NOT_REACHED();
160     }
161     return nullptr;
162 }
163
164 bool CSSImageGeneratorValue::isFixedSize() const
165 {
166     switch (classType()) {
167     case CanvasClass:
168         return downcast<CSSCanvasValue>(*this).isFixedSize();
169     case NamedImageClass:
170         return downcast<CSSNamedImageValue>(*this).isFixedSize();
171     case CrossfadeClass:
172         return downcast<CSSCrossfadeValue>(*this).isFixedSize();
173     case FilterImageClass:
174         return downcast<CSSFilterImageValue>(*this).isFixedSize();
175     case LinearGradientClass:
176         return downcast<CSSLinearGradientValue>(*this).isFixedSize();
177     case RadialGradientClass:
178         return downcast<CSSRadialGradientValue>(*this).isFixedSize();
179     case ConicGradientClass:
180         return downcast<CSSConicGradientValue>(*this).isFixedSize();
181 #if ENABLE(CSS_PAINTING_API)
182     case PaintImageClass:
183         return downcast<CSSPaintImageValue>(*this).isFixedSize();
184 #endif
185     default:
186         ASSERT_NOT_REACHED();
187     }
188     return false;
189 }
190
191 FloatSize CSSImageGeneratorValue::fixedSize(const RenderElement& renderer)
192 {
193     switch (classType()) {
194     case CanvasClass:
195         return downcast<CSSCanvasValue>(*this).fixedSize(&renderer);
196     case CrossfadeClass:
197         return downcast<CSSCrossfadeValue>(*this).fixedSize(renderer);
198     case FilterImageClass:
199         return downcast<CSSFilterImageValue>(*this).fixedSize(&renderer);
200     case LinearGradientClass:
201         return downcast<CSSLinearGradientValue>(*this).fixedSize(renderer);
202     case RadialGradientClass:
203         return downcast<CSSRadialGradientValue>(*this).fixedSize(renderer);
204     case ConicGradientClass:
205         return downcast<CSSConicGradientValue>(*this).fixedSize(renderer);
206 #if ENABLE(CSS_PAINTING_API)
207     case PaintImageClass:
208         return downcast<CSSPaintImageValue>(*this).fixedSize(renderer);
209 #endif
210     default:
211         ASSERT_NOT_REACHED();
212     }
213     return FloatSize();
214 }
215
216 bool CSSImageGeneratorValue::isPending() const
217 {
218     switch (classType()) {
219     case CrossfadeClass:
220         return downcast<CSSCrossfadeValue>(*this).isPending();
221     case CanvasClass:
222         return downcast<CSSCanvasValue>(*this).isPending();
223     case NamedImageClass:
224         return downcast<CSSNamedImageValue>(*this).isPending();
225     case FilterImageClass:
226         return downcast<CSSFilterImageValue>(*this).isPending();
227     case LinearGradientClass:
228         return downcast<CSSLinearGradientValue>(*this).isPending();
229     case RadialGradientClass:
230         return downcast<CSSRadialGradientValue>(*this).isPending();
231     case ConicGradientClass:
232         return downcast<CSSConicGradientValue>(*this).isPending();
233 #if ENABLE(CSS_PAINTING_API)
234     case PaintImageClass:
235         return downcast<CSSPaintImageValue>(*this).isPending();
236 #endif
237     default:
238         ASSERT_NOT_REACHED();
239     }
240     return false;
241 }
242
243 bool CSSImageGeneratorValue::knownToBeOpaque(const RenderElement& renderer) const
244 {
245     switch (classType()) {
246     case CrossfadeClass:
247         return downcast<CSSCrossfadeValue>(*this).knownToBeOpaque(renderer);
248     case CanvasClass:
249         return false;
250     case NamedImageClass:
251         return false;
252     case FilterImageClass:
253         return downcast<CSSFilterImageValue>(*this).knownToBeOpaque(renderer);
254     case LinearGradientClass:
255         return downcast<CSSLinearGradientValue>(*this).knownToBeOpaque(renderer);
256     case RadialGradientClass:
257         return downcast<CSSRadialGradientValue>(*this).knownToBeOpaque(renderer);
258     case ConicGradientClass:
259         return downcast<CSSConicGradientValue>(*this).knownToBeOpaque(renderer);
260 #if ENABLE(CSS_PAINTING_API)
261     case PaintImageClass:
262         return downcast<CSSPaintImageValue>(*this).knownToBeOpaque(renderer);
263 #endif
264     default:
265         ASSERT_NOT_REACHED();
266     }
267     return false;
268 }
269
270 void CSSImageGeneratorValue::loadSubimages(CachedResourceLoader& cachedResourceLoader, const ResourceLoaderOptions& options)
271 {
272     switch (classType()) {
273     case CrossfadeClass:
274         downcast<CSSCrossfadeValue>(*this).loadSubimages(cachedResourceLoader, options);
275         break;
276     case CanvasClass:
277         downcast<CSSCanvasValue>(*this).loadSubimages(cachedResourceLoader, options);
278         break;
279     case FilterImageClass:
280         downcast<CSSFilterImageValue>(*this).loadSubimages(cachedResourceLoader, options);
281         break;
282     case LinearGradientClass:
283         downcast<CSSLinearGradientValue>(*this).loadSubimages(cachedResourceLoader, options);
284         break;
285     case RadialGradientClass:
286         downcast<CSSRadialGradientValue>(*this).loadSubimages(cachedResourceLoader, options);
287         break;
288     case ConicGradientClass:
289         downcast<CSSConicGradientValue>(*this).loadSubimages(cachedResourceLoader, options);
290         break;
291 #if ENABLE(CSS_PAINTING_API)
292     case PaintImageClass:
293         downcast<CSSPaintImageValue>(*this).loadSubimages(cachedResourceLoader, options);
294         break;
295 #endif
296     default:
297         ASSERT_NOT_REACHED();
298     }
299 }
300
301 bool CSSImageGeneratorValue::subimageIsPending(const CSSValue& value)
302 {
303     if (is<CSSImageValue>(value))
304         return downcast<CSSImageValue>(value).isPending();
305     
306     if (is<CSSImageGeneratorValue>(value))
307         return downcast<CSSImageGeneratorValue>(value).isPending();
308
309     if (is<CSSPrimitiveValue>(value) && downcast<CSSPrimitiveValue>(value).valueID() == CSSValueNone)
310         return false;
311
312     ASSERT_NOT_REACHED();
313     return false;
314 }
315
316 CachedImage* CSSImageGeneratorValue::cachedImageForCSSValue(CSSValue& value, CachedResourceLoader& cachedResourceLoader, const ResourceLoaderOptions& options)
317 {
318     if (is<CSSImageValue>(value)) {
319         auto& imageValue = downcast<CSSImageValue>(value);
320         return imageValue.loadImage(cachedResourceLoader, options);
321     }
322     
323     if (is<CSSImageGeneratorValue>(value)) {
324         downcast<CSSImageGeneratorValue>(value).loadSubimages(cachedResourceLoader, options);
325         // FIXME: Handle CSSImageGeneratorValue (and thus cross-fades with gradients and canvas).
326         return nullptr;
327     }
328
329     if (is<CSSPrimitiveValue>(value) && downcast<CSSPrimitiveValue>(value).valueID() == CSSValueNone)
330         return nullptr;
331
332     ASSERT_NOT_REACHED();
333     return nullptr;
334 }
335
336 } // namespace WebCore