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

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: fix 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/ImageResourceContent.h"
27 #include "core/fetch/ImageResourceInfo.h"
26 #include "core/fetch/ImageResourceObserver.h" 28 #include "core/fetch/ImageResourceObserver.h"
yhirano 2016/12/05 09:02:03 Is this needed?
hiroshige 2016/12/06 09:32:50 Done.
27 #include "core/fetch/MemoryCache.h" 29 #include "core/fetch/MemoryCache.h"
28 #include "core/fetch/ResourceClient.h" 30 #include "core/fetch/ResourceClient.h"
29 #include "core/fetch/ResourceFetcher.h" 31 #include "core/fetch/ResourceFetcher.h"
30 #include "core/fetch/ResourceLoader.h" 32 #include "core/fetch/ResourceLoader.h"
31 #include "core/fetch/ResourceLoadingLog.h" 33 #include "core/fetch/ResourceLoadingLog.h"
32 #include "core/svg/graphics/SVGImage.h"
33 #include "platform/Histogram.h" 34 #include "platform/Histogram.h"
34 #include "platform/RuntimeEnabledFeatures.h" 35 #include "platform/RuntimeEnabledFeatures.h"
35 #include "platform/SharedBuffer.h" 36 #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" 37 #include "platform/tracing/TraceEvent.h"
40 #include "public/platform/Platform.h" 38 #include "public/platform/Platform.h"
41 #include "public/platform/WebCachePolicy.h"
42 #include "wtf/CurrentTime.h" 39 #include "wtf/CurrentTime.h"
43 #include "wtf/HashCountedSet.h" 40 #include "wtf/HashCountedSet.h"
yhirano 2016/12/05 09:02:03 Not needed?
hiroshige 2016/12/06 09:32:50 Done.
44 #include "wtf/StdLibExtras.h" 41 #include "wtf/StdLibExtras.h"
45 #include "wtf/Vector.h" 42 #include "wtf/Vector.h"
yhirano 2016/12/05 09:02:03 Not needed?
hiroshige 2016/12/06 09:32:50 Done.
46 #include <memory> 43 #include <memory>
47 #include <v8.h> 44 #include <v8.h>
48 45
49 namespace blink { 46 namespace blink {
50 namespace { 47 namespace {
51 // The amount of time to wait before informing the clients that the image has 48 // The amount of time to wait before informing the clients that the image has
52 // been updated (in seconds). This effectively throttles invalidations that 49 // been updated (in seconds). This effectively throttles invalidations that
53 // result from new data arriving for this image. 50 // result from new data arriving for this image.
54 constexpr double kFlushDelaySeconds = 1.; 51 constexpr double kFlushDelaySeconds = 1.;
55 } // namespace 52 } // namespace
56 53
54 class ImageResource::ImageResourceInfoImpl final
55 : public GarbageCollectedFinalized<ImageResourceInfoImpl>,
56 public ImageResourceInfo {
57 USING_GARBAGE_COLLECTED_MIXIN(ImageResourceInfoImpl);
58
59 public:
60 ImageResourceInfoImpl(ImageResource* resource) : m_resource(resource) {
61 DCHECK(m_resource);
62 }
63 DEFINE_INLINE_VIRTUAL_TRACE() {
64 visitor->trace(m_resource);
65 ImageResourceInfo::trace(visitor);
66 }
67
68 private:
69 const KURL& url() const override { return m_resource->url(); }
70 bool isSchedulingReload() const override {
71 return m_resource->m_isSchedulingReload;
72 }
73 bool hasDevicePixelRatioHeaderValue() const override {
74 return m_resource->m_hasDevicePixelRatioHeaderValue;
75 }
76 float devicePixelRatioHeaderValue() const override {
77 return m_resource->m_devicePixelRatioHeaderValue;
78 }
79 const ResourceResponse& response() const override {
80 return m_resource->response();
81 }
82 Resource::Status getStatus() const override {
83 return m_resource->getStatus();
84 }
85 bool isPlaceholder() const override { return m_resource->isPlaceholder(); }
86 bool isCacheValidator() const override {
87 return m_resource->isCacheValidator();
88 }
89 bool schedulingReloadOrShouldReloadBrokenPlaceholder() const override {
90 return m_resource->m_isSchedulingReload ||
91 m_resource->shouldReloadBrokenPlaceholder();
92 }
93 bool isAccessAllowed(
94 SecurityOrigin* securityOrigin,
95 bool doesCurrentFrameHasSingleSecurityOrigin) const override {
96 return m_resource->isAccessAllowed(securityOrigin,
97 doesCurrentFrameHasSingleSecurityOrigin);
98 }
99 bool hasCacheControlNoStoreHeader() const override {
100 return m_resource->hasCacheControlNoStoreHeader();
101 }
102 const ResourceError& resourceError() const override {
103 return m_resource->resourceError();
104 }
105
106 void decodeError(bool allDataReceived) override {
107 m_resource->decodeError(allDataReceived);
108 }
109 void setDecodedSize(size_t size) override {
110 m_resource->setDecodedSize(size);
111 }
112 void willAddClientOrObserver() override {
113 m_resource->willAddClientOrObserver(Resource::MarkAsReferenced);
114 }
115 void didRemoveClientOrObserver() override {
116 m_resource->didRemoveClientOrObserver();
117 }
118 void emulateLoadStartedForInspector(
119 ResourceFetcher* fetcher,
120 const KURL& url,
121 const AtomicString& initiatorName) override {
122 fetcher->emulateLoadStartedForInspector(m_resource.get(), url,
123 WebURLRequest::RequestContextImage,
124 initiatorName);
125 }
126
127 Member<ImageResource> m_resource;
yhirano 2016/12/05 09:02:03 [optional] const Member<ImageResource> m_resource;
hiroshige 2016/12/06 09:32:50 Done.
128 };
129
57 class ImageResource::ImageResourceFactory : public ResourceFactory { 130 class ImageResource::ImageResourceFactory : public ResourceFactory {
58 STACK_ALLOCATED(); 131 STACK_ALLOCATED();
59 132
60 public: 133 public:
61 ImageResourceFactory(const FetchRequest& fetchRequest) 134 ImageResourceFactory(const FetchRequest& fetchRequest)
62 : ResourceFactory(Resource::Image), m_fetchRequest(&fetchRequest) {} 135 : ResourceFactory(Resource::Image), m_fetchRequest(&fetchRequest) {}
63 136
64 Resource* create(const ResourceRequest& request, 137 Resource* create(const ResourceRequest& request,
65 const ResourceLoaderOptions& options, 138 const ResourceLoaderOptions& options,
66 const String&) const override { 139 const String&) const override {
67 return new ImageResource(request, options, 140 return new ImageResource(request, options, ImageResourceContent::create(),
68 m_fetchRequest->placeholderImageRequestType() == 141 m_fetchRequest->placeholderImageRequestType() ==
69 FetchRequest::AllowPlaceholder); 142 FetchRequest::AllowPlaceholder);
70 } 143 }
71 144
72 private: 145 private:
73 // Weak, unowned pointer. Must outlive |this|. 146 // Weak, unowned pointer. Must outlive |this|.
74 const FetchRequest* m_fetchRequest; 147 const FetchRequest* m_fetchRequest;
75 }; 148 };
76 149
77 ImageResource* ImageResource::fetch(FetchRequest& request, 150 ImageResource* ImageResource::fetch(FetchRequest& request,
(...skipping 21 matching lines...) Expand all
99 resource->m_isPlaceholder) { 172 resource->m_isPlaceholder) {
100 // 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
101 // 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
102 // 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.
103 resource->reloadIfLoFiOrPlaceholder(fetcher, 176 resource->reloadIfLoFiOrPlaceholder(fetcher,
104 ReloadCachePolicy::UseExistingPolicy); 177 ReloadCachePolicy::UseExistingPolicy);
105 } 178 }
106 return resource; 179 return resource;
107 } 180 }
108 181
182 ImageResource* ImageResource::create(const ResourceRequest& request) {
183 return new ImageResource(request, ResourceLoaderOptions(),
184 ImageResourceContent::create(), false);
185 }
186
109 ImageResource::ImageResource(const ResourceRequest& resourceRequest, 187 ImageResource::ImageResource(const ResourceRequest& resourceRequest,
110 const ResourceLoaderOptions& options, 188 const ResourceLoaderOptions& options,
189 ImageResourceContent* content,
111 bool isPlaceholder) 190 bool isPlaceholder)
112 : Resource(resourceRequest, Image, options), 191 : Resource(resourceRequest, Image, options),
192 m_content(content),
113 m_devicePixelRatioHeaderValue(1.0), 193 m_devicePixelRatioHeaderValue(1.0),
114 m_image(nullptr),
115 m_hasDevicePixelRatioHeaderValue(false), 194 m_hasDevicePixelRatioHeaderValue(false),
116 m_isSchedulingReload(false), 195 m_isSchedulingReload(false),
117 m_isPlaceholder(isPlaceholder), 196 m_isPlaceholder(isPlaceholder),
118 m_flushTimer(this, &ImageResource::flushImageIfNeeded), 197 m_flushTimer(this, &ImageResource::flushImageIfNeeded) {
119 m_isRefetchableDataFromDiskCache(true) { 198 DCHECK(getContent());
120 RESOURCE_LOADING_DVLOG(1) << "new ImageResource(ResourceRequest) " << this; 199 RESOURCE_LOADING_DVLOG(1) << "new ImageResource(ResourceRequest) " << this;
121 } 200 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 } 201 }
136 202
137 ImageResource::~ImageResource() { 203 ImageResource::~ImageResource() {
138 RESOURCE_LOADING_DVLOG(1) << "~ImageResource " << this; 204 RESOURCE_LOADING_DVLOG(1) << "~ImageResource " << this;
139 clearImage();
140 } 205 }
141 206
142 DEFINE_TRACE(ImageResource) { 207 DEFINE_TRACE(ImageResource) {
143 visitor->trace(m_multipartParser); 208 visitor->trace(m_multipartParser);
209 visitor->trace(m_content);
144 Resource::trace(visitor); 210 Resource::trace(visitor);
145 ImageObserver::trace(visitor);
146 MultipartImageResourceParser::Client::trace(visitor); 211 MultipartImageResourceParser::Client::trace(visitor);
147 } 212 }
148 213
149 void ImageResource::checkNotify() { 214 void ImageResource::checkNotify() {
150 // Don't notify clients of completion if this ImageResource is 215 // Don't notify clients of completion if this ImageResource is
151 // about to be reloaded. 216 // about to be reloaded.
152 if (m_isSchedulingReload || shouldReloadBrokenPlaceholder()) 217 if (m_isSchedulingReload || shouldReloadBrokenPlaceholder())
153 return; 218 return;
154 219
155 Resource::checkNotify(); 220 Resource::checkNotify();
156 } 221 }
157 222
158 void ImageResource::markObserverFinished(ImageResourceObserver* observer) { 223 bool ImageResource::hasClientsOrObservers() const {
159 if (m_observers.contains(observer)) { 224 return Resource::hasClientsOrObservers() || getContent()->hasObservers();
160 m_finishedObservers.add(observer);
161 m_observers.remove(observer);
162 }
163 } 225 }
164 226
165 void ImageResource::didAddClient(ResourceClient* client) { 227 void ImageResource::didAddClient(ResourceClient* client) {
166 DCHECK((m_multipartParser && isLoading()) || !data() || m_image); 228 DCHECK((m_multipartParser && isLoading()) || !data() ||
229 getContent()->hasImage());
167 230
168 // 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
169 // about to be reloaded. 232 // about to be reloaded.
170 if (m_isSchedulingReload || shouldReloadBrokenPlaceholder()) 233 if (m_isSchedulingReload || shouldReloadBrokenPlaceholder())
171 return; 234 return;
172 235
173 Resource::didAddClient(client); 236 Resource::didAddClient(client);
174 } 237 }
175 238
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() { 239 void ImageResource::destroyDecodedDataForFailedRevalidation() {
243 clearImage(); 240 getContent()->updateImage(nullptr, ImageResourceContent::ClearExistingImage,
241 false);
244 setDecodedSize(0); 242 setDecodedSize(0);
245 } 243 }
246 244
247 void ImageResource::destroyDecodedDataIfPossible() { 245 void ImageResource::destroyDecodedDataIfPossible() {
248 if (!m_image) 246 getContent()->destroyDecodedData();
249 return; 247 if (getContent()->hasImage() && !isPreloaded() &&
250 CHECK(!errorOccurred()); 248 getContent()->isRefetchableDataFromDiskCache()) {
251 m_image->destroyDecodedData();
252 if (!isPreloaded() && m_isRefetchableDataFromDiskCache) {
253 UMA_HISTOGRAM_MEMORY_KB("Memory.Renderer.EstimatedDroppableEncodedSize", 249 UMA_HISTOGRAM_MEMORY_KB("Memory.Renderer.EstimatedDroppableEncodedSize",
254 encodedSize() / 1024); 250 encodedSize() / 1024);
255 } 251 }
256 } 252 }
257 253
258 void ImageResource::doResetAnimation() {
259 if (m_image)
260 m_image->resetAnimation();
261 }
262
263 void ImageResource::allClientsAndObserversRemoved() { 254 void ImageResource::allClientsAndObserversRemoved() {
264 if (m_image) { 255 CHECK(!getContent()->hasImage() || !errorOccurred());
265 CHECK(!errorOccurred()); 256 // 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 257 // after a conservative GC prevents resetAnimation() from upsetting ongoing
267 // after a conservative GC prevents resetAnimation() from upsetting ongoing 258 // animation updates (crbug.com/613709)
268 // animation updates (crbug.com/613709) 259 if (!ThreadHeap::willObjectBeLazilySwept(this)) {
269 if (!ThreadHeap::willObjectBeLazilySwept(this)) { 260 Platform::current()->currentThread()->getWebTaskRunner()->postTask(
270 Platform::current()->currentThread()->getWebTaskRunner()->postTask( 261 BLINK_FROM_HERE, WTF::bind(&ImageResourceContent::doResetAnimation,
271 BLINK_FROM_HERE, WTF::bind(&ImageResource::doResetAnimation, 262 wrapWeakPersistent(getContent())));
272 wrapWeakPersistent(this))); 263 } else {
273 } else { 264 getContent()->doResetAnimation();
274 m_image->resetAnimation();
275 }
276 } 265 }
277 if (m_multipartParser) 266 if (m_multipartParser)
278 m_multipartParser->cancel(); 267 m_multipartParser->cancel();
279 Resource::allClientsAndObserversRemoved(); 268 Resource::allClientsAndObserversRemoved();
280 } 269 }
281 270
282 PassRefPtr<const SharedBuffer> ImageResource::resourceBuffer() const { 271 PassRefPtr<const SharedBuffer> ImageResource::resourceBuffer() const {
283 if (data()) 272 if (data())
284 return data(); 273 return data();
285 if (m_image) 274 if (getContent()->hasImage())
286 return m_image->data(); 275 return getContent()->getImage()->data();
287 return nullptr; 276 return nullptr;
288 } 277 }
289 278
290 void ImageResource::appendData(const char* data, size_t length) { 279 void ImageResource::appendData(const char* data, size_t length) {
291 v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(length); 280 v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(length);
292 if (m_multipartParser) { 281 if (m_multipartParser) {
293 m_multipartParser->appendData(data, length); 282 m_multipartParser->appendData(data, length);
294 } else { 283 } else {
295 Resource::appendData(data, length); 284 Resource::appendData(data, length);
296 285
297 // If we don't have the size available yet, then update immediately since 286 // 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 287 // 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 288 // animated images, update right away since we shouldn't throttle animated
300 // images. 289 // images.
301 if (m_sizeAvailable == Image::SizeUnavailable || 290 if (!getContent()->isSizeAvailable() ||
302 (m_image && m_image->maybeAnimated())) { 291 (getContent()->hasImage() &&
303 updateImage(false); 292 getContent()->getImage()->maybeAnimated())) {
293 getContent()->updateImage(this->data(),
294 ImageResourceContent::KeepExistingImage, false);
304 return; 295 return;
305 } 296 }
306 297
307 // For other cases, only update at |kFlushDelaySeconds| intervals. This 298 // For other cases, only update at |kFlushDelaySeconds| intervals. This
308 // throttles how frequently we update |m_image| and how frequently we 299 // throttles how frequently we update |m_image| and how frequently we
309 // inform the clients which causes an invalidation of this image. In other 300 // inform the clients which causes an invalidation of this image. In other
310 // words, we only invalidate this image every |kFlushDelaySeconds| seconds 301 // words, we only invalidate this image every |kFlushDelaySeconds| seconds
311 // while loading. 302 // while loading.
312 if (!m_flushTimer.isActive()) { 303 if (!m_flushTimer.isActive()) {
313 double now = WTF::monotonicallyIncreasingTime(); 304 double now = WTF::monotonicallyIncreasingTime();
314 if (!m_lastFlushTime) 305 if (!m_lastFlushTime)
315 m_lastFlushTime = now; 306 m_lastFlushTime = now;
316 307
317 DCHECK_LE(m_lastFlushTime, now); 308 DCHECK_LE(m_lastFlushTime, now);
318 double flushDelay = m_lastFlushTime - now + kFlushDelaySeconds; 309 double flushDelay = m_lastFlushTime - now + kFlushDelaySeconds;
319 if (flushDelay < 0.) 310 if (flushDelay < 0.)
320 flushDelay = 0.; 311 flushDelay = 0.;
321 m_flushTimer.startOneShot(flushDelay, BLINK_FROM_HERE); 312 m_flushTimer.startOneShot(flushDelay, BLINK_FROM_HERE);
322 } 313 }
323 } 314 }
324 } 315 }
325 316
326 void ImageResource::flushImageIfNeeded(TimerBase*) { 317 void ImageResource::flushImageIfNeeded(TimerBase*) {
327 // We might have already loaded the image fully, in which case we don't need 318 // We might have already loaded the image fully, in which case we don't need
328 // to call |updateImage()|. 319 // to call |updateImage()|.
329 if (isLoading()) { 320 if (isLoading()) {
330 m_lastFlushTime = WTF::monotonicallyIncreasingTime(); 321 m_lastFlushTime = WTF::monotonicallyIncreasingTime();
331 updateImage(false); 322 getContent()->updateImage(this->data(),
323 ImageResourceContent::KeepExistingImage, false);
332 } 324 }
333 } 325 }
334 326
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 { 327 bool ImageResource::willPaintBrokenImage() const {
349 return errorOccurred(); 328 return errorOccurred();
350 } 329 }
351 330
352 blink::Image* ImageResource::getImage() { 331 void ImageResource::decodeError(bool allDataReceived) {
353 if (errorOccurred()) { 332 size_t size = encodedSize();
354 // Returning the 1x broken image is non-ideal, but we cannot reliably access 333
355 // the appropriate deviceScaleFactor from here. It is critical that callers 334 clearData();
356 // use ImageResource::brokenImage() when they need the real, 335 setEncodedSize(0);
357 // deviceScaleFactor-appropriate broken image icon. 336 if (!errorOccurred())
358 return brokenImage(1).first; 337 setStatus(DecodeError);
338
339 if (!allDataReceived && loader()) {
340 // TODO(hiroshige): Do not call didFinishLoading() directly.
341 loader()->didFinishLoading(monotonicallyIncreasingTime(), size, size);
359 } 342 }
360 343
361 if (m_image) 344 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 } 345 }
514 346
515 void ImageResource::updateImageAndClearBuffer() { 347 void ImageResource::updateImageAndClearBuffer() {
516 clearImage(); 348 getContent()->updateImage(data(), ImageResourceContent::ClearExistingImage,
517 updateImage(true); 349 true);
518 clearData(); 350 clearData();
519 } 351 }
520 352
521 void ImageResource::finish(double loadFinishTime) { 353 void ImageResource::finish(double loadFinishTime) {
522 if (m_multipartParser) { 354 if (m_multipartParser) {
523 m_multipartParser->finish(); 355 m_multipartParser->finish();
524 if (data()) 356 if (data())
525 updateImageAndClearBuffer(); 357 updateImageAndClearBuffer();
526 } else { 358 } else {
527 updateImage(true); 359 getContent()->updateImage(data(), ImageResourceContent::KeepExistingImage,
360 true);
528 // As encoded image data can be created from m_image (see 361 // As encoded image data can be created from m_image (see
529 // ImageResource::resourceBuffer(), we don't have to keep m_data. Let's 362 // 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 363 // clear this. As for the lifetimes of m_image and m_data, see this
531 // document: 364 // document:
532 // https://docs.google.com/document/d/1v0yTAZ6wkqX2U_M6BNIGUJpM1s0TIw1Vsqpxo L7aciY/edit?usp=sharing 365 // https://docs.google.com/document/d/1v0yTAZ6wkqX2U_M6BNIGUJpM1s0TIw1Vsqpxo L7aciY/edit?usp=sharing
533 clearData(); 366 clearData();
534 } 367 }
535 Resource::finish(loadFinishTime); 368 Resource::finish(loadFinishTime);
536 } 369 }
537 370
538 void ImageResource::error(const ResourceError& error) { 371 void ImageResource::error(const ResourceError& error) {
539 if (m_multipartParser) 372 if (m_multipartParser)
540 m_multipartParser->cancel(); 373 m_multipartParser->cancel();
541 clear(); 374 clearData();
yhirano 2016/12/05 09:02:03 Resource::error calls clearData().
yhirano 2016/12/05 09:02:03 +setEncodedSize(0)?
hiroshige 2016/12/06 09:32:50 Done to keep the current behavior. But I'm not so
hiroshige 2016/12/06 09:32:50 Done.
542 Resource::error(error); 375 Resource::error(error);
543 notifyObservers(ShouldNotifyFinish); 376 getContent()->updateImage(nullptr, ImageResourceContent::ClearExistingImage,
377 true);
544 } 378 }
545 379
546 void ImageResource::responseReceived( 380 void ImageResource::responseReceived(
547 const ResourceResponse& response, 381 const ResourceResponse& response,
548 std::unique_ptr<WebDataConsumerHandle> handle) { 382 std::unique_ptr<WebDataConsumerHandle> handle) {
549 DCHECK(!handle); 383 DCHECK(!handle);
550 DCHECK(!m_multipartParser); 384 DCHECK(!m_multipartParser);
551 // If there's no boundary, just handle the request normally. 385 // If there's no boundary, just handle the request normally.
552 if (response.isMultipart() && !response.multipartBoundary().isEmpty()) { 386 if (response.isMultipart() && !response.multipartBoundary().isEmpty()) {
553 m_multipartParser = new MultipartImageResourceParser( 387 m_multipartParser = new MultipartImageResourceParser(
554 response, response.multipartBoundary(), this); 388 response, response.multipartBoundary(), this);
555 } 389 }
556 Resource::responseReceived(response, std::move(handle)); 390 Resource::responseReceived(response, std::move(handle));
557 if (RuntimeEnabledFeatures::clientHintsEnabled()) { 391 if (RuntimeEnabledFeatures::clientHintsEnabled()) {
558 m_devicePixelRatioHeaderValue = 392 m_devicePixelRatioHeaderValue =
559 this->response() 393 this->response()
560 .httpHeaderField(HTTPNames::Content_DPR) 394 .httpHeaderField(HTTPNames::Content_DPR)
561 .toFloat(&m_hasDevicePixelRatioHeaderValue); 395 .toFloat(&m_hasDevicePixelRatioHeaderValue);
562 if (!m_hasDevicePixelRatioHeaderValue || 396 if (!m_hasDevicePixelRatioHeaderValue ||
563 m_devicePixelRatioHeaderValue <= 0.0) { 397 m_devicePixelRatioHeaderValue <= 0.0) {
564 m_devicePixelRatioHeaderValue = 1.0; 398 m_devicePixelRatioHeaderValue = 1.0;
565 m_hasDevicePixelRatioHeaderValue = false; 399 m_hasDevicePixelRatioHeaderValue = false;
566 } 400 }
567 } 401 }
568 } 402 }
569 403
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) { 404 static bool isLoFiImage(const ImageResource& resource) {
624 if (resource.resourceRequest().loFiState() != WebURLRequest::LoFiOn) 405 if (resource.resourceRequest().loFiState() != WebURLRequest::LoFiOn)
625 return false; 406 return false;
626 return !resource.isLoaded() || 407 return !resource.isLoaded() ||
627 resource.response() 408 resource.response()
628 .httpHeaderField("chrome-proxy-content-transform") 409 .httpHeaderField("chrome-proxy-content-transform")
629 .contains("empty-image"); 410 .contains("empty-image");
630 } 411 }
631 412
632 void ImageResource::reloadIfLoFiOrPlaceholder( 413 void ImageResource::reloadIfLoFiOrPlaceholder(
(...skipping 17 matching lines...) Expand all
650 m_isPlaceholder = false; 431 m_isPlaceholder = false;
651 clearRangeRequestHeader(); 432 clearRangeRequestHeader();
652 } 433 }
653 434
654 if (isLoading()) { 435 if (isLoading()) {
655 loader()->cancel(); 436 loader()->cancel();
656 // Canceling the loader causes error() to be called, which in turn calls 437 // 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 438 // clear() and notifyObservers(), so there's no need to call these again
658 // here. 439 // here.
659 } else { 440 } else {
660 clear(); 441 clearData();
661 notifyObservers(DoNotNotifyFinish); 442 setEncodedSize(0);
443 getContent()->updateImage(nullptr, ImageResourceContent::ClearExistingImage,
444 false);
662 } 445 }
663 446
664 setStatus(NotStarted); 447 setStatus(NotStarted);
665 448
666 DCHECK(m_isSchedulingReload); 449 DCHECK(m_isSchedulingReload);
667 m_isSchedulingReload = false; 450 m_isSchedulingReload = false;
668 451
669 fetcher->startLoad(this); 452 fetcher->startLoad(this);
670 } 453 }
671 454
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( 455 void ImageResource::onePartInMultipartReceived(
680 const ResourceResponse& response) { 456 const ResourceResponse& response) {
681 DCHECK(m_multipartParser); 457 DCHECK(m_multipartParser);
682 458
683 setResponse(response); 459 setResponse(response);
684 if (m_multipartParsingState == MultipartParsingState::WaitingForFirstPart) { 460 if (m_multipartParsingState == MultipartParsingState::WaitingForFirstPart) {
685 // We have nothing to do because we don't have any data. 461 // We have nothing to do because we don't have any data.
686 m_multipartParsingState = MultipartParsingState::ParsingFirstPart; 462 m_multipartParsingState = MultipartParsingState::ParsingFirstPart;
687 return; 463 return;
688 } 464 }
(...skipping 11 matching lines...) Expand all
700 if (loader()) 476 if (loader())
701 loader()->didFinishLoadingFirstPartInMultipart(); 477 loader()->didFinishLoadingFirstPartInMultipart();
702 } 478 }
703 } 479 }
704 480
705 void ImageResource::multipartDataReceived(const char* bytes, size_t size) { 481 void ImageResource::multipartDataReceived(const char* bytes, size_t size) {
706 DCHECK(m_multipartParser); 482 DCHECK(m_multipartParser);
707 Resource::appendData(bytes, size); 483 Resource::appendData(bytes, size);
708 } 484 }
709 485
710 bool ImageResource::isAccessAllowed(SecurityOrigin* securityOrigin) { 486 bool ImageResource::isAccessAllowed(
487 SecurityOrigin* securityOrigin,
488 bool 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)
716 return false; 494 return false;
717 if (passesAccessControlCheck(securityOrigin)) 495 if (passesAccessControlCheck(securityOrigin))
718 return true; 496 return true;
719 return !securityOrigin->taintsCanvas(response().url()); 497 return !securityOrigin->taintsCanvas(response().url());
720 } 498 }
721 499
500 ImageResourceContent* ImageResource::getContent() const {
501 return m_content;
502 }
503
504 ResourcePriority ImageResource::priorityFromObservers() {
505 return getContent()->priorityFromObservers();
506 }
507
722 } // namespace blink 508 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698