/src/3rdparty/webkit/Source/WebCore/loader/cache/CachedImage.cpp

https://bitbucket.org/ultra_iter/qt-vtl · C++ · 381 lines · 280 code · 65 blank · 36 comment · 69 complexity · ff5d10f375fc74980fa7f24ac0fb8848 MD5 · raw file

  1. /*
  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.
  7. This library is free software; you can redistribute it and/or
  8. modify it under the terms of the GNU Library General Public
  9. License as published by the Free Software Foundation; either
  10. version 2 of the License, or (at your option) any later version.
  11. This library is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. Library General Public License for more details.
  15. You should have received a copy of the GNU Library General Public License
  16. along with this library; see the file COPYING.LIB. If not, write to
  17. the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  18. Boston, MA 02110-1301, USA.
  19. */
  20. #include "config.h"
  21. #include "CachedImage.h"
  22. #include "BitmapImage.h"
  23. #include "MemoryCache.h"
  24. #include "CachedResourceClient.h"
  25. #include "CachedResourceClientWalker.h"
  26. #include "CachedResourceLoader.h"
  27. #include "CachedResourceRequest.h"
  28. #include "Frame.h"
  29. #include "FrameLoaderClient.h"
  30. #include "FrameLoaderTypes.h"
  31. #include "FrameView.h"
  32. #include "Settings.h"
  33. #include "SharedBuffer.h"
  34. #include <wtf/CurrentTime.h>
  35. #include <wtf/StdLibExtras.h>
  36. #include <wtf/Vector.h>
  37. #if USE(CG)
  38. #include "PDFDocumentImage.h"
  39. #endif
  40. #if ENABLE(SVG_AS_IMAGE)
  41. #include "SVGImage.h"
  42. #endif
  43. using std::max;
  44. namespace WebCore {
  45. CachedImage::CachedImage(const String& url)
  46. : CachedResource(url, ImageResource)
  47. , m_image(0)
  48. , m_decodedDataDeletionTimer(this, &CachedImage::decodedDataDeletionTimerFired)
  49. , m_shouldPaintBrokenImage(true)
  50. {
  51. setStatus(Unknown);
  52. }
  53. CachedImage::CachedImage(Image* image)
  54. : CachedResource(String(), ImageResource)
  55. , m_image(image)
  56. , m_decodedDataDeletionTimer(this, &CachedImage::decodedDataDeletionTimerFired)
  57. , m_shouldPaintBrokenImage(true)
  58. {
  59. setStatus(Cached);
  60. setLoading(false);
  61. }
  62. CachedImage::~CachedImage()
  63. {
  64. }
  65. void CachedImage::decodedDataDeletionTimerFired(Timer<CachedImage>*)
  66. {
  67. ASSERT(!hasClients());
  68. destroyDecodedData();
  69. }
  70. void CachedImage::load(CachedResourceLoader* cachedResourceLoader)
  71. {
  72. if (!cachedResourceLoader || cachedResourceLoader->autoLoadImages())
  73. CachedResource::load(cachedResourceLoader, true, DoSecurityCheck, true);
  74. else
  75. setLoading(false);
  76. }
  77. void CachedImage::didAddClient(CachedResourceClient* c)
  78. {
  79. if (m_decodedDataDeletionTimer.isActive())
  80. m_decodedDataDeletionTimer.stop();
  81. if (m_data && !m_image && !errorOccurred()) {
  82. createImage();
  83. m_image->setData(m_data, true);
  84. }
  85. if (m_image && !m_image->isNull())
  86. c->imageChanged(this);
  87. CachedResource::didAddClient(c);
  88. }
  89. void CachedImage::allClientsRemoved()
  90. {
  91. if (m_image && !errorOccurred())
  92. m_image->resetAnimation();
  93. if (double interval = memoryCache()->deadDecodedDataDeletionInterval())
  94. m_decodedDataDeletionTimer.startOneShot(interval);
  95. }
  96. static Image* brokenImage()
  97. {
  98. DEFINE_STATIC_LOCAL(RefPtr<Image>, brokenImage, (Image::loadPlatformResource("missingImage")));
  99. return brokenImage.get();
  100. }
  101. Image* CachedImage::image() const
  102. {
  103. ASSERT(!isPurgeable());
  104. if (errorOccurred() && m_shouldPaintBrokenImage)
  105. return brokenImage();
  106. if (m_image)
  107. return m_image.get();
  108. return Image::nullImage();
  109. }
  110. void CachedImage::setImageContainerSize(const IntSize& containerSize)
  111. {
  112. if (m_image)
  113. m_image->setContainerSize(containerSize);
  114. }
  115. bool CachedImage::usesImageContainerSize() const
  116. {
  117. if (m_image)
  118. return m_image->usesContainerSize();
  119. return false;
  120. }
  121. bool CachedImage::imageHasRelativeWidth() const
  122. {
  123. if (m_image)
  124. return m_image->hasRelativeWidth();
  125. return false;
  126. }
  127. bool CachedImage::imageHasRelativeHeight() const
  128. {
  129. if (m_image)
  130. return m_image->hasRelativeHeight();
  131. return false;
  132. }
  133. IntSize CachedImage::imageSize(float multiplier) const
  134. {
  135. ASSERT(!isPurgeable());
  136. if (!m_image)
  137. return IntSize();
  138. if (multiplier == 1.0f)
  139. return m_image->size();
  140. // Don't let images that have a width/height >= 1 shrink below 1 when zoomed.
  141. bool hasWidth = m_image->size().width() > 0;
  142. bool hasHeight = m_image->size().height() > 0;
  143. int width = m_image->size().width() * (m_image->hasRelativeWidth() ? 1.0f : multiplier);
  144. int height = m_image->size().height() * (m_image->hasRelativeHeight() ? 1.0f : multiplier);
  145. if (hasWidth)
  146. width = max(1, width);
  147. if (hasHeight)
  148. height = max(1, height);
  149. return IntSize(width, height);
  150. }
  151. IntRect CachedImage::imageRect(float multiplier) const
  152. {
  153. ASSERT(!isPurgeable());
  154. if (!m_image)
  155. return IntRect();
  156. if (multiplier == 1.0f || (!m_image->hasRelativeWidth() && !m_image->hasRelativeHeight()))
  157. return m_image->rect();
  158. float widthMultiplier = (m_image->hasRelativeWidth() ? 1.0f : multiplier);
  159. float heightMultiplier = (m_image->hasRelativeHeight() ? 1.0f : multiplier);
  160. // Don't let images that have a width/height >= 1 shrink below 1 when zoomed.
  161. bool hasWidth = m_image->rect().width() > 0;
  162. bool hasHeight = m_image->rect().height() > 0;
  163. int width = static_cast<int>(m_image->rect().width() * widthMultiplier);
  164. int height = static_cast<int>(m_image->rect().height() * heightMultiplier);
  165. if (hasWidth)
  166. width = max(1, width);
  167. if (hasHeight)
  168. height = max(1, height);
  169. int x = static_cast<int>(m_image->rect().x() * widthMultiplier);
  170. int y = static_cast<int>(m_image->rect().y() * heightMultiplier);
  171. return IntRect(x, y, width, height);
  172. }
  173. void CachedImage::notifyObservers(const IntRect* changeRect)
  174. {
  175. CachedResourceClientWalker w(m_clients);
  176. while (CachedResourceClient* c = w.next())
  177. c->imageChanged(this, changeRect);
  178. }
  179. void CachedImage::checkShouldPaintBrokenImage()
  180. {
  181. Frame* frame = m_request ? m_request->cachedResourceLoader()->frame() : 0;
  182. if (!frame)
  183. return;
  184. m_shouldPaintBrokenImage = frame->loader()->client()->shouldPaintBrokenImage(KURL(ParsedURLString, m_url));
  185. }
  186. void CachedImage::clear()
  187. {
  188. destroyDecodedData();
  189. m_image = 0;
  190. setEncodedSize(0);
  191. }
  192. inline void CachedImage::createImage()
  193. {
  194. // Create the image if it doesn't yet exist.
  195. if (m_image)
  196. return;
  197. #if USE(CG) && !USE(WEBKIT_IMAGE_DECODERS)
  198. if (m_response.mimeType() == "application/pdf") {
  199. m_image = PDFDocumentImage::create();
  200. return;
  201. }
  202. #endif
  203. #if ENABLE(SVG_AS_IMAGE)
  204. if (m_response.mimeType() == "image/svg+xml") {
  205. m_image = SVGImage::create(this);
  206. return;
  207. }
  208. #endif
  209. m_image = BitmapImage::create(this);
  210. }
  211. size_t CachedImage::maximumDecodedImageSize()
  212. {
  213. Frame* frame = m_request ? m_request->cachedResourceLoader()->frame() : 0;
  214. if (!frame)
  215. return 0;
  216. Settings* settings = frame->settings();
  217. return settings ? settings->maximumDecodedImageSize() : 0;
  218. }
  219. void CachedImage::data(PassRefPtr<SharedBuffer> data, bool allDataReceived)
  220. {
  221. m_data = data;
  222. createImage();
  223. bool sizeAvailable = false;
  224. // Have the image update its data from its internal buffer.
  225. // It will not do anything now, but will delay decoding until
  226. // queried for info (like size or specific image frames).
  227. sizeAvailable = m_image->setData(m_data, allDataReceived);
  228. // Go ahead and tell our observers to try to draw if we have either
  229. // received all the data or the size is known. Each chunk from the
  230. // network causes observers to repaint, which will force that chunk
  231. // to decode.
  232. if (sizeAvailable || allDataReceived) {
  233. size_t maxDecodedImageSize = maximumDecodedImageSize();
  234. IntSize s = imageSize(1.0f);
  235. size_t estimatedDecodedImageSize = s.width() * s.height() * 4; // no overflow check
  236. if (m_image->isNull() || (maxDecodedImageSize > 0 && estimatedDecodedImageSize > maxDecodedImageSize)) {
  237. error(errorOccurred() ? status() : DecodeError);
  238. if (inCache())
  239. memoryCache()->remove(this);
  240. return;
  241. }
  242. // It would be nice to only redraw the decoded band of the image, but with the current design
  243. // (decoding delayed until painting) that seems hard.
  244. notifyObservers();
  245. if (m_image)
  246. setEncodedSize(m_image->data() ? m_image->data()->size() : 0);
  247. }
  248. if (allDataReceived) {
  249. setLoading(false);
  250. checkNotify();
  251. }
  252. }
  253. void CachedImage::error(CachedResource::Status status)
  254. {
  255. checkShouldPaintBrokenImage();
  256. clear();
  257. setStatus(status);
  258. ASSERT(errorOccurred());
  259. m_data.clear();
  260. notifyObservers();
  261. setLoading(false);
  262. checkNotify();
  263. }
  264. void CachedImage::destroyDecodedData()
  265. {
  266. bool canDeleteImage = !m_image || (m_image->hasOneRef() && m_image->isBitmapImage());
  267. if (isSafeToMakePurgeable() && canDeleteImage && !isLoading()) {
  268. // Image refs the data buffer so we should not make it purgeable while the image is alive.
  269. // Invoking addClient() will reconstruct the image object.
  270. m_image = 0;
  271. setDecodedSize(0);
  272. if (!MemoryCache::shouldMakeResourcePurgeableOnEviction())
  273. makePurgeable(true);
  274. } else if (m_image && !errorOccurred())
  275. m_image->destroyDecodedData();
  276. }
  277. void CachedImage::decodedSizeChanged(const Image* image, int delta)
  278. {
  279. if (image != m_image)
  280. return;
  281. setDecodedSize(decodedSize() + delta);
  282. }
  283. void CachedImage::didDraw(const Image* image)
  284. {
  285. if (image != m_image)
  286. return;
  287. double timeStamp = FrameView::currentPaintTimeStamp();
  288. if (!timeStamp) // If didDraw is called outside of a Frame paint.
  289. timeStamp = currentTime();
  290. CachedResource::didAccessDecodedData(timeStamp);
  291. }
  292. bool CachedImage::shouldPauseAnimation(const Image* image)
  293. {
  294. if (image != m_image)
  295. return false;
  296. CachedResourceClientWalker w(m_clients);
  297. while (CachedResourceClient* c = w.next()) {
  298. if (c->willRenderImage(this))
  299. return false;
  300. }
  301. return true;
  302. }
  303. void CachedImage::animationAdvanced(const Image* image)
  304. {
  305. if (image == m_image)
  306. notifyObservers();
  307. }
  308. void CachedImage::changedInRect(const Image* image, const IntRect& rect)
  309. {
  310. if (image == m_image)
  311. notifyObservers(&rect);
  312. }
  313. } //namespace WebCore