OLD | NEW |
---|---|
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 Loading... | |
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, | |
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; | |
Nate Chapin
2016/10/18 18:23:17
Instead of stashing the FetchRequest here and addi
sclittle
2016/10/18 23:53:03
I'm hesitant to just detect the range header, sinc
| |
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, false); | |
97 } | |
98 return resource; | |
68 } | 99 } |
69 | 100 |
70 ImageResource::ImageResource(const ResourceRequest& resourceRequest, | 101 ImageResource::ImageResource(const ResourceRequest& resourceRequest, |
71 const ResourceLoaderOptions& options) | 102 const ResourceLoaderOptions& options, |
103 bool isPlaceholder) | |
72 : Resource(resourceRequest, Image, options), | 104 : Resource(resourceRequest, Image, options), |
73 m_devicePixelRatioHeaderValue(1.0), | 105 m_devicePixelRatioHeaderValue(1.0), |
74 m_image(nullptr), | 106 m_image(nullptr), |
75 m_hasDevicePixelRatioHeaderValue(false), | 107 m_hasDevicePixelRatioHeaderValue(false), |
76 m_isSchedulingReload(false) { | 108 m_isSchedulingReload(false), |
109 m_isPlaceholder(isPlaceholder) { | |
77 RESOURCE_LOADING_DVLOG(1) << "new ImageResource(ResourceRequest) " << this; | 110 RESOURCE_LOADING_DVLOG(1) << "new ImageResource(ResourceRequest) " << this; |
78 } | 111 } |
79 | 112 |
80 ImageResource::ImageResource(blink::Image* image, | 113 ImageResource::ImageResource(blink::Image* image, |
81 const ResourceLoaderOptions& options) | 114 const ResourceLoaderOptions& options) |
82 : Resource(ResourceRequest(""), Image, options), | 115 : Resource(ResourceRequest(""), Image, options), |
83 m_devicePixelRatioHeaderValue(1.0), | 116 m_devicePixelRatioHeaderValue(1.0), |
84 m_image(image), | 117 m_image(image), |
85 m_hasDevicePixelRatioHeaderValue(false), | 118 m_hasDevicePixelRatioHeaderValue(false), |
86 m_isSchedulingReload(false) { | 119 m_isSchedulingReload(false), |
120 m_isPlaceholder(false) { | |
87 RESOURCE_LOADING_DVLOG(1) << "new ImageResource(Image) " << this; | 121 RESOURCE_LOADING_DVLOG(1) << "new ImageResource(Image) " << this; |
88 setStatus(Cached); | 122 setStatus(Cached); |
89 } | 123 } |
90 | 124 |
91 ImageResource::~ImageResource() { | 125 ImageResource::~ImageResource() { |
92 RESOURCE_LOADING_DVLOG(1) << "~ImageResource " << this; | 126 RESOURCE_LOADING_DVLOG(1) << "~ImageResource " << this; |
93 clearImage(); | 127 clearImage(); |
94 } | 128 } |
95 | 129 |
96 DEFINE_TRACE(ImageResource) { | 130 DEFINE_TRACE(ImageResource) { |
97 visitor->trace(m_multipartParser); | 131 visitor->trace(m_multipartParser); |
98 Resource::trace(visitor); | 132 Resource::trace(visitor); |
99 ImageObserver::trace(visitor); | 133 ImageObserver::trace(visitor); |
100 MultipartImageResourceParser::Client::trace(visitor); | 134 MultipartImageResourceParser::Client::trace(visitor); |
101 } | 135 } |
102 | 136 |
103 void ImageResource::checkNotify() { | 137 void ImageResource::checkNotify() { |
104 // Don't notify observers and clients of completion if this ImageResource is | 138 // Don't notify observers and clients of completion if this ImageResource is |
105 // about to be reloaded. | 139 // about to be reloaded. |
106 if (m_isSchedulingReload) | 140 if (m_isSchedulingReload || shouldReloadBrokenPlaceholder()) |
107 return; | 141 return; |
108 | 142 |
109 notifyObserversInternal(MarkFinishedOption::ShouldMarkFinished); | 143 notifyObserversInternal(MarkFinishedOption::ShouldMarkFinished); |
110 Resource::checkNotify(); | 144 Resource::checkNotify(); |
111 } | 145 } |
112 | 146 |
113 void ImageResource::notifyObserversInternal( | 147 void ImageResource::notifyObserversInternal( |
114 MarkFinishedOption markFinishedOption) { | 148 MarkFinishedOption markFinishedOption) { |
115 if (isLoading()) | 149 if (isLoading()) |
116 return; | 150 return; |
(...skipping 12 matching lines...) Expand all Loading... | |
129 m_finishedObservers.add(observer); | 163 m_finishedObservers.add(observer); |
130 m_observers.remove(observer); | 164 m_observers.remove(observer); |
131 } | 165 } |
132 } | 166 } |
133 | 167 |
134 void ImageResource::didAddClient(ResourceClient* client) { | 168 void ImageResource::didAddClient(ResourceClient* client) { |
135 DCHECK((m_multipartParser && isLoading()) || !data() || m_image); | 169 DCHECK((m_multipartParser && isLoading()) || !data() || m_image); |
136 | 170 |
137 // Don't notify observers and clients of completion if this ImageResource is | 171 // Don't notify observers and clients of completion if this ImageResource is |
138 // about to be reloaded. | 172 // about to be reloaded. |
139 if (m_isSchedulingReload) | 173 if (m_isSchedulingReload || shouldReloadBrokenPlaceholder()) |
140 return; | 174 return; |
141 | 175 |
142 Resource::didAddClient(client); | 176 Resource::didAddClient(client); |
143 } | 177 } |
144 | 178 |
145 void ImageResource::addObserver(ImageResourceObserver* observer) { | 179 void ImageResource::addObserver(ImageResourceObserver* observer) { |
146 willAddClientOrObserver(MarkAsReferenced); | 180 willAddClientOrObserver(MarkAsReferenced); |
147 | 181 |
148 m_observers.add(observer); | 182 m_observers.add(observer); |
149 | 183 |
150 if (isCacheValidator()) | 184 if (isCacheValidator()) |
151 return; | 185 return; |
152 | 186 |
153 // When the response is not multipart, if |data()| exists, |m_image| must be | 187 // When the response is not multipart, if |data()| exists, |m_image| must be |
154 // created. This is assured that |updateImage()| is called when |appendData()| | 188 // created. This is assured that |updateImage()| is called when |appendData()| |
155 // is called. | 189 // is called. |
156 // | 190 // |
157 // On the other hand, when the response is multipart, |updateImage()| is not | 191 // 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 | 192 // 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 | 193 // when |data()| exists. This is intentional since creating a |m_image| on |
160 // receiving data might destroy an existing image in a previous part. | 194 // receiving data might destroy an existing image in a previous part. |
161 DCHECK((m_multipartParser && isLoading()) || !data() || m_image); | 195 DCHECK((m_multipartParser && isLoading()) || !data() || m_image); |
162 | 196 |
163 if (m_image && !m_image->isNull()) { | 197 if (m_image && !m_image->isNull()) { |
164 observer->imageChanged(this); | 198 observer->imageChanged(this); |
165 } | 199 } |
166 | 200 |
167 if (isLoaded() && !m_isSchedulingReload) { | 201 if (isLoaded() && !m_isSchedulingReload && !shouldReloadBrokenPlaceholder()) { |
168 markObserverFinished(observer); | 202 markObserverFinished(observer); |
169 observer->imageNotifyFinished(this); | 203 observer->imageNotifyFinished(this); |
170 } | 204 } |
171 } | 205 } |
172 | 206 |
173 void ImageResource::removeObserver(ImageResourceObserver* observer) { | 207 void ImageResource::removeObserver(ImageResourceObserver* observer) { |
174 DCHECK(observer); | 208 DCHECK(observer); |
175 | 209 |
176 if (m_observers.contains(observer)) | 210 if (m_observers.contains(observer)) |
177 m_observers.remove(observer); | 211 m_observers.remove(observer); |
(...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
395 if (data()) { | 429 if (data()) { |
396 DCHECK(m_image); | 430 DCHECK(m_image); |
397 sizeAvailable = m_image->setData(data(), allDataReceived); | 431 sizeAvailable = m_image->setData(data(), allDataReceived); |
398 } | 432 } |
399 | 433 |
400 // Go ahead and tell our observers to try to draw if we have either received | 434 // 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 | 435 // 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. | 436 // observers to repaint, which will force that chunk to decode. |
403 if (sizeAvailable == Image::SizeUnavailable && !allDataReceived) | 437 if (sizeAvailable == Image::SizeUnavailable && !allDataReceived) |
404 return; | 438 return; |
439 | |
440 if (m_isPlaceholder && allDataReceived && m_image && !m_image->isNull()) { | |
441 if (sizeAvailable == Image::SizeAvailable) { | |
442 // TODO(sclittle): Show the original image if the response consists of the | |
443 // entire image, such as if the entire image response body is smaller than | |
444 // the requested range. | |
445 IntSize dimensions = m_image->size(); | |
446 clearImage(); | |
447 m_image = PlaceholderImage::create(this, dimensions); | |
448 } else { | |
449 // Clear the image so that it gets treated like a decoding error, since | |
450 // the attempt to build a placeholder image failed. | |
451 clearImage(); | |
452 } | |
453 } | |
454 | |
405 if (!m_image || m_image->isNull()) { | 455 if (!m_image || m_image->isNull()) { |
406 size_t size = encodedSize(); | 456 size_t size = encodedSize(); |
407 clear(); | 457 clear(); |
408 if (!errorOccurred()) | 458 if (!errorOccurred()) |
409 setStatus(DecodeError); | 459 setStatus(DecodeError); |
410 if (!allDataReceived && loader()) | 460 if (!allDataReceived && loader()) |
411 loader()->didFinishLoading(nullptr, monotonicallyIncreasingTime(), size); | 461 loader()->didFinishLoading(nullptr, monotonicallyIncreasingTime(), size); |
412 memoryCache()->remove(this); | 462 memoryCache()->remove(this); |
413 } | 463 } |
414 | 464 |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
528 observer->getImageAnimationPolicy(newPolicy)) | 578 observer->getImageAnimationPolicy(newPolicy)) |
529 break; | 579 break; |
530 } | 580 } |
531 | 581 |
532 if (m_image->animationPolicy() != newPolicy) { | 582 if (m_image->animationPolicy() != newPolicy) { |
533 m_image->resetAnimation(); | 583 m_image->resetAnimation(); |
534 m_image->setAnimationPolicy(newPolicy); | 584 m_image->setAnimationPolicy(newPolicy); |
535 } | 585 } |
536 } | 586 } |
537 | 587 |
538 void ImageResource::reloadIfLoFi(ResourceFetcher* fetcher) { | 588 void ImageResource::reloadIfLoFiOrPlaceholder(ResourceFetcher* fetcher, |
539 if (resourceRequest().loFiState() != WebURLRequest::LoFiOn) | 589 bool bypassCache) { |
Nate Chapin
2016/10/18 18:23:17
bypassCache should probably be an enum.
sclittle
2016/10/18 23:53:03
Done.
| |
590 if (!m_isPlaceholder && | |
Nate Chapin
2016/10/18 18:23:17
This if-statement is sufficiently complex that it
sclittle
2016/10/18 23:53:03
Done.
| |
591 (resourceRequest().loFiState() != WebURLRequest::LoFiOn || | |
592 (isLoaded() && | |
593 !response().httpHeaderField("chrome-proxy").contains("q=low")))) { | |
540 return; | 594 return; |
541 if (isLoaded() && | 595 } |
542 !response().httpHeaderField("chrome-proxy").contains("q=low")) | |
543 return; | |
544 | 596 |
545 // Prevent clients and observers from being notified of completion while the | 597 // 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 | 598 // 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 | 599 // progress doesn't cause clients and observers to be notified of completion |
548 // prematurely. | 600 // prematurely. |
549 DCHECK(!m_isSchedulingReload); | 601 DCHECK(!m_isSchedulingReload); |
550 m_isSchedulingReload = true; | 602 m_isSchedulingReload = true; |
551 | 603 |
552 setCachePolicyBypassingCache(); | 604 if (bypassCache) |
605 setCachePolicyBypassingCache(); | |
553 setLoFiStateOff(); | 606 setLoFiStateOff(); |
607 | |
608 if (m_isPlaceholder) { | |
609 m_isPlaceholder = false; | |
610 clearRangeRequestHeader(); | |
611 } | |
612 | |
554 if (isLoading()) { | 613 if (isLoading()) { |
555 loader()->cancel(); | 614 loader()->cancel(); |
556 // Canceling the loader causes error() to be called, which in turn calls | 615 // 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 | 616 // clear() and notifyObservers(), so there's no need to call these again |
558 // here. | 617 // here. |
559 } else { | 618 } else { |
560 clear(); | 619 clear(); |
561 notifyObservers(); | 620 notifyObservers(); |
562 } | 621 } |
563 | 622 |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
613 WebServiceWorkerResponseTypeOpaque; | 672 WebServiceWorkerResponseTypeOpaque; |
614 } | 673 } |
615 if (!getImage()->currentFrameHasSingleSecurityOrigin()) | 674 if (!getImage()->currentFrameHasSingleSecurityOrigin()) |
616 return false; | 675 return false; |
617 if (passesAccessControlCheck(securityOrigin)) | 676 if (passesAccessControlCheck(securityOrigin)) |
618 return true; | 677 return true; |
619 return !securityOrigin->taintsCanvas(response().url()); | 678 return !securityOrigin->taintsCanvas(response().url()); |
620 } | 679 } |
621 | 680 |
622 } // namespace blink | 681 } // namespace blink |
OLD | NEW |