97026e6f457f4b3bc61bf01955d3003b42dfae94
[WebKit-https.git] / Source / WebCore / loader / cache / CachedImage.cpp
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
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.
12
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.
17
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.
22 */
23
24 #include "config.h"
25 #include "CachedImage.h"
26
27 #include "BitmapImage.h"
28 #include "CachedImageClient.h"
29 #include "CachedResourceClient.h"
30 #include "CachedResourceClientWalker.h"
31 #include "CachedResourceLoader.h"
32 #include "Frame.h"
33 #include "FrameLoader.h"
34 #include "FrameLoaderClient.h"
35 #include "FrameLoaderTypes.h"
36 #include "FrameView.h"
37 #include "MemoryCache.h"
38 #include "RenderElement.h"
39 #include "SVGImage.h"
40 #include "SecurityOrigin.h"
41 #include "Settings.h"
42 #include "SharedBuffer.h"
43 #include "SubresourceLoader.h"
44 #include <wtf/CurrentTime.h>
45 #include <wtf/NeverDestroyed.h>
46 #include <wtf/StdLibExtras.h>
47
48 #if PLATFORM(IOS)
49 #include "SystemMemory.h"
50 #endif
51
52 #if USE(CG)
53 #include "PDFDocumentImage.h"
54 #endif
55
56 namespace WebCore {
57
58 CachedImage::CachedImage(CachedResourceRequest&& request, SessionID sessionID)
59     : CachedResource(WTFMove(request), ImageResource, sessionID)
60 {
61     setStatus(Unknown);
62 }
63
64 CachedImage::CachedImage(Image* image, SessionID sessionID)
65     : CachedResource(URL(), ImageResource, sessionID)
66     , m_image(image)
67 {
68 }
69
70 CachedImage::CachedImage(const URL& url, Image* image, SessionID sessionID)
71     : CachedResource(url, ImageResource, sessionID)
72     , m_image(image)
73     , m_isManuallyCached(true)
74 {
75     // Use the incoming URL in the response field. This ensures that code using the response directly,
76     // such as origin checks for security, actually see something.
77     m_response.setURL(url);
78 }
79
80 CachedImage::~CachedImage()
81 {
82     clearImage();
83 }
84
85 void CachedImage::load(CachedResourceLoader& loader)
86 {
87     if (loader.shouldPerformImageLoad(url()))
88         CachedResource::load(loader);
89     else
90         setLoading(false);
91 }
92
93 void CachedImage::setBodyDataFrom(const CachedResource& resource)
94 {
95     ASSERT(resource.type() == type());
96     const CachedImage& image = static_cast<const CachedImage&>(resource);
97
98     CachedResource::setBodyDataFrom(resource);
99
100     m_image = image.m_image;
101     m_imageObserver = image.m_imageObserver;
102     if (m_imageObserver)
103         m_imageObserver->cachedImages().add(this);
104
105     if (m_image && is<SVGImage>(*m_image))
106         m_svgImageCache = std::make_unique<SVGImageCache>(&downcast<SVGImage>(*m_image));
107 }
108
109 void CachedImage::didAddClient(CachedResourceClient& client)
110 {
111     if (m_data && !m_image && !errorOccurred()) {
112         createImage();
113         m_image->setData(m_data.copyRef(), true);
114     }
115
116     ASSERT(client.resourceClientType() == CachedImageClient::expectedType());
117     if (m_image && !m_image->isNull())
118         static_cast<CachedImageClient&>(client).imageChanged(this);
119
120     if (m_image)
121         m_image->startAnimationAsynchronously();
122
123     CachedResource::didAddClient(client);
124 }
125
126 void CachedImage::didRemoveClient(CachedResourceClient& client)
127 {
128     ASSERT(client.resourceClientType() == CachedImageClient::expectedType());
129
130     m_pendingContainerSizeRequests.remove(&static_cast<CachedImageClient&>(client));
131     m_pendingImageDrawingClients.remove(&static_cast<CachedImageClient&>(client));
132
133     if (m_svgImageCache)
134         m_svgImageCache->removeClientFromCache(&static_cast<CachedImageClient&>(client));
135
136     CachedResource::didRemoveClient(client);
137
138     static_cast<CachedImageClient&>(client).didRemoveCachedImageClient(*this);
139 }
140
141 void CachedImage::addPendingImageDrawingClient(CachedImageClient& client)
142 {
143     ASSERT(client.resourceClientType() == CachedImageClient::expectedType());
144     if (m_pendingImageDrawingClients.contains(&client))
145         return;
146     if (!m_clients.contains(&client)) {
147         // If the <html> element does not have its own background specified, painting the root box
148         // renderer uses the style of the <body> element, see RenderView::rendererForRootBackground().
149         // In this case, the client we are asked to add is the root box renderer. Since we can't add
150         // a client to m_pendingImageDrawingClients unless it is one of the m_clients, we are going
151         // to cancel the repaint optimization we do in CachedImage::imageFrameAvailable() by adding
152         // all the m_clients to m_pendingImageDrawingClients.
153         CachedResourceClientWalker<CachedImageClient> walker(m_clients);
154         while (auto* client = walker.next())
155             m_pendingImageDrawingClients.add(client);
156     } else
157         m_pendingImageDrawingClients.add(&client);
158 }
159
160 void CachedImage::switchClientsToRevalidatedResource()
161 {
162     ASSERT(is<CachedImage>(resourceToRevalidate()));
163     // Pending container size requests need to be transferred to the revalidated resource.
164     if (!m_pendingContainerSizeRequests.isEmpty()) {
165         // A copy of pending size requests is needed as they are deleted during CachedResource::switchClientsToRevalidateResouce().
166         ContainerSizeRequests switchContainerSizeRequests;
167         for (auto& request : m_pendingContainerSizeRequests)
168             switchContainerSizeRequests.set(request.key, request.value);
169         CachedResource::switchClientsToRevalidatedResource();
170         CachedImage& revalidatedCachedImage = downcast<CachedImage>(*resourceToRevalidate());
171         for (auto& request : switchContainerSizeRequests)
172             revalidatedCachedImage.setContainerSizeForRenderer(request.key, request.value.first, request.value.second);
173         return;
174     }
175
176     CachedResource::switchClientsToRevalidatedResource();
177 }
178
179 void CachedImage::allClientsRemoved()
180 {
181     m_pendingContainerSizeRequests.clear();
182     m_pendingImageDrawingClients.clear();
183     if (m_image && !errorOccurred())
184         m_image->resetAnimation();
185 }
186
187 std::pair<Image*, float> CachedImage::brokenImage(float deviceScaleFactor) const
188 {
189     if (deviceScaleFactor >= 3) {
190         static NeverDestroyed<Image*> brokenImageVeryHiRes(&Image::loadPlatformResource("missingImage@3x").leakRef());
191         return std::make_pair(brokenImageVeryHiRes, 3);
192     }
193
194     if (deviceScaleFactor >= 2) {
195         static NeverDestroyed<Image*> brokenImageHiRes(&Image::loadPlatformResource("missingImage@2x").leakRef());
196         return std::make_pair(brokenImageHiRes, 2);
197     }
198
199     static NeverDestroyed<Image*> brokenImageLoRes(&Image::loadPlatformResource("missingImage").leakRef());
200     return std::make_pair(brokenImageLoRes, 1);
201 }
202
203 bool CachedImage::willPaintBrokenImage() const
204 {
205     return errorOccurred() && m_shouldPaintBrokenImage;
206 }
207
208 Image* CachedImage::image()
209 {
210     if (errorOccurred() && m_shouldPaintBrokenImage) {
211         // Returning the 1x broken image is non-ideal, but we cannot reliably access the appropriate
212         // deviceScaleFactor from here. It is critical that callers use CachedImage::brokenImage() 
213         // when they need the real, deviceScaleFactor-appropriate broken image icon. 
214         return brokenImage(1).first;
215     }
216
217     if (m_image)
218         return m_image.get();
219
220     return &Image::nullImage();
221 }
222
223 Image* CachedImage::imageForRenderer(const RenderObject* renderer)
224 {
225     if (errorOccurred() && m_shouldPaintBrokenImage) {
226         // Returning the 1x broken image is non-ideal, but we cannot reliably access the appropriate
227         // deviceScaleFactor from here. It is critical that callers use CachedImage::brokenImage() 
228         // when they need the real, deviceScaleFactor-appropriate broken image icon. 
229         return brokenImage(1).first;
230     }
231
232     if (!m_image)
233         return &Image::nullImage();
234
235     if (m_image->isSVGImage()) {
236         Image* image = m_svgImageCache->imageForRenderer(renderer);
237         if (image != &Image::nullImage())
238             return image;
239     }
240     return m_image.get();
241 }
242
243 void CachedImage::setContainerSizeForRenderer(const CachedImageClient* renderer, const LayoutSize& containerSize, float containerZoom)
244 {
245     if (containerSize.isEmpty())
246         return;
247     ASSERT(renderer);
248     ASSERT(containerZoom);
249     if (!m_image) {
250         m_pendingContainerSizeRequests.set(renderer, SizeAndZoom(containerSize, containerZoom));
251         return;
252     }
253
254     if (!m_image->isSVGImage()) {
255         m_image->setContainerSize(containerSize);
256         return;
257     }
258
259     m_svgImageCache->setContainerSizeForRenderer(renderer, containerSize, containerZoom);
260 }
261
262 LayoutSize CachedImage::imageSizeForRenderer(const RenderElement* renderer, float multiplier, SizeType sizeType)
263 {
264     if (!m_image)
265         return LayoutSize();
266
267     LayoutSize imageSize;
268
269     if (is<BitmapImage>(*m_image) && renderer && renderer->shouldRespectImageOrientation() == RespectImageOrientation)
270         imageSize = LayoutSize(downcast<BitmapImage>(*m_image).sizeRespectingOrientation());
271     else if (is<SVGImage>(*m_image) && sizeType == UsedSize)
272         imageSize = LayoutSize(m_svgImageCache->imageSizeForRenderer(renderer));
273     else
274         imageSize = LayoutSize(m_image->size());
275
276     if (multiplier == 1.0f)
277         return imageSize;
278         
279     // Don't let images that have a width/height >= 1 shrink below 1 when zoomed.
280     float widthScale = m_image->hasRelativeWidth() ? 1.0f : multiplier;
281     float heightScale = m_image->hasRelativeHeight() ? 1.0f : multiplier;
282     LayoutSize minimumSize(imageSize.width() > 0 ? 1 : 0, imageSize.height() > 0 ? 1 : 0);
283     imageSize.scale(widthScale, heightScale);
284     imageSize.clampToMinimumSize(minimumSize);
285     ASSERT(multiplier != 1.0f || (imageSize.width().fraction() == 0.0f && imageSize.height().fraction() == 0.0f));
286     return imageSize;
287 }
288
289 void CachedImage::computeIntrinsicDimensions(Length& intrinsicWidth, Length& intrinsicHeight, FloatSize& intrinsicRatio)
290 {
291     if (m_image)
292         m_image->computeIntrinsicDimensions(intrinsicWidth, intrinsicHeight, intrinsicRatio);
293 }
294
295 void CachedImage::notifyObservers(const IntRect* changeRect)
296 {
297     CachedResourceClientWalker<CachedImageClient> w(m_clients);
298     while (CachedImageClient* c = w.next())
299         c->imageChanged(this, changeRect);
300 }
301
302 void CachedImage::checkShouldPaintBrokenImage()
303 {
304     if (!m_loader || m_loader->reachedTerminalState())
305         return;
306
307     m_shouldPaintBrokenImage = m_loader->frameLoader()->client().shouldPaintBrokenImage(url());
308 }
309
310 void CachedImage::clear()
311 {
312     destroyDecodedData();
313     clearImage();
314     m_pendingContainerSizeRequests.clear();
315     m_pendingImageDrawingClients.clear();
316     setEncodedSize(0);
317 }
318
319 inline void CachedImage::createImage()
320 {
321     // Create the image if it doesn't yet exist.
322     if (m_image)
323         return;
324
325     m_imageObserver = CachedImageObserver::create(*this);
326
327     if (m_response.mimeType() == "image/svg+xml") {
328         auto svgImage = SVGImage::create(*m_imageObserver, url());
329         m_svgImageCache = std::make_unique<SVGImageCache>(svgImage.ptr());
330         m_image = WTFMove(svgImage);
331 #if USE(CG) && !USE(WEBKIT_IMAGE_DECODERS)
332     } else if (m_response.mimeType() == "application/pdf") {
333         m_image = PDFDocumentImage::create(m_imageObserver.get());
334 #endif
335     } else
336         m_image = BitmapImage::create(m_imageObserver.get());
337
338     if (m_image) {
339         // Send queued container size requests.
340         if (m_image->usesContainerSize()) {
341             for (auto& request : m_pendingContainerSizeRequests)
342                 setContainerSizeForRenderer(request.key, request.value.first, request.value.second);
343         }
344         m_pendingContainerSizeRequests.clear();
345         m_pendingImageDrawingClients.clear();
346     }
347 }
348
349 CachedImage::CachedImageObserver::CachedImageObserver(CachedImage& image)
350 {
351     m_cachedImages.add(&image);
352 }
353
354 void CachedImage::CachedImageObserver::decodedSizeChanged(const Image& image, long long delta)
355 {
356     for (auto cachedImage : m_cachedImages)
357         cachedImage->decodedSizeChanged(image, delta);
358 }
359
360 void CachedImage::CachedImageObserver::didDraw(const Image& image)
361 {
362     for (auto cachedImage : m_cachedImages)
363         cachedImage->didDraw(image);
364 }
365
366 bool CachedImage::CachedImageObserver::canDestroyDecodedData(const Image& image)
367 {
368     for (auto cachedImage : m_cachedImages) {
369         if (&image != cachedImage->image())
370             continue;
371         if (!cachedImage->canDestroyDecodedData(image))
372             return false;
373     }
374     return true;
375 }
376
377 void CachedImage::CachedImageObserver::imageFrameAvailable(const Image& image, ImageAnimatingState animatingState, const IntRect* changeRect)
378 {
379     for (auto cachedImage : m_cachedImages)
380         cachedImage->imageFrameAvailable(image, animatingState, changeRect);
381 }
382
383 void CachedImage::CachedImageObserver::changedInRect(const Image& image, const IntRect* rect)
384 {
385     for (auto cachedImage : m_cachedImages)
386         cachedImage->changedInRect(image, rect);
387 }
388
389 inline void CachedImage::clearImage()
390 {
391     if (!m_image)
392         return;
393
394     if (m_imageObserver) {
395         m_imageObserver->cachedImages().remove(this);
396
397         if (m_imageObserver->cachedImages().isEmpty()) {
398             ASSERT(m_imageObserver->hasOneRef());
399             m_image->setImageObserver(nullptr);
400         }
401
402         m_imageObserver = nullptr;
403     }
404
405     m_image = nullptr;
406 }
407
408 void CachedImage::addIncrementalDataBuffer(SharedBuffer& data)
409 {
410     m_data = &data;
411
412     createImage();
413
414     // Have the image update its data from its internal buffer.
415     // It will not do anything now, but will delay decoding until
416     // queried for info (like size or specific image frames).
417     EncodedDataStatus encodedDataStatus = setImageDataBuffer(&data, false);
418     if (encodedDataStatus > EncodedDataStatus::Error && encodedDataStatus < EncodedDataStatus::SizeAvailable)
419         return;
420
421     if (encodedDataStatus == EncodedDataStatus::Error || m_image->isNull()) {
422         // Image decoding failed. Either we need more image data or the image data is malformed.
423         error(errorOccurred() ? status() : DecodeError);
424         if (m_loader && encodedDataStatus == EncodedDataStatus::Error)
425             m_loader->cancel();
426         if (inCache())
427             MemoryCache::singleton().remove(*this);
428         return;
429     }
430
431     // Tell our observers to try to draw.
432     // Each chunk from the network causes observers to repaint, which will force that chunk to decode.
433     // It would be nice to only redraw the decoded band of the image, but with the current design
434     // (decoding delayed until painting) that seems hard.
435     notifyObservers();
436
437     setEncodedSize(m_image->data() ? m_image->data()->size() : 0);
438 }
439
440 EncodedDataStatus CachedImage::setImageDataBuffer(SharedBuffer* data, bool allDataReceived)
441 {
442     return m_image ? m_image->setData(data, allDataReceived) : EncodedDataStatus::Error;
443 }
444
445 void CachedImage::addDataBuffer(SharedBuffer& data)
446 {
447     ASSERT(dataBufferingPolicy() == BufferData);
448     addIncrementalDataBuffer(data);
449     CachedResource::addDataBuffer(data);
450 }
451
452 void CachedImage::addData(const char* data, unsigned length)
453 {
454     ASSERT(dataBufferingPolicy() == DoNotBufferData);
455     addIncrementalDataBuffer(SharedBuffer::create(data, length));
456     CachedResource::addData(data, length);
457 }
458
459 void CachedImage::finishLoading(SharedBuffer* data)
460 {
461     m_data = data;
462     if (!m_image && data)
463         createImage();
464
465     EncodedDataStatus encodedDataStatus = setImageDataBuffer(data, true);
466
467     if (encodedDataStatus == EncodedDataStatus::Error || m_image->isNull()) {
468         // Image decoding failed; the image data is malformed.
469         error(errorOccurred() ? status() : DecodeError);
470         if (inCache())
471             MemoryCache::singleton().remove(*this);
472         return;
473     }
474
475     notifyObservers();
476     if (m_image)
477         setEncodedSize(m_image->data() ? m_image->data()->size() : 0);
478     CachedResource::finishLoading(data);
479 }
480
481 void CachedImage::didReplaceSharedBufferContents()
482 {
483     if (m_image) {
484         // Let the Image know that the SharedBuffer has been rejigged, so it can let go of any references to the heap-allocated resource buffer.
485         // FIXME(rdar://problem/24275617): It would be better if we could somehow tell the Image's decoder to swap in the new contents without destroying anything.
486         m_image->destroyDecodedData(true);
487     }
488     CachedResource::didReplaceSharedBufferContents();
489 }
490
491 void CachedImage::error(CachedResource::Status status)
492 {
493     checkShouldPaintBrokenImage();
494     clear();
495     CachedResource::error(status);
496     notifyObservers();
497 }
498
499 void CachedImage::responseReceived(const ResourceResponse& response)
500 {
501     if (!m_response.isNull())
502         clear();
503     CachedResource::responseReceived(response);
504 }
505
506 void CachedImage::destroyDecodedData()
507 {
508     bool canDeleteImage = !m_image || (m_image->hasOneRef() && m_image->isBitmapImage());
509     if (canDeleteImage && !isLoading() && !hasClients()) {
510         m_image = nullptr;
511         setDecodedSize(0);
512     } else if (m_image && !errorOccurred())
513         m_image->destroyDecodedData();
514 }
515
516 void CachedImage::decodedSizeChanged(const Image& image, long long delta)
517 {
518     if (&image != m_image)
519         return;
520
521     ASSERT(delta >= 0 || decodedSize() + delta >= 0);
522     setDecodedSize(static_cast<unsigned>(decodedSize() + delta));
523 }
524
525 void CachedImage::didDraw(const Image& image)
526 {
527     if (&image != m_image)
528         return;
529     
530     double timeStamp = FrameView::currentPaintTimeStamp();
531     if (!timeStamp) // If didDraw is called outside of a Frame paint.
532         timeStamp = monotonicallyIncreasingTime();
533     
534     CachedResource::didAccessDecodedData(timeStamp);
535 }
536
537 bool CachedImage::canDestroyDecodedData(const Image& image)
538 {
539     if (&image != m_image)
540         return false;
541
542     CachedResourceClientWalker<CachedImageClient> clientWalker(m_clients);
543     while (CachedImageClient* client = clientWalker.next()) {
544         if (!client->canDestroyDecodedData())
545             return false;
546     }
547
548     return true;
549 }
550
551 void CachedImage::imageFrameAvailable(const Image& image, ImageAnimatingState animatingState, const IntRect* changeRect)
552 {
553     if (&image != m_image)
554         return;
555
556     CachedResourceClientWalker<CachedImageClient> clientWalker(m_clients);
557     VisibleInViewportState visibleState = VisibleInViewportState::No;
558
559     while (CachedImageClient* client = clientWalker.next()) {
560         // All the clients of animated images have to be notified. The new frame has to be drawn in all of them.
561         if (animatingState == ImageAnimatingState::No && !m_pendingImageDrawingClients.contains(client))
562             continue;
563         if (client->imageFrameAvailable(*this, animatingState, changeRect) == VisibleInViewportState::Yes)
564             visibleState = VisibleInViewportState::Yes;
565     }
566
567     if (visibleState == VisibleInViewportState::No && animatingState == ImageAnimatingState::Yes)
568         m_image->stopAnimation();
569
570     m_pendingImageDrawingClients.clear();
571 }
572
573 void CachedImage::changedInRect(const Image& image, const IntRect* rect)
574 {
575     if (&image != m_image)
576         return;
577     notifyObservers(rect);
578 }
579
580 bool CachedImage::currentFrameKnownToBeOpaque(const RenderElement* renderer)
581 {
582     Image* image = imageForRenderer(renderer);
583     return image->currentFrameKnownToBeOpaque();
584 }
585
586 bool CachedImage::isOriginClean(SecurityOrigin* origin)
587 {
588     ASSERT_UNUSED(origin, origin);
589     ASSERT(this->origin());
590     ASSERT(origin->toString() == this->origin()->toString());
591     return !loadFailedOrCanceled() && isCORSSameOrigin();
592 }
593
594 CachedResource::RevalidationDecision CachedImage::makeRevalidationDecision(CachePolicy cachePolicy) const
595 {
596     if (UNLIKELY(isManuallyCached())) {
597         // Do not revalidate manually cached images. This mechanism is used as a
598         // way to efficiently share an image from the client to content and
599         // the URL for that image may not represent a resource that can be
600         // retrieved by standard means. If the manual caching SPI is used, it is
601         // incumbent on the client to only use valid resources.
602         return RevalidationDecision::No;
603     }
604     return CachedResource::makeRevalidationDecision(cachePolicy);
605 }
606
607 } // namespace WebCore