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