1/*
2 Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de)
3 Copyright (C) 2001 Dirk Mueller <mueller@kde.org>
4 Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
5 Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
6
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
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Library General Public License for more details.
16
17 You should have received a copy of the GNU Library General Public License
18 along with this library; see the file COPYING.LIB. If not, write to
19 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 Boston, MA 02110-1301, USA.
21*/
22
23#pragma once
24
25#include "CachedResource.h"
26#include "Image.h"
27#include "ImageObserver.h"
28#include "IntRect.h"
29#include "IntSizeHash.h"
30#include "LayoutSize.h"
31#include "SVGImageCache.h"
32#include <wtf/HashMap.h>
33
34namespace WebCore {
35
36class CachedImageClient;
37class CachedResourceLoader;
38class FloatSize;
39class MemoryCache;
40class RenderElement;
41class RenderObject;
42class SecurityOrigin;
43
44struct Length;
45
46class CachedImage final : public CachedResource {
47 friend class MemoryCache;
48
49public:
50 CachedImage(CachedResourceRequest&&, const PAL::SessionID&, const CookieJar*);
51 CachedImage(Image*, const PAL::SessionID&, const CookieJar*);
52 // Constructor to use for manually cached images.
53 CachedImage(const URL&, Image*, const PAL::SessionID&, const CookieJar*, const String& domainForCachePartition);
54 virtual ~CachedImage();
55
56 WEBCORE_EXPORT Image* image(); // Returns the nullImage() if the image is not available yet.
57 WEBCORE_EXPORT Image* imageForRenderer(const RenderObject*); // Returns the nullImage() if the image is not available yet.
58 bool hasImage() const { return m_image.get(); }
59 bool currentFrameKnownToBeOpaque(const RenderElement*);
60
61 std::pair<Image*, float> brokenImage(float deviceScaleFactor) const; // Returns an image and the image's resolution scale factor.
62 bool willPaintBrokenImage() const;
63
64 bool canRender(const RenderElement* renderer, float multiplier) { return !errorOccurred() && !imageSizeForRenderer(renderer, multiplier).isEmpty(); }
65
66 void setContainerContextForClient(const CachedImageClient&, const LayoutSize&, float, const URL&);
67 bool usesImageContainerSize() const { return m_image && m_image->usesContainerSize(); }
68 bool imageHasRelativeWidth() const { return m_image && m_image->hasRelativeWidth(); }
69 bool imageHasRelativeHeight() const { return m_image && m_image->hasRelativeHeight(); }
70
71 void updateBuffer(SharedBuffer&) override;
72 void finishLoading(SharedBuffer*) override;
73
74 enum SizeType {
75 UsedSize,
76 IntrinsicSize
77 };
78 // This method takes a zoom multiplier that can be used to increase the natural size of the image by the zoom.
79 LayoutSize imageSizeForRenderer(const RenderElement*, float multiplier, SizeType = UsedSize); // returns the size of the complete image.
80 void computeIntrinsicDimensions(Length& intrinsicWidth, Length& intrinsicHeight, FloatSize& intrinsicRatio);
81
82 bool isManuallyCached() const { return m_isManuallyCached; }
83 RevalidationDecision makeRevalidationDecision(CachePolicy) const override;
84 void load(CachedResourceLoader&) override;
85
86 bool isOriginClean(SecurityOrigin*);
87
88 bool isClientWaitingForAsyncDecoding(CachedImageClient&) const;
89 void addClientWaitingForAsyncDecoding(CachedImageClient&);
90 void removeAllClientsWaitingForAsyncDecoding();
91
92 void setForceUpdateImageDataEnabledForTesting(bool enabled) { m_forceUpdateImageDataEnabledForTesting = enabled; }
93
94private:
95 void clear();
96
97 CachedImage(CachedImage&, const ResourceRequest&, PAL::SessionID);
98
99 void setBodyDataFrom(const CachedResource&) final;
100
101 bool isPDFResource() const;
102 bool isPostScriptResource() const;
103
104 void createImage();
105 void clearImage();
106 // If not null, changeRect is the changed part of the image.
107 void notifyObservers(const IntRect* changeRect = nullptr);
108 void checkShouldPaintBrokenImage();
109
110 void switchClientsToRevalidatedResource() final;
111 bool mayTryReplaceEncodedData() const final { return true; }
112
113 void didAddClient(CachedResourceClient&) final;
114 void didRemoveClient(CachedResourceClient&) final;
115
116 void allClientsRemoved() override;
117 void destroyDecodedData() override;
118
119 bool shouldDeferUpdateImageData() const;
120 RefPtr<SharedBuffer> convertedDataIfNeeded(SharedBuffer* data) const;
121 void didUpdateImageData();
122 EncodedDataStatus updateImageData(bool allDataReceived);
123 void updateData(const char* data, unsigned length) override;
124 void error(CachedResource::Status) override;
125 void responseReceived(const ResourceResponse&) override;
126
127 // For compatibility, images keep loading even if there are HTTP errors.
128 bool shouldIgnoreHTTPStatusCodeErrors() const override { return true; }
129
130 bool stillNeedsLoad() const override { return !errorOccurred() && status() == Unknown && !isLoading(); }
131
132 class CachedImageObserver final : public RefCounted<CachedImageObserver>, public ImageObserver {
133 public:
134 static Ref<CachedImageObserver> create(CachedImage& image) { return adoptRef(*new CachedImageObserver(image)); }
135 HashSet<CachedImage*>& cachedImages() { return m_cachedImages; }
136 const HashSet<CachedImage*>& cachedImages() const { return m_cachedImages; }
137
138 private:
139 explicit CachedImageObserver(CachedImage&);
140
141 // ImageObserver API
142 URL sourceUrl() const override { return !m_cachedImages.isEmpty() ? (*m_cachedImages.begin())->url() : URL(); }
143 String mimeType() const override { return !m_cachedImages.isEmpty() ? (*m_cachedImages.begin())->mimeType() : emptyString(); }
144 long long expectedContentLength() const override { return !m_cachedImages.isEmpty() ? (*m_cachedImages.begin())->expectedContentLength() : 0; }
145
146 void encodedDataStatusChanged(const Image&, EncodedDataStatus) final;
147 void decodedSizeChanged(const Image&, long long delta) final;
148 void didDraw(const Image&) final;
149
150 bool canDestroyDecodedData(const Image&) final;
151 void imageFrameAvailable(const Image&, ImageAnimatingState, const IntRect* changeRect = nullptr, DecodingStatus = DecodingStatus::Invalid) final;
152 void changedInRect(const Image&, const IntRect*) final;
153
154 HashSet<CachedImage*> m_cachedImages;
155 };
156
157 void encodedDataStatusChanged(const Image&, EncodedDataStatus);
158 void decodedSizeChanged(const Image&, long long delta);
159 void didDraw(const Image&);
160 bool canDestroyDecodedData(const Image&);
161 void imageFrameAvailable(const Image&, ImageAnimatingState, const IntRect* changeRect = nullptr, DecodingStatus = DecodingStatus::Invalid);
162 void changedInRect(const Image&, const IntRect*);
163
164 void updateBufferInternal(SharedBuffer&);
165
166 void didReplaceSharedBufferContents() override;
167
168 struct ContainerContext {
169 LayoutSize containerSize;
170 float containerZoom;
171 URL imageURL;
172 };
173
174 using ContainerContextRequests = HashMap<const CachedImageClient*, ContainerContext>;
175 ContainerContextRequests m_pendingContainerContextRequests;
176
177 HashSet<CachedImageClient*> m_clientsWaitingForAsyncDecoding;
178
179 RefPtr<CachedImageObserver> m_imageObserver;
180 RefPtr<Image> m_image;
181 std::unique_ptr<SVGImageCache> m_svgImageCache;
182
183 MonotonicTime m_lastUpdateImageDataTime;
184
185 unsigned m_updateImageDataCount { 0 };
186 bool m_isManuallyCached { false };
187 bool m_shouldPaintBrokenImage { true };
188 bool m_forceUpdateImageDataEnabledForTesting { false };
189};
190
191} // namespace WebCore
192
193SPECIALIZE_TYPE_TRAITS_CACHED_RESOURCE(CachedImage, CachedResource::Type::ImageResource)
194