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

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

Issue 2469873002: [ImageResource 4] Split ImageResource into Resource and Image parts (Closed)
Patch Set: comments 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 // Copyright 2016 The Chromium Authors. All rights reserved.
2 Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de) 2 // Use of this source code is governed by a BSD-style license that can be
3 Copyright (C) 2001 Dirk Mueller (mueller@kde.org) 3 // found in the LICENSE file.
4 Copyright (C) 2002 Waldo Bastian (bastian@kde.org)
5 Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
6 Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
7 4
8 This library is free software; you can redistribute it and/or 5 #include "core/fetch/ImageResourceContent.h"
9 modify it under the terms of the GNU Library General Public
10 License as published by the Free Software Foundation; either
11 version 2 of the License, or (at your option) any later version.
12
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Library General Public License for more details.
17
18 You should have received a copy of the GNU Library General Public License
19 along with this library; see the file COPYING.LIB. If not, write to
20 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 Boston, MA 02110-1301, USA.
22 */
23 6
24 #include "core/fetch/ImageResource.h" 7 #include "core/fetch/ImageResource.h"
25
26 #include "core/fetch/ImageResourceObserver.h" 8 #include "core/fetch/ImageResourceObserver.h"
27 #include "core/fetch/MemoryCache.h"
28 #include "core/fetch/ResourceClient.h"
29 #include "core/fetch/ResourceFetcher.h"
30 #include "core/fetch/ResourceLoader.h"
31 #include "core/fetch/ResourceLoadingLog.h"
32 #include "core/svg/graphics/SVGImage.h" 9 #include "core/svg/graphics/SVGImage.h"
33 #include "platform/Histogram.h" 10 #include "platform/Histogram.h"
34 #include "platform/RuntimeEnabledFeatures.h" 11 #include "platform/RuntimeEnabledFeatures.h"
35 #include "platform/SharedBuffer.h" 12 #include "platform/SharedBuffer.h"
36 #include "platform/geometry/IntSize.h" 13 #include "platform/geometry/IntSize.h"
37 #include "platform/graphics/BitmapImage.h" 14 #include "platform/graphics/BitmapImage.h"
38 #include "platform/graphics/PlaceholderImage.h" 15 #include "platform/graphics/PlaceholderImage.h"
39 #include "platform/tracing/TraceEvent.h" 16 #include "platform/tracing/TraceEvent.h"
40 #include "public/platform/Platform.h"
41 #include "public/platform/WebCachePolicy.h"
42 #include "wtf/CurrentTime.h"
43 #include "wtf/HashCountedSet.h" 17 #include "wtf/HashCountedSet.h"
44 #include "wtf/StdLibExtras.h" 18 #include "wtf/StdLibExtras.h"
45 #include "wtf/Vector.h" 19 #include "wtf/Vector.h"
46 #include <memory> 20 #include <memory>
47 #include <v8.h> 21 #include <v8.h>
48 22
49 namespace blink { 23 namespace blink {
50 namespace { 24 namespace {
51 // The amount of time to wait before informing the clients that the image has 25 class NullImageResourceInfo final
52 // been updated (in seconds). This effectively throttles invalidations that 26 : public GarbageCollectedFinalized<NullImageResourceInfo>,
53 // result from new data arriving for this image. 27 public ImageResourceInfo {
54 constexpr double kFlushDelaySeconds = 1.; 28 USING_GARBAGE_COLLECTED_MIXIN(NullImageResourceInfo);
29
30 public:
31 NullImageResourceInfo() {}
32
33 DEFINE_INLINE_VIRTUAL_TRACE() { ImageResourceInfo::trace(visitor); }
34
35 private:
36 const KURL& url() const override { return m_url; }
37 bool isSchedulingReload() const override { return false; }
38 bool hasDevicePixelRatioHeaderValue() const override { return false; }
39 float devicePixelRatioHeaderValue() const override { return 1.0; }
40 const ResourceResponse& response() const override { return m_response; }
41 ResourceStatus getStatus() const override { return ResourceStatus::Cached; }
42 bool isPlaceholder() const override { return false; }
43 bool isCacheValidator() const override { return false; }
44 bool schedulingReloadOrShouldReloadBrokenPlaceholder() const override {
45 return false;
46 }
47 bool isAccessAllowed(
48 SecurityOrigin*,
49 bool doesCurrentFrameHasSingleSecurityOrigin) const override {
50 return true;
51 }
52 bool hasCacheControlNoStoreHeader() const override { return false; }
53
54 const KURL m_url;
55 const ResourceResponse m_response;
56 };
57
55 } // namespace 58 } // namespace
56 59
57 class ImageResource::ImageResourceFactory : public ResourceFactory { 60 class ResourceFetcher;
58 STACK_ALLOCATED();
59 61
60 public: 62 ImageResourceContent::ImageResourceContent(PassRefPtr<blink::Image> image)
61 ImageResourceFactory(const FetchRequest& fetchRequest) 63 : m_image(image), m_isRefetchableDataFromDiskCache(true) {
62 : ResourceFactory(Resource::Image), m_fetchRequest(&fetchRequest) {} 64 DEFINE_STATIC_LOCAL(NullImageResourceInfo, nullInfo,
63 65 (new NullImageResourceInfo()));
64 Resource* create(const ResourceRequest& request, 66 m_info = &nullInfo;
65 const ResourceLoaderOptions& options,
66 const String&) const override {
67 return new ImageResource(request, options,
68 m_fetchRequest->placeholderImageRequestType() ==
69 FetchRequest::AllowPlaceholder);
70 }
71
72 private:
73 // Weak, unowned pointer. Must outlive |this|.
74 const FetchRequest* m_fetchRequest;
75 };
76
77 ImageResource* ImageResource::fetch(FetchRequest& request,
78 ResourceFetcher* fetcher) {
79 if (request.resourceRequest().requestContext() ==
80 WebURLRequest::RequestContextUnspecified) {
81 request.mutableResourceRequest().setRequestContext(
82 WebURLRequest::RequestContextImage);
83 }
84 if (fetcher->context().pageDismissalEventBeingDispatched()) {
85 KURL requestURL = request.resourceRequest().url();
86 if (requestURL.isValid() &&
87 fetcher->context().canRequest(Resource::Image,
88 request.resourceRequest(), requestURL,
89 request.options(), request.forPreload(),
90 request.getOriginRestriction()))
91 fetcher->context().sendImagePing(requestURL);
92 return nullptr;
93 }
94
95 ImageResource* resource = toImageResource(
96 fetcher->requestResource(request, ImageResourceFactory(request)));
97 if (resource &&
98 request.placeholderImageRequestType() != FetchRequest::AllowPlaceholder &&
99 resource->m_isPlaceholder) {
100 // If the image is a placeholder, but this fetch doesn't allow a
101 // placeholder, then load the original image. Note that the cache is not
102 // bypassed here - it should be fine to use a cached copy if possible.
103 resource->reloadIfLoFiOrPlaceholder(fetcher,
104 ReloadCachePolicy::UseExistingPolicy);
105 }
106 return resource;
107 } 67 }
108 68
109 ImageResource::ImageResource(const ResourceRequest& resourceRequest, 69 ImageResourceContent* ImageResourceContent::fetch(FetchRequest& request,
110 const ResourceLoaderOptions& options, 70 ResourceFetcher* fetcher) {
111 bool isPlaceholder) 71 ImageResource* resource = ImageResource::fetch(request, fetcher);
112 : Resource(resourceRequest, Image, options), 72 if (!resource)
113 m_devicePixelRatioHeaderValue(1.0), 73 return nullptr;
114 m_image(nullptr), 74 return resource->getRealContent();
115 m_hasDevicePixelRatioHeaderValue(false),
116 m_isSchedulingReload(false),
117 m_isPlaceholder(isPlaceholder),
118 m_flushTimer(this, &ImageResource::flushImageIfNeeded),
119 m_isRefetchableDataFromDiskCache(true) {
120 RESOURCE_LOADING_DVLOG(1) << "new ImageResource(ResourceRequest) " << this;
121 } 75 }
122 76
123 ImageResource::ImageResource(blink::Image* image, 77 void ImageResourceContent::setImageResourceInfo(ImageResourceInfo* info) {
124 const ResourceLoaderOptions& options) 78 m_info = info;
125 : Resource(ResourceRequest(""), Image, options),
126 m_devicePixelRatioHeaderValue(1.0),
127 m_image(image),
128 m_hasDevicePixelRatioHeaderValue(false),
129 m_isSchedulingReload(false),
130 m_isPlaceholder(false),
131 m_flushTimer(this, &ImageResource::flushImageIfNeeded),
132 m_isRefetchableDataFromDiskCache(true) {
133 RESOURCE_LOADING_DVLOG(1) << "new ImageResource(Image) " << this;
134 setStatus(Cached);
135 } 79 }
136 80
137 ImageResource::~ImageResource() { 81 DEFINE_TRACE(ImageResourceContent) {
138 RESOURCE_LOADING_DVLOG(1) << "~ImageResource " << this; 82 visitor->trace(m_info);
139 clearImage(); 83 ImageObserver::trace(visitor);
84 ImageResourceContentInterface::trace(visitor);
140 } 85 }
141 86
142 DEFINE_TRACE(ImageResource) { 87 void ImageResourceContent::markObserverFinished(
143 visitor->trace(m_multipartParser); 88 ImageResourceObserver* observer) {
144 Resource::trace(visitor);
145 ImageObserver::trace(visitor);
146 MultipartImageResourceParser::Client::trace(visitor);
147 }
148
149 void ImageResource::checkNotify() {
150 // Don't notify clients of completion if this ImageResource is
151 // about to be reloaded.
152 if (m_isSchedulingReload || shouldReloadBrokenPlaceholder())
153 return;
154
155 Resource::checkNotify();
156 }
157
158 void ImageResource::markObserverFinished(ImageResourceObserver* observer) {
159 if (m_observers.contains(observer)) { 89 if (m_observers.contains(observer)) {
160 m_finishedObservers.add(observer); 90 m_finishedObservers.add(observer);
161 m_observers.remove(observer); 91 m_observers.remove(observer);
162 } 92 }
163 } 93 }
164 94
165 void ImageResource::didAddClient(ResourceClient* client) { 95 void ImageResourceContent::addObserver(ImageResourceObserver* observer) {
166 DCHECK((m_multipartParser && isLoading()) || !data() || m_image); 96 m_info->willAddClientOrObserver();
167
168 // Don't notify observers and clients of completion if this ImageResource is
169 // about to be reloaded.
170 if (m_isSchedulingReload || shouldReloadBrokenPlaceholder())
171 return;
172
173 Resource::didAddClient(client);
174 }
175
176 void ImageResource::addObserver(ImageResourceObserver* observer) {
177 willAddClientOrObserver(MarkAsReferenced);
178 97
179 m_observers.add(observer); 98 m_observers.add(observer);
180 99
181 if (isCacheValidator()) 100 if (m_info->isCacheValidator())
182 return; 101 return;
183 102
184 // When the response is not multipart, if |data()| exists, |m_image| must be
185 // created. This is assured that |updateImage()| is called when |appendData()|
186 // is called.
187 //
188 // On the other hand, when the response is multipart, |updateImage()| is not
189 // called in |appendData()|, which means |m_image| might not be created even
190 // when |data()| exists. This is intentional since creating a |m_image| on
191 // receiving data might destroy an existing image in a previous part.
192 DCHECK((m_multipartParser && isLoading()) || !data() || m_image);
193
194 if (m_image && !m_image->isNull()) { 103 if (m_image && !m_image->isNull()) {
195 observer->imageChanged(this); 104 observer->imageChanged(this);
196 } 105 }
197 106
198 if (isLoaded() && m_observers.contains(observer) && !m_isSchedulingReload && 107 if (isLoaded() && m_observers.contains(observer) &&
199 !shouldReloadBrokenPlaceholder()) { 108 !m_info->schedulingReloadOrShouldReloadBrokenPlaceholder()) {
200 markObserverFinished(observer); 109 markObserverFinished(observer);
201 observer->imageNotifyFinished(this); 110 observer->imageNotifyFinished(this);
202 } 111 }
203 } 112 }
204 113
205 void ImageResource::removeObserver(ImageResourceObserver* observer) { 114 void ImageResourceContent::removeObserver(ImageResourceObserver* observer) {
206 DCHECK(observer); 115 DCHECK(observer);
207 116
208 if (m_observers.contains(observer)) 117 if (m_observers.contains(observer))
209 m_observers.remove(observer); 118 m_observers.remove(observer);
210 else if (m_finishedObservers.contains(observer)) 119 else if (m_finishedObservers.contains(observer))
211 m_finishedObservers.remove(observer); 120 m_finishedObservers.remove(observer);
212 else 121 else
213 NOTREACHED(); 122 NOTREACHED();
214 123
215 didRemoveClientOrObserver(); 124 m_info->didRemoveClientOrObserver();
216 } 125 }
217 126
218 static void priorityFromObserver(const ImageResourceObserver* observer, 127 static void priorityFromObserver(const ImageResourceObserver* observer,
219 ResourcePriority& priority) { 128 ResourcePriority& priority) {
220 ResourcePriority nextPriority = observer->computeResourcePriority(); 129 ResourcePriority nextPriority = observer->computeResourcePriority();
221 if (nextPriority.visibility == ResourcePriority::NotVisible) 130 if (nextPriority.visibility == ResourcePriority::NotVisible)
222 return; 131 return;
223 priority.visibility = ResourcePriority::Visible; 132 priority.visibility = ResourcePriority::Visible;
224 priority.intraPriorityValue += nextPriority.intraPriorityValue; 133 priority.intraPriorityValue += nextPriority.intraPriorityValue;
225 } 134 }
226 135
227 ResourcePriority ImageResource::priorityFromObservers() { 136 ResourcePriority ImageResourceContent::priorityFromObservers() const {
228 ResourcePriority priority; 137 ResourcePriority priority;
229 138
230 for (auto* observer : m_finishedObservers.asVector()) { 139 for (auto* observer : m_finishedObservers.asVector()) {
231 if (m_finishedObservers.contains(observer)) 140 if (m_finishedObservers.contains(observer))
232 priorityFromObserver(observer, priority); 141 priorityFromObserver(observer, priority);
233 } 142 }
234 for (auto* observer : m_observers.asVector()) { 143 for (auto* observer : m_observers.asVector()) {
235 if (m_observers.contains(observer)) 144 if (m_observers.contains(observer))
236 priorityFromObserver(observer, priority); 145 priorityFromObserver(observer, priority);
237 } 146 }
238 147
239 return priority; 148 return priority;
240 } 149 }
241 150
242 void ImageResource::destroyDecodedDataForFailedRevalidation() { 151 void ImageResourceContent::destroyDecodedData() {
243 clearImage();
244 setDecodedSize(0);
245 }
246
247 void ImageResource::destroyDecodedDataIfPossible() {
248 if (!m_image) 152 if (!m_image)
249 return; 153 return;
250 CHECK(!errorOccurred()); 154 CHECK(!errorOccurred());
251 m_image->destroyDecodedData(); 155 m_image->destroyDecodedData();
hiroshige 2016/11/30 06:46:24 The UMA is collected in the caller of this method
252 if (!isPreloaded() && m_isRefetchableDataFromDiskCache) {
253 UMA_HISTOGRAM_MEMORY_KB("Memory.Renderer.EstimatedDroppableEncodedSize",
254 encodedSize() / 1024);
255 }
256 } 156 }
257 157
258 void ImageResource::doResetAnimation() { 158 void ImageResourceContent::doResetAnimation() {
259 if (m_image) 159 if (m_image)
260 m_image->resetAnimation(); 160 m_image->resetAnimation();
261 } 161 }
262 162
263 void ImageResource::allClientsAndObserversRemoved() { 163 std::pair<blink::Image*, float> ImageResourceContent::brokenImage(
264 if (m_image) {
265 CHECK(!errorOccurred());
266 // If possible, delay the resetting until back at the event loop. Doing so
267 // after a conservative GC prevents resetAnimation() from upsetting ongoing
268 // animation updates (crbug.com/613709)
269 if (!ThreadHeap::willObjectBeLazilySwept(this)) {
270 Platform::current()->currentThread()->getWebTaskRunner()->postTask(
271 BLINK_FROM_HERE, WTF::bind(&ImageResource::doResetAnimation,
272 wrapWeakPersistent(this)));
273 } else {
274 m_image->resetAnimation();
275 }
276 }
277 if (m_multipartParser)
278 m_multipartParser->cancel();
279 Resource::allClientsAndObserversRemoved();
280 }
281
282 PassRefPtr<const SharedBuffer> ImageResource::resourceBuffer() const {
283 if (data())
284 return data();
285 if (m_image)
286 return m_image->data();
287 return nullptr;
288 }
289
290 void ImageResource::appendData(const char* data, size_t length) {
291 v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(length);
292 if (m_multipartParser) {
293 m_multipartParser->appendData(data, length);
294 } else {
295 Resource::appendData(data, length);
296
297 // If we don't have the size available yet, then update immediately since
298 // we need to know the image size as soon as possible. Likewise for
299 // animated images, update right away since we shouldn't throttle animated
300 // images.
301 if (m_sizeAvailable == Image::SizeUnavailable ||
302 (m_image && m_image->maybeAnimated())) {
303 updateImage(false);
304 return;
305 }
306
307 // For other cases, only update at |kFlushDelaySeconds| intervals. This
308 // throttles how frequently we update |m_image| and how frequently we
309 // inform the clients which causes an invalidation of this image. In other
310 // words, we only invalidate this image every |kFlushDelaySeconds| seconds
311 // while loading.
312 if (!m_flushTimer.isActive()) {
313 double now = WTF::monotonicallyIncreasingTime();
314 if (!m_lastFlushTime)
315 m_lastFlushTime = now;
316
317 DCHECK_LE(m_lastFlushTime, now);
318 double flushDelay = m_lastFlushTime - now + kFlushDelaySeconds;
319 if (flushDelay < 0.)
320 flushDelay = 0.;
321 m_flushTimer.startOneShot(flushDelay, BLINK_FROM_HERE);
322 }
323 }
324 }
325
326 void ImageResource::flushImageIfNeeded(TimerBase*) {
327 // We might have already loaded the image fully, in which case we don't need
328 // to call |updateImage()|.
329 if (isLoading()) {
330 m_lastFlushTime = WTF::monotonicallyIncreasingTime();
331 updateImage(false);
332 }
333 }
334
335 std::pair<blink::Image*, float> ImageResource::brokenImage(
336 float deviceScaleFactor) { 164 float deviceScaleFactor) {
337 if (deviceScaleFactor >= 2) { 165 if (deviceScaleFactor >= 2) {
338 DEFINE_STATIC_REF(blink::Image, brokenImageHiRes, 166 DEFINE_STATIC_REF(blink::Image, brokenImageHiRes,
339 (blink::Image::loadPlatformResource("missingImage@2x"))); 167 (blink::Image::loadPlatformResource("missingImage@2x")));
340 return std::make_pair(brokenImageHiRes, 2); 168 return std::make_pair(brokenImageHiRes, 2);
341 } 169 }
342 170
343 DEFINE_STATIC_REF(blink::Image, brokenImageLoRes, 171 DEFINE_STATIC_REF(blink::Image, brokenImageLoRes,
344 (blink::Image::loadPlatformResource("missingImage"))); 172 (blink::Image::loadPlatformResource("missingImage")));
345 return std::make_pair(brokenImageLoRes, 1); 173 return std::make_pair(brokenImageLoRes, 1);
346 } 174 }
347 175
348 bool ImageResource::willPaintBrokenImage() const { 176 blink::Image* ImageResourceContent::getImage() const {
349 return errorOccurred();
350 }
351
352 blink::Image* ImageResource::getImage() {
353 if (errorOccurred()) { 177 if (errorOccurred()) {
354 // Returning the 1x broken image is non-ideal, but we cannot reliably access 178 // Returning the 1x broken image is non-ideal, but we cannot reliably access
355 // the appropriate deviceScaleFactor from here. It is critical that callers 179 // the appropriate deviceScaleFactor from here. It is critical that callers
356 // use ImageResource::brokenImage() when they need the real, 180 // use ImageResourceContent::brokenImage() when they need the real,
357 // deviceScaleFactor-appropriate broken image icon. 181 // deviceScaleFactor-appropriate broken image icon.
358 return brokenImage(1).first; 182 return brokenImage(1).first;
359 } 183 }
360 184
361 if (m_image) 185 if (m_image)
362 return m_image.get(); 186 return m_image.get();
363 187
364 return blink::Image::nullImage(); 188 return blink::Image::nullImage();
365 } 189 }
366 190
367 bool ImageResource::usesImageContainerSize() const { 191 bool ImageResourceContent::usesImageContainerSize() const {
368 if (m_image) 192 if (m_image)
369 return m_image->usesContainerSize(); 193 return m_image->usesContainerSize();
370 194
371 return false; 195 return false;
372 } 196 }
373 197
374 bool ImageResource::imageHasRelativeSize() const { 198 bool ImageResourceContent::imageHasRelativeSize() const {
375 if (m_image) 199 if (m_image)
376 return m_image->hasRelativeSize(); 200 return m_image->hasRelativeSize();
377 201
378 return false; 202 return false;
379 } 203 }
380 204
381 LayoutSize ImageResource::imageSize( 205 LayoutSize ImageResourceContent::imageSize(
382 RespectImageOrientationEnum shouldRespectImageOrientation, 206 RespectImageOrientationEnum shouldRespectImageOrientation,
383 float multiplier, 207 float multiplier,
384 SizeType sizeType) { 208 SizeType sizeType) {
385 if (!m_image) 209 if (!m_image)
386 return LayoutSize(); 210 return LayoutSize();
387 211
388 LayoutSize size; 212 LayoutSize size;
389 213
390 if (m_image->isBitmapImage() && 214 if (m_image->isBitmapImage() &&
391 shouldRespectImageOrientation == RespectImageOrientation) { 215 shouldRespectImageOrientation == RespectImageOrientation) {
392 size = 216 size =
393 LayoutSize(toBitmapImage(m_image.get())->sizeRespectingOrientation()); 217 LayoutSize(toBitmapImage(m_image.get())->sizeRespectingOrientation());
394 } else { 218 } else {
395 size = LayoutSize(m_image->size()); 219 size = LayoutSize(m_image->size());
396 } 220 }
397 221
398 if (sizeType == IntrinsicCorrectedToDPR && m_hasDevicePixelRatioHeaderValue && 222 if (sizeType == IntrinsicCorrectedToDPR && hasDevicePixelRatioHeaderValue() &&
399 m_devicePixelRatioHeaderValue > 0) 223 devicePixelRatioHeaderValue() > 0)
400 multiplier = 1 / m_devicePixelRatioHeaderValue; 224 multiplier = 1 / devicePixelRatioHeaderValue();
401 225
402 if (multiplier == 1 || m_image->hasRelativeSize()) 226 if (multiplier == 1 || m_image->hasRelativeSize())
403 return size; 227 return size;
404 228
405 // Don't let images that have a width/height >= 1 shrink below 1 when zoomed. 229 // Don't let images that have a width/height >= 1 shrink below 1 when zoomed.
406 LayoutSize minimumSize( 230 LayoutSize minimumSize(
407 size.width() > LayoutUnit() ? LayoutUnit(1) : LayoutUnit(), 231 size.width() > LayoutUnit() ? LayoutUnit(1) : LayoutUnit(),
408 LayoutUnit(size.height() > LayoutUnit() ? LayoutUnit(1) : LayoutUnit())); 232 LayoutUnit(size.height() > LayoutUnit() ? LayoutUnit(1) : LayoutUnit()));
409 size.scale(multiplier); 233 size.scale(multiplier);
410 size.clampToMinimumSize(minimumSize); 234 size.clampToMinimumSize(minimumSize);
411 return size; 235 return size;
412 } 236 }
413 237
414 void ImageResource::notifyObservers(NotifyFinishOption notifyingFinishOption, 238 void ImageResourceContent::notifyObservers(
415 const IntRect* changeRect) { 239 NotifyFinishOption notifyingFinishOption,
240 const IntRect* changeRect) {
416 for (auto* observer : m_finishedObservers.asVector()) { 241 for (auto* observer : m_finishedObservers.asVector()) {
417 if (m_finishedObservers.contains(observer)) 242 if (m_finishedObservers.contains(observer))
418 observer->imageChanged(this, changeRect); 243 observer->imageChanged(this, changeRect);
419 } 244 }
420 for (auto* observer : m_observers.asVector()) { 245 for (auto* observer : m_observers.asVector()) {
421 if (m_observers.contains(observer)) { 246 if (m_observers.contains(observer)) {
422 observer->imageChanged(this, changeRect); 247 observer->imageChanged(this, changeRect);
423 if (notifyingFinishOption == ShouldNotifyFinish && 248 if (notifyingFinishOption == ShouldNotifyFinish &&
424 m_observers.contains(observer) && !m_isSchedulingReload && 249 m_observers.contains(observer) &&
425 !shouldReloadBrokenPlaceholder()) { 250 !m_info->schedulingReloadOrShouldReloadBrokenPlaceholder()) {
426 markObserverFinished(observer); 251 markObserverFinished(observer);
427 observer->imageNotifyFinished(this); 252 observer->imageNotifyFinished(this);
428 } 253 }
429 } 254 }
430 } 255 }
431 } 256 }
432 257
433 void ImageResource::clear() { 258 inline PassRefPtr<Image> ImageResourceContent::createImage() {
434 clearImage(); 259 if (m_info->response().mimeType() == "image/svg+xml")
435 clearData(); 260 return SVGImage::create(this);
436 setEncodedSize(0); 261 return BitmapImage::create(this);
437 } 262 }
438 263
439 inline void ImageResource::createImage() { 264 inline void ImageResourceContent::clearImage() {
440 // Create the image if it doesn't yet exist.
441 if (m_image)
442 return;
443
444 if (response().mimeType() == "image/svg+xml") {
445 m_image = SVGImage::create(this);
446 } else {
447 m_image = BitmapImage::create(this);
448 }
449 }
450
451 inline void ImageResource::clearImage() {
452 if (!m_image) 265 if (!m_image)
453 return; 266 return;
454 int64_t length = m_image->data() ? m_image->data()->size() : 0; 267 int64_t length = m_image->data() ? m_image->data()->size() : 0;
455 v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(-length); 268 v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(-length);
456 269
457 // If our Image has an observer, it's always us so we need to clear the back 270 // If our Image has an observer, it's always us so we need to clear the back
458 // pointer before dropping our reference. 271 // pointer before dropping our reference.
459 m_image->clearImageObserver(); 272 m_image->clearImageObserver();
460 m_image.clear(); 273 m_image.clear();
461 m_sizeAvailable = Image::SizeUnavailable; 274 m_sizeAvailable = Image::SizeUnavailable;
462 } 275 }
463 276
464 void ImageResource::updateImage(bool allDataReceived) { 277 void ImageResourceContent::updateImage(PassRefPtr<SharedBuffer> data,
465 TRACE_EVENT0("blink", "ImageResource::updateImage"); 278 ClearImageOption clearImageOption,
279 bool allDataReceived) {
280 TRACE_EVENT0("blink", "ImageResourceContent::updateImage");
466 281
467 if (data()) 282 if (clearImageOption == ImageResourceContent::ClearExistingImage) {
468 createImage(); 283 clearImage();
284 }
469 285
470 // Have the image update its data from its internal buffer. It will not do 286 // Have the image update its data from its internal buffer. It will not do
471 // anything now, but will delay decoding until queried for info (like size or 287 // anything now, but will delay decoding until queried for info (like size or
472 // specific image frames). 288 // specific image frames).
473 if (data()) { 289 if (data) {
290 if (!m_image)
291 m_image = createImage();
474 DCHECK(m_image); 292 DCHECK(m_image);
475 m_sizeAvailable = m_image->setData(data(), allDataReceived); 293 m_sizeAvailable = m_image->setData(std::move(data), allDataReceived);
476 } 294 }
477 295
478 // Go ahead and tell our observers to try to draw if we have either received 296 // Go ahead and tell our observers to try to draw if we have either received
479 // all the data or the size is known. Each chunk from the network causes 297 // all the data or the size is known. Each chunk from the network causes
480 // observers to repaint, which will force that chunk to decode. 298 // observers to repaint, which will force that chunk to decode.
481 if (m_sizeAvailable == Image::SizeUnavailable && !allDataReceived) 299 if (m_sizeAvailable == Image::SizeUnavailable && !allDataReceived)
482 return; 300 return;
483 301
484 if (m_isPlaceholder && allDataReceived && m_image && !m_image->isNull()) { 302 if (m_info->isPlaceholder() && allDataReceived && m_image &&
303 !m_image->isNull()) {
485 if (m_sizeAvailable == Image::SizeAvailable) { 304 if (m_sizeAvailable == Image::SizeAvailable) {
486 // TODO(sclittle): Show the original image if the response consists of the 305 // TODO(sclittle): Show the original image if the response consists of the
487 // entire image, such as if the entire image response body is smaller than 306 // entire image, such as if the entire image response body is smaller than
488 // the requested range. 307 // the requested range.
489 IntSize dimensions = m_image->size(); 308 IntSize dimensions = m_image->size();
309
490 clearImage(); 310 clearImage();
491 m_image = PlaceholderImage::create(this, dimensions); 311 m_image = PlaceholderImage::create(this, dimensions);
492 } else { 312 } else {
493 // Clear the image so that it gets treated like a decoding error, since 313 // Clear the image so that it gets treated like a decoding error, since
494 // the attempt to build a placeholder image failed. 314 // the attempt to build a placeholder image failed.
495 clearImage(); 315 clearImage();
496 } 316 }
497 } 317 }
498 318
499 if (!m_image || m_image->isNull()) { 319 if (!m_image || m_image->isNull()) {
500 size_t size = encodedSize(); 320 clearImage();
501 clear(); 321 m_info->decodeError(allDataReceived);
502 if (!errorOccurred())
503 setStatus(DecodeError);
504 if (!allDataReceived && loader()) {
505 loader()->didFinishLoading(monotonicallyIncreasingTime(), size, size);
506 }
507 memoryCache()->remove(this);
508 } 322 }
509 323
510 // It would be nice to only redraw the decoded band of the image, but with the 324 // It would be nice to only redraw the decoded band of the image, but with the
511 // current design (decoding delayed until painting) that seems hard. 325 // current design (decoding delayed until painting) that seems hard.
512 notifyObservers(allDataReceived ? ShouldNotifyFinish : DoNotNotifyFinish); 326 notifyObservers(allDataReceived ? ShouldNotifyFinish : DoNotNotifyFinish);
513 } 327 }
514 328
515 void ImageResource::updateImageAndClearBuffer() { 329 void ImageResourceContent::decodedSizeChangedTo(const blink::Image* image,
516 clearImage(); 330 size_t newSize) {
517 updateImage(true); 331 if (!image || image != m_image)
518 clearData(); 332 return;
333 m_info->setDecodedSize(newSize);
519 } 334 }
520 335
521 void ImageResource::finish(double loadFinishTime) { 336 bool ImageResourceContent::shouldPauseAnimation(const blink::Image* image) {
522 if (m_multipartParser) {
523 m_multipartParser->finish();
524 if (data())
525 updateImageAndClearBuffer();
526 } else {
527 updateImage(true);
528 // As encoded image data can be created from m_image (see
529 // ImageResource::resourceBuffer(), we don't have to keep m_data. Let's
530 // clear this. As for the lifetimes of m_image and m_data, see this
531 // document:
532 // https://docs.google.com/document/d/1v0yTAZ6wkqX2U_M6BNIGUJpM1s0TIw1Vsqpxo L7aciY/edit?usp=sharing
533 clearData();
534 }
535 Resource::finish(loadFinishTime);
536 }
537
538 void ImageResource::error(const ResourceError& error) {
539 if (m_multipartParser)
540 m_multipartParser->cancel();
541 clear();
542 Resource::error(error);
543 notifyObservers(ShouldNotifyFinish);
544 }
545
546 void ImageResource::responseReceived(
547 const ResourceResponse& response,
548 std::unique_ptr<WebDataConsumerHandle> handle) {
549 DCHECK(!handle);
550 DCHECK(!m_multipartParser);
551 // If there's no boundary, just handle the request normally.
552 if (response.isMultipart() && !response.multipartBoundary().isEmpty()) {
553 m_multipartParser = new MultipartImageResourceParser(
554 response, response.multipartBoundary(), this);
555 }
556 Resource::responseReceived(response, std::move(handle));
557 if (RuntimeEnabledFeatures::clientHintsEnabled()) {
558 m_devicePixelRatioHeaderValue =
559 this->response()
560 .httpHeaderField(HTTPNames::Content_DPR)
561 .toFloat(&m_hasDevicePixelRatioHeaderValue);
562 if (!m_hasDevicePixelRatioHeaderValue ||
563 m_devicePixelRatioHeaderValue <= 0.0) {
564 m_devicePixelRatioHeaderValue = 1.0;
565 m_hasDevicePixelRatioHeaderValue = false;
566 }
567 }
568 }
569
570 void ImageResource::decodedSizeChangedTo(const blink::Image* image,
571 size_t newSize) {
572 if (!image || image != m_image)
573 return;
574
575 setDecodedSize(newSize);
576 }
577
578 bool ImageResource::shouldPauseAnimation(const blink::Image* image) {
579 if (!image || image != m_image) 337 if (!image || image != m_image)
580 return false; 338 return false;
581 339
582 for (auto* observer : m_finishedObservers.asVector()) { 340 for (auto* observer : m_finishedObservers.asVector()) {
583 if (m_finishedObservers.contains(observer) && observer->willRenderImage()) 341 if (m_finishedObservers.contains(observer) && observer->willRenderImage())
584 return false; 342 return false;
585 } 343 }
586 344
587 for (auto* observer : m_observers.asVector()) { 345 for (auto* observer : m_observers.asVector()) {
588 if (m_observers.contains(observer) && observer->willRenderImage()) 346 if (m_observers.contains(observer) && observer->willRenderImage())
589 return false; 347 return false;
590 } 348 }
591 349
592 return true; 350 return true;
593 } 351 }
594 352
595 void ImageResource::animationAdvanced(const blink::Image* image) { 353 void ImageResourceContent::animationAdvanced(const blink::Image* image) {
596 if (!image || image != m_image) 354 if (!image || image != m_image)
597 return; 355 return;
598 notifyObservers(DoNotNotifyFinish); 356 notifyObservers(DoNotNotifyFinish);
599 } 357 }
600 358
601 void ImageResource::updateImageAnimationPolicy() { 359 void ImageResourceContent::updateImageAnimationPolicy() {
602 if (!m_image) 360 if (!m_image)
603 return; 361 return;
604 362
605 ImageAnimationPolicy newPolicy = ImageAnimationPolicyAllowed; 363 ImageAnimationPolicy newPolicy = ImageAnimationPolicyAllowed;
606 for (auto* observer : m_finishedObservers.asVector()) { 364 for (auto* observer : m_finishedObservers.asVector()) {
607 if (m_finishedObservers.contains(observer) && 365 if (m_finishedObservers.contains(observer) &&
608 observer->getImageAnimationPolicy(newPolicy)) 366 observer->getImageAnimationPolicy(newPolicy))
609 break; 367 break;
610 } 368 }
611 for (auto* observer : m_observers.asVector()) { 369 for (auto* observer : m_observers.asVector()) {
612 if (m_observers.contains(observer) && 370 if (m_observers.contains(observer) &&
613 observer->getImageAnimationPolicy(newPolicy)) 371 observer->getImageAnimationPolicy(newPolicy))
614 break; 372 break;
615 } 373 }
616 374
617 if (m_image->animationPolicy() != newPolicy) { 375 if (m_image->animationPolicy() != newPolicy) {
618 m_image->resetAnimation(); 376 m_image->resetAnimation();
619 m_image->setAnimationPolicy(newPolicy); 377 m_image->setAnimationPolicy(newPolicy);
620 } 378 }
621 } 379 }
622 380
623 static bool isLoFiImage(const ImageResource& resource) { 381 void ImageResourceContent::changedInRect(const blink::Image* image,
624 if (resource.resourceRequest().loFiState() != WebURLRequest::LoFiOn) 382 const IntRect& rect) {
625 return false;
626 return !resource.isLoaded() ||
627 resource.response()
628 .httpHeaderField("chrome-proxy-content-transform")
629 .contains("empty-image");
630 }
631
632 void ImageResource::reloadIfLoFiOrPlaceholder(
633 ResourceFetcher* fetcher,
634 ReloadCachePolicy reloadCachePolicy) {
635 if (!m_isPlaceholder && !isLoFiImage(*this))
636 return;
637
638 // Prevent clients and observers from being notified of completion while the
639 // reload is being scheduled, so that e.g. canceling an existing load in
640 // progress doesn't cause clients and observers to be notified of completion
641 // prematurely.
642 DCHECK(!m_isSchedulingReload);
643 m_isSchedulingReload = true;
644
645 if (reloadCachePolicy == ReloadCachePolicy::BypassCache)
646 setCachePolicyBypassingCache();
647 setLoFiStateOff();
648
649 if (m_isPlaceholder) {
650 m_isPlaceholder = false;
651 clearRangeRequestHeader();
652 }
653
654 if (isLoading()) {
655 loader()->cancel();
656 // Canceling the loader causes error() to be called, which in turn calls
657 // clear() and notifyObservers(), so there's no need to call these again
658 // here.
659 } else {
660 clear();
661 notifyObservers(DoNotNotifyFinish);
662 }
663
664 setStatus(NotStarted);
665
666 DCHECK(m_isSchedulingReload);
667 m_isSchedulingReload = false;
668
669 fetcher->startLoad(this);
670 }
671
672 void ImageResource::changedInRect(const blink::Image* image,
673 const IntRect& rect) {
674 if (!image || image != m_image) 383 if (!image || image != m_image)
675 return; 384 return;
676 notifyObservers(DoNotNotifyFinish, &rect); 385 notifyObservers(DoNotNotifyFinish, &rect);
677 } 386 }
678 387
679 void ImageResource::onePartInMultipartReceived( 388 bool ImageResourceContent::isAccessAllowed(
680 const ResourceResponse& response) { 389 SecurityOrigin* securityOrigin) const {
681 DCHECK(m_multipartParser); 390 return m_info->isAccessAllowed(
682 391 securityOrigin, getImage()->currentFrameHasSingleSecurityOrigin());
683 setResponse(response);
684 if (m_multipartParsingState == MultipartParsingState::WaitingForFirstPart) {
685 // We have nothing to do because we don't have any data.
686 m_multipartParsingState = MultipartParsingState::ParsingFirstPart;
687 return;
688 }
689 updateImageAndClearBuffer();
690
691 if (m_multipartParsingState == MultipartParsingState::ParsingFirstPart) {
692 m_multipartParsingState = MultipartParsingState::FinishedParsingFirstPart;
693 // Notify finished when the first part ends.
694 if (!errorOccurred())
695 setStatus(Cached);
696 // We notify clients/observers of finish here, and they will not be
697 // notified again in Resource::finish()/error().
698 checkNotify();
699 if (loader())
700 loader()->didFinishLoadingFirstPartInMultipart();
701 }
702 } 392 }
703 393
704 void ImageResource::multipartDataReceived(const char* bytes, size_t size) { 394 void ImageResourceContent::emulateLoadStartedForInspector(
705 DCHECK(m_multipartParser); 395 ResourceFetcher* fetcher,
706 Resource::appendData(bytes, size); 396 const KURL& url,
397 const AtomicString& initiatorName) {
398 m_info->emulateLoadStartedForInspector(fetcher, url, initiatorName);
707 } 399 }
708 400
709 bool ImageResource::isAccessAllowed(SecurityOrigin* securityOrigin) { 401 // TODO(hiroshige): Consider removing the following methods, or stoping
710 if (response().wasFetchedViaServiceWorker()) { 402 // redirecting to ImageResource.
711 return response().serviceWorkerResponseType() != 403 bool ImageResourceContent::isLoaded() const {
712 WebServiceWorkerResponseTypeOpaque; 404 return getStatus() > ResourceStatus::Pending;
713 } 405 }
714 if (!getImage()->currentFrameHasSingleSecurityOrigin()) 406
715 return false; 407 bool ImageResourceContent::isLoading() const {
716 if (passesAccessControlCheck(securityOrigin)) 408 return getStatus() == ResourceStatus::Pending;
717 return true; 409 }
718 return !securityOrigin->taintsCanvas(response().url()); 410
411 bool ImageResourceContent::errorOccurred() const {
412 return getStatus() == ResourceStatus::LoadError ||
413 getStatus() == ResourceStatus::DecodeError;
414 }
415
416 bool ImageResourceContent::loadFailedOrCanceled() const {
417 return getStatus() == ResourceStatus::LoadError;
418 }
419
420 ResourceStatus ImageResourceContent::getStatus() const {
421 return m_info->getStatus();
422 }
423
424 const KURL& ImageResourceContent::url() const {
425 return m_info->url();
426 }
427
428 bool ImageResourceContent::hasCacheControlNoStoreHeader() const {
429 return m_info->hasCacheControlNoStoreHeader();
430 }
431
432 float ImageResourceContent::devicePixelRatioHeaderValue() const {
433 return m_info->devicePixelRatioHeaderValue();
434 }
435
436 bool ImageResourceContent::hasDevicePixelRatioHeaderValue() const {
437 return m_info->hasDevicePixelRatioHeaderValue();
438 }
439
440 const ResourceResponse& ImageResourceContent::response() const {
441 return m_info->response();
719 } 442 }
720 443
721 } // namespace blink 444 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698