cd901f4b4a42b0eb4a65558ebb9b91cdfbd93e6e
[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 "GraphicsContext.h"
25 #include "ImageBuffer.h"
26 #include "RenderSVGRoot.h"
27 #include "SVGImage.h"
28
29 namespace WebCore {
30
31 SVGImageCache::SVGImageCache(SVGImage* svgImage)
32     : m_svgImage(svgImage)
33     , m_redrawTimer(this, &SVGImageCache::redrawTimerFired)
34 {
35     ASSERT(m_svgImage);
36 }
37
38 SVGImageCache::~SVGImageCache()
39 {
40     m_sizeAndZoomMap.clear();
41
42     ImageDataMap::iterator end = m_imageDataMap.end();
43     for (ImageDataMap::iterator it = m_imageDataMap.begin(); it != end; ++it)
44         delete it->second.buffer;
45
46     m_imageDataMap.clear();
47 }
48
49 void SVGImageCache::removeRendererFromCache(const RenderObject* renderer)
50 {
51     ASSERT(renderer);
52     m_sizeAndZoomMap.remove(renderer);
53
54     ImageDataMap::iterator it = m_imageDataMap.find(renderer);
55     if (it == m_imageDataMap.end())
56         return;
57
58     delete it->second.buffer;
59     m_imageDataMap.remove(it);
60 }
61
62 void SVGImageCache::setRequestedSizeAndZoom(const RenderObject* renderer, const SizeAndZoom& sizeAndZoom)
63 {
64     ASSERT(renderer);
65     ASSERT(!sizeAndZoom.size.isEmpty());
66     m_sizeAndZoomMap.set(renderer, sizeAndZoom);
67 }
68
69 SVGImageCache::SizeAndZoom SVGImageCache::requestedSizeAndZoom(const RenderObject* renderer) const
70 {
71     ASSERT(renderer);
72     SizeAndZoomMap::const_iterator it = m_sizeAndZoomMap.find(renderer);
73     if (it == m_sizeAndZoomMap.end())
74         return SizeAndZoom();
75     return it->second;
76 }
77
78 void SVGImageCache::imageContentChanged()
79 {
80     ImageDataMap::iterator end = m_imageDataMap.end();
81     for (ImageDataMap::iterator it = m_imageDataMap.begin(); it != end; ++it)
82         it->second.imageNeedsUpdate = true;
83
84     // Start redrawing dirty images with a timer, as imageContentChanged() may be called
85     // by the FrameView of the SVGImage which is currently in FrameView::layout().
86     if (!m_redrawTimer.isActive())
87         m_redrawTimer.startOneShot(0);
88 }
89
90 void SVGImageCache::redrawTimerFired(Timer<SVGImageCache>*)
91 {
92     ImageDataMap::iterator end = m_imageDataMap.end();
93     for (ImageDataMap::iterator it = m_imageDataMap.begin(); it != end; ++it) {
94         ImageData& data = it->second;
95         if (!data.imageNeedsUpdate)
96             continue;
97         // If the content changed we redraw using our existing ImageBuffer.
98         ASSERT(data.buffer);
99         ASSERT(data.image);
100         m_svgImage->drawSVGToImageBuffer(data.buffer, data.sizeAndZoom.size, data.sizeAndZoom.zoom, SVGImage::ClearImageBuffer);
101         data.image = data.buffer->copyImage(CopyBackingStore);
102         data.imageNeedsUpdate = false;
103     }
104     ASSERT(m_svgImage->imageObserver());
105     m_svgImage->imageObserver()->animationAdvanced(m_svgImage);
106 }
107
108 Image* SVGImageCache::lookupOrCreateBitmapImageForRenderer(const RenderObject* renderer)
109 {
110     ASSERT(renderer);
111
112     // The cache needs to know the size of the renderer before querying an image for it.
113     SizeAndZoomMap::iterator sizeIt = m_sizeAndZoomMap.find(renderer);
114     if (sizeIt == m_sizeAndZoomMap.end())
115         return Image::nullImage();
116
117     IntSize size = sizeIt->second.size;
118     float zoom = sizeIt->second.zoom;
119     ASSERT(!size.isEmpty());
120
121     // Lookup image for renderer in cache and eventually update it.
122     ImageDataMap::iterator it = m_imageDataMap.find(renderer);
123     if (it != m_imageDataMap.end()) {
124         ImageData& data = it->second;
125
126         // Common case: image size & zoom remained the same.
127         if (data.sizeAndZoom.size == size && data.sizeAndZoom.zoom == zoom)
128             return data.image.get();
129
130         // If the image size for the renderer changed, we have to delete the buffer, remove the item from the cache and recreate it.
131         delete data.buffer;
132         m_imageDataMap.remove(it);
133     }
134
135     // Create and cache new image and image buffer at requested size.
136     OwnPtr<ImageBuffer> newBuffer = ImageBuffer::create(size);
137     if (!newBuffer)
138         return Image::nullImage();
139
140     m_svgImage->drawSVGToImageBuffer(newBuffer.get(), size, zoom, SVGImage::DontClearImageBuffer);
141
142     RefPtr<Image> newImage = newBuffer->copyImage(CopyBackingStore);
143     Image* newImagePtr = newImage.get();
144     ASSERT(newImagePtr);
145
146     m_imageDataMap.add(renderer, ImageData(newBuffer.leakPtr(), newImage.release(), sizeIt->second));
147     return newImagePtr;
148 }
149
150 } // namespace WebCore
151
152 #endif // ENABLE(SVG)