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 |
| 11 version 2 of the License, or (at your option) any later version. | 11 version 2 of the License, or (at your option) any later version. |
| 12 | 12 |
| 13 This library is distributed in the hope that it will be useful, | 13 This library is distributed in the hope that it will be useful, |
| 14 but WITHOUT ANY WARRANTY; without even the implied warranty of | 14 but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 16 Library General Public License for more details. | 16 Library General Public License for more details. |
| 17 | 17 |
| 18 You should have received a copy of the GNU Library General Public License | 18 You should have received a copy of the GNU Library General Public License |
| 19 along with this library; see the file COPYING.LIB. If not, write to | 19 along with this library; see the file COPYING.LIB. If not, write to |
| 20 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | 20 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
| 21 Boston, MA 02110-1301, USA. | 21 Boston, MA 02110-1301, USA. |
| 22 */ | 22 */ |
| 23 | 23 |
| 24 #include "core/fetch/ImageResource.h" | 24 #include "core/fetch/ImageResource.h" |
| 25 | 25 |
| 26 #include "core/fetch/ImageResourceObserver.h" | 26 #include "core/fetch/ImageResourceContent.h" |
| 27 #include "core/fetch/ImageResourceInfo.h" | |
| 27 #include "core/fetch/MemoryCache.h" | 28 #include "core/fetch/MemoryCache.h" |
| 28 #include "core/fetch/ResourceClient.h" | 29 #include "core/fetch/ResourceClient.h" |
| 29 #include "core/fetch/ResourceFetcher.h" | 30 #include "core/fetch/ResourceFetcher.h" |
| 30 #include "core/fetch/ResourceLoader.h" | 31 #include "core/fetch/ResourceLoader.h" |
| 31 #include "core/fetch/ResourceLoadingLog.h" | 32 #include "core/fetch/ResourceLoadingLog.h" |
| 32 #include "core/svg/graphics/SVGImage.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/geometry/IntSize.h" | |
| 37 #include "platform/graphics/BitmapImage.h" | |
| 38 #include "platform/graphics/PlaceholderImage.h" | |
| 39 #include "platform/tracing/TraceEvent.h" | 36 #include "platform/tracing/TraceEvent.h" |
| 40 #include "public/platform/Platform.h" | 37 #include "public/platform/Platform.h" |
| 41 #include "public/platform/WebCachePolicy.h" | |
| 42 #include "wtf/CurrentTime.h" | 38 #include "wtf/CurrentTime.h" |
| 43 #include "wtf/HashCountedSet.h" | |
| 44 #include "wtf/StdLibExtras.h" | 39 #include "wtf/StdLibExtras.h" |
| 45 #include "wtf/Vector.h" | |
| 46 #include <memory> | 40 #include <memory> |
| 47 #include <v8.h> | 41 #include <v8.h> |
| 48 | 42 |
| 49 namespace blink { | 43 namespace blink { |
| 50 namespace { | 44 namespace { |
| 51 // The amount of time to wait before informing the clients that the image has | 45 // The amount of time to wait before informing the clients that the image has |
| 52 // been updated (in seconds). This effectively throttles invalidations that | 46 // been updated (in seconds). This effectively throttles invalidations that |
| 53 // result from new data arriving for this image. | 47 // result from new data arriving for this image. |
| 54 constexpr double kFlushDelaySeconds = 1.; | 48 constexpr double kFlushDelaySeconds = 1.; |
| 55 } // namespace | 49 } // namespace |
| 56 | 50 |
| 51 class ImageResource::ImageResourceInfoImpl final | |
| 52 : public GarbageCollectedFinalized<ImageResourceInfoImpl>, | |
| 53 public ImageResourceInfo { | |
| 54 USING_GARBAGE_COLLECTED_MIXIN(ImageResourceInfoImpl); | |
| 55 | |
| 56 public: | |
| 57 ImageResourceInfoImpl(ImageResource* resource) : m_resource(resource) { | |
| 58 DCHECK(m_resource); | |
| 59 } | |
| 60 DEFINE_INLINE_VIRTUAL_TRACE() { | |
| 61 visitor->trace(m_resource); | |
| 62 ImageResourceInfo::trace(visitor); | |
| 63 } | |
| 64 | |
| 65 private: | |
| 66 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 { | |
| 71 return m_resource->m_hasDevicePixelRatioHeaderValue; | |
| 72 } | |
| 73 float devicePixelRatioHeaderValue() const override { | |
| 74 return m_resource->m_devicePixelRatioHeaderValue; | |
| 75 } | |
| 76 const ResourceResponse& response() const override { | |
| 77 return m_resource->response(); | |
| 78 } | |
| 79 Resource::Status getStatus() const override { | |
| 80 return m_resource->getStatus(); | |
| 81 } | |
| 82 bool isPlaceholder() const override { return m_resource->isPlaceholder(); } | |
| 83 bool isCacheValidator() const override { | |
| 84 return m_resource->isCacheValidator(); | |
| 85 } | |
| 86 bool schedulingReloadOrShouldReloadBrokenPlaceholder() const override { | |
| 87 return m_resource->m_isSchedulingReload || | |
| 88 m_resource->shouldReloadBrokenPlaceholder(); | |
| 89 } | |
| 90 bool isAccessAllowed( | |
| 91 SecurityOrigin* securityOrigin, | |
| 92 DoesCurrentFrameHaveSingleSecurityOrigin | |
| 93 doesCurrentFrameHasSingleSecurityOrigin) const override { | |
| 94 return m_resource->isAccessAllowed(securityOrigin, | |
| 95 doesCurrentFrameHasSingleSecurityOrigin); | |
| 96 } | |
| 97 bool hasCacheControlNoStoreHeader() const override { | |
| 98 return m_resource->hasCacheControlNoStoreHeader(); | |
| 99 } | |
| 100 const ResourceError& resourceError() const override { | |
| 101 return m_resource->resourceError(); | |
| 102 } | |
| 103 | |
| 104 void decodeError(bool allDataReceived) override { | |
| 105 m_resource->decodeError(allDataReceived); | |
| 106 } | |
| 107 void setDecodedSize(size_t size) override { | |
| 108 m_resource->setDecodedSize(size); | |
| 109 } | |
| 110 void willAddClientOrObserver() override { | |
| 111 m_resource->willAddClientOrObserver(Resource::MarkAsReferenced); | |
| 112 } | |
| 113 void didRemoveClientOrObserver() override { | |
| 114 m_resource->didRemoveClientOrObserver(); | |
| 115 } | |
| 116 void emulateLoadStartedForInspector( | |
| 117 ResourceFetcher* fetcher, | |
| 118 const KURL& url, | |
| 119 const AtomicString& initiatorName) override { | |
| 120 fetcher->emulateLoadStartedForInspector(m_resource.get(), url, | |
| 121 WebURLRequest::RequestContextImage, | |
| 122 initiatorName); | |
| 123 } | |
| 124 | |
| 125 const Member<ImageResource> m_resource; | |
| 126 }; | |
| 127 | |
| 57 class ImageResource::ImageResourceFactory : public ResourceFactory { | 128 class ImageResource::ImageResourceFactory : public ResourceFactory { |
| 58 STACK_ALLOCATED(); | 129 STACK_ALLOCATED(); |
| 59 | 130 |
| 60 public: | 131 public: |
| 61 ImageResourceFactory(const FetchRequest& fetchRequest) | 132 ImageResourceFactory(const FetchRequest& fetchRequest) |
| 62 : ResourceFactory(Resource::Image), m_fetchRequest(&fetchRequest) {} | 133 : ResourceFactory(Resource::Image), m_fetchRequest(&fetchRequest) {} |
| 63 | 134 |
| 64 Resource* create(const ResourceRequest& request, | 135 Resource* create(const ResourceRequest& request, |
| 65 const ResourceLoaderOptions& options, | 136 const ResourceLoaderOptions& options, |
| 66 const String&) const override { | 137 const String&) const override { |
| 67 return new ImageResource(request, options, | 138 return new ImageResource(request, options, ImageResourceContent::create(), |
| 68 m_fetchRequest->placeholderImageRequestType() == | 139 m_fetchRequest->placeholderImageRequestType() == |
| 69 FetchRequest::AllowPlaceholder); | 140 FetchRequest::AllowPlaceholder); |
| 70 } | 141 } |
| 71 | 142 |
| 72 private: | 143 private: |
| 73 // Weak, unowned pointer. Must outlive |this|. | 144 // Weak, unowned pointer. Must outlive |this|. |
| 74 const FetchRequest* m_fetchRequest; | 145 const FetchRequest* m_fetchRequest; |
| 75 }; | 146 }; |
| 76 | 147 |
| 77 ImageResource* ImageResource::fetch(FetchRequest& request, | 148 ImageResource* ImageResource::fetch(FetchRequest& request, |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 99 resource->m_isPlaceholder) { | 170 resource->m_isPlaceholder) { |
| 100 // If the image is a placeholder, but this fetch doesn't allow a | 171 // If the image is a placeholder, but this fetch doesn't allow a |
| 101 // placeholder, then load the original image. Note that the cache is not | 172 // placeholder, then load the original image. Note that the cache is not |
| 102 // bypassed here - it should be fine to use a cached copy if possible. | 173 // bypassed here - it should be fine to use a cached copy if possible. |
| 103 resource->reloadIfLoFiOrPlaceholder(fetcher, | 174 resource->reloadIfLoFiOrPlaceholder(fetcher, |
| 104 ReloadCachePolicy::UseExistingPolicy); | 175 ReloadCachePolicy::UseExistingPolicy); |
| 105 } | 176 } |
| 106 return resource; | 177 return resource; |
| 107 } | 178 } |
| 108 | 179 |
| 180 ImageResource* ImageResource::create(const ResourceRequest& request) { | |
| 181 return new ImageResource(request, ResourceLoaderOptions(), | |
| 182 ImageResourceContent::create(), false); | |
| 183 } | |
| 184 | |
| 109 ImageResource::ImageResource(const ResourceRequest& resourceRequest, | 185 ImageResource::ImageResource(const ResourceRequest& resourceRequest, |
| 110 const ResourceLoaderOptions& options, | 186 const ResourceLoaderOptions& options, |
| 187 ImageResourceContent* content, | |
| 111 bool isPlaceholder) | 188 bool isPlaceholder) |
| 112 : Resource(resourceRequest, Image, options), | 189 : Resource(resourceRequest, Image, options), |
| 190 m_content(content), | |
| 113 m_devicePixelRatioHeaderValue(1.0), | 191 m_devicePixelRatioHeaderValue(1.0), |
| 114 m_image(nullptr), | |
| 115 m_hasDevicePixelRatioHeaderValue(false), | 192 m_hasDevicePixelRatioHeaderValue(false), |
| 116 m_isSchedulingReload(false), | 193 m_isSchedulingReload(false), |
| 117 m_isPlaceholder(isPlaceholder), | 194 m_isPlaceholder(isPlaceholder), |
| 118 m_flushTimer(this, &ImageResource::flushImageIfNeeded), | 195 m_flushTimer(this, &ImageResource::flushImageIfNeeded) { |
| 119 m_isRefetchableDataFromDiskCache(true) { | 196 DCHECK(getContent()); |
| 120 RESOURCE_LOADING_DVLOG(1) << "new ImageResource(ResourceRequest) " << this; | 197 RESOURCE_LOADING_DVLOG(1) << "new ImageResource(ResourceRequest) " << this; |
| 121 } | 198 getContent()->setImageResourceInfo(new ImageResourceInfoImpl(this)); |
| 122 | |
| 123 ImageResource::ImageResource(blink::Image* image, | |
| 124 const ResourceLoaderOptions& options) | |
| 125 : Resource(ResourceRequest(""), Image, options), | |
| 126 m_devicePixelRatioHeaderValue(1.0), | |
| 127 m_image(image), | |
| 128 m_hasDevicePixelRatioHeaderValue(false), | |
| 129 m_isSchedulingReload(false), | |
| 130 m_isPlaceholder(false), | |
| 131 m_flushTimer(this, &ImageResource::flushImageIfNeeded), | |
| 132 m_isRefetchableDataFromDiskCache(true) { | |
| 133 RESOURCE_LOADING_DVLOG(1) << "new ImageResource(Image) " << this; | |
| 134 setStatus(Cached); | |
| 135 } | 199 } |
| 136 | 200 |
| 137 ImageResource::~ImageResource() { | 201 ImageResource::~ImageResource() { |
| 138 RESOURCE_LOADING_DVLOG(1) << "~ImageResource " << this; | 202 RESOURCE_LOADING_DVLOG(1) << "~ImageResource " << this; |
| 139 clearImage(); | |
| 140 } | 203 } |
| 141 | 204 |
| 142 DEFINE_TRACE(ImageResource) { | 205 DEFINE_TRACE(ImageResource) { |
| 143 visitor->trace(m_multipartParser); | 206 visitor->trace(m_multipartParser); |
| 207 visitor->trace(m_content); | |
| 144 Resource::trace(visitor); | 208 Resource::trace(visitor); |
| 145 ImageObserver::trace(visitor); | |
| 146 MultipartImageResourceParser::Client::trace(visitor); | 209 MultipartImageResourceParser::Client::trace(visitor); |
| 147 } | 210 } |
| 148 | 211 |
| 149 void ImageResource::checkNotify() { | 212 void ImageResource::checkNotify() { |
| 150 // Don't notify clients of completion if this ImageResource is | 213 // Don't notify clients of completion if this ImageResource is |
| 151 // about to be reloaded. | 214 // about to be reloaded. |
| 152 if (m_isSchedulingReload || shouldReloadBrokenPlaceholder()) | 215 if (m_isSchedulingReload || shouldReloadBrokenPlaceholder()) |
| 153 return; | 216 return; |
| 154 | 217 |
| 155 Resource::checkNotify(); | 218 Resource::checkNotify(); |
| 156 } | 219 } |
| 157 | 220 |
| 158 void ImageResource::markObserverFinished(ImageResourceObserver* observer) { | 221 bool ImageResource::hasClientsOrObservers() const { |
| 159 if (m_observers.contains(observer)) { | 222 return Resource::hasClientsOrObservers() || getContent()->hasObservers(); |
| 160 m_finishedObservers.add(observer); | |
| 161 m_observers.remove(observer); | |
| 162 } | |
| 163 } | 223 } |
| 164 | 224 |
| 165 void ImageResource::didAddClient(ResourceClient* client) { | 225 void ImageResource::didAddClient(ResourceClient* client) { |
| 166 DCHECK((m_multipartParser && isLoading()) || !data() || m_image); | 226 DCHECK((m_multipartParser && isLoading()) || !data() || |
| 227 getContent()->hasImage()); | |
| 167 | 228 |
| 168 // Don't notify observers and clients of completion if this ImageResource is | 229 // Don't notify observers and clients of completion if this ImageResource is |
| 169 // about to be reloaded. | 230 // about to be reloaded. |
| 170 if (m_isSchedulingReload || shouldReloadBrokenPlaceholder()) | 231 if (m_isSchedulingReload || shouldReloadBrokenPlaceholder()) |
| 171 return; | 232 return; |
| 172 | 233 |
| 173 Resource::didAddClient(client); | 234 Resource::didAddClient(client); |
| 174 } | 235 } |
| 175 | 236 |
| 176 void ImageResource::addObserver(ImageResourceObserver* observer) { | |
| 177 willAddClientOrObserver(MarkAsReferenced); | |
| 178 | |
| 179 m_observers.add(observer); | |
| 180 | |
| 181 if (isCacheValidator()) | |
| 182 return; | |
| 183 | |
| 184 // When the response is not multipart, if |data()| exists, |m_image| must be | |
| 185 // created. This is assured that |updateImage()| is called when |appendData()| | |
| 186 // is called. | |
| 187 // | |
| 188 // On the other hand, when the response is multipart, |updateImage()| is not | |
| 189 // called in |appendData()|, which means |m_image| might not be created even | |
| 190 // when |data()| exists. This is intentional since creating a |m_image| on | |
| 191 // receiving data might destroy an existing image in a previous part. | |
| 192 DCHECK((m_multipartParser && isLoading()) || !data() || m_image); | |
| 193 | |
| 194 if (m_image && !m_image->isNull()) { | |
| 195 observer->imageChanged(this); | |
| 196 } | |
| 197 | |
| 198 if (isLoaded() && m_observers.contains(observer) && !m_isSchedulingReload && | |
| 199 !shouldReloadBrokenPlaceholder()) { | |
| 200 markObserverFinished(observer); | |
| 201 observer->imageNotifyFinished(this); | |
| 202 } | |
| 203 } | |
| 204 | |
| 205 void ImageResource::removeObserver(ImageResourceObserver* observer) { | |
| 206 DCHECK(observer); | |
| 207 | |
| 208 if (m_observers.contains(observer)) | |
| 209 m_observers.remove(observer); | |
| 210 else if (m_finishedObservers.contains(observer)) | |
| 211 m_finishedObservers.remove(observer); | |
| 212 else | |
| 213 NOTREACHED(); | |
| 214 | |
| 215 didRemoveClientOrObserver(); | |
| 216 } | |
| 217 | |
| 218 static void priorityFromObserver(const ImageResourceObserver* observer, | |
| 219 ResourcePriority& priority) { | |
| 220 ResourcePriority nextPriority = observer->computeResourcePriority(); | |
| 221 if (nextPriority.visibility == ResourcePriority::NotVisible) | |
| 222 return; | |
| 223 priority.visibility = ResourcePriority::Visible; | |
| 224 priority.intraPriorityValue += nextPriority.intraPriorityValue; | |
| 225 } | |
| 226 | |
| 227 ResourcePriority ImageResource::priorityFromObservers() { | |
| 228 ResourcePriority priority; | |
| 229 | |
| 230 for (auto* observer : m_finishedObservers.asVector()) { | |
| 231 if (m_finishedObservers.contains(observer)) | |
| 232 priorityFromObserver(observer, priority); | |
| 233 } | |
| 234 for (auto* observer : m_observers.asVector()) { | |
| 235 if (m_observers.contains(observer)) | |
| 236 priorityFromObserver(observer, priority); | |
| 237 } | |
| 238 | |
| 239 return priority; | |
| 240 } | |
| 241 | |
| 242 void ImageResource::destroyDecodedDataForFailedRevalidation() { | 237 void ImageResource::destroyDecodedDataForFailedRevalidation() { |
| 243 clearImage(); | 238 getContent()->clearImage(); |
| 244 setDecodedSize(0); | 239 setDecodedSize(0); |
| 245 } | 240 } |
| 246 | 241 |
| 247 void ImageResource::destroyDecodedDataIfPossible() { | 242 void ImageResource::destroyDecodedDataIfPossible() { |
| 248 if (!m_image) | 243 getContent()->destroyDecodedData(); |
| 249 return; | 244 if (getContent()->hasImage() && !isPreloaded() && |
| 250 CHECK(!errorOccurred()); | 245 getContent()->isRefetchableDataFromDiskCache()) { |
| 251 m_image->destroyDecodedData(); | |
| 252 if (!isPreloaded() && m_isRefetchableDataFromDiskCache) { | |
| 253 UMA_HISTOGRAM_MEMORY_KB("Memory.Renderer.EstimatedDroppableEncodedSize", | 246 UMA_HISTOGRAM_MEMORY_KB("Memory.Renderer.EstimatedDroppableEncodedSize", |
| 254 encodedSize() / 1024); | 247 encodedSize() / 1024); |
| 255 } | 248 } |
| 256 } | 249 } |
| 257 | 250 |
| 258 void ImageResource::doResetAnimation() { | |
| 259 if (m_image) | |
| 260 m_image->resetAnimation(); | |
| 261 } | |
| 262 | |
| 263 void ImageResource::allClientsAndObserversRemoved() { | 251 void ImageResource::allClientsAndObserversRemoved() { |
| 264 if (m_image) { | 252 CHECK(!getContent()->hasImage() || !errorOccurred()); |
| 265 CHECK(!errorOccurred()); | 253 // If possible, delay the resetting until back at the event loop. Doing so |
| 266 // If possible, delay the resetting until back at the event loop. Doing so | 254 // after a conservative GC prevents resetAnimation() from upsetting ongoing |
| 267 // after a conservative GC prevents resetAnimation() from upsetting ongoing | 255 // animation updates (crbug.com/613709) |
| 268 // animation updates (crbug.com/613709) | 256 if (!ThreadHeap::willObjectBeLazilySwept(this)) { |
| 269 if (!ThreadHeap::willObjectBeLazilySwept(this)) { | 257 Platform::current()->currentThread()->getWebTaskRunner()->postTask( |
| 270 Platform::current()->currentThread()->getWebTaskRunner()->postTask( | 258 BLINK_FROM_HERE, WTF::bind(&ImageResourceContent::doResetAnimation, |
| 271 BLINK_FROM_HERE, WTF::bind(&ImageResource::doResetAnimation, | 259 wrapWeakPersistent(getContent()))); |
| 272 wrapWeakPersistent(this))); | 260 } else { |
| 273 } else { | 261 getContent()->doResetAnimation(); |
| 274 m_image->resetAnimation(); | |
| 275 } | |
| 276 } | 262 } |
| 277 if (m_multipartParser) | 263 if (m_multipartParser) |
| 278 m_multipartParser->cancel(); | 264 m_multipartParser->cancel(); |
| 279 Resource::allClientsAndObserversRemoved(); | 265 Resource::allClientsAndObserversRemoved(); |
| 280 } | 266 } |
| 281 | 267 |
| 282 PassRefPtr<const SharedBuffer> ImageResource::resourceBuffer() const { | 268 PassRefPtr<const SharedBuffer> ImageResource::resourceBuffer() const { |
| 283 if (data()) | 269 if (data()) |
| 284 return data(); | 270 return data(); |
| 285 if (m_image) | 271 if (getContent()->hasImage()) |
| 286 return m_image->data(); | 272 return getContent()->getImage()->data(); |
| 287 return nullptr; | 273 return nullptr; |
| 288 } | 274 } |
| 289 | 275 |
| 290 void ImageResource::appendData(const char* data, size_t length) { | 276 void ImageResource::appendData(const char* data, size_t length) { |
| 291 v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(length); | 277 v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(length); |
| 292 if (m_multipartParser) { | 278 if (m_multipartParser) { |
| 293 m_multipartParser->appendData(data, length); | 279 m_multipartParser->appendData(data, length); |
| 294 } else { | 280 } else { |
| 295 Resource::appendData(data, length); | 281 Resource::appendData(data, length); |
| 296 | 282 |
| 297 // If we don't have the size available yet, then update immediately since | 283 // If we don't have the size available yet, then update immediately since |
| 298 // we need to know the image size as soon as possible. Likewise for | 284 // we need to know the image size as soon as possible. Likewise for |
| 299 // animated images, update right away since we shouldn't throttle animated | 285 // animated images, update right away since we shouldn't throttle animated |
| 300 // images. | 286 // images. |
| 301 if (m_sizeAvailable == Image::SizeUnavailable || | 287 if (!getContent()->isSizeAvailable() || |
|
Nate Chapin
2016/12/07 20:27:28
Should this if() block be a helper ImageResourceCo
hiroshige
2016/12/09 22:50:39
I'd like to call updateImage() directly here, rath
hiroshige
2016/12/11 19:17:01
I moved only the |if| conditional expression to Im
| |
| 302 (m_image && m_image->maybeAnimated())) { | 288 (getContent()->hasImage() && |
| 303 updateImage(false); | 289 getContent()->getImage()->maybeAnimated())) { |
| 290 getContent()->updateImage(this->data(), | |
| 291 ImageResourceContent::KeepExistingImage, false); | |
| 304 return; | 292 return; |
| 305 } | 293 } |
| 306 | 294 |
| 307 // For other cases, only update at |kFlushDelaySeconds| intervals. This | 295 // For other cases, only update at |kFlushDelaySeconds| intervals. This |
| 308 // throttles how frequently we update |m_image| and how frequently we | 296 // throttles how frequently we update |m_image| and how frequently we |
| 309 // inform the clients which causes an invalidation of this image. In other | 297 // inform the clients which causes an invalidation of this image. In other |
| 310 // words, we only invalidate this image every |kFlushDelaySeconds| seconds | 298 // words, we only invalidate this image every |kFlushDelaySeconds| seconds |
| 311 // while loading. | 299 // while loading. |
| 312 if (!m_flushTimer.isActive()) { | 300 if (!m_flushTimer.isActive()) { |
| 313 double now = WTF::monotonicallyIncreasingTime(); | 301 double now = WTF::monotonicallyIncreasingTime(); |
| 314 if (!m_lastFlushTime) | 302 if (!m_lastFlushTime) |
| 315 m_lastFlushTime = now; | 303 m_lastFlushTime = now; |
| 316 | 304 |
| 317 DCHECK_LE(m_lastFlushTime, now); | 305 DCHECK_LE(m_lastFlushTime, now); |
| 318 double flushDelay = m_lastFlushTime - now + kFlushDelaySeconds; | 306 double flushDelay = m_lastFlushTime - now + kFlushDelaySeconds; |
| 319 if (flushDelay < 0.) | 307 if (flushDelay < 0.) |
| 320 flushDelay = 0.; | 308 flushDelay = 0.; |
| 321 m_flushTimer.startOneShot(flushDelay, BLINK_FROM_HERE); | 309 m_flushTimer.startOneShot(flushDelay, BLINK_FROM_HERE); |
| 322 } | 310 } |
| 323 } | 311 } |
| 324 } | 312 } |
| 325 | 313 |
| 326 void ImageResource::flushImageIfNeeded(TimerBase*) { | 314 void ImageResource::flushImageIfNeeded(TimerBase*) { |
| 327 // We might have already loaded the image fully, in which case we don't need | 315 // We might have already loaded the image fully, in which case we don't need |
| 328 // to call |updateImage()|. | 316 // to call |updateImage()|. |
| 329 if (isLoading()) { | 317 if (isLoading()) { |
| 330 m_lastFlushTime = WTF::monotonicallyIncreasingTime(); | 318 m_lastFlushTime = WTF::monotonicallyIncreasingTime(); |
| 331 updateImage(false); | 319 getContent()->updateImage(this->data(), |
| 320 ImageResourceContent::KeepExistingImage, false); | |
| 332 } | 321 } |
| 333 } | 322 } |
| 334 | 323 |
| 335 std::pair<blink::Image*, float> ImageResource::brokenImage( | |
| 336 float deviceScaleFactor) { | |
| 337 if (deviceScaleFactor >= 2) { | |
| 338 DEFINE_STATIC_REF(blink::Image, brokenImageHiRes, | |
| 339 (blink::Image::loadPlatformResource("missingImage@2x"))); | |
| 340 return std::make_pair(brokenImageHiRes, 2); | |
| 341 } | |
| 342 | |
| 343 DEFINE_STATIC_REF(blink::Image, brokenImageLoRes, | |
| 344 (blink::Image::loadPlatformResource("missingImage"))); | |
| 345 return std::make_pair(brokenImageLoRes, 1); | |
| 346 } | |
| 347 | |
| 348 bool ImageResource::willPaintBrokenImage() const { | 324 bool ImageResource::willPaintBrokenImage() const { |
| 349 return errorOccurred(); | 325 return errorOccurred(); |
| 350 } | 326 } |
| 351 | 327 |
| 352 blink::Image* ImageResource::getImage() { | 328 void ImageResource::decodeError(bool allDataReceived) { |
| 353 if (errorOccurred()) { | 329 size_t size = encodedSize(); |
| 354 // Returning the 1x broken image is non-ideal, but we cannot reliably access | 330 |
| 355 // the appropriate deviceScaleFactor from here. It is critical that callers | 331 clearData(); |
| 356 // use ImageResource::brokenImage() when they need the real, | 332 setEncodedSize(0); |
| 357 // deviceScaleFactor-appropriate broken image icon. | 333 if (!errorOccurred()) |
| 358 return brokenImage(1).first; | 334 setStatus(DecodeError); |
| 335 | |
| 336 if (!allDataReceived && loader()) { | |
| 337 // TODO(hiroshige): Do not call didFinishLoading() directly. | |
| 338 loader()->didFinishLoading(monotonicallyIncreasingTime(), size, size); | |
| 359 } | 339 } |
| 360 | 340 |
| 361 if (m_image) | 341 memoryCache()->remove(this); |
| 362 return m_image.get(); | |
| 363 | |
| 364 return blink::Image::nullImage(); | |
| 365 } | |
| 366 | |
| 367 bool ImageResource::usesImageContainerSize() const { | |
| 368 if (m_image) | |
| 369 return m_image->usesContainerSize(); | |
| 370 | |
| 371 return false; | |
| 372 } | |
| 373 | |
| 374 bool ImageResource::imageHasRelativeSize() const { | |
| 375 if (m_image) | |
| 376 return m_image->hasRelativeSize(); | |
| 377 | |
| 378 return false; | |
| 379 } | |
| 380 | |
| 381 LayoutSize ImageResource::imageSize( | |
| 382 RespectImageOrientationEnum shouldRespectImageOrientation, | |
| 383 float multiplier, | |
| 384 SizeType sizeType) { | |
| 385 if (!m_image) | |
| 386 return LayoutSize(); | |
| 387 | |
| 388 LayoutSize size; | |
| 389 | |
| 390 if (m_image->isBitmapImage() && | |
| 391 shouldRespectImageOrientation == RespectImageOrientation) { | |
| 392 size = | |
| 393 LayoutSize(toBitmapImage(m_image.get())->sizeRespectingOrientation()); | |
| 394 } else { | |
| 395 size = LayoutSize(m_image->size()); | |
| 396 } | |
| 397 | |
| 398 if (sizeType == IntrinsicCorrectedToDPR && m_hasDevicePixelRatioHeaderValue && | |
| 399 m_devicePixelRatioHeaderValue > 0) | |
| 400 multiplier = 1 / m_devicePixelRatioHeaderValue; | |
| 401 | |
| 402 if (multiplier == 1 || m_image->hasRelativeSize()) | |
| 403 return size; | |
| 404 | |
| 405 // Don't let images that have a width/height >= 1 shrink below 1 when zoomed. | |
| 406 LayoutSize minimumSize( | |
| 407 size.width() > LayoutUnit() ? LayoutUnit(1) : LayoutUnit(), | |
| 408 LayoutUnit(size.height() > LayoutUnit() ? LayoutUnit(1) : LayoutUnit())); | |
| 409 size.scale(multiplier); | |
| 410 size.clampToMinimumSize(minimumSize); | |
| 411 return size; | |
| 412 } | |
| 413 | |
| 414 void ImageResource::notifyObservers(NotifyFinishOption notifyingFinishOption, | |
| 415 const IntRect* changeRect) { | |
| 416 for (auto* observer : m_finishedObservers.asVector()) { | |
| 417 if (m_finishedObservers.contains(observer)) | |
| 418 observer->imageChanged(this, changeRect); | |
| 419 } | |
| 420 for (auto* observer : m_observers.asVector()) { | |
| 421 if (m_observers.contains(observer)) { | |
| 422 observer->imageChanged(this, changeRect); | |
| 423 if (notifyingFinishOption == ShouldNotifyFinish && | |
| 424 m_observers.contains(observer) && !m_isSchedulingReload && | |
| 425 !shouldReloadBrokenPlaceholder()) { | |
| 426 markObserverFinished(observer); | |
| 427 observer->imageNotifyFinished(this); | |
| 428 } | |
| 429 } | |
| 430 } | |
| 431 } | |
| 432 | |
| 433 void ImageResource::clear() { | |
| 434 clearImage(); | |
| 435 clearData(); | |
| 436 setEncodedSize(0); | |
| 437 } | |
| 438 | |
| 439 inline void ImageResource::createImage() { | |
| 440 // Create the image if it doesn't yet exist. | |
| 441 if (m_image) | |
| 442 return; | |
| 443 | |
| 444 if (response().mimeType() == "image/svg+xml") { | |
| 445 m_image = SVGImage::create(this); | |
| 446 } else { | |
| 447 m_image = BitmapImage::create(this); | |
| 448 } | |
| 449 } | |
| 450 | |
| 451 inline void ImageResource::clearImage() { | |
| 452 if (!m_image) | |
| 453 return; | |
| 454 int64_t length = m_image->data() ? m_image->data()->size() : 0; | |
| 455 v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(-length); | |
| 456 | |
| 457 // If our Image has an observer, it's always us so we need to clear the back | |
| 458 // pointer before dropping our reference. | |
| 459 m_image->clearImageObserver(); | |
| 460 m_image.clear(); | |
| 461 m_sizeAvailable = Image::SizeUnavailable; | |
| 462 } | |
| 463 | |
| 464 void ImageResource::updateImage(bool allDataReceived) { | |
| 465 TRACE_EVENT0("blink", "ImageResource::updateImage"); | |
| 466 | |
| 467 if (data()) | |
| 468 createImage(); | |
| 469 | |
| 470 // Have the image update its data from its internal buffer. It will not do | |
| 471 // anything now, but will delay decoding until queried for info (like size or | |
| 472 // specific image frames). | |
| 473 if (data()) { | |
| 474 DCHECK(m_image); | |
| 475 m_sizeAvailable = m_image->setData(data(), allDataReceived); | |
| 476 } | |
| 477 | |
| 478 // Go ahead and tell our observers to try to draw if we have either received | |
| 479 // all the data or the size is known. Each chunk from the network causes | |
| 480 // observers to repaint, which will force that chunk to decode. | |
| 481 if (m_sizeAvailable == Image::SizeUnavailable && !allDataReceived) | |
| 482 return; | |
| 483 | |
| 484 if (m_isPlaceholder && allDataReceived && m_image && !m_image->isNull()) { | |
| 485 if (m_sizeAvailable == Image::SizeAvailable) { | |
| 486 // TODO(sclittle): Show the original image if the response consists of the | |
| 487 // entire image, such as if the entire image response body is smaller than | |
| 488 // the requested range. | |
| 489 IntSize dimensions = m_image->size(); | |
| 490 clearImage(); | |
| 491 m_image = PlaceholderImage::create(this, dimensions); | |
| 492 } else { | |
| 493 // Clear the image so that it gets treated like a decoding error, since | |
| 494 // the attempt to build a placeholder image failed. | |
| 495 clearImage(); | |
| 496 } | |
| 497 } | |
| 498 | |
| 499 if (!m_image || m_image->isNull()) { | |
| 500 size_t size = encodedSize(); | |
| 501 clear(); | |
| 502 if (!errorOccurred()) | |
| 503 setStatus(DecodeError); | |
| 504 if (!allDataReceived && loader()) { | |
| 505 loader()->didFinishLoading(monotonicallyIncreasingTime(), size, size); | |
| 506 } | |
| 507 memoryCache()->remove(this); | |
| 508 } | |
| 509 | |
| 510 // It would be nice to only redraw the decoded band of the image, but with the | |
| 511 // current design (decoding delayed until painting) that seems hard. | |
| 512 notifyObservers(allDataReceived ? ShouldNotifyFinish : DoNotNotifyFinish); | |
| 513 } | 342 } |
| 514 | 343 |
| 515 void ImageResource::updateImageAndClearBuffer() { | 344 void ImageResource::updateImageAndClearBuffer() { |
| 516 clearImage(); | 345 getContent()->updateImage(data(), ImageResourceContent::ClearExistingImage, |
| 517 updateImage(true); | 346 true); |
| 518 clearData(); | 347 clearData(); |
| 519 } | 348 } |
| 520 | 349 |
| 521 void ImageResource::finish(double loadFinishTime) { | 350 void ImageResource::finish(double loadFinishTime) { |
| 522 if (m_multipartParser) { | 351 if (m_multipartParser) { |
| 523 m_multipartParser->finish(); | 352 m_multipartParser->finish(); |
| 524 if (data()) | 353 if (data()) |
| 525 updateImageAndClearBuffer(); | 354 updateImageAndClearBuffer(); |
| 526 } else { | 355 } else { |
| 527 updateImage(true); | 356 getContent()->updateImage(data(), ImageResourceContent::KeepExistingImage, |
| 357 true); | |
| 528 // As encoded image data can be created from m_image (see | 358 // As encoded image data can be created from m_image (see |
| 529 // ImageResource::resourceBuffer(), we don't have to keep m_data. Let's | 359 // ImageResource::resourceBuffer(), we don't have to keep m_data. Let's |
| 530 // clear this. As for the lifetimes of m_image and m_data, see this | 360 // clear this. As for the lifetimes of m_image and m_data, see this |
| 531 // document: | 361 // document: |
| 532 // https://docs.google.com/document/d/1v0yTAZ6wkqX2U_M6BNIGUJpM1s0TIw1Vsqpxo L7aciY/edit?usp=sharing | 362 // https://docs.google.com/document/d/1v0yTAZ6wkqX2U_M6BNIGUJpM1s0TIw1Vsqpxo L7aciY/edit?usp=sharing |
| 533 clearData(); | 363 clearData(); |
| 534 } | 364 } |
| 535 Resource::finish(loadFinishTime); | 365 Resource::finish(loadFinishTime); |
| 536 } | 366 } |
| 537 | 367 |
| 538 void ImageResource::error(const ResourceError& error) { | 368 void ImageResource::error(const ResourceError& error) { |
| 539 if (m_multipartParser) | 369 if (m_multipartParser) |
| 540 m_multipartParser->cancel(); | 370 m_multipartParser->cancel(); |
| 541 clear(); | 371 // TODO(hiroshige): Move setEncodedSize() call to Resource::error() if it |
| 372 // is really needed, or remove it otherwise. | |
| 373 setEncodedSize(0); | |
| 542 Resource::error(error); | 374 Resource::error(error); |
| 543 notifyObservers(ShouldNotifyFinish); | 375 getContent()->clearImageAndNotifyObservers( |
| 376 ImageResourceContent::ShouldNotifyFinish); | |
| 544 } | 377 } |
| 545 | 378 |
| 546 void ImageResource::responseReceived( | 379 void ImageResource::responseReceived( |
| 547 const ResourceResponse& response, | 380 const ResourceResponse& response, |
| 548 std::unique_ptr<WebDataConsumerHandle> handle) { | 381 std::unique_ptr<WebDataConsumerHandle> handle) { |
| 549 DCHECK(!handle); | 382 DCHECK(!handle); |
| 550 DCHECK(!m_multipartParser); | 383 DCHECK(!m_multipartParser); |
| 551 // If there's no boundary, just handle the request normally. | 384 // If there's no boundary, just handle the request normally. |
| 552 if (response.isMultipart() && !response.multipartBoundary().isEmpty()) { | 385 if (response.isMultipart() && !response.multipartBoundary().isEmpty()) { |
| 553 m_multipartParser = new MultipartImageResourceParser( | 386 m_multipartParser = new MultipartImageResourceParser( |
| 554 response, response.multipartBoundary(), this); | 387 response, response.multipartBoundary(), this); |
| 555 } | 388 } |
| 556 Resource::responseReceived(response, std::move(handle)); | 389 Resource::responseReceived(response, std::move(handle)); |
| 557 if (RuntimeEnabledFeatures::clientHintsEnabled()) { | 390 if (RuntimeEnabledFeatures::clientHintsEnabled()) { |
| 558 m_devicePixelRatioHeaderValue = | 391 m_devicePixelRatioHeaderValue = |
| 559 this->response() | 392 this->response() |
| 560 .httpHeaderField(HTTPNames::Content_DPR) | 393 .httpHeaderField(HTTPNames::Content_DPR) |
| 561 .toFloat(&m_hasDevicePixelRatioHeaderValue); | 394 .toFloat(&m_hasDevicePixelRatioHeaderValue); |
| 562 if (!m_hasDevicePixelRatioHeaderValue || | 395 if (!m_hasDevicePixelRatioHeaderValue || |
| 563 m_devicePixelRatioHeaderValue <= 0.0) { | 396 m_devicePixelRatioHeaderValue <= 0.0) { |
| 564 m_devicePixelRatioHeaderValue = 1.0; | 397 m_devicePixelRatioHeaderValue = 1.0; |
| 565 m_hasDevicePixelRatioHeaderValue = false; | 398 m_hasDevicePixelRatioHeaderValue = false; |
| 566 } | 399 } |
| 567 } | 400 } |
| 568 } | 401 } |
| 569 | 402 |
| 570 void ImageResource::decodedSizeChangedTo(const blink::Image* image, | |
| 571 size_t newSize) { | |
| 572 if (!image || image != m_image) | |
| 573 return; | |
| 574 | |
| 575 setDecodedSize(newSize); | |
| 576 } | |
| 577 | |
| 578 bool ImageResource::shouldPauseAnimation(const blink::Image* image) { | |
| 579 if (!image || image != m_image) | |
| 580 return false; | |
| 581 | |
| 582 for (auto* observer : m_finishedObservers.asVector()) { | |
| 583 if (m_finishedObservers.contains(observer) && observer->willRenderImage()) | |
| 584 return false; | |
| 585 } | |
| 586 | |
| 587 for (auto* observer : m_observers.asVector()) { | |
| 588 if (m_observers.contains(observer) && observer->willRenderImage()) | |
| 589 return false; | |
| 590 } | |
| 591 | |
| 592 return true; | |
| 593 } | |
| 594 | |
| 595 void ImageResource::animationAdvanced(const blink::Image* image) { | |
| 596 if (!image || image != m_image) | |
| 597 return; | |
| 598 notifyObservers(DoNotNotifyFinish); | |
| 599 } | |
| 600 | |
| 601 void ImageResource::updateImageAnimationPolicy() { | |
| 602 if (!m_image) | |
| 603 return; | |
| 604 | |
| 605 ImageAnimationPolicy newPolicy = ImageAnimationPolicyAllowed; | |
| 606 for (auto* observer : m_finishedObservers.asVector()) { | |
| 607 if (m_finishedObservers.contains(observer) && | |
| 608 observer->getImageAnimationPolicy(newPolicy)) | |
| 609 break; | |
| 610 } | |
| 611 for (auto* observer : m_observers.asVector()) { | |
| 612 if (m_observers.contains(observer) && | |
| 613 observer->getImageAnimationPolicy(newPolicy)) | |
| 614 break; | |
| 615 } | |
| 616 | |
| 617 if (m_image->animationPolicy() != newPolicy) { | |
| 618 m_image->resetAnimation(); | |
| 619 m_image->setAnimationPolicy(newPolicy); | |
| 620 } | |
| 621 } | |
| 622 | |
| 623 static bool isLoFiImage(const ImageResource& resource) { | 403 static bool isLoFiImage(const ImageResource& resource) { |
| 624 if (resource.resourceRequest().loFiState() != WebURLRequest::LoFiOn) | 404 if (resource.resourceRequest().loFiState() != WebURLRequest::LoFiOn) |
| 625 return false; | 405 return false; |
| 626 return !resource.isLoaded() || | 406 return !resource.isLoaded() || |
| 627 resource.response() | 407 resource.response() |
| 628 .httpHeaderField("chrome-proxy-content-transform") | 408 .httpHeaderField("chrome-proxy-content-transform") |
| 629 .contains("empty-image"); | 409 .contains("empty-image"); |
| 630 } | 410 } |
| 631 | 411 |
| 632 void ImageResource::reloadIfLoFiOrPlaceholder( | 412 void ImageResource::reloadIfLoFiOrPlaceholder( |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 650 m_isPlaceholder = false; | 430 m_isPlaceholder = false; |
| 651 clearRangeRequestHeader(); | 431 clearRangeRequestHeader(); |
| 652 } | 432 } |
| 653 | 433 |
| 654 if (isLoading()) { | 434 if (isLoading()) { |
| 655 loader()->cancel(); | 435 loader()->cancel(); |
| 656 // Canceling the loader causes error() to be called, which in turn calls | 436 // Canceling the loader causes error() to be called, which in turn calls |
| 657 // clear() and notifyObservers(), so there's no need to call these again | 437 // clear() and notifyObservers(), so there's no need to call these again |
| 658 // here. | 438 // here. |
| 659 } else { | 439 } else { |
| 660 clear(); | 440 clearData(); |
| 661 notifyObservers(DoNotNotifyFinish); | 441 setEncodedSize(0); |
| 442 getContent()->clearImageAndNotifyObservers( | |
| 443 ImageResourceContent::DoNotNotifyFinish); | |
| 662 } | 444 } |
| 663 | 445 |
| 664 setStatus(NotStarted); | 446 setStatus(NotStarted); |
| 665 | 447 |
| 666 DCHECK(m_isSchedulingReload); | 448 DCHECK(m_isSchedulingReload); |
| 667 m_isSchedulingReload = false; | 449 m_isSchedulingReload = false; |
| 668 | 450 |
| 669 fetcher->startLoad(this); | 451 fetcher->startLoad(this); |
| 670 } | 452 } |
| 671 | 453 |
| 672 void ImageResource::changedInRect(const blink::Image* image, | |
| 673 const IntRect& rect) { | |
| 674 if (!image || image != m_image) | |
| 675 return; | |
| 676 notifyObservers(DoNotNotifyFinish, &rect); | |
| 677 } | |
| 678 | |
| 679 void ImageResource::onePartInMultipartReceived( | 454 void ImageResource::onePartInMultipartReceived( |
| 680 const ResourceResponse& response) { | 455 const ResourceResponse& response) { |
| 681 DCHECK(m_multipartParser); | 456 DCHECK(m_multipartParser); |
| 682 | 457 |
| 683 setResponse(response); | 458 setResponse(response); |
| 684 if (m_multipartParsingState == MultipartParsingState::WaitingForFirstPart) { | 459 if (m_multipartParsingState == MultipartParsingState::WaitingForFirstPart) { |
| 685 // We have nothing to do because we don't have any data. | 460 // We have nothing to do because we don't have any data. |
| 686 m_multipartParsingState = MultipartParsingState::ParsingFirstPart; | 461 m_multipartParsingState = MultipartParsingState::ParsingFirstPart; |
| 687 return; | 462 return; |
| 688 } | 463 } |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 700 if (loader()) | 475 if (loader()) |
| 701 loader()->didFinishLoadingFirstPartInMultipart(); | 476 loader()->didFinishLoadingFirstPartInMultipart(); |
| 702 } | 477 } |
| 703 } | 478 } |
| 704 | 479 |
| 705 void ImageResource::multipartDataReceived(const char* bytes, size_t size) { | 480 void ImageResource::multipartDataReceived(const char* bytes, size_t size) { |
| 706 DCHECK(m_multipartParser); | 481 DCHECK(m_multipartParser); |
| 707 Resource::appendData(bytes, size); | 482 Resource::appendData(bytes, size); |
| 708 } | 483 } |
| 709 | 484 |
| 710 bool ImageResource::isAccessAllowed(SecurityOrigin* securityOrigin) { | 485 bool ImageResource::isAccessAllowed( |
| 486 SecurityOrigin* securityOrigin, | |
| 487 ImageResourceInfo::DoesCurrentFrameHaveSingleSecurityOrigin | |
| 488 doesCurrentFrameHasSingleSecurityOrigin) const { | |
| 711 if (response().wasFetchedViaServiceWorker()) { | 489 if (response().wasFetchedViaServiceWorker()) { |
| 712 return response().serviceWorkerResponseType() != | 490 return response().serviceWorkerResponseType() != |
| 713 WebServiceWorkerResponseTypeOpaque; | 491 WebServiceWorkerResponseTypeOpaque; |
| 714 } | 492 } |
| 715 if (!getImage()->currentFrameHasSingleSecurityOrigin()) | 493 if (doesCurrentFrameHasSingleSecurityOrigin != |
| 494 ImageResourceInfo::HasSingleSecurityOrigin) | |
| 716 return false; | 495 return false; |
| 717 if (passesAccessControlCheck(securityOrigin)) | 496 if (passesAccessControlCheck(securityOrigin)) |
| 718 return true; | 497 return true; |
| 719 return !securityOrigin->taintsCanvas(response().url()); | 498 return !securityOrigin->taintsCanvas(response().url()); |
| 720 } | 499 } |
| 721 | 500 |
| 501 ImageResourceContent* ImageResource::getContent() const { | |
| 502 return m_content; | |
| 503 } | |
| 504 | |
| 505 ResourcePriority ImageResource::priorityFromObservers() { | |
| 506 return getContent()->priorityFromObservers(); | |
| 507 } | |
| 508 | |
| 722 } // namespace blink | 509 } // namespace blink |
| OLD | NEW |