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

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

Issue 2423683002: Add Blink support for showing image placeholders using range requests. (Closed)
Patch Set: Addressed comments Created 4 years, 2 months 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
(...skipping 14 matching lines...) Expand all
25 25
26 #include "core/fetch/ImageResourceObserver.h" 26 #include "core/fetch/ImageResourceObserver.h"
27 #include "core/fetch/MemoryCache.h" 27 #include "core/fetch/MemoryCache.h"
28 #include "core/fetch/ResourceClient.h" 28 #include "core/fetch/ResourceClient.h"
29 #include "core/fetch/ResourceFetcher.h" 29 #include "core/fetch/ResourceFetcher.h"
30 #include "core/fetch/ResourceLoader.h" 30 #include "core/fetch/ResourceLoader.h"
31 #include "core/fetch/ResourceLoadingLog.h" 31 #include "core/fetch/ResourceLoadingLog.h"
32 #include "core/svg/graphics/SVGImage.h" 32 #include "core/svg/graphics/SVGImage.h"
33 #include "platform/RuntimeEnabledFeatures.h" 33 #include "platform/RuntimeEnabledFeatures.h"
34 #include "platform/SharedBuffer.h" 34 #include "platform/SharedBuffer.h"
35 #include "platform/geometry/IntSize.h"
35 #include "platform/graphics/BitmapImage.h" 36 #include "platform/graphics/BitmapImage.h"
37 #include "platform/graphics/PlaceholderImage.h"
36 #include "platform/tracing/TraceEvent.h" 38 #include "platform/tracing/TraceEvent.h"
37 #include "public/platform/Platform.h" 39 #include "public/platform/Platform.h"
38 #include "public/platform/WebCachePolicy.h" 40 #include "public/platform/WebCachePolicy.h"
39 #include "wtf/CurrentTime.h" 41 #include "wtf/CurrentTime.h"
40 #include "wtf/HashCountedSet.h" 42 #include "wtf/HashCountedSet.h"
41 #include "wtf/StdLibExtras.h" 43 #include "wtf/StdLibExtras.h"
42 #include "wtf/Vector.h" 44 #include "wtf/Vector.h"
43 #include <memory> 45 #include <memory>
44 #include <v8.h> 46 #include <v8.h>
45 47
46 namespace blink { 48 namespace blink {
47 49
50 class ImageResource::ImageResourceFactory : public ResourceFactory {
51 STACK_ALLOCATED();
52
53 public:
54 ImageResourceFactory(const FetchRequest& fetchRequest)
55 : ResourceFactory(Resource::Image), m_fetchRequest(&fetchRequest) {}
56
57 Resource* create(const ResourceRequest& request,
Nate Chapin 2016/10/21 18:23:55 Every caller of ResourceFactory::create() just gen
sclittle 2016/10/21 18:57:25 Ok; the String charset parameter is probably still
Nate Chapin 2016/10/21 19:13:10 I thought it looked like the charset param always
58 const ResourceLoaderOptions& options,
59 const String&) const override {
60 return new ImageResource(request, options,
61 m_fetchRequest->placeholderImageRequestType() ==
62 FetchRequest::AllowPlaceholder);
63 }
64
65 private:
66 // Weak, unowned pointer. Must outlive |this|.
67 const FetchRequest* m_fetchRequest;
68 };
69
48 ImageResource* ImageResource::fetch(FetchRequest& request, 70 ImageResource* ImageResource::fetch(FetchRequest& request,
49 ResourceFetcher* fetcher) { 71 ResourceFetcher* fetcher) {
50 if (request.resourceRequest().requestContext() == 72 if (request.resourceRequest().requestContext() ==
51 WebURLRequest::RequestContextUnspecified) { 73 WebURLRequest::RequestContextUnspecified) {
52 request.mutableResourceRequest().setRequestContext( 74 request.mutableResourceRequest().setRequestContext(
53 WebURLRequest::RequestContextImage); 75 WebURLRequest::RequestContextImage);
54 } 76 }
55 if (fetcher->context().pageDismissalEventBeingDispatched()) { 77 if (fetcher->context().pageDismissalEventBeingDispatched()) {
56 KURL requestURL = request.resourceRequest().url(); 78 KURL requestURL = request.resourceRequest().url();
57 if (requestURL.isValid() && 79 if (requestURL.isValid() &&
58 fetcher->context().canRequest(Resource::Image, 80 fetcher->context().canRequest(Resource::Image,
59 request.resourceRequest(), requestURL, 81 request.resourceRequest(), requestURL,
60 request.options(), request.forPreload(), 82 request.options(), request.forPreload(),
61 request.getOriginRestriction())) 83 request.getOriginRestriction()))
62 fetcher->context().sendImagePing(requestURL); 84 fetcher->context().sendImagePing(requestURL);
63 return nullptr; 85 return nullptr;
64 } 86 }
65 87
66 return toImageResource( 88 ImageResource* resource = toImageResource(
67 fetcher->requestResource(request, ImageResourceFactory())); 89 fetcher->requestResource(request, ImageResourceFactory(request)));
90 if (resource &&
91 request.placeholderImageRequestType() != FetchRequest::AllowPlaceholder &&
92 resource->m_isPlaceholder) {
93 // If the image is a placeholder, but this fetch doesn't allow a
94 // placeholder, then load the original image. Note that the cache is not
95 // bypassed here - it should be fine to use a cached copy if possible.
96 resource->reloadIfLoFiOrPlaceholder(fetcher,
97 ReloadCachePolicy::UseExistingPolicy);
98 }
99 return resource;
68 } 100 }
69 101
70 ImageResource::ImageResource(const ResourceRequest& resourceRequest, 102 ImageResource::ImageResource(const ResourceRequest& resourceRequest,
71 const ResourceLoaderOptions& options) 103 const ResourceLoaderOptions& options,
104 bool isPlaceholder)
72 : Resource(resourceRequest, Image, options), 105 : Resource(resourceRequest, Image, options),
73 m_devicePixelRatioHeaderValue(1.0), 106 m_devicePixelRatioHeaderValue(1.0),
74 m_image(nullptr), 107 m_image(nullptr),
75 m_hasDevicePixelRatioHeaderValue(false), 108 m_hasDevicePixelRatioHeaderValue(false),
76 m_isSchedulingReload(false) { 109 m_isSchedulingReload(false),
110 m_isPlaceholder(isPlaceholder) {
77 RESOURCE_LOADING_DVLOG(1) << "new ImageResource(ResourceRequest) " << this; 111 RESOURCE_LOADING_DVLOG(1) << "new ImageResource(ResourceRequest) " << this;
78 } 112 }
79 113
80 ImageResource::ImageResource(blink::Image* image, 114 ImageResource::ImageResource(blink::Image* image,
81 const ResourceLoaderOptions& options) 115 const ResourceLoaderOptions& options)
82 : Resource(ResourceRequest(""), Image, options), 116 : Resource(ResourceRequest(""), Image, options),
83 m_devicePixelRatioHeaderValue(1.0), 117 m_devicePixelRatioHeaderValue(1.0),
84 m_image(image), 118 m_image(image),
85 m_hasDevicePixelRatioHeaderValue(false), 119 m_hasDevicePixelRatioHeaderValue(false),
86 m_isSchedulingReload(false) { 120 m_isSchedulingReload(false),
121 m_isPlaceholder(false) {
87 RESOURCE_LOADING_DVLOG(1) << "new ImageResource(Image) " << this; 122 RESOURCE_LOADING_DVLOG(1) << "new ImageResource(Image) " << this;
88 setStatus(Cached); 123 setStatus(Cached);
89 } 124 }
90 125
91 ImageResource::~ImageResource() { 126 ImageResource::~ImageResource() {
92 RESOURCE_LOADING_DVLOG(1) << "~ImageResource " << this; 127 RESOURCE_LOADING_DVLOG(1) << "~ImageResource " << this;
93 clearImage(); 128 clearImage();
94 } 129 }
95 130
96 DEFINE_TRACE(ImageResource) { 131 DEFINE_TRACE(ImageResource) {
97 visitor->trace(m_multipartParser); 132 visitor->trace(m_multipartParser);
98 Resource::trace(visitor); 133 Resource::trace(visitor);
99 ImageObserver::trace(visitor); 134 ImageObserver::trace(visitor);
100 MultipartImageResourceParser::Client::trace(visitor); 135 MultipartImageResourceParser::Client::trace(visitor);
101 } 136 }
102 137
103 void ImageResource::checkNotify() { 138 void ImageResource::checkNotify() {
104 // Don't notify observers and clients of completion if this ImageResource is 139 // Don't notify observers and clients of completion if this ImageResource is
105 // about to be reloaded. 140 // about to be reloaded.
106 if (m_isSchedulingReload) 141 if (m_isSchedulingReload || shouldReloadBrokenPlaceholder())
107 return; 142 return;
108 143
109 notifyObserversInternal(MarkFinishedOption::ShouldMarkFinished); 144 notifyObserversInternal(MarkFinishedOption::ShouldMarkFinished);
110 Resource::checkNotify(); 145 Resource::checkNotify();
111 } 146 }
112 147
113 void ImageResource::notifyObserversInternal( 148 void ImageResource::notifyObserversInternal(
114 MarkFinishedOption markFinishedOption) { 149 MarkFinishedOption markFinishedOption) {
115 if (isLoading()) 150 if (isLoading())
116 return; 151 return;
(...skipping 12 matching lines...) Expand all
129 m_finishedObservers.add(observer); 164 m_finishedObservers.add(observer);
130 m_observers.remove(observer); 165 m_observers.remove(observer);
131 } 166 }
132 } 167 }
133 168
134 void ImageResource::didAddClient(ResourceClient* client) { 169 void ImageResource::didAddClient(ResourceClient* client) {
135 DCHECK((m_multipartParser && isLoading()) || !data() || m_image); 170 DCHECK((m_multipartParser && isLoading()) || !data() || m_image);
136 171
137 // Don't notify observers and clients of completion if this ImageResource is 172 // Don't notify observers and clients of completion if this ImageResource is
138 // about to be reloaded. 173 // about to be reloaded.
139 if (m_isSchedulingReload) 174 if (m_isSchedulingReload || shouldReloadBrokenPlaceholder())
140 return; 175 return;
141 176
142 Resource::didAddClient(client); 177 Resource::didAddClient(client);
143 } 178 }
144 179
145 void ImageResource::addObserver(ImageResourceObserver* observer) { 180 void ImageResource::addObserver(ImageResourceObserver* observer) {
146 willAddClientOrObserver(MarkAsReferenced); 181 willAddClientOrObserver(MarkAsReferenced);
147 182
148 m_observers.add(observer); 183 m_observers.add(observer);
149 184
150 if (isCacheValidator()) 185 if (isCacheValidator())
151 return; 186 return;
152 187
153 // When the response is not multipart, if |data()| exists, |m_image| must be 188 // When the response is not multipart, if |data()| exists, |m_image| must be
154 // created. This is assured that |updateImage()| is called when |appendData()| 189 // created. This is assured that |updateImage()| is called when |appendData()|
155 // is called. 190 // is called.
156 // 191 //
157 // On the other hand, when the response is multipart, |updateImage()| is not 192 // On the other hand, when the response is multipart, |updateImage()| is not
158 // called in |appendData()|, which means |m_image| might not be created even 193 // called in |appendData()|, which means |m_image| might not be created even
159 // when |data()| exists. This is intentional since creating a |m_image| on 194 // when |data()| exists. This is intentional since creating a |m_image| on
160 // receiving data might destroy an existing image in a previous part. 195 // receiving data might destroy an existing image in a previous part.
161 DCHECK((m_multipartParser && isLoading()) || !data() || m_image); 196 DCHECK((m_multipartParser && isLoading()) || !data() || m_image);
162 197
163 if (m_image && !m_image->isNull()) { 198 if (m_image && !m_image->isNull()) {
164 observer->imageChanged(this); 199 observer->imageChanged(this);
165 } 200 }
166 201
167 if (isLoaded() && !m_isSchedulingReload) { 202 if (isLoaded() && !m_isSchedulingReload && !shouldReloadBrokenPlaceholder()) {
168 markObserverFinished(observer); 203 markObserverFinished(observer);
169 observer->imageNotifyFinished(this); 204 observer->imageNotifyFinished(this);
170 } 205 }
171 } 206 }
172 207
173 void ImageResource::removeObserver(ImageResourceObserver* observer) { 208 void ImageResource::removeObserver(ImageResourceObserver* observer) {
174 DCHECK(observer); 209 DCHECK(observer);
175 210
176 if (m_observers.contains(observer)) 211 if (m_observers.contains(observer))
177 m_observers.remove(observer); 212 m_observers.remove(observer);
(...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after
395 if (data()) { 430 if (data()) {
396 DCHECK(m_image); 431 DCHECK(m_image);
397 sizeAvailable = m_image->setData(data(), allDataReceived); 432 sizeAvailable = m_image->setData(data(), allDataReceived);
398 } 433 }
399 434
400 // Go ahead and tell our observers to try to draw if we have either received 435 // Go ahead and tell our observers to try to draw if we have either received
401 // all the data or the size is known. Each chunk from the network causes 436 // all the data or the size is known. Each chunk from the network causes
402 // observers to repaint, which will force that chunk to decode. 437 // observers to repaint, which will force that chunk to decode.
403 if (sizeAvailable == Image::SizeUnavailable && !allDataReceived) 438 if (sizeAvailable == Image::SizeUnavailable && !allDataReceived)
404 return; 439 return;
440
441 if (m_isPlaceholder && allDataReceived && m_image && !m_image->isNull()) {
442 if (sizeAvailable == Image::SizeAvailable) {
443 // TODO(sclittle): Show the original image if the response consists of the
444 // entire image, such as if the entire image response body is smaller than
445 // the requested range.
446 IntSize dimensions = m_image->size();
447 clearImage();
448 m_image = PlaceholderImage::create(this, dimensions);
449 } else {
450 // Clear the image so that it gets treated like a decoding error, since
451 // the attempt to build a placeholder image failed.
452 clearImage();
453 }
454 }
455
405 if (!m_image || m_image->isNull()) { 456 if (!m_image || m_image->isNull()) {
406 size_t size = encodedSize(); 457 size_t size = encodedSize();
407 clear(); 458 clear();
408 if (!errorOccurred()) 459 if (!errorOccurred())
409 setStatus(DecodeError); 460 setStatus(DecodeError);
410 if (!allDataReceived && loader()) 461 if (!allDataReceived && loader())
411 loader()->didFinishLoading(nullptr, monotonicallyIncreasingTime(), size); 462 loader()->didFinishLoading(nullptr, monotonicallyIncreasingTime(), size);
412 memoryCache()->remove(this); 463 memoryCache()->remove(this);
413 } 464 }
414 465
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after
528 observer->getImageAnimationPolicy(newPolicy)) 579 observer->getImageAnimationPolicy(newPolicy))
529 break; 580 break;
530 } 581 }
531 582
532 if (m_image->animationPolicy() != newPolicy) { 583 if (m_image->animationPolicy() != newPolicy) {
533 m_image->resetAnimation(); 584 m_image->resetAnimation();
534 m_image->setAnimationPolicy(newPolicy); 585 m_image->setAnimationPolicy(newPolicy);
535 } 586 }
536 } 587 }
537 588
538 void ImageResource::reloadIfLoFi(ResourceFetcher* fetcher) { 589 static bool isLoFiImage(const ImageResource& resource) {
539 if (resourceRequest().loFiState() != WebURLRequest::LoFiOn) 590 if (resource.resourceRequest().loFiState() != WebURLRequest::LoFiOn)
540 return; 591 return false;
541 if (isLoaded() && 592 return !resource.isLoaded() ||
542 !response().httpHeaderField("chrome-proxy").contains("q=low")) 593 resource.response().httpHeaderField("chrome-proxy").contains("q=low");
594 }
595
596 void ImageResource::reloadIfLoFiOrPlaceholder(
597 ResourceFetcher* fetcher,
598 ReloadCachePolicy reloadCachePolicy) {
599 if (!m_isPlaceholder && !isLoFiImage(*this))
543 return; 600 return;
544 601
545 // Prevent clients and observers from being notified of completion while the 602 // Prevent clients and observers from being notified of completion while the
546 // reload is being scheduled, so that e.g. canceling an existing load in 603 // reload is being scheduled, so that e.g. canceling an existing load in
547 // progress doesn't cause clients and observers to be notified of completion 604 // progress doesn't cause clients and observers to be notified of completion
548 // prematurely. 605 // prematurely.
549 DCHECK(!m_isSchedulingReload); 606 DCHECK(!m_isSchedulingReload);
550 m_isSchedulingReload = true; 607 m_isSchedulingReload = true;
551 608
552 setCachePolicyBypassingCache(); 609 if (reloadCachePolicy == ReloadCachePolicy::BypassCache)
610 setCachePolicyBypassingCache();
553 setLoFiStateOff(); 611 setLoFiStateOff();
612
613 if (m_isPlaceholder) {
614 m_isPlaceholder = false;
615 clearRangeRequestHeader();
616 }
617
554 if (isLoading()) { 618 if (isLoading()) {
555 loader()->cancel(); 619 loader()->cancel();
556 // Canceling the loader causes error() to be called, which in turn calls 620 // Canceling the loader causes error() to be called, which in turn calls
557 // clear() and notifyObservers(), so there's no need to call these again 621 // clear() and notifyObservers(), so there's no need to call these again
558 // here. 622 // here.
559 } else { 623 } else {
560 clear(); 624 clear();
561 notifyObservers(); 625 notifyObservers();
562 } 626 }
563 627
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
613 WebServiceWorkerResponseTypeOpaque; 677 WebServiceWorkerResponseTypeOpaque;
614 } 678 }
615 if (!getImage()->currentFrameHasSingleSecurityOrigin()) 679 if (!getImage()->currentFrameHasSingleSecurityOrigin())
616 return false; 680 return false;
617 if (passesAccessControlCheck(securityOrigin)) 681 if (passesAccessControlCheck(securityOrigin))
618 return true; 682 return true;
619 return !securityOrigin->taintsCanvas(response().url()); 683 return !securityOrigin->taintsCanvas(response().url());
620 } 684 }
621 685
622 } // namespace blink 686 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698