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