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