Rename first/second to key/value in HashMap iterators
[WebKit-https.git] / Source / WebCore / svg / graphics / SVGImageCache.cpp
1 /*
2  * Copyright (C) 2011 Research In Motion Limited. All rights reserved.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public License
15  * along with this library; see the file COPYING.LIB.  If not, write to
16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19
20 #include "config.h"
21 #include "SVGImageCache.h"
22
23 #if ENABLE(SVG)
24 #include "CachedImage.h"
25 #include "FrameView.h"
26 #include "GraphicsContext.h"
27 #include "ImageBuffer.h"
28 #include "Page.h"
29 #include "RenderSVGRoot.h"
30 #include "SVGImage.h"
31
32 namespace WebCore {
33
34 SVGImageCache::SVGImageCache(SVGImage* svgImage)
35     : m_svgImage(svgImage)
36     , m_redrawTimer(this, &SVGImageCache::redrawTimerFired)
37 {
38     ASSERT(m_svgImage);
39 }
40
41 SVGImageCache::~SVGImageCache()
42 {
43     m_sizeAndScalesMap.clear();
44
45     ImageDataMap::iterator end = m_imageDataMap.end();
46     for (ImageDataMap::iterator it = m_imageDataMap.begin(); it != end; ++it) {
47         // Checks if the client (it->key) is still valid. The client should remove itself from this
48         // cache before its end of life, otherwise the following ASSERT will crash on pure virtual
49         // function call or a general crash.
50         ASSERT(it->key->resourceClientType() == CachedImageClient::expectedType());
51         delete it->value.buffer;
52     }
53
54     m_imageDataMap.clear();
55 }
56
57 void SVGImageCache::removeClientFromCache(const CachedImageClient* client)
58 {
59     ASSERT(client);
60     m_sizeAndScalesMap.remove(client);
61
62     ImageDataMap::iterator it = m_imageDataMap.find(client);
63     if (it == m_imageDataMap.end())
64         return;
65
66     delete it->value.buffer;
67     m_imageDataMap.remove(it);
68 }
69
70 void SVGImageCache::setRequestedSizeAndScales(const CachedImageClient* client, const SizeAndScales& sizeAndScales)
71 {
72     ASSERT(client);
73     ASSERT(!sizeAndScales.size.isEmpty());
74     m_sizeAndScalesMap.set(client, sizeAndScales);
75 }
76
77 SVGImageCache::SizeAndScales SVGImageCache::requestedSizeAndScales(const CachedImageClient* client) const
78 {
79     ASSERT(client);
80     SizeAndScalesMap::const_iterator it = m_sizeAndScalesMap.find(client);
81     if (it == m_sizeAndScalesMap.end())
82         return SizeAndScales();
83     return it->value;
84 }
85
86 void SVGImageCache::imageContentChanged()
87 {
88     ImageDataMap::iterator end = m_imageDataMap.end();
89     for (ImageDataMap::iterator it = m_imageDataMap.begin(); it != end; ++it)
90         it->value.imageNeedsUpdate = true;
91
92     // If we're in the middle of layout, start redrawing dirty
93     // images on a timer; otherwise it's safe to draw immediately.
94     FrameView* frameView = m_svgImage->frameView();
95     if (frameView && (frameView->needsLayout() || frameView->isInLayout())) {
96         if (!m_redrawTimer.isActive())
97             m_redrawTimer.startOneShot(0);
98     } else
99        redraw();
100 }
101
102 void SVGImageCache::redraw()
103 {
104     ImageDataMap::iterator end = m_imageDataMap.end();
105     for (ImageDataMap::iterator it = m_imageDataMap.begin(); it != end; ++it) {
106         ImageData& data = it->value;
107         if (!data.imageNeedsUpdate)
108             continue;
109         // If the content changed we redraw using our existing ImageBuffer.
110         ASSERT(data.buffer);
111         ASSERT(data.image);
112         m_svgImage->drawSVGToImageBuffer(data.buffer, data.sizeAndScales.size, data.sizeAndScales.zoom, data.sizeAndScales.scale, SVGImage::ClearImageBuffer);
113         data.image = data.buffer->copyImage(CopyBackingStore);
114         data.imageNeedsUpdate = false;
115     }
116     ASSERT(m_svgImage->imageObserver());
117     m_svgImage->imageObserver()->animationAdvanced(m_svgImage);
118 }
119
120 void SVGImageCache::redrawTimerFired(Timer<SVGImageCache>*)
121 {
122     // We have no guarantee that the frame does not require layout when the timer fired.
123     // So be sure to check again in case it is still not safe to run redraw.
124     FrameView* frameView = m_svgImage->frameView();
125     if (frameView && (frameView->needsLayout() || frameView->isInLayout())) {
126         if (!m_redrawTimer.isActive())
127             m_redrawTimer.startOneShot(0);
128     } else
129        redraw();
130 }
131
132 Image* SVGImageCache::lookupOrCreateBitmapImageForRenderer(const RenderObject* renderer)
133 {
134     ASSERT(renderer);
135     const CachedImageClient* client = renderer;
136
137     // The cache needs to know the size of the renderer before querying an image for it.
138     SizeAndScalesMap::iterator sizeIt = m_sizeAndScalesMap.find(renderer);
139     if (sizeIt == m_sizeAndScalesMap.end())
140         return Image::nullImage();
141
142     IntSize size = sizeIt->value.size;
143     float zoom = sizeIt->value.zoom;
144     float scale = sizeIt->value.scale;
145
146     // FIXME (85335): This needs to take CSS transform scale into account as well.
147     Page* page = renderer->document()->page();
148     if (!scale)
149         scale = page->deviceScaleFactor() * page->pageScaleFactor();
150
151     ASSERT(!size.isEmpty());
152
153     // Lookup image for client in cache and eventually update it.
154     ImageDataMap::iterator it = m_imageDataMap.find(client);
155     if (it != m_imageDataMap.end()) {
156         ImageData& data = it->value;
157
158         // Common case: image size & zoom remained the same.
159         if (data.sizeAndScales.size == size && data.sizeAndScales.zoom == zoom && data.sizeAndScales.scale == scale)
160             return data.image.get();
161
162         // If the image size for the client changed, we have to delete the buffer, remove the item from the cache and recreate it.
163         delete data.buffer;
164         m_imageDataMap.remove(it);
165     }
166
167     FloatSize scaledSize(size);
168     scaledSize.scale(scale);
169
170     // Create and cache new image and image buffer at requested size.
171     OwnPtr<ImageBuffer> newBuffer = ImageBuffer::create(expandedIntSize(scaledSize), 1);
172     if (!newBuffer)
173         return Image::nullImage();
174
175     m_svgImage->drawSVGToImageBuffer(newBuffer.get(), size, zoom, scale, SVGImage::DontClearImageBuffer);
176
177     RefPtr<Image> newImage = newBuffer->copyImage(CopyBackingStore);
178     Image* newImagePtr = newImage.get();
179     ASSERT(newImagePtr);
180
181     m_imageDataMap.add(client, ImageData(newBuffer.leakPtr(), newImage.release(), SizeAndScales(size, zoom, scale)));
182     return newImagePtr;
183 }
184
185 } // namespace WebCore
186
187 #endif // ENABLE(SVG)