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

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: Rebase 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 if (getContent()->hasImage())
286 return m_image->data(); 274 return getContent()->getImage()->data();
287 return nullptr; 275 return nullptr;
288 } 276 }
289 277
290 void ImageResource::appendData(const char* data, size_t length) { 278 void ImageResource::appendData(const char* data, size_t length) {
291 v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(length); 279 v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(length);
292 if (m_multipartParser) { 280 if (m_multipartParser) {
293 m_multipartParser->appendData(data, length); 281 m_multipartParser->appendData(data, length);
294 } else { 282 } else {
295 Resource::appendData(data, length); 283 Resource::appendData(data, length);
296 284
297 // If we don't have the size available yet, then update immediately since 285 // 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 286 // 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 287 // animated images, update right away since we shouldn't throttle animated
300 // images. 288 // images.
301 if (m_sizeAvailable == Image::SizeUnavailable || 289 if (!getContent()->isSizeAvailable() ||
302 (m_image && m_image->maybeAnimated())) { 290 (getContent()->hasImage() &&
303 updateImage(false); 291 getContent()->getImage()->maybeAnimated())) {
292 getContent()->updateImage(this->data(),
293 ImageResourceContent::KeepExistingImage, false);
304 return; 294 return;
305 } 295 }
306 296
307 // For other cases, only update at |kFlushDelaySeconds| intervals. This 297 // For other cases, only update at |kFlushDelaySeconds| intervals. This
308 // throttles how frequently we update |m_image| and how frequently we 298 // throttles how frequently we update |m_image| and how frequently we
309 // inform the clients which causes an invalidation of this image. In other 299 // inform the clients which causes an invalidation of this image. In other
310 // words, we only invalidate this image every |kFlushDelaySeconds| seconds 300 // words, we only invalidate this image every |kFlushDelaySeconds| seconds
311 // while loading. 301 // while loading.
312 if (!m_flushTimer.isActive()) { 302 if (!m_flushTimer.isActive()) {
313 double now = WTF::monotonicallyIncreasingTime(); 303 double now = WTF::monotonicallyIncreasingTime();
314 if (!m_lastFlushTime) 304 if (!m_lastFlushTime)
315 m_lastFlushTime = now; 305 m_lastFlushTime = now;
316 306
317 DCHECK_LE(m_lastFlushTime, now); 307 DCHECK_LE(m_lastFlushTime, now);
318 double flushDelay = m_lastFlushTime - now + kFlushDelaySeconds; 308 double flushDelay = m_lastFlushTime - now + kFlushDelaySeconds;
319 if (flushDelay < 0.) 309 if (flushDelay < 0.)
320 flushDelay = 0.; 310 flushDelay = 0.;
321 m_flushTimer.startOneShot(flushDelay, BLINK_FROM_HERE); 311 m_flushTimer.startOneShot(flushDelay, BLINK_FROM_HERE);
322 } 312 }
323 } 313 }
324 } 314 }
325 315
326 void ImageResource::flushImageIfNeeded(TimerBase*) { 316 void ImageResource::flushImageIfNeeded(TimerBase*) {
327 // We might have already loaded the image fully, in which case we don't need 317 // We might have already loaded the image fully, in which case we don't need
328 // to call |updateImage()|. 318 // to call |updateImage()|.
329 if (isLoading()) { 319 if (isLoading()) {
330 m_lastFlushTime = WTF::monotonicallyIncreasingTime(); 320 m_lastFlushTime = WTF::monotonicallyIncreasingTime();
331 updateImage(false); 321 getContent()->updateImage(this->data(),
322 ImageResourceContent::KeepExistingImage, false);
332 } 323 }
333 } 324 }
334 325
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 { 326 bool ImageResource::willPaintBrokenImage() const {
349 return errorOccurred(); 327 return errorOccurred();
350 } 328 }
351 329
352 blink::Image* ImageResource::getImage() { 330 void ImageResource::decodeError(bool allDataReceived) {
353 if (errorOccurred()) { 331 size_t size = encodedSize();
354 // Returning the 1x broken image is non-ideal, but we cannot reliably access 332
355 // the appropriate deviceScaleFactor from here. It is critical that callers 333 clearData();
356 // use ImageResource::brokenImage() when they need the real, 334 setEncodedSize(0);
357 // deviceScaleFactor-appropriate broken image icon. 335 if (!errorOccurred())
358 return brokenImage(1).first; 336 setStatus(DecodeError);
337
338 if (!allDataReceived && loader()) {
339 // TODO(hiroshige): Do not call didFinishLoading() directly.
340 loader()->didFinishLoading(monotonicallyIncreasingTime(), size, size);
359 } 341 }
360 342
361 if (m_image) 343 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 } 344 }
514 345
515 void ImageResource::updateImageAndClearBuffer() { 346 void ImageResource::updateImageAndClearBuffer() {
516 clearImage(); 347 getContent()->updateImage(data(), ImageResourceContent::ClearExistingImage,
517 updateImage(true); 348 true);
518 clearData(); 349 clearData();
519 } 350 }
520 351
521 void ImageResource::finish(double loadFinishTime) { 352 void ImageResource::finish(double loadFinishTime) {
522 if (m_multipartParser) { 353 if (m_multipartParser) {
523 m_multipartParser->finish(); 354 m_multipartParser->finish();
524 if (data()) 355 if (data())
525 updateImageAndClearBuffer(); 356 updateImageAndClearBuffer();
526 } else { 357 } else {
527 updateImage(true); 358 getContent()->updateImage(data(), ImageResourceContent::KeepExistingImage,
359 true);
528 // As encoded image data can be created from m_image (see 360 // As encoded image data can be created from m_image (see
529 // ImageResource::resourceBuffer(), we don't have to keep m_data. Let's 361 // 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 362 // clear this. As for the lifetimes of m_image and m_data, see this
531 // document: 363 // document:
532 // https://docs.google.com/document/d/1v0yTAZ6wkqX2U_M6BNIGUJpM1s0TIw1Vsqpxo L7aciY/edit?usp=sharing 364 // https://docs.google.com/document/d/1v0yTAZ6wkqX2U_M6BNIGUJpM1s0TIw1Vsqpxo L7aciY/edit?usp=sharing
533 clearData(); 365 clearData();
534 } 366 }
535 Resource::finish(loadFinishTime); 367 Resource::finish(loadFinishTime);
536 } 368 }
537 369
538 void ImageResource::error(const ResourceError& error) { 370 void ImageResource::error(const ResourceError& error) {
539 if (m_multipartParser) 371 if (m_multipartParser)
540 m_multipartParser->cancel(); 372 m_multipartParser->cancel();
541 clear(); 373 // TODO(hiroshige): Move setEncodedSize() call to Resource::error() if it
374 // is really needed, or remove it otherwise.
375 setEncodedSize(0);
542 Resource::error(error); 376 Resource::error(error);
543 notifyObservers(ShouldNotifyFinish); 377 getContent()->clearImageAndNotifyObservers(
378 ImageResourceContent::ShouldNotifyFinish);
544 } 379 }
545 380
546 void ImageResource::responseReceived( 381 void ImageResource::responseReceived(
547 const ResourceResponse& response, 382 const ResourceResponse& response,
548 std::unique_ptr<WebDataConsumerHandle> handle) { 383 std::unique_ptr<WebDataConsumerHandle> handle) {
549 DCHECK(!handle); 384 DCHECK(!handle);
550 DCHECK(!m_multipartParser); 385 DCHECK(!m_multipartParser);
551 // If there's no boundary, just handle the request normally. 386 // If there's no boundary, just handle the request normally.
552 if (response.isMultipart() && !response.multipartBoundary().isEmpty()) { 387 if (response.isMultipart() && !response.multipartBoundary().isEmpty()) {
553 m_multipartParser = new MultipartImageResourceParser( 388 m_multipartParser = new MultipartImageResourceParser(
554 response, response.multipartBoundary(), this); 389 response, response.multipartBoundary(), this);
555 } 390 }
556 Resource::responseReceived(response, std::move(handle)); 391 Resource::responseReceived(response, std::move(handle));
557 if (RuntimeEnabledFeatures::clientHintsEnabled()) { 392 if (RuntimeEnabledFeatures::clientHintsEnabled()) {
558 m_devicePixelRatioHeaderValue = 393 m_devicePixelRatioHeaderValue =
559 this->response() 394 this->response()
560 .httpHeaderField(HTTPNames::Content_DPR) 395 .httpHeaderField(HTTPNames::Content_DPR)
561 .toFloat(&m_hasDevicePixelRatioHeaderValue); 396 .toFloat(&m_hasDevicePixelRatioHeaderValue);
562 if (!m_hasDevicePixelRatioHeaderValue || 397 if (!m_hasDevicePixelRatioHeaderValue ||
563 m_devicePixelRatioHeaderValue <= 0.0) { 398 m_devicePixelRatioHeaderValue <= 0.0) {
564 m_devicePixelRatioHeaderValue = 1.0; 399 m_devicePixelRatioHeaderValue = 1.0;
565 m_hasDevicePixelRatioHeaderValue = false; 400 m_hasDevicePixelRatioHeaderValue = false;
566 } 401 }
567 } 402 }
568 } 403 }
569 404
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) { 405 static bool isLoFiImage(const ImageResource& resource) {
620 if (resource.resourceRequest().loFiState() != WebURLRequest::LoFiOn) 406 if (resource.resourceRequest().loFiState() != WebURLRequest::LoFiOn)
621 return false; 407 return false;
622 return !resource.isLoaded() || 408 return !resource.isLoaded() ||
623 resource.response() 409 resource.response()
624 .httpHeaderField("chrome-proxy-content-transform") 410 .httpHeaderField("chrome-proxy-content-transform")
625 .contains("empty-image"); 411 .contains("empty-image");
626 } 412 }
627 413
628 void ImageResource::reloadIfLoFiOrPlaceholder( 414 void ImageResource::reloadIfLoFiOrPlaceholder(
(...skipping 17 matching lines...) Expand all
646 m_isPlaceholder = false; 432 m_isPlaceholder = false;
647 clearRangeRequestHeader(); 433 clearRangeRequestHeader();
648 } 434 }
649 435
650 if (isLoading()) { 436 if (isLoading()) {
651 loader()->cancel(); 437 loader()->cancel();
652 // Canceling the loader causes error() to be called, which in turn calls 438 // 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 439 // clear() and notifyObservers(), so there's no need to call these again
654 // here. 440 // here.
655 } else { 441 } else {
656 clear(); 442 clearData();
657 notifyObservers(DoNotNotifyFinish); 443 setEncodedSize(0);
444 getContent()->clearImageAndNotifyObservers(
445 ImageResourceContent::DoNotNotifyFinish);
658 } 446 }
659 447
660 setStatus(NotStarted); 448 setStatus(NotStarted);
661 449
662 DCHECK(m_isSchedulingReload); 450 DCHECK(m_isSchedulingReload);
663 m_isSchedulingReload = false; 451 m_isSchedulingReload = false;
664 452
665 fetcher->startLoad(this); 453 fetcher->startLoad(this);
666 } 454 }
667 455
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( 456 void ImageResource::onePartInMultipartReceived(
676 const ResourceResponse& response) { 457 const ResourceResponse& response) {
677 DCHECK(m_multipartParser); 458 DCHECK(m_multipartParser);
678 459
679 setResponse(response); 460 setResponse(response);
680 if (m_multipartParsingState == MultipartParsingState::WaitingForFirstPart) { 461 if (m_multipartParsingState == MultipartParsingState::WaitingForFirstPart) {
681 // We have nothing to do because we don't have any data. 462 // We have nothing to do because we don't have any data.
682 m_multipartParsingState = MultipartParsingState::ParsingFirstPart; 463 m_multipartParsingState = MultipartParsingState::ParsingFirstPart;
683 return; 464 return;
684 } 465 }
(...skipping 11 matching lines...) Expand all
696 if (loader()) 477 if (loader())
697 loader()->didFinishLoadingFirstPartInMultipart(); 478 loader()->didFinishLoadingFirstPartInMultipart();
698 } 479 }
699 } 480 }
700 481
701 void ImageResource::multipartDataReceived(const char* bytes, size_t size) { 482 void ImageResource::multipartDataReceived(const char* bytes, size_t size) {
702 DCHECK(m_multipartParser); 483 DCHECK(m_multipartParser);
703 Resource::appendData(bytes, size); 484 Resource::appendData(bytes, size);
704 } 485 }
705 486
706 bool ImageResource::isAccessAllowed(SecurityOrigin* securityOrigin) { 487 bool ImageResource::isAccessAllowed(
488 SecurityOrigin* securityOrigin,
489 ImageResourceInfo::DoesCurrentFrameHaveSingleSecurityOrigin
490 doesCurrentFrameHasSingleSecurityOrigin) const {
707 if (response().wasFetchedViaServiceWorker()) { 491 if (response().wasFetchedViaServiceWorker()) {
708 return response().serviceWorkerResponseType() != 492 return response().serviceWorkerResponseType() !=
709 WebServiceWorkerResponseTypeOpaque; 493 WebServiceWorkerResponseTypeOpaque;
710 } 494 }
711 if (!getImage()->currentFrameHasSingleSecurityOrigin()) 495 if (doesCurrentFrameHasSingleSecurityOrigin !=
496 ImageResourceInfo::HasSingleSecurityOrigin)
712 return false; 497 return false;
713 if (passesAccessControlCheck(securityOrigin)) 498 if (passesAccessControlCheck(securityOrigin))
714 return true; 499 return true;
715 return !securityOrigin->taintsCanvas(response().url()); 500 return !securityOrigin->taintsCanvas(response().url());
716 } 501 }
717 502
503 ImageResourceContent* ImageResource::getContent() const {
504 return m_content;
505 }
506
507 ResourcePriority ImageResource::priorityFromObservers() {
508 return getContent()->priorityFromObservers();
509 }
510
718 } // namespace blink 511 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698