Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(227)

Side by Side Diff: third_party/WebKit/Source/core/fetch/ImageResource.cpp

Issue 2469873002: [ImageResource 4] Split ImageResource into Resource and Image parts (Closed)
Patch Set: style Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 23 matching lines...) Expand all
101 resource->m_isPlaceholder) { 172 resource->m_isPlaceholder) {
102 // If the image is a placeholder, but this fetch doesn't allow a 173 // If the image is a placeholder, but this fetch doesn't allow a
103 // placeholder, then load the original image. Note that the cache is not 174 // placeholder, then load the original image. Note that the cache is not
104 // bypassed here - it should be fine to use a cached copy if possible. 175 // bypassed here - it should be fine to use a cached copy if possible.
105 resource->reloadIfLoFiOrPlaceholder(fetcher, 176 resource->reloadIfLoFiOrPlaceholder(fetcher,
106 ReloadCachePolicy::UseExistingPolicy); 177 ReloadCachePolicy::UseExistingPolicy);
107 } 178 }
108 return resource; 179 return resource;
109 } 180 }
110 181
182 ImageResource* ImageResource::create(const ResourceRequest& request) {
183 return new ImageResource(request, ResourceLoaderOptions(),
184 ImageResourceContent::create(), false);
185 }
186
111 ImageResource::ImageResource(const ResourceRequest& resourceRequest, 187 ImageResource::ImageResource(const ResourceRequest& resourceRequest,
112 const ResourceLoaderOptions& options, 188 const ResourceLoaderOptions& options,
189 ImageResourceContent* content,
113 bool isPlaceholder) 190 bool isPlaceholder)
114 : Resource(resourceRequest, Image, options), 191 : Resource(resourceRequest, Image, options),
192 m_content(content),
115 m_devicePixelRatioHeaderValue(1.0), 193 m_devicePixelRatioHeaderValue(1.0),
116 m_image(nullptr),
117 m_hasDevicePixelRatioHeaderValue(false), 194 m_hasDevicePixelRatioHeaderValue(false),
118 m_isSchedulingReload(false), 195 m_isSchedulingReload(false),
119 m_isPlaceholder(isPlaceholder), 196 m_isPlaceholder(isPlaceholder),
120 m_flushTimer(this, &ImageResource::flushImageIfNeeded), 197 m_flushTimer(this, &ImageResource::flushImageIfNeeded) {
121 m_isRefetchableDataFromDiskCache(true) { 198 DCHECK(getContent());
122 RESOURCE_LOADING_DVLOG(1) << "new ImageResource(ResourceRequest) " << this; 199 RESOURCE_LOADING_DVLOG(1) << "new ImageResource(ResourceRequest) " << this;
123 } 200 getContent()->setImageResourceInfo(new ImageResourceInfoImpl(this));
124
125 ImageResource::ImageResource(blink::Image* image,
126 const ResourceLoaderOptions& options)
127 : Resource(ResourceRequest(""), Image, options),
128 m_devicePixelRatioHeaderValue(1.0),
129 m_image(image),
130 m_hasDevicePixelRatioHeaderValue(false),
131 m_isSchedulingReload(false),
132 m_isPlaceholder(false),
133 m_flushTimer(this, &ImageResource::flushImageIfNeeded),
134 m_isRefetchableDataFromDiskCache(true) {
135 RESOURCE_LOADING_DVLOG(1) << "new ImageResource(Image) " << this;
136 setStatus(Cached);
137 } 201 }
138 202
139 ImageResource::~ImageResource() { 203 ImageResource::~ImageResource() {
140 RESOURCE_LOADING_DVLOG(1) << "~ImageResource " << this; 204 RESOURCE_LOADING_DVLOG(1) << "~ImageResource " << this;
141 clearImage();
142 } 205 }
143 206
144 DEFINE_TRACE(ImageResource) { 207 DEFINE_TRACE(ImageResource) {
145 visitor->trace(m_multipartParser); 208 visitor->trace(m_multipartParser);
209 visitor->trace(m_content);
146 Resource::trace(visitor); 210 Resource::trace(visitor);
147 ImageObserver::trace(visitor);
148 MultipartImageResourceParser::Client::trace(visitor); 211 MultipartImageResourceParser::Client::trace(visitor);
149 } 212 }
150 213
151 void ImageResource::checkNotify() { 214 void ImageResource::checkNotify() {
152 // Don't notify clients of completion if this ImageResource is 215 // Don't notify clients of completion if this ImageResource is
153 // about to be reloaded. 216 // about to be reloaded.
154 if (m_isSchedulingReload || shouldReloadBrokenPlaceholder()) 217 if (m_isSchedulingReload || shouldReloadBrokenPlaceholder())
155 return; 218 return;
156 219
157 Resource::checkNotify(); 220 Resource::checkNotify();
158 } 221 }
159 222
160 void ImageResource::markObserverFinished(ImageResourceObserver* observer) { 223 bool ImageResource::hasClientsOrObservers() const {
161 auto it = m_observers.find(observer); 224 return Resource::hasClientsOrObservers() || getContent()->hasObservers();
162 if (it == m_observers.end())
163 return;
164 m_observers.remove(it);
165 m_finishedObservers.add(observer);
166 } 225 }
167 226
168 void ImageResource::didAddClient(ResourceClient* client) { 227 void ImageResource::didAddClient(ResourceClient* client) {
169 DCHECK((m_multipartParser && isLoading()) || !data() || m_image); 228 DCHECK((m_multipartParser && isLoading()) || !data() ||
229 getContent()->hasImage());
170 230
171 // Don't notify observers and clients of completion if this ImageResource is 231 // Don't notify observers and clients of completion if this ImageResource is
172 // about to be reloaded. 232 // about to be reloaded.
173 if (m_isSchedulingReload || shouldReloadBrokenPlaceholder()) 233 if (m_isSchedulingReload || shouldReloadBrokenPlaceholder())
174 return; 234 return;
175 235
176 Resource::didAddClient(client); 236 Resource::didAddClient(client);
177 } 237 }
178 238
179 void ImageResource::addObserver(ImageResourceObserver* observer) {
180 willAddClientOrObserver(MarkAsReferenced);
181
182 m_observers.add(observer);
183
184 if (isCacheValidator())
185 return;
186
187 // When the response is not multipart, if |data()| exists, |m_image| must be
188 // created. This is assured that |updateImage()| is called when |appendData()|
189 // is called.
190 //
191 // On the other hand, when the response is multipart, |updateImage()| is not
192 // called in |appendData()|, which means |m_image| might not be created even
193 // when |data()| exists. This is intentional since creating a |m_image| on
194 // receiving data might destroy an existing image in a previous part.
195 DCHECK((m_multipartParser && isLoading()) || !data() || m_image);
196
197 if (m_image && !m_image->isNull()) {
198 observer->imageChanged(this);
199 }
200
201 if (isLoaded() && m_observers.contains(observer) && !m_isSchedulingReload &&
202 !shouldReloadBrokenPlaceholder()) {
203 markObserverFinished(observer);
204 observer->imageNotifyFinished(this);
205 }
206 }
207
208 void ImageResource::removeObserver(ImageResourceObserver* observer) {
209 DCHECK(observer);
210
211 auto it = m_observers.find(observer);
212 if (it != m_observers.end()) {
213 m_observers.remove(it);
214 } else {
215 it = m_finishedObservers.find(observer);
216 DCHECK(it != m_finishedObservers.end());
217 m_finishedObservers.remove(it);
218 }
219 didRemoveClientOrObserver();
220 }
221
222 static void priorityFromObserver(const ImageResourceObserver* observer,
223 ResourcePriority& priority) {
224 ResourcePriority nextPriority = observer->computeResourcePriority();
225 if (nextPriority.visibility == ResourcePriority::NotVisible)
226 return;
227 priority.visibility = ResourcePriority::Visible;
228 priority.intraPriorityValue += nextPriority.intraPriorityValue;
229 }
230
231 ResourcePriority ImageResource::priorityFromObservers() {
232 ResourcePriority priority;
233
234 for (const auto& it : m_finishedObservers)
235 priorityFromObserver(it.key, priority);
236 for (const auto& it : m_observers)
237 priorityFromObserver(it.key, priority);
238
239 return priority;
240 }
241
242 void ImageResource::destroyDecodedDataForFailedRevalidation() { 239 void ImageResource::destroyDecodedDataForFailedRevalidation() {
243 clearImage(); 240 getContent()->clearImage();
244 setDecodedSize(0); 241 setDecodedSize(0);
245 } 242 }
246 243
247 void ImageResource::destroyDecodedDataIfPossible() { 244 void ImageResource::destroyDecodedDataIfPossible() {
248 if (!m_image) 245 getContent()->destroyDecodedData();
249 return; 246 if (getContent()->hasImage() && !isPreloaded() &&
250 CHECK(!errorOccurred()); 247 getContent()->isRefetchableDataFromDiskCache()) {
251 m_image->destroyDecodedData();
252 if (!isPreloaded() && m_isRefetchableDataFromDiskCache) {
253 UMA_HISTOGRAM_MEMORY_KB("Memory.Renderer.EstimatedDroppableEncodedSize", 248 UMA_HISTOGRAM_MEMORY_KB("Memory.Renderer.EstimatedDroppableEncodedSize",
254 encodedSize() / 1024); 249 encodedSize() / 1024);
255 } 250 }
256 } 251 }
257 252
258 void ImageResource::doResetAnimation() {
259 if (m_image)
260 m_image->resetAnimation();
261 }
262
263 void ImageResource::allClientsAndObserversRemoved() { 253 void ImageResource::allClientsAndObserversRemoved() {
264 if (m_image) { 254 CHECK(!getContent()->hasImage() || !errorOccurred());
265 CHECK(!errorOccurred()); 255 // 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 256 // after a conservative GC prevents resetAnimation() from upsetting ongoing
267 // after a conservative GC prevents resetAnimation() from upsetting ongoing 257 // animation updates (crbug.com/613709)
268 // animation updates (crbug.com/613709) 258 if (!ThreadHeap::willObjectBeLazilySwept(this)) {
269 if (!ThreadHeap::willObjectBeLazilySwept(this)) { 259 Platform::current()->currentThread()->getWebTaskRunner()->postTask(
270 Platform::current()->currentThread()->getWebTaskRunner()->postTask( 260 BLINK_FROM_HERE, WTF::bind(&ImageResourceContent::doResetAnimation,
271 BLINK_FROM_HERE, WTF::bind(&ImageResource::doResetAnimation, 261 wrapWeakPersistent(getContent())));
272 wrapWeakPersistent(this))); 262 } else {
273 } else { 263 getContent()->doResetAnimation();
274 m_image->resetAnimation();
275 }
276 } 264 }
277 if (m_multipartParser) 265 if (m_multipartParser)
278 m_multipartParser->cancel(); 266 m_multipartParser->cancel();
279 Resource::allClientsAndObserversRemoved(); 267 Resource::allClientsAndObserversRemoved();
280 } 268 }
281 269
282 PassRefPtr<const SharedBuffer> ImageResource::resourceBuffer() const { 270 PassRefPtr<const SharedBuffer> ImageResource::resourceBuffer() const {
283 if (data()) 271 if (data())
284 return data(); 272 return data();
285 if (m_image) 273 return getContent()->resourceBuffer();
286 return m_image->data();
287 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 // Update the image immediately if needed.
298 // we need to know the image size as soon as possible. Likewise for 284 if (getContent()->shouldUpdateImageImmediately()) {
299 // animated images, update right away since we shouldn't throttle animated 285 getContent()->updateImage(this->data(),
300 // images. 286 ImageResourceContent::KeepExistingImage, false);
301 if (m_sizeAvailable == Image::SizeUnavailable ||
302 (m_image && m_image->maybeAnimated())) {
303 updateImage(false);
304 return; 287 return;
305 } 288 }
306 289
307 // For other cases, only update at |kFlushDelaySeconds| intervals. This 290 // For other cases, only update at |kFlushDelaySeconds| intervals. This
308 // throttles how frequently we update |m_image| and how frequently we 291 // throttles how frequently we update |m_image| and how frequently we
309 // inform the clients which causes an invalidation of this image. In other 292 // inform the clients which causes an invalidation of this image. In other
310 // words, we only invalidate this image every |kFlushDelaySeconds| seconds 293 // words, we only invalidate this image every |kFlushDelaySeconds| seconds
311 // while loading. 294 // while loading.
312 if (!m_flushTimer.isActive()) { 295 if (!m_flushTimer.isActive()) {
313 double now = WTF::monotonicallyIncreasingTime(); 296 double now = WTF::monotonicallyIncreasingTime();
314 if (!m_lastFlushTime) 297 if (!m_lastFlushTime)
315 m_lastFlushTime = now; 298 m_lastFlushTime = now;
316 299
317 DCHECK_LE(m_lastFlushTime, now); 300 DCHECK_LE(m_lastFlushTime, now);
318 double flushDelay = m_lastFlushTime - now + kFlushDelaySeconds; 301 double flushDelay = m_lastFlushTime - now + kFlushDelaySeconds;
319 if (flushDelay < 0.) 302 if (flushDelay < 0.)
320 flushDelay = 0.; 303 flushDelay = 0.;
321 m_flushTimer.startOneShot(flushDelay, BLINK_FROM_HERE); 304 m_flushTimer.startOneShot(flushDelay, BLINK_FROM_HERE);
322 } 305 }
323 } 306 }
324 } 307 }
325 308
326 void ImageResource::flushImageIfNeeded(TimerBase*) { 309 void ImageResource::flushImageIfNeeded(TimerBase*) {
327 // We might have already loaded the image fully, in which case we don't need 310 // We might have already loaded the image fully, in which case we don't need
328 // to call |updateImage()|. 311 // to call |updateImage()|.
329 if (isLoading()) { 312 if (isLoading()) {
330 m_lastFlushTime = WTF::monotonicallyIncreasingTime(); 313 m_lastFlushTime = WTF::monotonicallyIncreasingTime();
331 updateImage(false); 314 getContent()->updateImage(this->data(),
315 ImageResourceContent::KeepExistingImage, false);
332 } 316 }
333 } 317 }
334 318
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 { 319 bool ImageResource::willPaintBrokenImage() const {
349 return errorOccurred(); 320 return errorOccurred();
350 } 321 }
351 322
352 blink::Image* ImageResource::getImage() { 323 void ImageResource::decodeError(bool allDataReceived) {
353 if (errorOccurred()) { 324 size_t size = encodedSize();
354 // Returning the 1x broken image is non-ideal, but we cannot reliably access 325
355 // the appropriate deviceScaleFactor from here. It is critical that callers 326 clearData();
356 // use ImageResource::brokenImage() when they need the real, 327 setEncodedSize(0);
357 // deviceScaleFactor-appropriate broken image icon. 328 if (!errorOccurred())
358 return brokenImage(1).first; 329 setStatus(DecodeError);
330
331 if (!allDataReceived && loader()) {
332 // TODO(hiroshige): Do not call didFinishLoading() directly.
333 loader()->didFinishLoading(monotonicallyIncreasingTime(), size, size);
359 } 334 }
360 335
361 if (m_image) 336 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 } 337 }
514 338
515 void ImageResource::updateImageAndClearBuffer() { 339 void ImageResource::updateImageAndClearBuffer() {
516 clearImage(); 340 getContent()->updateImage(data(), ImageResourceContent::ClearExistingImage,
517 updateImage(true); 341 true);
518 clearData(); 342 clearData();
519 } 343 }
520 344
521 void ImageResource::finish(double loadFinishTime) { 345 void ImageResource::finish(double loadFinishTime) {
522 if (m_multipartParser) { 346 if (m_multipartParser) {
523 m_multipartParser->finish(); 347 m_multipartParser->finish();
524 if (data()) 348 if (data())
525 updateImageAndClearBuffer(); 349 updateImageAndClearBuffer();
526 } else { 350 } else {
527 updateImage(true); 351 getContent()->updateImage(data(), ImageResourceContent::KeepExistingImage,
352 true);
528 // As encoded image data can be created from m_image (see 353 // As encoded image data can be created from m_image (see
529 // ImageResource::resourceBuffer(), we don't have to keep m_data. Let's 354 // 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 355 // clear this. As for the lifetimes of m_image and m_data, see this
531 // document: 356 // document:
532 // https://docs.google.com/document/d/1v0yTAZ6wkqX2U_M6BNIGUJpM1s0TIw1Vsqpxo L7aciY/edit?usp=sharing 357 // https://docs.google.com/document/d/1v0yTAZ6wkqX2U_M6BNIGUJpM1s0TIw1Vsqpxo L7aciY/edit?usp=sharing
533 clearData(); 358 clearData();
534 } 359 }
535 Resource::finish(loadFinishTime); 360 Resource::finish(loadFinishTime);
536 } 361 }
537 362
538 void ImageResource::error(const ResourceError& error) { 363 void ImageResource::error(const ResourceError& error) {
539 if (m_multipartParser) 364 if (m_multipartParser)
540 m_multipartParser->cancel(); 365 m_multipartParser->cancel();
541 clear(); 366 // TODO(hiroshige): Move setEncodedSize() call to Resource::error() if it
367 // is really needed, or remove it otherwise.
368 setEncodedSize(0);
542 Resource::error(error); 369 Resource::error(error);
543 notifyObservers(ShouldNotifyFinish); 370 getContent()->clearImageAndNotifyObservers(
371 ImageResourceContent::ShouldNotifyFinish);
544 } 372 }
545 373
546 void ImageResource::responseReceived( 374 void ImageResource::responseReceived(
547 const ResourceResponse& response, 375 const ResourceResponse& response,
548 std::unique_ptr<WebDataConsumerHandle> handle) { 376 std::unique_ptr<WebDataConsumerHandle> handle) {
549 DCHECK(!handle); 377 DCHECK(!handle);
550 DCHECK(!m_multipartParser); 378 DCHECK(!m_multipartParser);
551 // If there's no boundary, just handle the request normally. 379 // If there's no boundary, just handle the request normally.
552 if (response.isMultipart() && !response.multipartBoundary().isEmpty()) { 380 if (response.isMultipart() && !response.multipartBoundary().isEmpty()) {
553 m_multipartParser = new MultipartImageResourceParser( 381 m_multipartParser = new MultipartImageResourceParser(
554 response, response.multipartBoundary(), this); 382 response, response.multipartBoundary(), this);
555 } 383 }
556 Resource::responseReceived(response, std::move(handle)); 384 Resource::responseReceived(response, std::move(handle));
557 if (RuntimeEnabledFeatures::clientHintsEnabled()) { 385 if (RuntimeEnabledFeatures::clientHintsEnabled()) {
558 m_devicePixelRatioHeaderValue = 386 m_devicePixelRatioHeaderValue =
559 this->response() 387 this->response()
560 .httpHeaderField(HTTPNames::Content_DPR) 388 .httpHeaderField(HTTPNames::Content_DPR)
561 .toFloat(&m_hasDevicePixelRatioHeaderValue); 389 .toFloat(&m_hasDevicePixelRatioHeaderValue);
562 if (!m_hasDevicePixelRatioHeaderValue || 390 if (!m_hasDevicePixelRatioHeaderValue ||
563 m_devicePixelRatioHeaderValue <= 0.0) { 391 m_devicePixelRatioHeaderValue <= 0.0) {
564 m_devicePixelRatioHeaderValue = 1.0; 392 m_devicePixelRatioHeaderValue = 1.0;
565 m_hasDevicePixelRatioHeaderValue = false; 393 m_hasDevicePixelRatioHeaderValue = false;
566 } 394 }
567 } 395 }
568 } 396 }
569 397
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 (const auto& it : m_finishedObservers)
583 if (it.key->willRenderImage())
584 return false;
585
586 for (const auto& it : m_observers)
587 if (it.key->willRenderImage())
588 return false;
589
590 return true;
591 }
592
593 void ImageResource::animationAdvanced(const blink::Image* image) {
594 if (!image || image != m_image)
595 return;
596 notifyObservers(DoNotNotifyFinish);
597 }
598
599 void ImageResource::updateImageAnimationPolicy() {
600 if (!m_image)
601 return;
602
603 ImageAnimationPolicy newPolicy = ImageAnimationPolicyAllowed;
604 for (const auto& it : m_finishedObservers) {
605 if (it.key->getImageAnimationPolicy(newPolicy))
606 break;
607 }
608 for (const auto& it : m_observers) {
609 if (it.key->getImageAnimationPolicy(newPolicy))
610 break;
611 }
612
613 if (m_image->animationPolicy() != newPolicy) {
614 m_image->resetAnimation();
615 m_image->setAnimationPolicy(newPolicy);
616 }
617 }
618
619 static bool isLoFiImage(const ImageResource& resource) { 398 static bool isLoFiImage(const ImageResource& resource) {
620 if (resource.resourceRequest().loFiState() != WebURLRequest::LoFiOn) 399 if (resource.resourceRequest().loFiState() != WebURLRequest::LoFiOn)
621 return false; 400 return false;
622 return !resource.isLoaded() || 401 return !resource.isLoaded() ||
623 resource.response() 402 resource.response()
624 .httpHeaderField("chrome-proxy-content-transform") 403 .httpHeaderField("chrome-proxy-content-transform")
625 .contains("empty-image"); 404 .contains("empty-image");
626 } 405 }
627 406
628 void ImageResource::reloadIfLoFiOrPlaceholder( 407 void ImageResource::reloadIfLoFiOrPlaceholder(
(...skipping 17 matching lines...) Expand all
646 m_isPlaceholder = false; 425 m_isPlaceholder = false;
647 clearRangeRequestHeader(); 426 clearRangeRequestHeader();
648 } 427 }
649 428
650 if (isLoading()) { 429 if (isLoading()) {
651 loader()->cancel(); 430 loader()->cancel();
652 // Canceling the loader causes error() to be called, which in turn calls 431 // Canceling the loader causes error() to be called, which in turn calls
653 // clear() and notifyObservers(), so there's no need to call these again 432 // clear() and notifyObservers(), so there's no need to call these again
654 // here. 433 // here.
655 } else { 434 } else {
656 clear(); 435 clearData();
657 notifyObservers(DoNotNotifyFinish); 436 setEncodedSize(0);
437 getContent()->clearImageAndNotifyObservers(
438 ImageResourceContent::DoNotNotifyFinish);
658 } 439 }
659 440
660 setStatus(NotStarted); 441 setStatus(NotStarted);
661 442
662 DCHECK(m_isSchedulingReload); 443 DCHECK(m_isSchedulingReload);
663 m_isSchedulingReload = false; 444 m_isSchedulingReload = false;
664 445
665 fetcher->startLoad(this); 446 fetcher->startLoad(this);
666 } 447 }
667 448
668 void ImageResource::changedInRect(const blink::Image* image,
669 const IntRect& rect) {
670 if (!image || image != m_image)
671 return;
672 notifyObservers(DoNotNotifyFinish, &rect);
673 }
674
675 void ImageResource::onePartInMultipartReceived( 449 void ImageResource::onePartInMultipartReceived(
676 const ResourceResponse& response) { 450 const ResourceResponse& response) {
677 DCHECK(m_multipartParser); 451 DCHECK(m_multipartParser);
678 452
679 setResponse(response); 453 setResponse(response);
680 if (m_multipartParsingState == MultipartParsingState::WaitingForFirstPart) { 454 if (m_multipartParsingState == MultipartParsingState::WaitingForFirstPart) {
681 // We have nothing to do because we don't have any data. 455 // We have nothing to do because we don't have any data.
682 m_multipartParsingState = MultipartParsingState::ParsingFirstPart; 456 m_multipartParsingState = MultipartParsingState::ParsingFirstPart;
683 return; 457 return;
684 } 458 }
(...skipping 11 matching lines...) Expand all
696 if (loader()) 470 if (loader())
697 loader()->didFinishLoadingFirstPartInMultipart(); 471 loader()->didFinishLoadingFirstPartInMultipart();
698 } 472 }
699 } 473 }
700 474
701 void ImageResource::multipartDataReceived(const char* bytes, size_t size) { 475 void ImageResource::multipartDataReceived(const char* bytes, size_t size) {
702 DCHECK(m_multipartParser); 476 DCHECK(m_multipartParser);
703 Resource::appendData(bytes, size); 477 Resource::appendData(bytes, size);
704 } 478 }
705 479
706 bool ImageResource::isAccessAllowed(SecurityOrigin* securityOrigin) { 480 bool ImageResource::isAccessAllowed(
481 SecurityOrigin* securityOrigin,
482 ImageResourceInfo::DoesCurrentFrameHaveSingleSecurityOrigin
483 doesCurrentFrameHasSingleSecurityOrigin) const {
707 if (response().wasFetchedViaServiceWorker()) { 484 if (response().wasFetchedViaServiceWorker()) {
708 return response().serviceWorkerResponseType() != 485 return response().serviceWorkerResponseType() !=
709 WebServiceWorkerResponseTypeOpaque; 486 WebServiceWorkerResponseTypeOpaque;
710 } 487 }
711 if (!getImage()->currentFrameHasSingleSecurityOrigin()) 488 if (doesCurrentFrameHasSingleSecurityOrigin !=
489 ImageResourceInfo::HasSingleSecurityOrigin)
712 return false; 490 return false;
713 if (passesAccessControlCheck(securityOrigin)) 491 if (passesAccessControlCheck(securityOrigin))
714 return true; 492 return true;
715 return !securityOrigin->taintsCanvas(response().url()); 493 return !securityOrigin->taintsCanvas(response().url());
716 } 494 }
717 495
496 ImageResourceContent* ImageResource::getContent() {
497 return m_content;
498 }
499
500 const ImageResourceContent* ImageResource::getContent() const {
501 return m_content;
502 }
503
504 ResourcePriority ImageResource::priorityFromObservers() {
505 return getContent()->priorityFromObservers();
506 }
507
718 } // namespace blink 508 } // namespace blink
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/core/fetch/ImageResource.h ('k') | third_party/WebKit/Source/core/fetch/ImageResourceContent.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698