2 Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de)
3 Copyright (C) 2001 Dirk Mueller (mueller@kde.org)
4 Copyright (C) 2002 Waldo Bastian (bastian@kde.org)
5 Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
6 Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
8 This library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Library General Public
10 License as published by the Free Software Foundation; either
11 version 2 of the License, or (at your option) any later version.
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Library General Public License for more details.
18 You should have received a copy of the GNU Library General Public License
19 along with this library; see the file COPYING.LIB. If not, write to
20 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 Boston, MA 02110-1301, USA.
25 #include "CachedImage.h"
27 #include "BitmapImage.h"
29 #include "CachedResourceClient.h"
30 #include "CachedResourceClientWalker.h"
31 #include "DocLoader.h"
33 #include "FrameView.h"
36 #include "SystemTime.h"
37 #include <wtf/Vector.h>
40 #include "PDFDocumentImage.h"
43 #if ENABLE(SVG_AS_IMAGE)
51 CachedImage::CachedImage(const String& url)
52 : CachedResource(url, ImageResource)
54 , m_decodedDataDeletionTimer(this, &CachedImage::decodedDataDeletionTimerFired)
59 CachedImage::CachedImage(Image* image)
60 : CachedResource(String(), ImageResource)
62 , m_decodedDataDeletionTimer(this, &CachedImage::decodedDataDeletionTimerFired)
68 CachedImage::~CachedImage()
72 void CachedImage::decodedDataDeletionTimerFired(Timer<CachedImage>*)
74 ASSERT(!hasClients());
78 void CachedImage::load(DocLoader* docLoader)
80 if (!docLoader || docLoader->autoLoadImages())
81 CachedResource::load(docLoader, true, false, true);
86 void CachedImage::addClient(CachedResourceClient* c)
88 CachedResource::addClient(c);
90 if (m_decodedDataDeletionTimer.isActive())
91 m_decodedDataDeletionTimer.stop();
93 if (m_image && !m_image->rect().isEmpty())
94 c->imageChanged(this);
97 c->notifyFinished(this);
100 void CachedImage::allClientsRemoved()
102 if (m_image && !m_errorOccurred)
103 m_image->resetAnimation();
104 if (double interval = cache()->deadDecodedDataDeletionInterval())
105 m_decodedDataDeletionTimer.startOneShot(interval);
108 static Image* brokenImage()
110 static RefPtr<Image> brokenImage;
112 brokenImage = Image::loadPlatformResource("missingImage");
113 return brokenImage.get();
116 static Image* nullImage()
118 static RefPtr<BitmapImage> nullImage = BitmapImage::create();
119 return nullImage.get();
122 Image* CachedImage::image() const
125 return brokenImage();
128 return m_image.get();
133 void CachedImage::setImageContainerSize(const IntSize& containerSize)
136 m_image->setContainerSize(containerSize);
139 bool CachedImage::usesImageContainerSize() const
142 return m_image->usesContainerSize();
147 bool CachedImage::imageHasRelativeWidth() const
150 return m_image->hasRelativeWidth();
155 bool CachedImage::imageHasRelativeHeight() const
158 return m_image->hasRelativeHeight();
163 IntSize CachedImage::imageSize(float multiplier) const
167 if (multiplier == 1.0f)
168 return m_image->size();
170 // Don't let images that have a width/height >= 1 shrink below 1 when zoomed.
171 bool hasWidth = m_image->size().width() > 0;
172 bool hasHeight = m_image->size().height() > 0;
173 int width = m_image->size().width() * (m_image->hasRelativeWidth() ? 1.0f : multiplier);
174 int height = m_image->size().height() * (m_image->hasRelativeHeight() ? 1.0f : multiplier);
176 width = max(1, width);
178 height = max(1, height);
179 return IntSize(width, height);
182 IntRect CachedImage::imageRect(float multiplier) const
186 if (multiplier == 1.0f || (!m_image->hasRelativeWidth() && !m_image->hasRelativeHeight()))
187 return m_image->rect();
189 float widthMultiplier = (m_image->hasRelativeWidth() ? 1.0f : multiplier);
190 float heightMultiplier = (m_image->hasRelativeHeight() ? 1.0f : multiplier);
192 // Don't let images that have a width/height >= 1 shrink below 1 when zoomed.
193 bool hasWidth = m_image->rect().width() > 0;
194 bool hasHeight = m_image->rect().height() > 0;
196 int width = static_cast<int>(m_image->rect().width() * widthMultiplier);
197 int height = static_cast<int>(m_image->rect().height() * heightMultiplier);
199 width = max(1, width);
201 height = max(1, height);
203 int x = static_cast<int>(m_image->rect().x() * widthMultiplier);
204 int y = static_cast<int>(m_image->rect().y() * heightMultiplier);
206 return IntRect(x, y, width, height);
209 void CachedImage::notifyObservers()
211 CachedResourceClientWalker w(m_clients);
212 while (CachedResourceClient* c = w.next())
213 c->imageChanged(this);
216 void CachedImage::clear()
218 destroyDecodedData();
223 inline void CachedImage::createImage()
225 // Create the image if it doesn't yet exist.
229 if (m_response.mimeType() == "application/pdf") {
230 m_image = PDFDocumentImage::create();
234 #if ENABLE(SVG_AS_IMAGE)
235 if (m_response.mimeType() == "image/svg+xml") {
236 m_image = SVGImage::create(this);
240 m_image = BitmapImage::create(this);
243 size_t CachedImage::maximumDecodedImageSize()
245 Frame* frame = m_request ? m_request->docLoader()->frame() : 0;
248 Settings* settings = frame->settings();
249 return settings ? settings->maximumDecodedImageSize() : 0;
252 void CachedImage::data(PassRefPtr<SharedBuffer> data, bool allDataReceived)
258 bool sizeAvailable = false;
260 // Have the image update its data from its internal buffer.
261 // It will not do anything now, but will delay decoding until
262 // queried for info (like size or specific image frames).
263 sizeAvailable = m_image->setData(m_data, allDataReceived);
265 // Go ahead and tell our observers to try to draw if we have either
266 // received all the data or the size is known. Each chunk from the
267 // network causes observers to repaint, which will force that chunk
269 if (sizeAvailable || allDataReceived) {
270 size_t maxDecodedImageSize = maximumDecodedImageSize();
271 IntSize s = imageSize(1.0f);
272 size_t estimatedDecodedImageSize = s.width() * s.height() * 4; // no overflow check
273 if (m_image->isNull() || (maxDecodedImageSize > 0 && estimatedDecodedImageSize > maxDecodedImageSize)) {
276 cache()->remove(this);
283 setEncodedSize(m_image->data() ? m_image->data()->size() : 0);
286 if (allDataReceived) {
292 void CachedImage::error()
295 m_errorOccurred = true;
301 void CachedImage::checkNotify()
306 CachedResourceClientWalker w(m_clients);
307 while (CachedResourceClient* c = w.next())
308 c->notifyFinished(this);
311 void CachedImage::destroyDecodedData()
313 if (m_image && !m_errorOccurred)
314 m_image->destroyDecodedData();
317 void CachedImage::decodedSizeChanged(const Image* image, int delta)
319 if (image != m_image)
322 setDecodedSize(decodedSize() + delta);
325 void CachedImage::didDraw(const Image* image)
327 if (image != m_image)
330 double timeStamp = FrameView::currentPaintTimeStamp();
331 if (!timeStamp) // If didDraw is called outside of a Frame paint.
332 timeStamp = currentTime();
334 CachedResource::didAccessDecodedData(timeStamp);
337 bool CachedImage::shouldPauseAnimation(const Image* image)
339 if (image != m_image)
342 CachedResourceClientWalker w(m_clients);
343 while (CachedResourceClient* c = w.next()) {
344 if (c->willRenderImage(this))
351 void CachedImage::animationAdvanced(const Image* image)
353 if (image == m_image)
357 } //namespace WebCore