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