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 | |
| 26 #include "core/fetch/ImageResourceObserver.h" | 8 #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" | 9 #include "core/svg/graphics/SVGImage.h" |
| 33 #include "platform/Histogram.h" | 10 #include "platform/Histogram.h" |
| 34 #include "platform/RuntimeEnabledFeatures.h" | 11 #include "platform/RuntimeEnabledFeatures.h" |
| 35 #include "platform/SharedBuffer.h" | 12 #include "platform/SharedBuffer.h" |
| 36 #include "platform/geometry/IntSize.h" | 13 #include "platform/geometry/IntSize.h" |
| 37 #include "platform/graphics/BitmapImage.h" | 14 #include "platform/graphics/BitmapImage.h" |
| 38 #include "platform/graphics/PlaceholderImage.h" | 15 #include "platform/graphics/PlaceholderImage.h" |
| 39 #include "platform/tracing/TraceEvent.h" | 16 #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" | 17 #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 bool doesCurrentFrameHasSingleSecurityOrigin) const override { | |
| 50 return true; | |
| 51 } | |
| 52 bool hasCacheControlNoStoreHeader() const override { return false; } | |
| 53 | |
| 54 const KURL m_url; | |
| 55 const ResourceResponse m_response; | |
| 56 }; | |
| 57 | |
| 55 } // namespace | 58 } // namespace |
| 56 | 59 |
| 57 class ImageResource::ImageResourceFactory : public ResourceFactory { | 60 class ResourceFetcher; |
| 58 STACK_ALLOCATED(); | |
| 59 | 61 |
| 60 public: | 62 ImageResourceContent::ImageResourceContent(PassRefPtr<blink::Image> image) |
| 61 ImageResourceFactory(const FetchRequest& fetchRequest) | 63 : m_image(image), m_isRefetchableDataFromDiskCache(true) { |
| 62 : ResourceFactory(Resource::Image), m_fetchRequest(&fetchRequest) {} | 64 DEFINE_STATIC_LOCAL(NullImageResourceInfo, nullInfo, |
| 63 | 65 (new NullImageResourceInfo())); |
| 64 Resource* create(const ResourceRequest& request, | 66 m_info = &nullInfo; |
| 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 } | 67 } |
| 108 | 68 |
| 109 ImageResource::ImageResource(const ResourceRequest& resourceRequest, | 69 ImageResourceContent* ImageResourceContent::fetch(FetchRequest& request, |
| 110 const ResourceLoaderOptions& options, | 70 ResourceFetcher* fetcher) { |
| 111 bool isPlaceholder) | 71 ImageResource* resource = ImageResource::fetch(request, fetcher); |
| 112 : Resource(resourceRequest, Image, options), | 72 if (!resource) |
| 113 m_devicePixelRatioHeaderValue(1.0), | 73 return nullptr; |
| 114 m_image(nullptr), | 74 return resource->getRealContent(); |
| 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 } | 75 } |
| 122 | 76 |
| 123 ImageResource::ImageResource(blink::Image* image, | 77 void ImageResourceContent::setImageResourceInfo(ImageResourceInfo* info) { |
| 124 const ResourceLoaderOptions& options) | 78 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 } | 79 } |
| 136 | 80 |
| 137 ImageResource::~ImageResource() { | 81 DEFINE_TRACE(ImageResourceContent) { |
| 138 RESOURCE_LOADING_DVLOG(1) << "~ImageResource " << this; | 82 visitor->trace(m_info); |
| 139 clearImage(); | 83 ImageObserver::trace(visitor); |
| 84 ImageResourceContentInterface::trace(visitor); | |
| 140 } | 85 } |
| 141 | 86 |
| 142 DEFINE_TRACE(ImageResource) { | 87 void ImageResourceContent::markObserverFinished( |
| 143 visitor->trace(m_multipartParser); | 88 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)) { | 89 if (m_observers.contains(observer)) { |
| 160 m_finishedObservers.add(observer); | 90 m_finishedObservers.add(observer); |
| 161 m_observers.remove(observer); | 91 m_observers.remove(observer); |
| 162 } | 92 } |
| 163 } | 93 } |
| 164 | 94 |
| 165 void ImageResource::didAddClient(ResourceClient* client) { | 95 void ImageResourceContent::addObserver(ImageResourceObserver* observer) { |
| 166 DCHECK((m_multipartParser && isLoading()) || !data() || m_image); | 96 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 | 97 |
| 179 m_observers.add(observer); | 98 m_observers.add(observer); |
| 180 | 99 |
| 181 if (isCacheValidator()) | 100 if (m_info->isCacheValidator()) |
| 182 return; | 101 return; |
| 183 | 102 |
| 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()) { | 103 if (m_image && !m_image->isNull()) { |
| 195 observer->imageChanged(this); | 104 observer->imageChanged(this); |
| 196 } | 105 } |
| 197 | 106 |
| 198 if (isLoaded() && m_observers.contains(observer) && !m_isSchedulingReload && | 107 if (isLoaded() && m_observers.contains(observer) && |
| 199 !shouldReloadBrokenPlaceholder()) { | 108 !m_info->schedulingReloadOrShouldReloadBrokenPlaceholder()) { |
| 200 markObserverFinished(observer); | 109 markObserverFinished(observer); |
| 201 observer->imageNotifyFinished(this); | 110 observer->imageNotifyFinished(this); |
| 202 } | 111 } |
| 203 } | 112 } |
| 204 | 113 |
| 205 void ImageResource::removeObserver(ImageResourceObserver* observer) { | 114 void ImageResourceContent::removeObserver(ImageResourceObserver* observer) { |
| 206 DCHECK(observer); | 115 DCHECK(observer); |
| 207 | 116 |
| 208 if (m_observers.contains(observer)) | 117 if (m_observers.contains(observer)) |
| 209 m_observers.remove(observer); | 118 m_observers.remove(observer); |
| 210 else if (m_finishedObservers.contains(observer)) | 119 else if (m_finishedObservers.contains(observer)) |
| 211 m_finishedObservers.remove(observer); | 120 m_finishedObservers.remove(observer); |
| 212 else | 121 else |
| 213 NOTREACHED(); | 122 NOTREACHED(); |
| 214 | 123 |
| 215 didRemoveClientOrObserver(); | 124 m_info->didRemoveClientOrObserver(); |
| 216 } | 125 } |
| 217 | 126 |
| 218 static void priorityFromObserver(const ImageResourceObserver* observer, | 127 static void priorityFromObserver(const ImageResourceObserver* observer, |
| 219 ResourcePriority& priority) { | 128 ResourcePriority& priority) { |
| 220 ResourcePriority nextPriority = observer->computeResourcePriority(); | 129 ResourcePriority nextPriority = observer->computeResourcePriority(); |
| 221 if (nextPriority.visibility == ResourcePriority::NotVisible) | 130 if (nextPriority.visibility == ResourcePriority::NotVisible) |
| 222 return; | 131 return; |
| 223 priority.visibility = ResourcePriority::Visible; | 132 priority.visibility = ResourcePriority::Visible; |
| 224 priority.intraPriorityValue += nextPriority.intraPriorityValue; | 133 priority.intraPriorityValue += nextPriority.intraPriorityValue; |
| 225 } | 134 } |
| 226 | 135 |
| 227 ResourcePriority ImageResource::priorityFromObservers() { | 136 ResourcePriority ImageResourceContent::priorityFromObservers() const { |
| 228 ResourcePriority priority; | 137 ResourcePriority priority; |
| 229 | 138 |
| 230 for (auto* observer : m_finishedObservers.asVector()) { | 139 for (auto* observer : m_finishedObservers.asVector()) { |
| 231 if (m_finishedObservers.contains(observer)) | 140 if (m_finishedObservers.contains(observer)) |
| 232 priorityFromObserver(observer, priority); | 141 priorityFromObserver(observer, priority); |
| 233 } | 142 } |
| 234 for (auto* observer : m_observers.asVector()) { | 143 for (auto* observer : m_observers.asVector()) { |
| 235 if (m_observers.contains(observer)) | 144 if (m_observers.contains(observer)) |
| 236 priorityFromObserver(observer, priority); | 145 priorityFromObserver(observer, priority); |
| 237 } | 146 } |
| 238 | 147 |
| 239 return priority; | 148 return priority; |
| 240 } | 149 } |
| 241 | 150 |
| 242 void ImageResource::destroyDecodedDataForFailedRevalidation() { | 151 void ImageResourceContent::destroyDecodedData() { |
| 243 clearImage(); | |
| 244 setDecodedSize(0); | |
| 245 } | |
| 246 | |
| 247 void ImageResource::destroyDecodedDataIfPossible() { | |
| 248 if (!m_image) | 152 if (!m_image) |
| 249 return; | 153 return; |
| 250 CHECK(!errorOccurred()); | 154 CHECK(!errorOccurred()); |
| 251 m_image->destroyDecodedData(); | 155 m_image->destroyDecodedData(); |
|
hiroshige
2016/11/30 06:46:24
The UMA is collected in the caller of this method
| |
| 252 if (!isPreloaded() && m_isRefetchableDataFromDiskCache) { | |
| 253 UMA_HISTOGRAM_MEMORY_KB("Memory.Renderer.EstimatedDroppableEncodedSize", | |
| 254 encodedSize() / 1024); | |
| 255 } | |
| 256 } | 156 } |
| 257 | 157 |
| 258 void ImageResource::doResetAnimation() { | 158 void ImageResourceContent::doResetAnimation() { |
| 259 if (m_image) | 159 if (m_image) |
| 260 m_image->resetAnimation(); | 160 m_image->resetAnimation(); |
| 261 } | 161 } |
| 262 | 162 |
| 263 void ImageResource::allClientsAndObserversRemoved() { | 163 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) { | 164 float deviceScaleFactor) { |
| 337 if (deviceScaleFactor >= 2) { | 165 if (deviceScaleFactor >= 2) { |
| 338 DEFINE_STATIC_REF(blink::Image, brokenImageHiRes, | 166 DEFINE_STATIC_REF(blink::Image, brokenImageHiRes, |
| 339 (blink::Image::loadPlatformResource("missingImage@2x"))); | 167 (blink::Image::loadPlatformResource("missingImage@2x"))); |
| 340 return std::make_pair(brokenImageHiRes, 2); | 168 return std::make_pair(brokenImageHiRes, 2); |
| 341 } | 169 } |
| 342 | 170 |
| 343 DEFINE_STATIC_REF(blink::Image, brokenImageLoRes, | 171 DEFINE_STATIC_REF(blink::Image, brokenImageLoRes, |
| 344 (blink::Image::loadPlatformResource("missingImage"))); | 172 (blink::Image::loadPlatformResource("missingImage"))); |
| 345 return std::make_pair(brokenImageLoRes, 1); | 173 return std::make_pair(brokenImageLoRes, 1); |
| 346 } | 174 } |
| 347 | 175 |
| 348 bool ImageResource::willPaintBrokenImage() const { | 176 blink::Image* ImageResourceContent::getImage() const { |
| 349 return errorOccurred(); | |
| 350 } | |
| 351 | |
| 352 blink::Image* ImageResource::getImage() { | |
| 353 if (errorOccurred()) { | 177 if (errorOccurred()) { |
| 354 // Returning the 1x broken image is non-ideal, but we cannot reliably access | 178 // Returning the 1x broken image is non-ideal, but we cannot reliably access |
| 355 // the appropriate deviceScaleFactor from here. It is critical that callers | 179 // the appropriate deviceScaleFactor from here. It is critical that callers |
| 356 // use ImageResource::brokenImage() when they need the real, | 180 // use ImageResourceContent::brokenImage() when they need the real, |
| 357 // deviceScaleFactor-appropriate broken image icon. | 181 // deviceScaleFactor-appropriate broken image icon. |
| 358 return brokenImage(1).first; | 182 return brokenImage(1).first; |
| 359 } | 183 } |
| 360 | 184 |
| 361 if (m_image) | 185 if (m_image) |
| 362 return m_image.get(); | 186 return m_image.get(); |
| 363 | 187 |
| 364 return blink::Image::nullImage(); | 188 return blink::Image::nullImage(); |
| 365 } | 189 } |
| 366 | 190 |
| 367 bool ImageResource::usesImageContainerSize() const { | 191 bool ImageResourceContent::usesImageContainerSize() const { |
| 368 if (m_image) | 192 if (m_image) |
| 369 return m_image->usesContainerSize(); | 193 return m_image->usesContainerSize(); |
| 370 | 194 |
| 371 return false; | 195 return false; |
| 372 } | 196 } |
| 373 | 197 |
| 374 bool ImageResource::imageHasRelativeSize() const { | 198 bool ImageResourceContent::imageHasRelativeSize() const { |
| 375 if (m_image) | 199 if (m_image) |
| 376 return m_image->hasRelativeSize(); | 200 return m_image->hasRelativeSize(); |
| 377 | 201 |
| 378 return false; | 202 return false; |
| 379 } | 203 } |
| 380 | 204 |
| 381 LayoutSize ImageResource::imageSize( | 205 LayoutSize ImageResourceContent::imageSize( |
| 382 RespectImageOrientationEnum shouldRespectImageOrientation, | 206 RespectImageOrientationEnum shouldRespectImageOrientation, |
| 383 float multiplier, | 207 float multiplier, |
| 384 SizeType sizeType) { | 208 SizeType sizeType) { |
| 385 if (!m_image) | 209 if (!m_image) |
| 386 return LayoutSize(); | 210 return LayoutSize(); |
| 387 | 211 |
| 388 LayoutSize size; | 212 LayoutSize size; |
| 389 | 213 |
| 390 if (m_image->isBitmapImage() && | 214 if (m_image->isBitmapImage() && |
| 391 shouldRespectImageOrientation == RespectImageOrientation) { | 215 shouldRespectImageOrientation == RespectImageOrientation) { |
| 392 size = | 216 size = |
| 393 LayoutSize(toBitmapImage(m_image.get())->sizeRespectingOrientation()); | 217 LayoutSize(toBitmapImage(m_image.get())->sizeRespectingOrientation()); |
| 394 } else { | 218 } else { |
| 395 size = LayoutSize(m_image->size()); | 219 size = LayoutSize(m_image->size()); |
| 396 } | 220 } |
| 397 | 221 |
| 398 if (sizeType == IntrinsicCorrectedToDPR && m_hasDevicePixelRatioHeaderValue && | 222 if (sizeType == IntrinsicCorrectedToDPR && hasDevicePixelRatioHeaderValue() && |
| 399 m_devicePixelRatioHeaderValue > 0) | 223 devicePixelRatioHeaderValue() > 0) |
| 400 multiplier = 1 / m_devicePixelRatioHeaderValue; | 224 multiplier = 1 / devicePixelRatioHeaderValue(); |
| 401 | 225 |
| 402 if (multiplier == 1 || m_image->hasRelativeSize()) | 226 if (multiplier == 1 || m_image->hasRelativeSize()) |
| 403 return size; | 227 return size; |
| 404 | 228 |
| 405 // Don't let images that have a width/height >= 1 shrink below 1 when zoomed. | 229 // Don't let images that have a width/height >= 1 shrink below 1 when zoomed. |
| 406 LayoutSize minimumSize( | 230 LayoutSize minimumSize( |
| 407 size.width() > LayoutUnit() ? LayoutUnit(1) : LayoutUnit(), | 231 size.width() > LayoutUnit() ? LayoutUnit(1) : LayoutUnit(), |
| 408 LayoutUnit(size.height() > LayoutUnit() ? LayoutUnit(1) : LayoutUnit())); | 232 LayoutUnit(size.height() > LayoutUnit() ? LayoutUnit(1) : LayoutUnit())); |
| 409 size.scale(multiplier); | 233 size.scale(multiplier); |
| 410 size.clampToMinimumSize(minimumSize); | 234 size.clampToMinimumSize(minimumSize); |
| 411 return size; | 235 return size; |
| 412 } | 236 } |
| 413 | 237 |
| 414 void ImageResource::notifyObservers(NotifyFinishOption notifyingFinishOption, | 238 void ImageResourceContent::notifyObservers( |
| 415 const IntRect* changeRect) { | 239 NotifyFinishOption notifyingFinishOption, |
| 240 const IntRect* changeRect) { | |
| 416 for (auto* observer : m_finishedObservers.asVector()) { | 241 for (auto* observer : m_finishedObservers.asVector()) { |
| 417 if (m_finishedObservers.contains(observer)) | 242 if (m_finishedObservers.contains(observer)) |
| 418 observer->imageChanged(this, changeRect); | 243 observer->imageChanged(this, changeRect); |
| 419 } | 244 } |
| 420 for (auto* observer : m_observers.asVector()) { | 245 for (auto* observer : m_observers.asVector()) { |
| 421 if (m_observers.contains(observer)) { | 246 if (m_observers.contains(observer)) { |
| 422 observer->imageChanged(this, changeRect); | 247 observer->imageChanged(this, changeRect); |
| 423 if (notifyingFinishOption == ShouldNotifyFinish && | 248 if (notifyingFinishOption == ShouldNotifyFinish && |
| 424 m_observers.contains(observer) && !m_isSchedulingReload && | 249 m_observers.contains(observer) && |
| 425 !shouldReloadBrokenPlaceholder()) { | 250 !m_info->schedulingReloadOrShouldReloadBrokenPlaceholder()) { |
| 426 markObserverFinished(observer); | 251 markObserverFinished(observer); |
| 427 observer->imageNotifyFinished(this); | 252 observer->imageNotifyFinished(this); |
| 428 } | 253 } |
| 429 } | 254 } |
| 430 } | 255 } |
| 431 } | 256 } |
| 432 | 257 |
| 433 void ImageResource::clear() { | 258 inline PassRefPtr<Image> ImageResourceContent::createImage() { |
| 434 clearImage(); | 259 if (m_info->response().mimeType() == "image/svg+xml") |
| 435 clearData(); | 260 return SVGImage::create(this); |
| 436 setEncodedSize(0); | 261 return BitmapImage::create(this); |
| 437 } | 262 } |
| 438 | 263 |
| 439 inline void ImageResource::createImage() { | 264 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) | 265 if (!m_image) |
| 453 return; | 266 return; |
| 454 int64_t length = m_image->data() ? m_image->data()->size() : 0; | 267 int64_t length = m_image->data() ? m_image->data()->size() : 0; |
| 455 v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(-length); | 268 v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(-length); |
| 456 | 269 |
| 457 // If our Image has an observer, it's always us so we need to clear the back | 270 // If our Image has an observer, it's always us so we need to clear the back |
| 458 // pointer before dropping our reference. | 271 // pointer before dropping our reference. |
| 459 m_image->clearImageObserver(); | 272 m_image->clearImageObserver(); |
| 460 m_image.clear(); | 273 m_image.clear(); |
| 461 m_sizeAvailable = Image::SizeUnavailable; | 274 m_sizeAvailable = Image::SizeUnavailable; |
| 462 } | 275 } |
| 463 | 276 |
| 464 void ImageResource::updateImage(bool allDataReceived) { | 277 void ImageResourceContent::updateImage(PassRefPtr<SharedBuffer> data, |
| 465 TRACE_EVENT0("blink", "ImageResource::updateImage"); | 278 ClearImageOption clearImageOption, |
| 279 bool allDataReceived) { | |
| 280 TRACE_EVENT0("blink", "ImageResourceContent::updateImage"); | |
| 466 | 281 |
| 467 if (data()) | 282 if (clearImageOption == ImageResourceContent::ClearExistingImage) { |
| 468 createImage(); | 283 clearImage(); |
| 284 } | |
| 469 | 285 |
| 470 // Have the image update its data from its internal buffer. It will not do | 286 // 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 | 287 // anything now, but will delay decoding until queried for info (like size or |
| 472 // specific image frames). | 288 // specific image frames). |
| 473 if (data()) { | 289 if (data) { |
| 290 if (!m_image) | |
| 291 m_image = createImage(); | |
| 474 DCHECK(m_image); | 292 DCHECK(m_image); |
| 475 m_sizeAvailable = m_image->setData(data(), allDataReceived); | 293 m_sizeAvailable = m_image->setData(std::move(data), allDataReceived); |
| 476 } | 294 } |
| 477 | 295 |
| 478 // Go ahead and tell our observers to try to draw if we have either received | 296 // 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 | 297 // 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. | 298 // observers to repaint, which will force that chunk to decode. |
| 481 if (m_sizeAvailable == Image::SizeUnavailable && !allDataReceived) | 299 if (m_sizeAvailable == Image::SizeUnavailable && !allDataReceived) |
| 482 return; | 300 return; |
| 483 | 301 |
| 484 if (m_isPlaceholder && allDataReceived && m_image && !m_image->isNull()) { | 302 if (m_info->isPlaceholder() && allDataReceived && m_image && |
| 303 !m_image->isNull()) { | |
| 485 if (m_sizeAvailable == Image::SizeAvailable) { | 304 if (m_sizeAvailable == Image::SizeAvailable) { |
| 486 // TODO(sclittle): Show the original image if the response consists of the | 305 // 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 | 306 // entire image, such as if the entire image response body is smaller than |
| 488 // the requested range. | 307 // the requested range. |
| 489 IntSize dimensions = m_image->size(); | 308 IntSize dimensions = m_image->size(); |
| 309 | |
| 490 clearImage(); | 310 clearImage(); |
| 491 m_image = PlaceholderImage::create(this, dimensions); | 311 m_image = PlaceholderImage::create(this, dimensions); |
| 492 } else { | 312 } else { |
| 493 // Clear the image so that it gets treated like a decoding error, since | 313 // Clear the image so that it gets treated like a decoding error, since |
| 494 // the attempt to build a placeholder image failed. | 314 // the attempt to build a placeholder image failed. |
| 495 clearImage(); | 315 clearImage(); |
| 496 } | 316 } |
| 497 } | 317 } |
| 498 | 318 |
| 499 if (!m_image || m_image->isNull()) { | 319 if (!m_image || m_image->isNull()) { |
| 500 size_t size = encodedSize(); | 320 clearImage(); |
| 501 clear(); | 321 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 } | 322 } |
| 509 | 323 |
| 510 // It would be nice to only redraw the decoded band of the image, but with the | 324 // 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. | 325 // current design (decoding delayed until painting) that seems hard. |
| 512 notifyObservers(allDataReceived ? ShouldNotifyFinish : DoNotNotifyFinish); | 326 notifyObservers(allDataReceived ? ShouldNotifyFinish : DoNotNotifyFinish); |
| 513 } | 327 } |
| 514 | 328 |
| 515 void ImageResource::updateImageAndClearBuffer() { | 329 void ImageResourceContent::decodedSizeChangedTo(const blink::Image* image, |
| 516 clearImage(); | 330 size_t newSize) { |
| 517 updateImage(true); | 331 if (!image || image != m_image) |
| 518 clearData(); | 332 return; |
| 333 m_info->setDecodedSize(newSize); | |
| 519 } | 334 } |
| 520 | 335 |
| 521 void ImageResource::finish(double loadFinishTime) { | 336 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) | 337 if (!image || image != m_image) |
| 580 return false; | 338 return false; |
| 581 | 339 |
| 582 for (auto* observer : m_finishedObservers.asVector()) { | 340 for (auto* observer : m_finishedObservers.asVector()) { |
| 583 if (m_finishedObservers.contains(observer) && observer->willRenderImage()) | 341 if (m_finishedObservers.contains(observer) && observer->willRenderImage()) |
| 584 return false; | 342 return false; |
| 585 } | 343 } |
| 586 | 344 |
| 587 for (auto* observer : m_observers.asVector()) { | 345 for (auto* observer : m_observers.asVector()) { |
| 588 if (m_observers.contains(observer) && observer->willRenderImage()) | 346 if (m_observers.contains(observer) && observer->willRenderImage()) |
| 589 return false; | 347 return false; |
| 590 } | 348 } |
| 591 | 349 |
| 592 return true; | 350 return true; |
| 593 } | 351 } |
| 594 | 352 |
| 595 void ImageResource::animationAdvanced(const blink::Image* image) { | 353 void ImageResourceContent::animationAdvanced(const blink::Image* image) { |
| 596 if (!image || image != m_image) | 354 if (!image || image != m_image) |
| 597 return; | 355 return; |
| 598 notifyObservers(DoNotNotifyFinish); | 356 notifyObservers(DoNotNotifyFinish); |
| 599 } | 357 } |
| 600 | 358 |
| 601 void ImageResource::updateImageAnimationPolicy() { | 359 void ImageResourceContent::updateImageAnimationPolicy() { |
| 602 if (!m_image) | 360 if (!m_image) |
| 603 return; | 361 return; |
| 604 | 362 |
| 605 ImageAnimationPolicy newPolicy = ImageAnimationPolicyAllowed; | 363 ImageAnimationPolicy newPolicy = ImageAnimationPolicyAllowed; |
| 606 for (auto* observer : m_finishedObservers.asVector()) { | 364 for (auto* observer : m_finishedObservers.asVector()) { |
| 607 if (m_finishedObservers.contains(observer) && | 365 if (m_finishedObservers.contains(observer) && |
| 608 observer->getImageAnimationPolicy(newPolicy)) | 366 observer->getImageAnimationPolicy(newPolicy)) |
| 609 break; | 367 break; |
| 610 } | 368 } |
| 611 for (auto* observer : m_observers.asVector()) { | 369 for (auto* observer : m_observers.asVector()) { |
| 612 if (m_observers.contains(observer) && | 370 if (m_observers.contains(observer) && |
| 613 observer->getImageAnimationPolicy(newPolicy)) | 371 observer->getImageAnimationPolicy(newPolicy)) |
| 614 break; | 372 break; |
| 615 } | 373 } |
| 616 | 374 |
| 617 if (m_image->animationPolicy() != newPolicy) { | 375 if (m_image->animationPolicy() != newPolicy) { |
| 618 m_image->resetAnimation(); | 376 m_image->resetAnimation(); |
| 619 m_image->setAnimationPolicy(newPolicy); | 377 m_image->setAnimationPolicy(newPolicy); |
| 620 } | 378 } |
| 621 } | 379 } |
| 622 | 380 |
| 623 static bool isLoFiImage(const ImageResource& resource) { | 381 void ImageResourceContent::changedInRect(const blink::Image* image, |
| 624 if (resource.resourceRequest().loFiState() != WebURLRequest::LoFiOn) | 382 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) | 383 if (!image || image != m_image) |
| 675 return; | 384 return; |
| 676 notifyObservers(DoNotNotifyFinish, &rect); | 385 notifyObservers(DoNotNotifyFinish, &rect); |
| 677 } | 386 } |
| 678 | 387 |
| 679 void ImageResource::onePartInMultipartReceived( | 388 bool ImageResourceContent::isAccessAllowed( |
| 680 const ResourceResponse& response) { | 389 SecurityOrigin* securityOrigin) const { |
| 681 DCHECK(m_multipartParser); | 390 return m_info->isAccessAllowed( |
| 682 | 391 securityOrigin, getImage()->currentFrameHasSingleSecurityOrigin()); |
| 683 setResponse(response); | |
| 684 if (m_multipartParsingState == MultipartParsingState::WaitingForFirstPart) { | |
| 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/observers of finish here, and they will not be | |
| 697 // notified again in Resource::finish()/error(). | |
| 698 checkNotify(); | |
| 699 if (loader()) | |
| 700 loader()->didFinishLoadingFirstPartInMultipart(); | |
| 701 } | |
| 702 } | 392 } |
| 703 | 393 |
| 704 void ImageResource::multipartDataReceived(const char* bytes, size_t size) { | 394 void ImageResourceContent::emulateLoadStartedForInspector( |
| 705 DCHECK(m_multipartParser); | 395 ResourceFetcher* fetcher, |
| 706 Resource::appendData(bytes, size); | 396 const KURL& url, |
| 397 const AtomicString& initiatorName) { | |
| 398 m_info->emulateLoadStartedForInspector(fetcher, url, initiatorName); | |
| 707 } | 399 } |
| 708 | 400 |
| 709 bool ImageResource::isAccessAllowed(SecurityOrigin* securityOrigin) { | 401 // TODO(hiroshige): Consider removing the following methods, or stoping |
| 710 if (response().wasFetchedViaServiceWorker()) { | 402 // redirecting to ImageResource. |
| 711 return response().serviceWorkerResponseType() != | 403 bool ImageResourceContent::isLoaded() const { |
| 712 WebServiceWorkerResponseTypeOpaque; | 404 return getStatus() > ResourceStatus::Pending; |
| 713 } | 405 } |
| 714 if (!getImage()->currentFrameHasSingleSecurityOrigin()) | 406 |
| 715 return false; | 407 bool ImageResourceContent::isLoading() const { |
| 716 if (passesAccessControlCheck(securityOrigin)) | 408 return getStatus() == ResourceStatus::Pending; |
| 717 return true; | 409 } |
| 718 return !securityOrigin->taintsCanvas(response().url()); | 410 |
| 411 bool ImageResourceContent::errorOccurred() const { | |
| 412 return getStatus() == ResourceStatus::LoadError || | |
| 413 getStatus() == ResourceStatus::DecodeError; | |
| 414 } | |
| 415 | |
| 416 bool ImageResourceContent::loadFailedOrCanceled() const { | |
| 417 return getStatus() == ResourceStatus::LoadError; | |
| 418 } | |
| 419 | |
| 420 ResourceStatus ImageResourceContent::getStatus() const { | |
| 421 return m_info->getStatus(); | |
| 422 } | |
| 423 | |
| 424 const KURL& ImageResourceContent::url() const { | |
| 425 return m_info->url(); | |
| 426 } | |
| 427 | |
| 428 bool ImageResourceContent::hasCacheControlNoStoreHeader() const { | |
| 429 return m_info->hasCacheControlNoStoreHeader(); | |
| 430 } | |
| 431 | |
| 432 float ImageResourceContent::devicePixelRatioHeaderValue() const { | |
| 433 return m_info->devicePixelRatioHeaderValue(); | |
| 434 } | |
| 435 | |
| 436 bool ImageResourceContent::hasDevicePixelRatioHeaderValue() const { | |
| 437 return m_info->hasDevicePixelRatioHeaderValue(); | |
| 438 } | |
| 439 | |
| 440 const ResourceResponse& ImageResourceContent::response() const { | |
| 441 return m_info->response(); | |
| 719 } | 442 } |
| 720 | 443 |
| 721 } // namespace blink | 444 } // namespace blink |
| OLD | NEW |