Chromium Code Reviews| Index: third_party/WebKit/Source/core/loader/resource/ImageResource.cpp |
| diff --git a/third_party/WebKit/Source/core/loader/resource/ImageResource.cpp b/third_party/WebKit/Source/core/loader/resource/ImageResource.cpp |
| index beafff04f6fcd1482b844c2e1f6fbbda4fc7d554..19ebc6c25799f5c3b3203d2a92e318bd911897ec 100644 |
| --- a/third_party/WebKit/Source/core/loader/resource/ImageResource.cpp |
| +++ b/third_party/WebKit/Source/core/loader/resource/ImageResource.cpp |
| @@ -35,6 +35,7 @@ |
| #include "platform/SharedBuffer.h" |
| #include "platform/tracing/TraceEvent.h" |
| #include "public/platform/Platform.h" |
| +#include "public/platform/WebCachePolicy.h" |
| #include "wtf/CurrentTime.h" |
| #include "wtf/StdLibExtras.h" |
| #include <memory> |
| @@ -64,9 +65,6 @@ class ImageResource::ImageResourceInfoImpl final |
| private: |
| const KURL& url() const override { return m_resource->url(); } |
| - bool isSchedulingReload() const override { |
| - return m_resource->m_isSchedulingReload; |
| - } |
| bool hasDevicePixelRatioHeaderValue() const override { |
| return m_resource->m_hasDevicePixelRatioHeaderValue; |
| } |
| @@ -83,10 +81,6 @@ class ImageResource::ImageResourceInfoImpl final |
| bool isCacheValidator() const override { |
| return m_resource->isCacheValidator(); |
| } |
| - bool schedulingReloadOrShouldReloadBrokenPlaceholder() const override { |
| - return m_resource->m_isSchedulingReload || |
| - m_resource->shouldReloadBrokenPlaceholder(); |
| - } |
| bool isAccessAllowed( |
| SecurityOrigin* securityOrigin, |
| DoesCurrentFrameHaveSingleSecurityOrigin |
| @@ -100,6 +94,7 @@ class ImageResource::ImageResourceInfoImpl final |
| const ResourceError& resourceError() const override { |
| return m_resource->resourceError(); |
| } |
| + const ImageResource* resourceForTest() const override { return m_resource; } |
| void decodeError(bool allDataReceived) override { |
| m_resource->decodeError(allDataReceived); |
| @@ -121,6 +116,11 @@ class ImageResource::ImageResourceInfoImpl final |
| WebURLRequest::RequestContextImage, |
| initiatorName); |
| } |
| + bool reloadIfLoFiOrPlaceholderIfNeeded( |
| + ResourceFetcher* fetcherForReload) override { |
| + return m_resource->reloadIfLoFiOrPlaceholderImage(fetcherForReload, |
| + kReloadIfNeeded); |
| + } |
| const Member<ImageResource> m_resource; |
| }; |
| @@ -129,20 +129,26 @@ class ImageResource::ImageResourceFactory : public ResourceFactory { |
| STACK_ALLOCATED(); |
| public: |
| - ImageResourceFactory(const FetchRequest& fetchRequest) |
| - : ResourceFactory(Resource::Image), m_fetchRequest(&fetchRequest) {} |
| + ImageResourceFactory(const FetchRequest& fetchRequest, |
| + ImageResourceContent* content) |
| + : ResourceFactory(Resource::Image), |
| + m_fetchRequest(&fetchRequest), |
| + m_content(content) {} |
| Resource* create(const ResourceRequest& request, |
| const ResourceLoaderOptions& options, |
| const String&) const override { |
| - return new ImageResource(request, options, ImageResourceContent::create(), |
| - m_fetchRequest->placeholderImageRequestType() == |
| - FetchRequest::AllowPlaceholder); |
| + return new ImageResource( |
| + request, options, |
| + m_content ? m_content.get() : ImageResourceContent::create(), |
| + m_fetchRequest->placeholderImageRequestType() == |
| + FetchRequest::AllowPlaceholder); |
| } |
| private: |
| // Weak, unowned pointer. Must outlive |this|. |
| const FetchRequest* m_fetchRequest; |
| + Persistent<ImageResourceContent> m_content; |
| }; |
| ImageResource* ImageResource::fetch(FetchRequest& request, |
| @@ -165,16 +171,18 @@ ImageResource* ImageResource::fetch(FetchRequest& request, |
| return nullptr; |
| } |
| - ImageResource* resource = toImageResource( |
| - fetcher->requestResource(request, ImageResourceFactory(request))); |
| + ImageResource* resource = toImageResource(fetcher->requestResource( |
| + request, ImageResourceFactory(request, nullptr))); |
| if (resource && |
| request.placeholderImageRequestType() != FetchRequest::AllowPlaceholder && |
|
Nate Chapin
2016/12/28 00:14:57
This also seems like a case where we could have Im
hiroshige
2016/12/28 01:04:21
Sounds good, I created a separate CL: https://code
|
| resource->m_isPlaceholder) { |
| // If the image is a placeholder, but this fetch doesn't allow a |
| // placeholder, then load the original image. Note that the cache is not |
| // bypassed here - it should be fine to use a cached copy if possible. |
| - resource->reloadIfLoFiOrPlaceholderImage( |
| + ImageResource* reloadingResource = resource->reloadIfLoFiOrPlaceholderImage( |
| fetcher, kReloadAlwaysWithExistingCachePolicy); |
| + if (reloadingResource) |
| + resource = reloadingResource; |
| } |
| return resource; |
| } |
| @@ -192,7 +200,6 @@ ImageResource::ImageResource(const ResourceRequest& resourceRequest, |
| m_content(content), |
| m_devicePixelRatioHeaderValue(1.0), |
| m_hasDevicePixelRatioHeaderValue(false), |
| - m_isSchedulingReload(false), |
| m_isPlaceholder(isPlaceholder), |
| m_flushTimer(this, &ImageResource::flushImageIfNeeded) { |
| DCHECK(getContent()); |
| @@ -211,28 +218,14 @@ DEFINE_TRACE(ImageResource) { |
| MultipartImageResourceParser::Client::trace(visitor); |
| } |
| -void ImageResource::checkNotify() { |
| - // Don't notify clients of completion if this ImageResource is |
| - // about to be reloaded. |
| - if (m_isSchedulingReload || shouldReloadBrokenPlaceholder()) |
| - return; |
| - |
| - Resource::checkNotify(); |
| -} |
| - |
| bool ImageResource::hasClientsOrObservers() const { |
| - return Resource::hasClientsOrObservers() || getContent()->hasObservers(); |
| + return Resource::hasClientsOrObservers() || |
| + (getContent() && getContent()->hasObservers()); |
| } |
| void ImageResource::didAddClient(ResourceClient* client) { |
| DCHECK((m_multipartParser && isLoading()) || !data() || |
| - getContent()->hasImage()); |
| - |
| - // Don't notify observers and clients of completion if this ImageResource is |
| - // about to be reloaded. |
| - if (m_isSchedulingReload || shouldReloadBrokenPlaceholder()) |
| - return; |
| - |
| + (getContent() && getContent()->hasImage())); |
| Resource::didAddClient(client); |
| } |
| @@ -244,6 +237,8 @@ void ImageResource::destroyDecodedDataForFailedRevalidation() { |
| } |
| void ImageResource::destroyDecodedDataIfPossible() { |
| + if (!getContent()) |
| + return; |
| getContent()->destroyDecodedData(); |
| if (getContent()->hasImage() && !isPreloaded() && |
| getContent()->isRefetchableDataFromDiskCache()) { |
| @@ -253,16 +248,18 @@ void ImageResource::destroyDecodedDataIfPossible() { |
| } |
| void ImageResource::allClientsAndObserversRemoved() { |
| - CHECK(!getContent()->hasImage() || !errorOccurred()); |
| + CHECK(!getContent() || !getContent()->hasImage() || !errorOccurred()); |
| // If possible, delay the resetting until back at the event loop. Doing so |
| // after a conservative GC prevents resetAnimation() from upsetting ongoing |
| // animation updates (crbug.com/613709) |
| - if (!ThreadHeap::willObjectBeLazilySwept(this)) { |
| - Platform::current()->currentThread()->getWebTaskRunner()->postTask( |
| - BLINK_FROM_HERE, WTF::bind(&ImageResourceContent::doResetAnimation, |
| - wrapWeakPersistent(getContent()))); |
| - } else { |
| - getContent()->doResetAnimation(); |
| + if (getContent()) { |
| + if (!ThreadHeap::willObjectBeLazilySwept(this)) { |
| + Platform::current()->currentThread()->getWebTaskRunner()->postTask( |
| + BLINK_FROM_HERE, WTF::bind(&ImageResourceContent::doResetAnimation, |
| + wrapWeakPersistent(getContent()))); |
| + } else { |
| + getContent()->doResetAnimation(); |
| + } |
| } |
| if (m_multipartParser) |
| m_multipartParser->cancel(); |
| @@ -272,6 +269,8 @@ void ImageResource::allClientsAndObserversRemoved() { |
| PassRefPtr<const SharedBuffer> ImageResource::resourceBuffer() const { |
| if (data()) |
| return data(); |
| + if (!getContent()) |
| + return nullptr; |
| return getContent()->resourceBuffer(); |
| } |
| @@ -282,6 +281,9 @@ void ImageResource::appendData(const char* data, size_t length) { |
| } else { |
| Resource::appendData(data, length); |
| + if (!getContent()) |
| + return; |
| + |
| // Update the image immediately if needed. |
| if (getContent()->shouldUpdateImageImmediately()) { |
| updateImage(this->data(), ImageResourceContent::UpdateImage, false); |
| @@ -341,13 +343,15 @@ void ImageResource::updateImageAndClearBuffer() { |
| clearData(); |
| } |
| -void ImageResource::finish(double loadFinishTime) { |
| +void ImageResource::finish(double loadFinishTime, |
| + ResourceFetcher* fetcherForReload) { |
| if (m_multipartParser) { |
| m_multipartParser->finish(); |
| if (data()) |
| updateImageAndClearBuffer(); |
| } else { |
| - updateImage(data(), ImageResourceContent::UpdateImage, true); |
| + updateImage(data(), ImageResourceContent::UpdateImage, true, |
| + fetcherForReload); |
| // As encoded image data can be created from m_image (see |
| // ImageResource::resourceBuffer(), we don't have to keep m_data. Let's |
| // clear this. As for the lifetimes of m_image and m_data, see this |
| @@ -355,17 +359,19 @@ void ImageResource::finish(double loadFinishTime) { |
| // https://docs.google.com/document/d/1v0yTAZ6wkqX2U_M6BNIGUJpM1s0TIw1VsqpxoL7aciY/edit?usp=sharing |
| clearData(); |
| } |
| - Resource::finish(loadFinishTime); |
| + Resource::finish(loadFinishTime, fetcherForReload); |
| } |
| -void ImageResource::error(const ResourceError& error) { |
| +void ImageResource::error(const ResourceError& error, |
| + ResourceFetcher* fetcherForReload) { |
| if (m_multipartParser) |
| m_multipartParser->cancel(); |
| // TODO(hiroshige): Move setEncodedSize() call to Resource::error() if it |
| // is really needed, or remove it otherwise. |
| setEncodedSize(0); |
| - Resource::error(error); |
| - updateImage(nullptr, ImageResourceContent::ClearImageOnly, true); |
| + Resource::error(error, fetcherForReload); |
| + updateImage(nullptr, ImageResourceContent::ClearImageOnly, true, |
| + fetcherForReload); |
| } |
| void ImageResource::responseReceived( |
| @@ -392,6 +398,17 @@ void ImageResource::responseReceived( |
| } |
| } |
| +void ImageResource::detachContent() { |
| + bool hasObservers = getContent() && getContent()->hasObservers(); |
| + |
| + m_content = nullptr; |
| + clearData(); |
| + memoryCache()->remove(this); |
| + |
| + if (hasObservers) |
| + didRemoveClientOrObserver(); |
| +} |
| + |
| static bool isLoFiImage(const ImageResource& resource) { |
| if (resource.resourceRequest().loFiState() != WebURLRequest::LoFiOn) |
| return false; |
| @@ -401,48 +418,44 @@ static bool isLoFiImage(const ImageResource& resource) { |
| .contains("empty-image"); |
| } |
| -void ImageResource::reloadIfLoFiOrPlaceholderImage( |
| +ImageResource* ImageResource::reloadIfLoFiOrPlaceholderImage( |
| ResourceFetcher* fetcher, |
| ReloadLoFiOrPlaceholderPolicy policy) { |
| + if (!fetcher) |
| + return nullptr; |
| if (policy == kReloadIfNeeded && !shouldReloadBrokenPlaceholder()) |
| - return; |
| + return nullptr; |
| if (!m_isPlaceholder && !isLoFiImage(*this)) |
| - return; |
| - |
| - // Prevent clients and observers from being notified of completion while the |
| - // reload is being scheduled, so that e.g. canceling an existing load in |
| - // progress doesn't cause clients and observers to be notified of completion |
| - // prematurely. |
| - DCHECK(!m_isSchedulingReload); |
| - m_isSchedulingReload = true; |
| - |
| - if (policy != kReloadAlwaysWithExistingCachePolicy) |
| - setCachePolicyBypassingCache(); |
| - setLoFiStateOff(); |
| - |
| - if (m_isPlaceholder) { |
| - m_isPlaceholder = false; |
| - clearRangeRequestHeader(); |
| - } |
| - |
| - if (isLoading()) { |
| - loader()->cancel(); |
| - // Canceling the loader causes error() to be called, which in turn calls |
| - // clear() and notifyObservers(), so there's no need to call these again |
| - // here. |
| - } else { |
| - clearData(); |
| - setEncodedSize(0); |
| - updateImage(nullptr, ImageResourceContent::ClearImageOnly, false); |
| - } |
| + return nullptr; |
| - setStatus(NotStarted); |
| + ImageResourceContent* content = getContent(); |
| + if (!content) |
| + return nullptr; |
| - DCHECK(m_isSchedulingReload); |
| - m_isSchedulingReload = false; |
| + // Creates request/options for new ImageResource for reloading. |
| + ResourceRequest reloadingRequest = resourceRequest(); |
| + ResourceLoaderOptions reloadingOptions = options(); |
| - fetcher->startLoad(this); |
| + if (policy != kReloadAlwaysWithExistingCachePolicy) |
| + reloadingRequest.setCachePolicy(WebCachePolicy::BypassingCache); |
| + reloadingRequest.setLoFiState(WebURLRequest::LoFiOff); |
| + if (m_isPlaceholder) |
| + reloadingRequest.clearHTTPHeaderField("range"); |
| + |
| + detachContent(); |
| + // Do not touch |this| after this point. |
| + |
| + FetchRequest fetchRequest( |
| + reloadingRequest, reloadingOptions.initiatorInfo.name, reloadingOptions); |
| + DCHECK_EQ(FetchRequest::DisallowPlaceholder, |
| + fetchRequest.placeholderImageRequestType()); |
| + fetchRequest.setEnforceNewResource(); |
| + |
| + ImageResource* reloadingResource = toImageResource(fetcher->requestResource( |
| + fetchRequest, ImageResourceFactory(fetchRequest, content))); |
| + DCHECK(!reloadingResource || content == reloadingResource->getContent()); |
| + return reloadingResource; |
| } |
| void ImageResource::onePartInMultipartReceived( |
| @@ -504,19 +517,24 @@ const ImageResourceContent* ImageResource::getContent() const { |
| } |
| ResourcePriority ImageResource::priorityFromObservers() { |
| + if (!getContent()) |
| + return ResourcePriority(); |
| return getContent()->priorityFromObservers(); |
| } |
| void ImageResource::updateImage( |
| PassRefPtr<SharedBuffer> sharedBuffer, |
| ImageResourceContent::UpdateImageOption updateImageOption, |
| - bool allDataReceived) { |
| + bool allDataReceived, |
| + ResourceFetcher* fetcherForReload) { |
| + if (!getContent()) |
| + return; |
| if (!m_isUpdateImageCalled && |
| updateImageOption == ImageResourceContent::UpdateImage) |
| updateImageOption = ImageResourceContent::ClearAndUpdateImage; |
| m_isUpdateImageCalled = true; |
| getContent()->updateImage(std::move(sharedBuffer), updateImageOption, |
| - allDataReceived); |
| + allDataReceived, fetcherForReload); |
| } |
| } // namespace blink |