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 17 matching lines...) Expand all Loading... | |
| 28 #include "core/fetch/ResourceFetcher.h" | 28 #include "core/fetch/ResourceFetcher.h" |
| 29 #include "core/fetch/ResourceLoader.h" | 29 #include "core/fetch/ResourceLoader.h" |
| 30 #include "core/fetch/ResourceLoadingLog.h" | 30 #include "core/fetch/ResourceLoadingLog.h" |
| 31 #include "core/loader/resource/ImageResourceContent.h" | 31 #include "core/loader/resource/ImageResourceContent.h" |
| 32 #include "core/loader/resource/ImageResourceInfo.h" | 32 #include "core/loader/resource/ImageResourceInfo.h" |
| 33 #include "platform/Histogram.h" | 33 #include "platform/Histogram.h" |
| 34 #include "platform/RuntimeEnabledFeatures.h" | 34 #include "platform/RuntimeEnabledFeatures.h" |
| 35 #include "platform/SharedBuffer.h" | 35 #include "platform/SharedBuffer.h" |
| 36 #include "platform/tracing/TraceEvent.h" | 36 #include "platform/tracing/TraceEvent.h" |
| 37 #include "public/platform/Platform.h" | 37 #include "public/platform/Platform.h" |
| 38 #include "public/platform/WebCachePolicy.h" | |
| 38 #include "wtf/CurrentTime.h" | 39 #include "wtf/CurrentTime.h" |
| 39 #include "wtf/StdLibExtras.h" | 40 #include "wtf/StdLibExtras.h" |
| 40 #include <memory> | 41 #include <memory> |
| 41 #include <v8.h> | 42 #include <v8.h> |
| 42 | 43 |
| 43 namespace blink { | 44 namespace blink { |
| 44 namespace { | 45 namespace { |
| 45 // The amount of time to wait before informing the clients that the image has | 46 // The amount of time to wait before informing the clients that the image has |
| 46 // been updated (in seconds). This effectively throttles invalidations that | 47 // been updated (in seconds). This effectively throttles invalidations that |
| 47 // result from new data arriving for this image. | 48 // result from new data arriving for this image. |
| 48 constexpr double kFlushDelaySeconds = 1.; | 49 constexpr double kFlushDelaySeconds = 1.; |
| 49 } // namespace | 50 } // namespace |
| 50 | 51 |
| 51 class ImageResource::ImageResourceInfoImpl final | 52 class ImageResource::ImageResourceInfoImpl final |
| 52 : public GarbageCollectedFinalized<ImageResourceInfoImpl>, | 53 : public GarbageCollectedFinalized<ImageResourceInfoImpl>, |
| 53 public ImageResourceInfo { | 54 public ImageResourceInfo { |
| 54 USING_GARBAGE_COLLECTED_MIXIN(ImageResourceInfoImpl); | 55 USING_GARBAGE_COLLECTED_MIXIN(ImageResourceInfoImpl); |
| 55 | 56 |
| 56 public: | 57 public: |
| 57 ImageResourceInfoImpl(ImageResource* resource) : m_resource(resource) { | 58 ImageResourceInfoImpl(ImageResource* resource) : m_resource(resource) { |
| 58 DCHECK(m_resource); | 59 DCHECK(m_resource); |
| 59 } | 60 } |
| 60 DEFINE_INLINE_VIRTUAL_TRACE() { | 61 DEFINE_INLINE_VIRTUAL_TRACE() { |
| 61 visitor->trace(m_resource); | 62 visitor->trace(m_resource); |
| 62 ImageResourceInfo::trace(visitor); | 63 ImageResourceInfo::trace(visitor); |
| 63 } | 64 } |
| 64 | 65 |
| 65 private: | 66 private: |
| 66 const KURL& url() const override { return m_resource->url(); } | 67 const KURL& url() const override { return m_resource->url(); } |
| 67 bool isSchedulingReload() const override { | |
| 68 return m_resource->m_isSchedulingReload; | |
| 69 } | |
| 70 bool hasDevicePixelRatioHeaderValue() const override { | 68 bool hasDevicePixelRatioHeaderValue() const override { |
| 71 return m_resource->m_hasDevicePixelRatioHeaderValue; | 69 return m_resource->m_hasDevicePixelRatioHeaderValue; |
| 72 } | 70 } |
| 73 float devicePixelRatioHeaderValue() const override { | 71 float devicePixelRatioHeaderValue() const override { |
| 74 return m_resource->m_devicePixelRatioHeaderValue; | 72 return m_resource->m_devicePixelRatioHeaderValue; |
| 75 } | 73 } |
| 76 const ResourceResponse& response() const override { | 74 const ResourceResponse& response() const override { |
| 77 return m_resource->response(); | 75 return m_resource->response(); |
| 78 } | 76 } |
| 79 Resource::Status getStatus() const override { | 77 Resource::Status getStatus() const override { |
| 80 return m_resource->getStatus(); | 78 return m_resource->getStatus(); |
| 81 } | 79 } |
| 82 bool isPlaceholder() const override { return m_resource->isPlaceholder(); } | 80 bool isPlaceholder() const override { return m_resource->isPlaceholder(); } |
| 83 bool isCacheValidator() const override { | 81 bool isCacheValidator() const override { |
| 84 return m_resource->isCacheValidator(); | 82 return m_resource->isCacheValidator(); |
| 85 } | 83 } |
| 86 bool schedulingReloadOrShouldReloadBrokenPlaceholder() const override { | |
| 87 return m_resource->m_isSchedulingReload || | |
| 88 m_resource->shouldReloadBrokenPlaceholder(); | |
| 89 } | |
| 90 bool isAccessAllowed( | 84 bool isAccessAllowed( |
| 91 SecurityOrigin* securityOrigin, | 85 SecurityOrigin* securityOrigin, |
| 92 DoesCurrentFrameHaveSingleSecurityOrigin | 86 DoesCurrentFrameHaveSingleSecurityOrigin |
| 93 doesCurrentFrameHasSingleSecurityOrigin) const override { | 87 doesCurrentFrameHasSingleSecurityOrigin) const override { |
| 94 return m_resource->isAccessAllowed(securityOrigin, | 88 return m_resource->isAccessAllowed(securityOrigin, |
| 95 doesCurrentFrameHasSingleSecurityOrigin); | 89 doesCurrentFrameHasSingleSecurityOrigin); |
| 96 } | 90 } |
| 97 bool hasCacheControlNoStoreHeader() const override { | 91 bool hasCacheControlNoStoreHeader() const override { |
| 98 return m_resource->hasCacheControlNoStoreHeader(); | 92 return m_resource->hasCacheControlNoStoreHeader(); |
| 99 } | 93 } |
| 100 const ResourceError& resourceError() const override { | 94 const ResourceError& resourceError() const override { |
| 101 return m_resource->resourceError(); | 95 return m_resource->resourceError(); |
| 102 } | 96 } |
| 97 const ImageResource* resourceForTest() const override { return m_resource; } | |
| 103 | 98 |
| 104 void decodeError(bool allDataReceived) override { | 99 void decodeError(bool allDataReceived) override { |
| 105 m_resource->decodeError(allDataReceived); | 100 m_resource->decodeError(allDataReceived); |
| 106 } | 101 } |
| 107 void setDecodedSize(size_t size) override { | 102 void setDecodedSize(size_t size) override { |
| 108 m_resource->setDecodedSize(size); | 103 m_resource->setDecodedSize(size); |
| 109 } | 104 } |
| 110 void willAddClientOrObserver() override { | 105 void willAddClientOrObserver() override { |
| 111 m_resource->willAddClientOrObserver(Resource::MarkAsReferenced); | 106 m_resource->willAddClientOrObserver(Resource::MarkAsReferenced); |
| 112 } | 107 } |
| 113 void didRemoveClientOrObserver() override { | 108 void didRemoveClientOrObserver() override { |
| 114 m_resource->didRemoveClientOrObserver(); | 109 m_resource->didRemoveClientOrObserver(); |
| 115 } | 110 } |
| 116 void emulateLoadStartedForInspector( | 111 void emulateLoadStartedForInspector( |
| 117 ResourceFetcher* fetcher, | 112 ResourceFetcher* fetcher, |
| 118 const KURL& url, | 113 const KURL& url, |
| 119 const AtomicString& initiatorName) override { | 114 const AtomicString& initiatorName) override { |
| 120 fetcher->emulateLoadStartedForInspector(m_resource.get(), url, | 115 fetcher->emulateLoadStartedForInspector(m_resource.get(), url, |
| 121 WebURLRequest::RequestContextImage, | 116 WebURLRequest::RequestContextImage, |
| 122 initiatorName); | 117 initiatorName); |
| 123 } | 118 } |
| 119 bool reloadIfLoFiOrPlaceholderIfNeeded( | |
| 120 ResourceFetcher* fetcherForReload) override { | |
| 121 return m_resource->reloadIfLoFiOrPlaceholderImage(fetcherForReload, | |
| 122 kReloadIfNeeded); | |
| 123 } | |
| 124 | 124 |
| 125 const Member<ImageResource> m_resource; | 125 const Member<ImageResource> m_resource; |
| 126 }; | 126 }; |
| 127 | 127 |
| 128 class ImageResource::ImageResourceFactory : public ResourceFactory { | 128 class ImageResource::ImageResourceFactory : public ResourceFactory { |
| 129 STACK_ALLOCATED(); | 129 STACK_ALLOCATED(); |
| 130 | 130 |
| 131 public: | 131 public: |
| 132 ImageResourceFactory(const FetchRequest& fetchRequest) | 132 ImageResourceFactory(const FetchRequest& fetchRequest, |
| 133 : ResourceFactory(Resource::Image), m_fetchRequest(&fetchRequest) {} | 133 ImageResourceContent* content) |
| 134 : ResourceFactory(Resource::Image), | |
| 135 m_fetchRequest(&fetchRequest), | |
| 136 m_content(content) {} | |
| 134 | 137 |
| 135 Resource* create(const ResourceRequest& request, | 138 Resource* create(const ResourceRequest& request, |
| 136 const ResourceLoaderOptions& options, | 139 const ResourceLoaderOptions& options, |
| 137 const String&) const override { | 140 const String&) const override { |
| 138 return new ImageResource(request, options, ImageResourceContent::create(), | 141 return new ImageResource( |
| 139 m_fetchRequest->placeholderImageRequestType() == | 142 request, options, |
| 140 FetchRequest::AllowPlaceholder); | 143 m_content ? m_content.get() : ImageResourceContent::create(), |
| 144 m_fetchRequest->placeholderImageRequestType() == | |
| 145 FetchRequest::AllowPlaceholder); | |
| 141 } | 146 } |
| 142 | 147 |
| 143 private: | 148 private: |
| 144 // Weak, unowned pointer. Must outlive |this|. | 149 // Weak, unowned pointer. Must outlive |this|. |
| 145 const FetchRequest* m_fetchRequest; | 150 const FetchRequest* m_fetchRequest; |
| 151 Persistent<ImageResourceContent> m_content; | |
| 146 }; | 152 }; |
| 147 | 153 |
| 148 ImageResource* ImageResource::fetch(FetchRequest& request, | 154 ImageResource* ImageResource::fetch(FetchRequest& request, |
| 149 ResourceFetcher* fetcher) { | 155 ResourceFetcher* fetcher) { |
| 150 if (request.resourceRequest().requestContext() == | 156 if (request.resourceRequest().requestContext() == |
| 151 WebURLRequest::RequestContextUnspecified) { | 157 WebURLRequest::RequestContextUnspecified) { |
| 152 request.mutableResourceRequest().setRequestContext( | 158 request.mutableResourceRequest().setRequestContext( |
| 153 WebURLRequest::RequestContextImage); | 159 WebURLRequest::RequestContextImage); |
| 154 } | 160 } |
| 155 if (fetcher->context().pageDismissalEventBeingDispatched()) { | 161 if (fetcher->context().pageDismissalEventBeingDispatched()) { |
| 156 KURL requestURL = request.resourceRequest().url(); | 162 KURL requestURL = request.resourceRequest().url(); |
| 157 if (requestURL.isValid()) { | 163 if (requestURL.isValid()) { |
| 158 ResourceRequestBlockedReason blockReason = fetcher->context().canRequest( | 164 ResourceRequestBlockedReason blockReason = fetcher->context().canRequest( |
| 159 Resource::Image, request.resourceRequest(), requestURL, | 165 Resource::Image, request.resourceRequest(), requestURL, |
| 160 request.options(), request.forPreload(), | 166 request.options(), request.forPreload(), |
| 161 request.getOriginRestriction()); | 167 request.getOriginRestriction()); |
| 162 if (blockReason == ResourceRequestBlockedReason::None) | 168 if (blockReason == ResourceRequestBlockedReason::None) |
| 163 fetcher->context().sendImagePing(requestURL); | 169 fetcher->context().sendImagePing(requestURL); |
| 164 } | 170 } |
| 165 return nullptr; | 171 return nullptr; |
| 166 } | 172 } |
| 167 | 173 |
| 168 ImageResource* resource = toImageResource( | 174 ImageResource* resource = toImageResource(fetcher->requestResource( |
| 169 fetcher->requestResource(request, ImageResourceFactory(request))); | 175 request, ImageResourceFactory(request, nullptr))); |
| 170 if (resource && | 176 if (resource && |
| 171 request.placeholderImageRequestType() != FetchRequest::AllowPlaceholder && | 177 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
| |
| 172 resource->m_isPlaceholder) { | 178 resource->m_isPlaceholder) { |
| 173 // If the image is a placeholder, but this fetch doesn't allow a | 179 // If the image is a placeholder, but this fetch doesn't allow a |
| 174 // placeholder, then load the original image. Note that the cache is not | 180 // placeholder, then load the original image. Note that the cache is not |
| 175 // bypassed here - it should be fine to use a cached copy if possible. | 181 // bypassed here - it should be fine to use a cached copy if possible. |
| 176 resource->reloadIfLoFiOrPlaceholderImage( | 182 ImageResource* reloadingResource = resource->reloadIfLoFiOrPlaceholderImage( |
| 177 fetcher, kReloadAlwaysWithExistingCachePolicy); | 183 fetcher, kReloadAlwaysWithExistingCachePolicy); |
| 184 if (reloadingResource) | |
| 185 resource = reloadingResource; | |
| 178 } | 186 } |
| 179 return resource; | 187 return resource; |
| 180 } | 188 } |
| 181 | 189 |
| 182 ImageResource* ImageResource::create(const ResourceRequest& request) { | 190 ImageResource* ImageResource::create(const ResourceRequest& request) { |
| 183 return new ImageResource(request, ResourceLoaderOptions(), | 191 return new ImageResource(request, ResourceLoaderOptions(), |
| 184 ImageResourceContent::create(), false); | 192 ImageResourceContent::create(), false); |
| 185 } | 193 } |
| 186 | 194 |
| 187 ImageResource::ImageResource(const ResourceRequest& resourceRequest, | 195 ImageResource::ImageResource(const ResourceRequest& resourceRequest, |
| 188 const ResourceLoaderOptions& options, | 196 const ResourceLoaderOptions& options, |
| 189 ImageResourceContent* content, | 197 ImageResourceContent* content, |
| 190 bool isPlaceholder) | 198 bool isPlaceholder) |
| 191 : Resource(resourceRequest, Image, options), | 199 : Resource(resourceRequest, Image, options), |
| 192 m_content(content), | 200 m_content(content), |
| 193 m_devicePixelRatioHeaderValue(1.0), | 201 m_devicePixelRatioHeaderValue(1.0), |
| 194 m_hasDevicePixelRatioHeaderValue(false), | 202 m_hasDevicePixelRatioHeaderValue(false), |
| 195 m_isSchedulingReload(false), | |
| 196 m_isPlaceholder(isPlaceholder), | 203 m_isPlaceholder(isPlaceholder), |
| 197 m_flushTimer(this, &ImageResource::flushImageIfNeeded) { | 204 m_flushTimer(this, &ImageResource::flushImageIfNeeded) { |
| 198 DCHECK(getContent()); | 205 DCHECK(getContent()); |
| 199 RESOURCE_LOADING_DVLOG(1) << "new ImageResource(ResourceRequest) " << this; | 206 RESOURCE_LOADING_DVLOG(1) << "new ImageResource(ResourceRequest) " << this; |
| 200 getContent()->setImageResourceInfo(new ImageResourceInfoImpl(this)); | 207 getContent()->setImageResourceInfo(new ImageResourceInfoImpl(this)); |
| 201 } | 208 } |
| 202 | 209 |
| 203 ImageResource::~ImageResource() { | 210 ImageResource::~ImageResource() { |
| 204 RESOURCE_LOADING_DVLOG(1) << "~ImageResource " << this; | 211 RESOURCE_LOADING_DVLOG(1) << "~ImageResource " << this; |
| 205 } | 212 } |
| 206 | 213 |
| 207 DEFINE_TRACE(ImageResource) { | 214 DEFINE_TRACE(ImageResource) { |
| 208 visitor->trace(m_multipartParser); | 215 visitor->trace(m_multipartParser); |
| 209 visitor->trace(m_content); | 216 visitor->trace(m_content); |
| 210 Resource::trace(visitor); | 217 Resource::trace(visitor); |
| 211 MultipartImageResourceParser::Client::trace(visitor); | 218 MultipartImageResourceParser::Client::trace(visitor); |
| 212 } | 219 } |
| 213 | 220 |
| 214 void ImageResource::checkNotify() { | |
| 215 // Don't notify clients of completion if this ImageResource is | |
| 216 // about to be reloaded. | |
| 217 if (m_isSchedulingReload || shouldReloadBrokenPlaceholder()) | |
| 218 return; | |
| 219 | |
| 220 Resource::checkNotify(); | |
| 221 } | |
| 222 | |
| 223 bool ImageResource::hasClientsOrObservers() const { | 221 bool ImageResource::hasClientsOrObservers() const { |
| 224 return Resource::hasClientsOrObservers() || getContent()->hasObservers(); | 222 return Resource::hasClientsOrObservers() || |
| 223 (getContent() && getContent()->hasObservers()); | |
| 225 } | 224 } |
| 226 | 225 |
| 227 void ImageResource::didAddClient(ResourceClient* client) { | 226 void ImageResource::didAddClient(ResourceClient* client) { |
| 228 DCHECK((m_multipartParser && isLoading()) || !data() || | 227 DCHECK((m_multipartParser && isLoading()) || !data() || |
| 229 getContent()->hasImage()); | 228 (getContent() && getContent()->hasImage())); |
| 230 | |
| 231 // Don't notify observers and clients of completion if this ImageResource is | |
| 232 // about to be reloaded. | |
| 233 if (m_isSchedulingReload || shouldReloadBrokenPlaceholder()) | |
| 234 return; | |
| 235 | |
| 236 Resource::didAddClient(client); | 229 Resource::didAddClient(client); |
| 237 } | 230 } |
| 238 | 231 |
| 239 void ImageResource::destroyDecodedDataForFailedRevalidation() { | 232 void ImageResource::destroyDecodedDataForFailedRevalidation() { |
| 240 // Clears the image, as we must create a new image for the failed | 233 // Clears the image, as we must create a new image for the failed |
| 241 // revalidation response. | 234 // revalidation response. |
| 242 updateImage(nullptr, ImageResourceContent::ClearAndUpdateImage, false); | 235 updateImage(nullptr, ImageResourceContent::ClearAndUpdateImage, false); |
| 243 setDecodedSize(0); | 236 setDecodedSize(0); |
| 244 } | 237 } |
| 245 | 238 |
| 246 void ImageResource::destroyDecodedDataIfPossible() { | 239 void ImageResource::destroyDecodedDataIfPossible() { |
| 240 if (!getContent()) | |
| 241 return; | |
| 247 getContent()->destroyDecodedData(); | 242 getContent()->destroyDecodedData(); |
| 248 if (getContent()->hasImage() && !isPreloaded() && | 243 if (getContent()->hasImage() && !isPreloaded() && |
| 249 getContent()->isRefetchableDataFromDiskCache()) { | 244 getContent()->isRefetchableDataFromDiskCache()) { |
| 250 UMA_HISTOGRAM_MEMORY_KB("Memory.Renderer.EstimatedDroppableEncodedSize", | 245 UMA_HISTOGRAM_MEMORY_KB("Memory.Renderer.EstimatedDroppableEncodedSize", |
| 251 encodedSize() / 1024); | 246 encodedSize() / 1024); |
| 252 } | 247 } |
| 253 } | 248 } |
| 254 | 249 |
| 255 void ImageResource::allClientsAndObserversRemoved() { | 250 void ImageResource::allClientsAndObserversRemoved() { |
| 256 CHECK(!getContent()->hasImage() || !errorOccurred()); | 251 CHECK(!getContent() || !getContent()->hasImage() || !errorOccurred()); |
| 257 // If possible, delay the resetting until back at the event loop. Doing so | 252 // If possible, delay the resetting until back at the event loop. Doing so |
| 258 // after a conservative GC prevents resetAnimation() from upsetting ongoing | 253 // after a conservative GC prevents resetAnimation() from upsetting ongoing |
| 259 // animation updates (crbug.com/613709) | 254 // animation updates (crbug.com/613709) |
| 260 if (!ThreadHeap::willObjectBeLazilySwept(this)) { | 255 if (getContent()) { |
| 261 Platform::current()->currentThread()->getWebTaskRunner()->postTask( | 256 if (!ThreadHeap::willObjectBeLazilySwept(this)) { |
| 262 BLINK_FROM_HERE, WTF::bind(&ImageResourceContent::doResetAnimation, | 257 Platform::current()->currentThread()->getWebTaskRunner()->postTask( |
| 263 wrapWeakPersistent(getContent()))); | 258 BLINK_FROM_HERE, WTF::bind(&ImageResourceContent::doResetAnimation, |
| 264 } else { | 259 wrapWeakPersistent(getContent()))); |
| 265 getContent()->doResetAnimation(); | 260 } else { |
| 261 getContent()->doResetAnimation(); | |
| 262 } | |
| 266 } | 263 } |
| 267 if (m_multipartParser) | 264 if (m_multipartParser) |
| 268 m_multipartParser->cancel(); | 265 m_multipartParser->cancel(); |
| 269 Resource::allClientsAndObserversRemoved(); | 266 Resource::allClientsAndObserversRemoved(); |
| 270 } | 267 } |
| 271 | 268 |
| 272 PassRefPtr<const SharedBuffer> ImageResource::resourceBuffer() const { | 269 PassRefPtr<const SharedBuffer> ImageResource::resourceBuffer() const { |
| 273 if (data()) | 270 if (data()) |
| 274 return data(); | 271 return data(); |
| 272 if (!getContent()) | |
| 273 return nullptr; | |
| 275 return getContent()->resourceBuffer(); | 274 return getContent()->resourceBuffer(); |
| 276 } | 275 } |
| 277 | 276 |
| 278 void ImageResource::appendData(const char* data, size_t length) { | 277 void ImageResource::appendData(const char* data, size_t length) { |
| 279 v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(length); | 278 v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(length); |
| 280 if (m_multipartParser) { | 279 if (m_multipartParser) { |
| 281 m_multipartParser->appendData(data, length); | 280 m_multipartParser->appendData(data, length); |
| 282 } else { | 281 } else { |
| 283 Resource::appendData(data, length); | 282 Resource::appendData(data, length); |
| 284 | 283 |
| 284 if (!getContent()) | |
| 285 return; | |
| 286 | |
| 285 // Update the image immediately if needed. | 287 // Update the image immediately if needed. |
| 286 if (getContent()->shouldUpdateImageImmediately()) { | 288 if (getContent()->shouldUpdateImageImmediately()) { |
| 287 updateImage(this->data(), ImageResourceContent::UpdateImage, false); | 289 updateImage(this->data(), ImageResourceContent::UpdateImage, false); |
| 288 return; | 290 return; |
| 289 } | 291 } |
| 290 | 292 |
| 291 // For other cases, only update at |kFlushDelaySeconds| intervals. This | 293 // For other cases, only update at |kFlushDelaySeconds| intervals. This |
| 292 // throttles how frequently we update |m_image| and how frequently we | 294 // throttles how frequently we update |m_image| and how frequently we |
| 293 // inform the clients which causes an invalidation of this image. In other | 295 // inform the clients which causes an invalidation of this image. In other |
| 294 // words, we only invalidate this image every |kFlushDelaySeconds| seconds | 296 // words, we only invalidate this image every |kFlushDelaySeconds| seconds |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 334 } | 336 } |
| 335 | 337 |
| 336 memoryCache()->remove(this); | 338 memoryCache()->remove(this); |
| 337 } | 339 } |
| 338 | 340 |
| 339 void ImageResource::updateImageAndClearBuffer() { | 341 void ImageResource::updateImageAndClearBuffer() { |
| 340 updateImage(data(), ImageResourceContent::ClearAndUpdateImage, true); | 342 updateImage(data(), ImageResourceContent::ClearAndUpdateImage, true); |
| 341 clearData(); | 343 clearData(); |
| 342 } | 344 } |
| 343 | 345 |
| 344 void ImageResource::finish(double loadFinishTime) { | 346 void ImageResource::finish(double loadFinishTime, |
| 347 ResourceFetcher* fetcherForReload) { | |
| 345 if (m_multipartParser) { | 348 if (m_multipartParser) { |
| 346 m_multipartParser->finish(); | 349 m_multipartParser->finish(); |
| 347 if (data()) | 350 if (data()) |
| 348 updateImageAndClearBuffer(); | 351 updateImageAndClearBuffer(); |
| 349 } else { | 352 } else { |
| 350 updateImage(data(), ImageResourceContent::UpdateImage, true); | 353 updateImage(data(), ImageResourceContent::UpdateImage, true, |
| 354 fetcherForReload); | |
| 351 // As encoded image data can be created from m_image (see | 355 // As encoded image data can be created from m_image (see |
| 352 // ImageResource::resourceBuffer(), we don't have to keep m_data. Let's | 356 // ImageResource::resourceBuffer(), we don't have to keep m_data. Let's |
| 353 // clear this. As for the lifetimes of m_image and m_data, see this | 357 // clear this. As for the lifetimes of m_image and m_data, see this |
| 354 // document: | 358 // document: |
| 355 // https://docs.google.com/document/d/1v0yTAZ6wkqX2U_M6BNIGUJpM1s0TIw1Vsqpxo L7aciY/edit?usp=sharing | 359 // https://docs.google.com/document/d/1v0yTAZ6wkqX2U_M6BNIGUJpM1s0TIw1Vsqpxo L7aciY/edit?usp=sharing |
| 356 clearData(); | 360 clearData(); |
| 357 } | 361 } |
| 358 Resource::finish(loadFinishTime); | 362 Resource::finish(loadFinishTime, fetcherForReload); |
| 359 } | 363 } |
| 360 | 364 |
| 361 void ImageResource::error(const ResourceError& error) { | 365 void ImageResource::error(const ResourceError& error, |
| 366 ResourceFetcher* fetcherForReload) { | |
| 362 if (m_multipartParser) | 367 if (m_multipartParser) |
| 363 m_multipartParser->cancel(); | 368 m_multipartParser->cancel(); |
| 364 // TODO(hiroshige): Move setEncodedSize() call to Resource::error() if it | 369 // TODO(hiroshige): Move setEncodedSize() call to Resource::error() if it |
| 365 // is really needed, or remove it otherwise. | 370 // is really needed, or remove it otherwise. |
| 366 setEncodedSize(0); | 371 setEncodedSize(0); |
| 367 Resource::error(error); | 372 Resource::error(error, fetcherForReload); |
| 368 updateImage(nullptr, ImageResourceContent::ClearImageOnly, true); | 373 updateImage(nullptr, ImageResourceContent::ClearImageOnly, true, |
| 374 fetcherForReload); | |
| 369 } | 375 } |
| 370 | 376 |
| 371 void ImageResource::responseReceived( | 377 void ImageResource::responseReceived( |
| 372 const ResourceResponse& response, | 378 const ResourceResponse& response, |
| 373 std::unique_ptr<WebDataConsumerHandle> handle) { | 379 std::unique_ptr<WebDataConsumerHandle> handle) { |
| 374 DCHECK(!handle); | 380 DCHECK(!handle); |
| 375 DCHECK(!m_multipartParser); | 381 DCHECK(!m_multipartParser); |
| 376 // If there's no boundary, just handle the request normally. | 382 // If there's no boundary, just handle the request normally. |
| 377 if (response.isMultipart() && !response.multipartBoundary().isEmpty()) { | 383 if (response.isMultipart() && !response.multipartBoundary().isEmpty()) { |
| 378 m_multipartParser = new MultipartImageResourceParser( | 384 m_multipartParser = new MultipartImageResourceParser( |
| 379 response, response.multipartBoundary(), this); | 385 response, response.multipartBoundary(), this); |
| 380 } | 386 } |
| 381 Resource::responseReceived(response, std::move(handle)); | 387 Resource::responseReceived(response, std::move(handle)); |
| 382 if (RuntimeEnabledFeatures::clientHintsEnabled()) { | 388 if (RuntimeEnabledFeatures::clientHintsEnabled()) { |
| 383 m_devicePixelRatioHeaderValue = | 389 m_devicePixelRatioHeaderValue = |
| 384 this->response() | 390 this->response() |
| 385 .httpHeaderField(HTTPNames::Content_DPR) | 391 .httpHeaderField(HTTPNames::Content_DPR) |
| 386 .toFloat(&m_hasDevicePixelRatioHeaderValue); | 392 .toFloat(&m_hasDevicePixelRatioHeaderValue); |
| 387 if (!m_hasDevicePixelRatioHeaderValue || | 393 if (!m_hasDevicePixelRatioHeaderValue || |
| 388 m_devicePixelRatioHeaderValue <= 0.0) { | 394 m_devicePixelRatioHeaderValue <= 0.0) { |
| 389 m_devicePixelRatioHeaderValue = 1.0; | 395 m_devicePixelRatioHeaderValue = 1.0; |
| 390 m_hasDevicePixelRatioHeaderValue = false; | 396 m_hasDevicePixelRatioHeaderValue = false; |
| 391 } | 397 } |
| 392 } | 398 } |
| 393 } | 399 } |
| 394 | 400 |
| 401 void ImageResource::detachContent() { | |
| 402 bool hasObservers = getContent() && getContent()->hasObservers(); | |
| 403 | |
| 404 m_content = nullptr; | |
| 405 clearData(); | |
| 406 memoryCache()->remove(this); | |
| 407 | |
| 408 if (hasObservers) | |
| 409 didRemoveClientOrObserver(); | |
| 410 } | |
| 411 | |
| 395 static bool isLoFiImage(const ImageResource& resource) { | 412 static bool isLoFiImage(const ImageResource& resource) { |
| 396 if (resource.resourceRequest().loFiState() != WebURLRequest::LoFiOn) | 413 if (resource.resourceRequest().loFiState() != WebURLRequest::LoFiOn) |
| 397 return false; | 414 return false; |
| 398 return !resource.isLoaded() || | 415 return !resource.isLoaded() || |
| 399 resource.response() | 416 resource.response() |
| 400 .httpHeaderField("chrome-proxy-content-transform") | 417 .httpHeaderField("chrome-proxy-content-transform") |
| 401 .contains("empty-image"); | 418 .contains("empty-image"); |
| 402 } | 419 } |
| 403 | 420 |
| 404 void ImageResource::reloadIfLoFiOrPlaceholderImage( | 421 ImageResource* ImageResource::reloadIfLoFiOrPlaceholderImage( |
| 405 ResourceFetcher* fetcher, | 422 ResourceFetcher* fetcher, |
| 406 ReloadLoFiOrPlaceholderPolicy policy) { | 423 ReloadLoFiOrPlaceholderPolicy policy) { |
| 424 if (!fetcher) | |
| 425 return nullptr; | |
| 407 if (policy == kReloadIfNeeded && !shouldReloadBrokenPlaceholder()) | 426 if (policy == kReloadIfNeeded && !shouldReloadBrokenPlaceholder()) |
| 408 return; | 427 return nullptr; |
| 409 | 428 |
| 410 if (!m_isPlaceholder && !isLoFiImage(*this)) | 429 if (!m_isPlaceholder && !isLoFiImage(*this)) |
| 411 return; | 430 return nullptr; |
| 412 | 431 |
| 413 // Prevent clients and observers from being notified of completion while the | 432 ImageResourceContent* content = getContent(); |
| 414 // reload is being scheduled, so that e.g. canceling an existing load in | 433 if (!content) |
| 415 // progress doesn't cause clients and observers to be notified of completion | 434 return nullptr; |
| 416 // prematurely. | 435 |
| 417 DCHECK(!m_isSchedulingReload); | 436 // Creates request/options for new ImageResource for reloading. |
| 418 m_isSchedulingReload = true; | 437 ResourceRequest reloadingRequest = resourceRequest(); |
| 438 ResourceLoaderOptions reloadingOptions = options(); | |
| 419 | 439 |
| 420 if (policy != kReloadAlwaysWithExistingCachePolicy) | 440 if (policy != kReloadAlwaysWithExistingCachePolicy) |
| 421 setCachePolicyBypassingCache(); | 441 reloadingRequest.setCachePolicy(WebCachePolicy::BypassingCache); |
| 422 setLoFiStateOff(); | 442 reloadingRequest.setLoFiState(WebURLRequest::LoFiOff); |
| 443 if (m_isPlaceholder) | |
| 444 reloadingRequest.clearHTTPHeaderField("range"); | |
| 423 | 445 |
| 424 if (m_isPlaceholder) { | 446 detachContent(); |
| 425 m_isPlaceholder = false; | 447 // Do not touch |this| after this point. |
| 426 clearRangeRequestHeader(); | |
| 427 } | |
| 428 | 448 |
| 429 if (isLoading()) { | 449 FetchRequest fetchRequest( |
| 430 loader()->cancel(); | 450 reloadingRequest, reloadingOptions.initiatorInfo.name, reloadingOptions); |
| 431 // Canceling the loader causes error() to be called, which in turn calls | 451 DCHECK_EQ(FetchRequest::DisallowPlaceholder, |
| 432 // clear() and notifyObservers(), so there's no need to call these again | 452 fetchRequest.placeholderImageRequestType()); |
| 433 // here. | 453 fetchRequest.setEnforceNewResource(); |
| 434 } else { | |
| 435 clearData(); | |
| 436 setEncodedSize(0); | |
| 437 updateImage(nullptr, ImageResourceContent::ClearImageOnly, false); | |
| 438 } | |
| 439 | 454 |
| 440 setStatus(NotStarted); | 455 ImageResource* reloadingResource = toImageResource(fetcher->requestResource( |
| 441 | 456 fetchRequest, ImageResourceFactory(fetchRequest, content))); |
| 442 DCHECK(m_isSchedulingReload); | 457 DCHECK(!reloadingResource || content == reloadingResource->getContent()); |
| 443 m_isSchedulingReload = false; | 458 return reloadingResource; |
| 444 | |
| 445 fetcher->startLoad(this); | |
| 446 } | 459 } |
| 447 | 460 |
| 448 void ImageResource::onePartInMultipartReceived( | 461 void ImageResource::onePartInMultipartReceived( |
| 449 const ResourceResponse& response) { | 462 const ResourceResponse& response) { |
| 450 DCHECK(m_multipartParser); | 463 DCHECK(m_multipartParser); |
| 451 | 464 |
| 452 setResponse(response); | 465 setResponse(response); |
| 453 if (m_multipartParsingState == MultipartParsingState::WaitingForFirstPart) { | 466 if (m_multipartParsingState == MultipartParsingState::WaitingForFirstPart) { |
| 454 // We have nothing to do because we don't have any data. | 467 // We have nothing to do because we don't have any data. |
| 455 m_multipartParsingState = MultipartParsingState::ParsingFirstPart; | 468 m_multipartParsingState = MultipartParsingState::ParsingFirstPart; |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 497 | 510 |
| 498 ImageResourceContent* ImageResource::getContent() { | 511 ImageResourceContent* ImageResource::getContent() { |
| 499 return m_content; | 512 return m_content; |
| 500 } | 513 } |
| 501 | 514 |
| 502 const ImageResourceContent* ImageResource::getContent() const { | 515 const ImageResourceContent* ImageResource::getContent() const { |
| 503 return m_content; | 516 return m_content; |
| 504 } | 517 } |
| 505 | 518 |
| 506 ResourcePriority ImageResource::priorityFromObservers() { | 519 ResourcePriority ImageResource::priorityFromObservers() { |
| 520 if (!getContent()) | |
| 521 return ResourcePriority(); | |
| 507 return getContent()->priorityFromObservers(); | 522 return getContent()->priorityFromObservers(); |
| 508 } | 523 } |
| 509 | 524 |
| 510 void ImageResource::updateImage( | 525 void ImageResource::updateImage( |
| 511 PassRefPtr<SharedBuffer> sharedBuffer, | 526 PassRefPtr<SharedBuffer> sharedBuffer, |
| 512 ImageResourceContent::UpdateImageOption updateImageOption, | 527 ImageResourceContent::UpdateImageOption updateImageOption, |
| 513 bool allDataReceived) { | 528 bool allDataReceived, |
| 529 ResourceFetcher* fetcherForReload) { | |
| 530 if (!getContent()) | |
| 531 return; | |
| 514 if (!m_isUpdateImageCalled && | 532 if (!m_isUpdateImageCalled && |
| 515 updateImageOption == ImageResourceContent::UpdateImage) | 533 updateImageOption == ImageResourceContent::UpdateImage) |
| 516 updateImageOption = ImageResourceContent::ClearAndUpdateImage; | 534 updateImageOption = ImageResourceContent::ClearAndUpdateImage; |
| 517 m_isUpdateImageCalled = true; | 535 m_isUpdateImageCalled = true; |
| 518 getContent()->updateImage(std::move(sharedBuffer), updateImageOption, | 536 getContent()->updateImage(std::move(sharedBuffer), updateImageOption, |
| 519 allDataReceived); | 537 allDataReceived, fetcherForReload); |
| 520 } | 538 } |
| 521 | 539 |
| 522 } // namespace blink | 540 } // namespace blink |
| OLD | NEW |