Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(176)

Side by Side Diff: third_party/WebKit/Source/core/fetch/ImageResource.cpp

Issue 2469873002: [ImageResource 4] Split ImageResource into Resource and Image parts (Closed)
Patch Set: Rebase. Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de) 2 Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de)
3 Copyright (C) 2001 Dirk Mueller (mueller@kde.org) 3 Copyright (C) 2001 Dirk Mueller (mueller@kde.org)
4 Copyright (C) 2002 Waldo Bastian (bastian@kde.org) 4 Copyright (C) 2002 Waldo Bastian (bastian@kde.org)
5 Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com) 5 Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
6 Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. 6 Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
7 7
8 This library is free software; you can redistribute it and/or 8 This library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Library General Public 9 modify it under the terms of the GNU Library General Public
10 License as published by the Free Software Foundation; either 10 License as published by the Free Software Foundation; either
11 version 2 of the License, or (at your option) any later version. 11 version 2 of the License, or (at your option) any later version.
12 12
13 This library is distributed in the hope that it will be useful, 13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Library General Public License for more details. 16 Library General Public License for more details.
17 17
18 You should have received a copy of the GNU Library General Public License 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 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, 20 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 Boston, MA 02110-1301, USA. 21 Boston, MA 02110-1301, USA.
22 */ 22 */
23 23
24 #include "core/fetch/ImageResource.h" 24 #include "core/fetch/ImageResource.h"
25 25
26 #include "core/fetch/ImageResourceContent.h"
27 #include "core/fetch/ImageResourceInfo.h"
26 #include "core/fetch/ImageResourceObserver.h" 28 #include "core/fetch/ImageResourceObserver.h"
27 #include "core/fetch/MemoryCache.h" 29 #include "core/fetch/MemoryCache.h"
28 #include "core/fetch/ResourceClient.h" 30 #include "core/fetch/ResourceClient.h"
29 #include "core/fetch/ResourceFetcher.h" 31 #include "core/fetch/ResourceFetcher.h"
30 #include "core/fetch/ResourceLoader.h" 32 #include "core/fetch/ResourceLoader.h"
31 #include "core/fetch/ResourceLoadingLog.h" 33 #include "core/fetch/ResourceLoadingLog.h"
32 #include "core/svg/graphics/SVGImage.h"
33 #include "platform/Histogram.h" 34 #include "platform/Histogram.h"
34 #include "platform/RuntimeEnabledFeatures.h" 35 #include "platform/RuntimeEnabledFeatures.h"
35 #include "platform/SharedBuffer.h" 36 #include "platform/SharedBuffer.h"
36 #include "platform/geometry/IntSize.h"
37 #include "platform/graphics/BitmapImage.h"
38 #include "platform/graphics/PlaceholderImage.h"
39 #include "platform/tracing/TraceEvent.h" 37 #include "platform/tracing/TraceEvent.h"
40 #include "public/platform/Platform.h" 38 #include "public/platform/Platform.h"
41 #include "public/platform/WebCachePolicy.h"
42 #include "wtf/CurrentTime.h" 39 #include "wtf/CurrentTime.h"
43 #include "wtf/HashCountedSet.h" 40 #include "wtf/HashCountedSet.h"
44 #include "wtf/StdLibExtras.h" 41 #include "wtf/StdLibExtras.h"
45 #include "wtf/Vector.h" 42 #include "wtf/Vector.h"
46 #include <memory> 43 #include <memory>
47 #include <v8.h> 44 #include <v8.h>
48 45
49 namespace blink { 46 namespace blink {
50 namespace { 47 namespace {
51 // The amount of time to wait before informing the clients that the image has 48 // The amount of time to wait before informing the clients that the image has
52 // been updated (in seconds). This effectively throttles invalidations that 49 // been updated (in seconds). This effectively throttles invalidations that
53 // result from new data arriving for this image. 50 // result from new data arriving for this image.
54 constexpr double kFlushDelaySeconds = 1.; 51 constexpr double kFlushDelaySeconds = 1.;
55 } // namespace 52 } // namespace
56 53
54 class ImageResource::ImageResourceInfoImpl final
55 : public GarbageCollectedFinalized<ImageResourceInfoImpl>,
56 public ImageResourceInfo {
57 USING_GARBAGE_COLLECTED_MIXIN(ImageResourceInfoImpl);
58
59 public:
60 ImageResourceInfoImpl(ImageResource* resource) : m_resource(resource) {
61 DCHECK(m_resource);
62 }
63 DEFINE_INLINE_VIRTUAL_TRACE() {
64 visitor->trace(m_resource);
65 ImageResourceInfo::trace(visitor);
66 }
67
68 private:
69 const KURL& url() const override { return m_resource->url(); }
70 bool isSchedulingReload() const override {
71 return m_resource->m_isSchedulingReload;
72 }
73 bool hasDevicePixelRatioHeaderValue() const override {
74 return m_resource->m_hasDevicePixelRatioHeaderValue;
75 }
76 float devicePixelRatioHeaderValue() const override {
77 return m_resource->m_devicePixelRatioHeaderValue;
78 }
79 const ResourceResponse& response() const override {
80 return m_resource->response();
81 }
82 Resource::Status getStatus() const override {
83 return m_resource->getStatus();
84 }
85 bool isPlaceholder() const override { return m_resource->isPlaceholder(); }
86 bool isCacheValidator() const override {
87 return m_resource->isCacheValidator();
88 }
89 bool schedulingReloadOrShouldReloadBrokenPlaceholder() const override {
90 return m_resource->m_isSchedulingReload ||
91 m_resource->shouldReloadBrokenPlaceholder();
92 }
93 bool isAccessAllowed(
94 SecurityOrigin* securityOrigin,
95 bool doesCurrentFrameHasSingleSecurityOrigin) const override {
96 return m_resource->isAccessAllowed(securityOrigin,
97 doesCurrentFrameHasSingleSecurityOrigin);
98 }
99 bool hasCacheControlNoStoreHeader() const override {
100 return m_resource->hasCacheControlNoStoreHeader();
101 }
102 const ResourceError& resourceError() const override {
103 return m_resource->resourceError();
104 }
105
106 void decodeError(bool allDataReceived) override {
107 m_resource->decodeError(allDataReceived);
108 }
109 void setDecodedSize(size_t size) override {
110 m_resource->setDecodedSize(size);
111 }
112 void willAddClientOrObserver() override {
113 m_resource->willAddClientOrObserver(Resource::MarkAsReferenced);
114 }
115 void didRemoveClientOrObserver() override {
116 m_resource->didRemoveClientOrObserver();
117 }
118 void emulateLoadStartedForInspector(
119 ResourceFetcher* fetcher,
120 const KURL& url,
121 const AtomicString& initiatorName) override {
122 fetcher->emulateLoadStartedForInspector(m_resource.get(), url,
123 WebURLRequest::RequestContextImage,
124 initiatorName);
125 }
126
127 Member<ImageResource> m_resource;
128 };
129
57 class ImageResource::ImageResourceFactory : public ResourceFactory { 130 class ImageResource::ImageResourceFactory : public ResourceFactory {
58 STACK_ALLOCATED(); 131 STACK_ALLOCATED();
59 132
60 public: 133 public:
61 ImageResourceFactory(const FetchRequest& fetchRequest) 134 ImageResourceFactory(const FetchRequest& fetchRequest)
62 : ResourceFactory(Resource::Image), m_fetchRequest(&fetchRequest) {} 135 : ResourceFactory(Resource::Image), m_fetchRequest(&fetchRequest) {}
63 136
64 Resource* create(const ResourceRequest& request, 137 Resource* create(const ResourceRequest& request,
65 const ResourceLoaderOptions& options, 138 const ResourceLoaderOptions& options,
66 const String&) const override { 139 const String&) const override {
67 return new ImageResource(request, options, 140 return new ImageResource(request, options, ImageResourceContent::create(),
68 m_fetchRequest->placeholderImageRequestType() == 141 m_fetchRequest->placeholderImageRequestType() ==
69 FetchRequest::AllowPlaceholder); 142 FetchRequest::AllowPlaceholder);
70 } 143 }
71 144
72 private: 145 private:
73 // Weak, unowned pointer. Must outlive |this|. 146 // Weak, unowned pointer. Must outlive |this|.
74 const FetchRequest* m_fetchRequest; 147 const FetchRequest* m_fetchRequest;
75 }; 148 };
76 149
77 ImageResource* ImageResource::fetch(FetchRequest& request, 150 ImageResource* ImageResource::fetch(FetchRequest& request,
(...skipping 21 matching lines...) Expand all
99 resource->m_isPlaceholder) { 172 resource->m_isPlaceholder) {
100 // If the image is a placeholder, but this fetch doesn't allow a 173 // If the image is a placeholder, but this fetch doesn't allow a
101 // placeholder, then load the original image. Note that the cache is not 174 // placeholder, then load the original image. Note that the cache is not
102 // bypassed here - it should be fine to use a cached copy if possible. 175 // bypassed here - it should be fine to use a cached copy if possible.
103 resource->reloadIfLoFiOrPlaceholder(fetcher, 176 resource->reloadIfLoFiOrPlaceholder(fetcher,
104 ReloadCachePolicy::UseExistingPolicy); 177 ReloadCachePolicy::UseExistingPolicy);
105 } 178 }
106 return resource; 179 return resource;
107 } 180 }
108 181
182 ImageResource* ImageResource::create(const ResourceRequest& request) {
183 return new ImageResource(request, ResourceLoaderOptions(),
184 ImageResourceContent::create(), false);
185 }
186
109 ImageResource::ImageResource(const ResourceRequest& resourceRequest, 187 ImageResource::ImageResource(const ResourceRequest& resourceRequest,
110 const ResourceLoaderOptions& options, 188 const ResourceLoaderOptions& options,
189 ImageResourceContent* content,
111 bool isPlaceholder) 190 bool isPlaceholder)
112 : Resource(resourceRequest, Image, options), 191 : Resource(resourceRequest, Image, options),
192 m_content(content),
113 m_devicePixelRatioHeaderValue(1.0), 193 m_devicePixelRatioHeaderValue(1.0),
114 m_image(nullptr),
115 m_hasDevicePixelRatioHeaderValue(false), 194 m_hasDevicePixelRatioHeaderValue(false),
116 m_isSchedulingReload(false), 195 m_isSchedulingReload(false),
117 m_isPlaceholder(isPlaceholder), 196 m_isPlaceholder(isPlaceholder),
118 m_flushTimer(this, &ImageResource::flushImageIfNeeded), 197 m_flushTimer(this, &ImageResource::flushImageIfNeeded) {
119 m_isRefetchableDataFromDiskCache(true) { 198 DCHECK(getContent());
120 RESOURCE_LOADING_DVLOG(1) << "new ImageResource(ResourceRequest) " << this; 199 RESOURCE_LOADING_DVLOG(1) << "new ImageResource(ResourceRequest) " << this;
121 } 200 getContent()->setImageResourceInfo(new ImageResourceInfoImpl(this));
122
123 ImageResource::ImageResource(blink::Image* image,
124 const ResourceLoaderOptions& options)
125 : Resource(ResourceRequest(""), Image, options),
126 m_devicePixelRatioHeaderValue(1.0),
127 m_image(image),
128 m_hasDevicePixelRatioHeaderValue(false),
129 m_isSchedulingReload(false),
130 m_isPlaceholder(false),
131 m_flushTimer(this, &ImageResource::flushImageIfNeeded),
132 m_isRefetchableDataFromDiskCache(true) {
133 RESOURCE_LOADING_DVLOG(1) << "new ImageResource(Image) " << this;
134 setStatus(Cached);
135 } 201 }
136 202
137 ImageResource::~ImageResource() { 203 ImageResource::~ImageResource() {
138 RESOURCE_LOADING_DVLOG(1) << "~ImageResource " << this; 204 RESOURCE_LOADING_DVLOG(1) << "~ImageResource " << this;
139 clearImage();
140 } 205 }
141 206
142 DEFINE_TRACE(ImageResource) { 207 DEFINE_TRACE(ImageResource) {
143 visitor->trace(m_multipartParser); 208 visitor->trace(m_multipartParser);
209 visitor->trace(m_content);
144 Resource::trace(visitor); 210 Resource::trace(visitor);
145 ImageObserver::trace(visitor);
146 MultipartImageResourceParser::Client::trace(visitor); 211 MultipartImageResourceParser::Client::trace(visitor);
147 } 212 }
148 213
149 void ImageResource::checkNotify() { 214 void ImageResource::checkNotify() {
150 // Don't notify clients of completion if this ImageResource is 215 // Don't notify clients of completion if this ImageResource is
151 // about to be reloaded. 216 // about to be reloaded.
152 if (m_isSchedulingReload || shouldReloadBrokenPlaceholder()) 217 if (m_isSchedulingReload || shouldReloadBrokenPlaceholder())
153 return; 218 return;
154 219
155 Resource::checkNotify(); 220 Resource::checkNotify();
156 } 221 }
157 222
158 void ImageResource::markObserverFinished(ImageResourceObserver* observer) {
159 if (m_observers.contains(observer)) {
160 m_finishedObservers.add(observer);
161 m_observers.remove(observer);
162 }
163 }
164
165 void ImageResource::didAddClient(ResourceClient* client) { 223 void ImageResource::didAddClient(ResourceClient* client) {
166 DCHECK((m_multipartParser && isLoading()) || !data() || m_image); 224 DCHECK((m_multipartParser && isLoading()) || !data() ||
225 getContent()->hasImage());
167 226
168 // Don't notify observers and clients of completion if this ImageResource is 227 // Don't notify observers and clients of completion if this ImageResource is
169 // about to be reloaded. 228 // about to be reloaded.
170 if (m_isSchedulingReload || shouldReloadBrokenPlaceholder()) 229 if (m_isSchedulingReload || shouldReloadBrokenPlaceholder())
171 return; 230 return;
172 231
173 Resource::didAddClient(client); 232 Resource::didAddClient(client);
174 } 233 }
175 234
176 void ImageResource::addObserver(ImageResourceObserver* observer) {
177 willAddClientOrObserver(MarkAsReferenced);
178
179 m_observers.add(observer);
180
181 if (isCacheValidator())
182 return;
183
184 // When the response is not multipart, if |data()| exists, |m_image| must be
185 // created. This is assured that |updateImage()| is called when |appendData()|
186 // is called.
187 //
188 // On the other hand, when the response is multipart, |updateImage()| is not
189 // called in |appendData()|, which means |m_image| might not be created even
190 // when |data()| exists. This is intentional since creating a |m_image| on
191 // receiving data might destroy an existing image in a previous part.
192 DCHECK((m_multipartParser && isLoading()) || !data() || m_image);
193
194 if (m_image && !m_image->isNull()) {
195 observer->imageChanged(this);
196 }
197
198 if (isLoaded() && m_observers.contains(observer) && !m_isSchedulingReload &&
199 !shouldReloadBrokenPlaceholder()) {
200 markObserverFinished(observer);
201 observer->imageNotifyFinished(this);
202 }
203 }
204
205 void ImageResource::removeObserver(ImageResourceObserver* observer) {
206 DCHECK(observer);
207
208 if (m_observers.contains(observer))
209 m_observers.remove(observer);
210 else if (m_finishedObservers.contains(observer))
211 m_finishedObservers.remove(observer);
212 else
213 NOTREACHED();
214
215 didRemoveClientOrObserver();
216 }
217
218 static void priorityFromObserver(const ImageResourceObserver* observer,
219 ResourcePriority& priority) {
220 ResourcePriority nextPriority = observer->computeResourcePriority();
221 if (nextPriority.visibility == ResourcePriority::NotVisible)
222 return;
223 priority.visibility = ResourcePriority::Visible;
224 priority.intraPriorityValue += nextPriority.intraPriorityValue;
225 }
226
227 ResourcePriority ImageResource::priorityFromObservers() {
228 ResourcePriority priority;
229
230 for (auto* observer : m_finishedObservers.asVector()) {
231 if (m_finishedObservers.contains(observer))
232 priorityFromObserver(observer, priority);
233 }
234 for (auto* observer : m_observers.asVector()) {
235 if (m_observers.contains(observer))
236 priorityFromObserver(observer, priority);
237 }
238
239 return priority;
240 }
241
242 void ImageResource::destroyDecodedDataForFailedRevalidation() { 235 void ImageResource::destroyDecodedDataForFailedRevalidation() {
243 clearImage(); 236 getContent()->updateImage(
237 nullptr, ImageResourceContentInterface::ClearExistingImage, false);
244 setDecodedSize(0); 238 setDecodedSize(0);
245 } 239 }
246 240
247 void ImageResource::destroyDecodedDataIfPossible() { 241 void ImageResource::destroyDecodedDataIfPossible() {
248 if (!m_image) 242 getContent()->destroyDecodedData();
249 return; 243 if (getContent()->hasImage() && !isPreloaded() &&
250 CHECK(!errorOccurred()); 244 getContent()->isRefetchableDataFromDiskCache()) {
251 m_image->destroyDecodedData();
252 if (!isPreloaded() && m_isRefetchableDataFromDiskCache) {
253 UMA_HISTOGRAM_MEMORY_KB("Memory.Renderer.EstimatedDroppableEncodedSize", 245 UMA_HISTOGRAM_MEMORY_KB("Memory.Renderer.EstimatedDroppableEncodedSize",
254 encodedSize() / 1024); 246 encodedSize() / 1024);
255 } 247 }
256 } 248 }
257 249
258 void ImageResource::doResetAnimation() {
259 if (m_image)
260 m_image->resetAnimation();
261 }
262
263 void ImageResource::allClientsAndObserversRemoved() { 250 void ImageResource::allClientsAndObserversRemoved() {
264 if (m_image) { 251 CHECK(!getContent()->hasImage() || !errorOccurred());
265 CHECK(!errorOccurred()); 252 // If possible, delay the resetting until back at the event loop. Doing so
266 // If possible, delay the resetting until back at the event loop. Doing so 253 // after a conservative GC prevents resetAnimation() from upsetting ongoing
267 // after a conservative GC prevents resetAnimation() from upsetting ongoing 254 // animation updates (crbug.com/613709)
268 // animation updates (crbug.com/613709) 255 if (!ThreadHeap::willObjectBeLazilySwept(this)) {
269 if (!ThreadHeap::willObjectBeLazilySwept(this)) { 256 Platform::current()->currentThread()->getWebTaskRunner()->postTask(
270 Platform::current()->currentThread()->getWebTaskRunner()->postTask( 257 BLINK_FROM_HERE,
271 BLINK_FROM_HERE, WTF::bind(&ImageResource::doResetAnimation, 258 WTF::bind(&ImageResourceContentInterface::doResetAnimation,
272 wrapWeakPersistent(this))); 259 wrapWeakPersistent(getContent())));
273 } else { 260 } else {
274 m_image->resetAnimation(); 261 getContent()->doResetAnimation();
275 }
276 } 262 }
277 if (m_multipartParser) 263 if (m_multipartParser)
278 m_multipartParser->cancel(); 264 m_multipartParser->cancel();
279 Resource::allClientsAndObserversRemoved(); 265 Resource::allClientsAndObserversRemoved();
280 } 266 }
281 267
282 PassRefPtr<const SharedBuffer> ImageResource::resourceBuffer() const { 268 PassRefPtr<const SharedBuffer> ImageResource::resourceBuffer() const {
283 if (data()) 269 if (data())
284 return data(); 270 return data();
285 if (m_image) 271 if (getContent()->hasImage())
286 return m_image->data(); 272 return getContent()->getImage()->data();
287 return nullptr; 273 return nullptr;
288 } 274 }
289 275
290 void ImageResource::appendData(const char* data, size_t length) { 276 void ImageResource::appendData(const char* data, size_t length) {
291 v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(length); 277 v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(length);
292 if (m_multipartParser) { 278 if (m_multipartParser) {
293 m_multipartParser->appendData(data, length); 279 m_multipartParser->appendData(data, length);
294 } else { 280 } else {
295 Resource::appendData(data, length); 281 Resource::appendData(data, length);
296 282
297 // If we don't have the size available yet, then update immediately since 283 // If we don't have the size available yet, then update immediately since
298 // we need to know the image size as soon as possible. Likewise for 284 // we need to know the image size as soon as possible. Likewise for
299 // animated images, update right away since we shouldn't throttle animated 285 // animated images, update right away since we shouldn't throttle animated
300 // images. 286 // images.
301 if (m_sizeAvailable == Image::SizeUnavailable || 287 if (!getContent()->isSizeAvailable() ||
302 (m_image && m_image->maybeAnimated())) { 288 (getContent()->hasImage() &&
303 updateImage(false); 289 getContent()->getImage()->maybeAnimated())) {
290 getContent()->updateImage(
291 this->data(), ImageResourceContentInterface::KeepExistingImage,
292 false);
304 return; 293 return;
305 } 294 }
306 295
307 // For other cases, only update at |kFlushDelaySeconds| intervals. This 296 // For other cases, only update at |kFlushDelaySeconds| intervals. This
308 // throttles how frequently we update |m_image| and how frequently we 297 // throttles how frequently we update |m_image| and how frequently we
309 // inform the clients which causes an invalidation of this image. In other 298 // inform the clients which causes an invalidation of this image. In other
310 // words, we only invalidate this image every |kFlushDelaySeconds| seconds 299 // words, we only invalidate this image every |kFlushDelaySeconds| seconds
311 // while loading. 300 // while loading.
312 if (!m_flushTimer.isActive()) { 301 if (!m_flushTimer.isActive()) {
313 double now = WTF::monotonicallyIncreasingTime(); 302 double now = WTF::monotonicallyIncreasingTime();
314 if (!m_lastFlushTime) 303 if (!m_lastFlushTime)
315 m_lastFlushTime = now; 304 m_lastFlushTime = now;
316 305
317 DCHECK_LE(m_lastFlushTime, now); 306 DCHECK_LE(m_lastFlushTime, now);
318 double flushDelay = m_lastFlushTime - now + kFlushDelaySeconds; 307 double flushDelay = m_lastFlushTime - now + kFlushDelaySeconds;
319 if (flushDelay < 0.) 308 if (flushDelay < 0.)
320 flushDelay = 0.; 309 flushDelay = 0.;
321 m_flushTimer.startOneShot(flushDelay, BLINK_FROM_HERE); 310 m_flushTimer.startOneShot(flushDelay, BLINK_FROM_HERE);
322 } 311 }
323 } 312 }
324 } 313 }
325 314
326 void ImageResource::flushImageIfNeeded(TimerBase*) { 315 void ImageResource::flushImageIfNeeded(TimerBase*) {
327 // We might have already loaded the image fully, in which case we don't need 316 // We might have already loaded the image fully, in which case we don't need
328 // to call |updateImage()|. 317 // to call |updateImage()|.
329 if (isLoading()) { 318 if (isLoading()) {
330 m_lastFlushTime = WTF::monotonicallyIncreasingTime(); 319 m_lastFlushTime = WTF::monotonicallyIncreasingTime();
331 updateImage(false); 320 getContent()->updateImage(
321 this->data(), ImageResourceContentInterface::KeepExistingImage, false);
332 } 322 }
333 } 323 }
334 324
335 std::pair<blink::Image*, float> ImageResource::brokenImage(
336 float deviceScaleFactor) {
337 if (deviceScaleFactor >= 2) {
338 DEFINE_STATIC_REF(blink::Image, brokenImageHiRes,
339 (blink::Image::loadPlatformResource("missingImage@2x")));
340 return std::make_pair(brokenImageHiRes, 2);
341 }
342
343 DEFINE_STATIC_REF(blink::Image, brokenImageLoRes,
344 (blink::Image::loadPlatformResource("missingImage")));
345 return std::make_pair(brokenImageLoRes, 1);
346 }
347
348 bool ImageResource::willPaintBrokenImage() const { 325 bool ImageResource::willPaintBrokenImage() const {
349 return errorOccurred(); 326 return errorOccurred();
350 } 327 }
351 328
352 blink::Image* ImageResource::getImage() { 329 void ImageResource::decodeError(bool allDataReceived) {
353 if (errorOccurred()) { 330 size_t size = encodedSize();
354 // Returning the 1x broken image is non-ideal, but we cannot reliably access 331
355 // the appropriate deviceScaleFactor from here. It is critical that callers 332 clearData();
356 // use ImageResource::brokenImage() when they need the real, 333 setEncodedSize(0);
357 // deviceScaleFactor-appropriate broken image icon. 334 if (!errorOccurred())
358 return brokenImage(1).first; 335 setStatus(DecodeError);
336
337 if (!allDataReceived && loader()) {
338 // TODO(hiroshige): Do not call didFinishLoading() directly.
339 loader()->didFinishLoading(monotonicallyIncreasingTime(), size, size);
359 } 340 }
360 341
361 if (m_image) 342 memoryCache()->remove(this);
362 return m_image.get();
363
364 return blink::Image::nullImage();
365 }
366
367 bool ImageResource::usesImageContainerSize() const {
368 if (m_image)
369 return m_image->usesContainerSize();
370
371 return false;
372 }
373
374 bool ImageResource::imageHasRelativeSize() const {
375 if (m_image)
376 return m_image->hasRelativeSize();
377
378 return false;
379 }
380
381 LayoutSize ImageResource::imageSize(
382 RespectImageOrientationEnum shouldRespectImageOrientation,
383 float multiplier,
384 SizeType sizeType) {
385 if (!m_image)
386 return LayoutSize();
387
388 LayoutSize size;
389
390 if (m_image->isBitmapImage() &&
391 shouldRespectImageOrientation == RespectImageOrientation) {
392 size =
393 LayoutSize(toBitmapImage(m_image.get())->sizeRespectingOrientation());
394 } else {
395 size = LayoutSize(m_image->size());
396 }
397
398 if (sizeType == IntrinsicCorrectedToDPR && m_hasDevicePixelRatioHeaderValue &&
399 m_devicePixelRatioHeaderValue > 0)
400 multiplier = 1 / m_devicePixelRatioHeaderValue;
401
402 if (multiplier == 1 || m_image->hasRelativeSize())
403 return size;
404
405 // Don't let images that have a width/height >= 1 shrink below 1 when zoomed.
406 LayoutSize minimumSize(
407 size.width() > LayoutUnit() ? LayoutUnit(1) : LayoutUnit(),
408 LayoutUnit(size.height() > LayoutUnit() ? LayoutUnit(1) : LayoutUnit()));
409 size.scale(multiplier);
410 size.clampToMinimumSize(minimumSize);
411 return size;
412 }
413
414 void ImageResource::notifyObservers(NotifyFinishOption notifyingFinishOption,
415 const IntRect* changeRect) {
416 for (auto* observer : m_finishedObservers.asVector()) {
417 if (m_finishedObservers.contains(observer))
418 observer->imageChanged(this, changeRect);
419 }
420 for (auto* observer : m_observers.asVector()) {
421 if (m_observers.contains(observer)) {
422 observer->imageChanged(this, changeRect);
423 if (notifyingFinishOption == ShouldNotifyFinish &&
424 m_observers.contains(observer) && !m_isSchedulingReload &&
425 !shouldReloadBrokenPlaceholder()) {
426 markObserverFinished(observer);
427 observer->imageNotifyFinished(this);
428 }
429 }
430 }
431 }
432
433 void ImageResource::clear() {
434 clearImage();
435 clearData();
436 setEncodedSize(0);
437 }
438
439 inline void ImageResource::createImage() {
440 // Create the image if it doesn't yet exist.
441 if (m_image)
442 return;
443
444 if (response().mimeType() == "image/svg+xml") {
445 m_image = SVGImage::create(this);
446 } else {
447 m_image = BitmapImage::create(this);
448 }
449 }
450
451 inline void ImageResource::clearImage() {
452 if (!m_image)
453 return;
454 int64_t length = m_image->data() ? m_image->data()->size() : 0;
455 v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(-length);
456
457 // If our Image has an observer, it's always us so we need to clear the back
458 // pointer before dropping our reference.
459 m_image->clearImageObserver();
460 m_image.clear();
461 m_sizeAvailable = Image::SizeUnavailable;
462 }
463
464 void ImageResource::updateImage(bool allDataReceived) {
465 TRACE_EVENT0("blink", "ImageResource::updateImage");
466
467 if (data())
468 createImage();
469
470 // Have the image update its data from its internal buffer. It will not do
471 // anything now, but will delay decoding until queried for info (like size or
472 // specific image frames).
473 if (data()) {
474 DCHECK(m_image);
475 m_sizeAvailable = m_image->setData(data(), allDataReceived);
476 }
477
478 // Go ahead and tell our observers to try to draw if we have either received
479 // all the data or the size is known. Each chunk from the network causes
480 // observers to repaint, which will force that chunk to decode.
481 if (m_sizeAvailable == Image::SizeUnavailable && !allDataReceived)
482 return;
483
484 if (m_isPlaceholder && allDataReceived && m_image && !m_image->isNull()) {
485 if (m_sizeAvailable == Image::SizeAvailable) {
486 // TODO(sclittle): Show the original image if the response consists of the
487 // entire image, such as if the entire image response body is smaller than
488 // the requested range.
489 IntSize dimensions = m_image->size();
490 clearImage();
491 m_image = PlaceholderImage::create(this, dimensions);
492 } else {
493 // Clear the image so that it gets treated like a decoding error, since
494 // the attempt to build a placeholder image failed.
495 clearImage();
496 }
497 }
498
499 if (!m_image || m_image->isNull()) {
500 size_t size = encodedSize();
501 clear();
502 if (!errorOccurred())
503 setStatus(DecodeError);
504 if (!allDataReceived && loader()) {
505 loader()->didFinishLoading(monotonicallyIncreasingTime(), size, size);
506 }
507 memoryCache()->remove(this);
508 }
509
510 // It would be nice to only redraw the decoded band of the image, but with the
511 // current design (decoding delayed until painting) that seems hard.
512 notifyObservers(allDataReceived ? ShouldNotifyFinish : DoNotNotifyFinish);
513 } 343 }
514 344
515 void ImageResource::updateImageAndClearBuffer() { 345 void ImageResource::updateImageAndClearBuffer() {
516 clearImage(); 346 getContent()->updateImage(
517 updateImage(true); 347 data(), ImageResourceContentInterface::ClearExistingImage, true);
518 clearData(); 348 clearData();
519 } 349 }
520 350
521 void ImageResource::finish(double loadFinishTime) { 351 void ImageResource::finish(double loadFinishTime) {
522 if (m_multipartParser) { 352 if (m_multipartParser) {
523 m_multipartParser->finish(); 353 m_multipartParser->finish();
524 if (data()) 354 if (data())
525 updateImageAndClearBuffer(); 355 updateImageAndClearBuffer();
526 } else { 356 } else {
527 updateImage(true); 357 getContent()->updateImage(
358 data(), ImageResourceContentInterface::KeepExistingImage, true);
528 // As encoded image data can be created from m_image (see 359 // As encoded image data can be created from m_image (see
529 // ImageResource::resourceBuffer(), we don't have to keep m_data. Let's 360 // ImageResource::resourceBuffer(), we don't have to keep m_data. Let's
530 // clear this. As for the lifetimes of m_image and m_data, see this 361 // clear this. As for the lifetimes of m_image and m_data, see this
531 // document: 362 // document:
532 // https://docs.google.com/document/d/1v0yTAZ6wkqX2U_M6BNIGUJpM1s0TIw1Vsqpxo L7aciY/edit?usp=sharing 363 // https://docs.google.com/document/d/1v0yTAZ6wkqX2U_M6BNIGUJpM1s0TIw1Vsqpxo L7aciY/edit?usp=sharing
533 clearData(); 364 clearData();
534 } 365 }
535 Resource::finish(loadFinishTime); 366 Resource::finish(loadFinishTime);
536 } 367 }
537 368
538 void ImageResource::error(const ResourceError& error) { 369 void ImageResource::error(const ResourceError& error) {
539 if (m_multipartParser) 370 if (m_multipartParser)
540 m_multipartParser->cancel(); 371 m_multipartParser->cancel();
541 clear(); 372 clearData();
542 Resource::error(error); 373 Resource::error(error);
543 notifyObservers(ShouldNotifyFinish); 374 getContent()->updateImage(
375 nullptr, ImageResourceContentInterface::ClearExistingImage, true);
544 } 376 }
545 377
546 void ImageResource::responseReceived( 378 void ImageResource::responseReceived(
547 const ResourceResponse& response, 379 const ResourceResponse& response,
548 std::unique_ptr<WebDataConsumerHandle> handle) { 380 std::unique_ptr<WebDataConsumerHandle> handle) {
549 DCHECK(!handle); 381 DCHECK(!handle);
550 DCHECK(!m_multipartParser); 382 DCHECK(!m_multipartParser);
551 // If there's no boundary, just handle the request normally. 383 // If there's no boundary, just handle the request normally.
552 if (response.isMultipart() && !response.multipartBoundary().isEmpty()) { 384 if (response.isMultipart() && !response.multipartBoundary().isEmpty()) {
553 m_multipartParser = new MultipartImageResourceParser( 385 m_multipartParser = new MultipartImageResourceParser(
554 response, response.multipartBoundary(), this); 386 response, response.multipartBoundary(), this);
555 } 387 }
556 Resource::responseReceived(response, std::move(handle)); 388 Resource::responseReceived(response, std::move(handle));
557 if (RuntimeEnabledFeatures::clientHintsEnabled()) { 389 if (RuntimeEnabledFeatures::clientHintsEnabled()) {
558 m_devicePixelRatioHeaderValue = 390 m_devicePixelRatioHeaderValue =
559 this->response() 391 this->response()
560 .httpHeaderField(HTTPNames::Content_DPR) 392 .httpHeaderField(HTTPNames::Content_DPR)
561 .toFloat(&m_hasDevicePixelRatioHeaderValue); 393 .toFloat(&m_hasDevicePixelRatioHeaderValue);
562 if (!m_hasDevicePixelRatioHeaderValue || 394 if (!m_hasDevicePixelRatioHeaderValue ||
563 m_devicePixelRatioHeaderValue <= 0.0) { 395 m_devicePixelRatioHeaderValue <= 0.0) {
564 m_devicePixelRatioHeaderValue = 1.0; 396 m_devicePixelRatioHeaderValue = 1.0;
565 m_hasDevicePixelRatioHeaderValue = false; 397 m_hasDevicePixelRatioHeaderValue = false;
566 } 398 }
567 } 399 }
568 } 400 }
569 401
570 void ImageResource::decodedSizeChangedTo(const blink::Image* image,
571 size_t newSize) {
572 if (!image || image != m_image)
573 return;
574
575 setDecodedSize(newSize);
576 }
577
578 bool ImageResource::shouldPauseAnimation(const blink::Image* image) {
579 if (!image || image != m_image)
580 return false;
581
582 for (auto* observer : m_finishedObservers.asVector()) {
583 if (m_finishedObservers.contains(observer) && observer->willRenderImage())
584 return false;
585 }
586
587 for (auto* observer : m_observers.asVector()) {
588 if (m_observers.contains(observer) && observer->willRenderImage())
589 return false;
590 }
591
592 return true;
593 }
594
595 void ImageResource::animationAdvanced(const blink::Image* image) {
596 if (!image || image != m_image)
597 return;
598 notifyObservers(DoNotNotifyFinish);
599 }
600
601 void ImageResource::updateImageAnimationPolicy() {
602 if (!m_image)
603 return;
604
605 ImageAnimationPolicy newPolicy = ImageAnimationPolicyAllowed;
606 for (auto* observer : m_finishedObservers.asVector()) {
607 if (m_finishedObservers.contains(observer) &&
608 observer->getImageAnimationPolicy(newPolicy))
609 break;
610 }
611 for (auto* observer : m_observers.asVector()) {
612 if (m_observers.contains(observer) &&
613 observer->getImageAnimationPolicy(newPolicy))
614 break;
615 }
616
617 if (m_image->animationPolicy() != newPolicy) {
618 m_image->resetAnimation();
619 m_image->setAnimationPolicy(newPolicy);
620 }
621 }
622
623 static bool isLoFiImage(const ImageResource& resource) { 402 static bool isLoFiImage(const ImageResource& resource) {
624 if (resource.resourceRequest().loFiState() != WebURLRequest::LoFiOn) 403 if (resource.resourceRequest().loFiState() != WebURLRequest::LoFiOn)
625 return false; 404 return false;
626 return !resource.isLoaded() || 405 return !resource.isLoaded() ||
627 resource.response() 406 resource.response()
628 .httpHeaderField("chrome-proxy-content-transform") 407 .httpHeaderField("chrome-proxy-content-transform")
629 .contains("empty-image"); 408 .contains("empty-image");
630 } 409 }
631 410
632 void ImageResource::reloadIfLoFiOrPlaceholder( 411 void ImageResource::reloadIfLoFiOrPlaceholder(
(...skipping 17 matching lines...) Expand all
650 m_isPlaceholder = false; 429 m_isPlaceholder = false;
651 clearRangeRequestHeader(); 430 clearRangeRequestHeader();
652 } 431 }
653 432
654 if (isLoading()) { 433 if (isLoading()) {
655 loader()->cancel(); 434 loader()->cancel();
656 // Canceling the loader causes error() to be called, which in turn calls 435 // Canceling the loader causes error() to be called, which in turn calls
657 // clear() and notifyObservers(), so there's no need to call these again 436 // clear() and notifyObservers(), so there's no need to call these again
658 // here. 437 // here.
659 } else { 438 } else {
660 clear(); 439 clearData();
661 notifyObservers(DoNotNotifyFinish); 440 setEncodedSize(0);
441 getContent()->updateImage(
442 nullptr, ImageResourceContentInterface::ClearExistingImage, false);
662 } 443 }
663 444
664 setStatus(NotStarted); 445 setStatus(NotStarted);
665 446
666 DCHECK(m_isSchedulingReload); 447 DCHECK(m_isSchedulingReload);
667 m_isSchedulingReload = false; 448 m_isSchedulingReload = false;
668 449
669 fetcher->startLoad(this); 450 fetcher->startLoad(this);
670 } 451 }
671 452
672 void ImageResource::changedInRect(const blink::Image* image,
673 const IntRect& rect) {
674 if (!image || image != m_image)
675 return;
676 notifyObservers(DoNotNotifyFinish, &rect);
677 }
678
679 void ImageResource::onePartInMultipartReceived( 453 void ImageResource::onePartInMultipartReceived(
680 const ResourceResponse& response) { 454 const ResourceResponse& response) {
681 DCHECK(m_multipartParser); 455 DCHECK(m_multipartParser);
682 456
683 setResponse(response); 457 setResponse(response);
684 if (m_multipartParsingState == MultipartParsingState::WaitingForFirstPart) { 458 if (m_multipartParsingState == MultipartParsingState::WaitingForFirstPart) {
685 // We have nothing to do because we don't have any data. 459 // We have nothing to do because we don't have any data.
686 m_multipartParsingState = MultipartParsingState::ParsingFirstPart; 460 m_multipartParsingState = MultipartParsingState::ParsingFirstPart;
687 return; 461 return;
688 } 462 }
(...skipping 11 matching lines...) Expand all
700 if (loader()) 474 if (loader())
701 loader()->didFinishLoadingFirstPartInMultipart(); 475 loader()->didFinishLoadingFirstPartInMultipart();
702 } 476 }
703 } 477 }
704 478
705 void ImageResource::multipartDataReceived(const char* bytes, size_t size) { 479 void ImageResource::multipartDataReceived(const char* bytes, size_t size) {
706 DCHECK(m_multipartParser); 480 DCHECK(m_multipartParser);
707 Resource::appendData(bytes, size); 481 Resource::appendData(bytes, size);
708 } 482 }
709 483
710 bool ImageResource::isAccessAllowed(SecurityOrigin* securityOrigin) { 484 bool ImageResource::isAccessAllowed(
485 SecurityOrigin* securityOrigin,
486 bool doesCurrentFrameHasSingleSecurityOrigin) const {
711 if (response().wasFetchedViaServiceWorker()) { 487 if (response().wasFetchedViaServiceWorker()) {
712 return response().serviceWorkerResponseType() != 488 return response().serviceWorkerResponseType() !=
713 WebServiceWorkerResponseTypeOpaque; 489 WebServiceWorkerResponseTypeOpaque;
714 } 490 }
715 if (!getImage()->currentFrameHasSingleSecurityOrigin()) 491 if (!doesCurrentFrameHasSingleSecurityOrigin)
716 return false; 492 return false;
717 if (passesAccessControlCheck(securityOrigin)) 493 if (passesAccessControlCheck(securityOrigin))
718 return true; 494 return true;
719 return !securityOrigin->taintsCanvas(response().url()); 495 return !securityOrigin->taintsCanvas(response().url());
720 } 496 }
721 497
498 ImageResourceContentInterface* ImageResource::getContent() const {
499 return m_content;
500 }
501
502 ImageResourceContent* ImageResource::getRealContent() const {
503 return m_content;
504 }
505
506 ResourcePriority ImageResource::priorityFromObservers() {
507 return getContent()->priorityFromObservers();
508 }
509
722 } // namespace blink 510 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698