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