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

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

Powered by Google App Engine
This is Rietveld 408576698