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

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: 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 // 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 8 #include "core/fetch/ImageResourceInfo.h"
26 #include "core/fetch/ImageResourceObserver.h" 9 #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" 10 #include "core/svg/graphics/SVGImage.h"
33 #include "platform/Histogram.h" 11 #include "platform/Histogram.h"
34 #include "platform/RuntimeEnabledFeatures.h" 12 #include "platform/RuntimeEnabledFeatures.h"
35 #include "platform/SharedBuffer.h" 13 #include "platform/SharedBuffer.h"
36 #include "platform/geometry/IntSize.h" 14 #include "platform/geometry/IntSize.h"
37 #include "platform/graphics/BitmapImage.h" 15 #include "platform/graphics/BitmapImage.h"
38 #include "platform/graphics/PlaceholderImage.h" 16 #include "platform/graphics/PlaceholderImage.h"
39 #include "platform/tracing/TraceEvent.h" 17 #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" 18 #include "wtf/HashCountedSet.h"
yhirano 2016/12/05 09:02:03 This should be moved to the header file.
hiroshige 2016/12/06 09:32:51 Done.
44 #include "wtf/StdLibExtras.h" 19 #include "wtf/StdLibExtras.h"
45 #include "wtf/Vector.h" 20 #include "wtf/Vector.h"
46 #include <memory> 21 #include <memory>
47 #include <v8.h> 22 #include <v8.h>
48 23
49 namespace blink { 24 namespace blink {
50 namespace { 25 namespace {
51 // The amount of time to wait before informing the clients that the image has 26 class NullImageResourceInfo final
52 // been updated (in seconds). This effectively throttles invalidations that 27 : public GarbageCollectedFinalized<NullImageResourceInfo>,
53 // result from new data arriving for this image. 28 public ImageResourceInfo {
54 constexpr double kFlushDelaySeconds = 1.; 29 USING_GARBAGE_COLLECTED_MIXIN(NullImageResourceInfo);
30
31 public:
32 NullImageResourceInfo() {}
33
34 DEFINE_INLINE_VIRTUAL_TRACE() { ImageResourceInfo::trace(visitor); }
35
36 private:
37 const KURL& url() const override { return m_url; }
38 bool isSchedulingReload() const override { return false; }
39 bool hasDevicePixelRatioHeaderValue() const override { return false; }
40 float devicePixelRatioHeaderValue() const override { return 1.0; }
41 const ResourceResponse& response() const override { return m_response; }
42 ResourceStatus getStatus() const override { return ResourceStatus::Cached; }
43 bool isPlaceholder() const override { return false; }
44 bool isCacheValidator() const override { return false; }
45 bool schedulingReloadOrShouldReloadBrokenPlaceholder() const override {
46 return false;
47 }
48 bool isAccessAllowed(
49 SecurityOrigin*,
50 bool doesCurrentFrameHasSingleSecurityOrigin) const override {
51 return true;
52 }
53 bool hasCacheControlNoStoreHeader() const override { return false; }
54 const ResourceError& resourceError() const override { return m_error; }
55
56 const KURL m_url;
57 const ResourceResponse m_response;
58 const ResourceError m_error;
59 };
60
55 } // namespace 61 } // namespace
56 62
57 class ImageResource::ImageResourceFactory : public ResourceFactory { 63 class ResourceFetcher;
yhirano 2016/12/05 09:02:03 Not needed?
hiroshige 2016/12/06 09:32:51 Done.
58 STACK_ALLOCATED();
59 64
60 public: 65 ImageResourceContent::ImageResourceContent(PassRefPtr<blink::Image> image)
61 ImageResourceFactory(const FetchRequest& fetchRequest) 66 : m_image(image), m_isRefetchableDataFromDiskCache(true) {
62 : ResourceFactory(Resource::Image), m_fetchRequest(&fetchRequest) {} 67 DEFINE_STATIC_LOCAL(NullImageResourceInfo, nullInfo,
63 68 (new NullImageResourceInfo()));
64 Resource* create(const ResourceRequest& request, 69 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 } 70 }
108 71
109 ImageResource::ImageResource(const ResourceRequest& resourceRequest, 72 ImageResourceContent* ImageResourceContent::fetch(FetchRequest& request,
110 const ResourceLoaderOptions& options, 73 ResourceFetcher* fetcher) {
111 bool isPlaceholder) 74 ImageResource* resource = ImageResource::fetch(request, fetcher);
112 : Resource(resourceRequest, Image, options), 75 if (!resource)
113 m_devicePixelRatioHeaderValue(1.0), 76 return nullptr;
114 m_image(nullptr), 77 return resource->getContent();
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 } 78 }
122 79
123 ImageResource::ImageResource(blink::Image* image, 80 void ImageResourceContent::setImageResourceInfo(ImageResourceInfo* info) {
124 const ResourceLoaderOptions& options) 81 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 } 82 }
136 83
137 ImageResource::~ImageResource() { 84 DEFINE_TRACE(ImageResourceContent) {
138 RESOURCE_LOADING_DVLOG(1) << "~ImageResource " << this; 85 visitor->trace(m_info);
139 clearImage(); 86 ImageObserver::trace(visitor);
140 } 87 }
141 88
142 DEFINE_TRACE(ImageResource) { 89 void ImageResourceContent::markObserverFinished(
143 visitor->trace(m_multipartParser); 90 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)) { 91 if (m_observers.contains(observer)) {
160 m_finishedObservers.add(observer); 92 m_finishedObservers.add(observer);
161 m_observers.remove(observer); 93 m_observers.remove(observer);
162 } 94 }
163 } 95 }
164 96
165 void ImageResource::didAddClient(ResourceClient* client) { 97 void ImageResourceContent::addObserver(ImageResourceObserver* observer) {
166 DCHECK((m_multipartParser && isLoading()) || !data() || m_image); 98 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 99
179 m_observers.add(observer); 100 m_observers.add(observer);
180 101
181 if (isCacheValidator()) 102 if (m_info->isCacheValidator())
182 return; 103 return;
183 104
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()) { 105 if (m_image && !m_image->isNull()) {
195 observer->imageChanged(this); 106 observer->imageChanged(this);
196 } 107 }
197 108
198 if (isLoaded() && m_observers.contains(observer) && !m_isSchedulingReload && 109 if (isLoaded() && m_observers.contains(observer) &&
199 !shouldReloadBrokenPlaceholder()) { 110 !m_info->schedulingReloadOrShouldReloadBrokenPlaceholder()) {
200 markObserverFinished(observer); 111 markObserverFinished(observer);
201 observer->imageNotifyFinished(this); 112 observer->imageNotifyFinished(this);
202 } 113 }
203 } 114 }
204 115
205 void ImageResource::removeObserver(ImageResourceObserver* observer) { 116 void ImageResourceContent::removeObserver(ImageResourceObserver* observer) {
206 DCHECK(observer); 117 DCHECK(observer);
207 118
208 if (m_observers.contains(observer)) 119 if (m_observers.contains(observer))
209 m_observers.remove(observer); 120 m_observers.remove(observer);
210 else if (m_finishedObservers.contains(observer)) 121 else if (m_finishedObservers.contains(observer))
211 m_finishedObservers.remove(observer); 122 m_finishedObservers.remove(observer);
212 else 123 else
213 NOTREACHED(); 124 NOTREACHED();
214 125
215 didRemoveClientOrObserver(); 126 m_info->didRemoveClientOrObserver();
216 } 127 }
217 128
218 static void priorityFromObserver(const ImageResourceObserver* observer, 129 static void priorityFromObserver(const ImageResourceObserver* observer,
219 ResourcePriority& priority) { 130 ResourcePriority& priority) {
220 ResourcePriority nextPriority = observer->computeResourcePriority(); 131 ResourcePriority nextPriority = observer->computeResourcePriority();
221 if (nextPriority.visibility == ResourcePriority::NotVisible) 132 if (nextPriority.visibility == ResourcePriority::NotVisible)
222 return; 133 return;
223 priority.visibility = ResourcePriority::Visible; 134 priority.visibility = ResourcePriority::Visible;
224 priority.intraPriorityValue += nextPriority.intraPriorityValue; 135 priority.intraPriorityValue += nextPriority.intraPriorityValue;
225 } 136 }
226 137
227 ResourcePriority ImageResource::priorityFromObservers() { 138 ResourcePriority ImageResourceContent::priorityFromObservers() const {
228 ResourcePriority priority; 139 ResourcePriority priority;
229 140
230 for (auto* observer : m_finishedObservers.asVector()) { 141 for (auto* observer : m_finishedObservers.asVector()) {
231 if (m_finishedObservers.contains(observer)) 142 if (m_finishedObservers.contains(observer))
232 priorityFromObserver(observer, priority); 143 priorityFromObserver(observer, priority);
233 } 144 }
234 for (auto* observer : m_observers.asVector()) { 145 for (auto* observer : m_observers.asVector()) {
235 if (m_observers.contains(observer)) 146 if (m_observers.contains(observer))
236 priorityFromObserver(observer, priority); 147 priorityFromObserver(observer, priority);
237 } 148 }
238 149
239 return priority; 150 return priority;
240 } 151 }
241 152
242 void ImageResource::destroyDecodedDataForFailedRevalidation() { 153 void ImageResourceContent::destroyDecodedData() {
243 clearImage();
244 setDecodedSize(0);
245 }
246
247 void ImageResource::destroyDecodedDataIfPossible() {
248 if (!m_image) 154 if (!m_image)
249 return; 155 return;
250 CHECK(!errorOccurred()); 156 CHECK(!errorOccurred());
251 m_image->destroyDecodedData(); 157 m_image->destroyDecodedData();
252 if (!isPreloaded() && m_isRefetchableDataFromDiskCache) {
253 UMA_HISTOGRAM_MEMORY_KB("Memory.Renderer.EstimatedDroppableEncodedSize",
254 encodedSize() / 1024);
255 }
256 } 158 }
257 159
258 void ImageResource::doResetAnimation() { 160 void ImageResourceContent::doResetAnimation() {
259 if (m_image) 161 if (m_image)
260 m_image->resetAnimation(); 162 m_image->resetAnimation();
261 } 163 }
262 164
263 void ImageResource::allClientsAndObserversRemoved() { 165 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) { 166 float deviceScaleFactor) {
337 if (deviceScaleFactor >= 2) { 167 if (deviceScaleFactor >= 2) {
338 DEFINE_STATIC_REF(blink::Image, brokenImageHiRes, 168 DEFINE_STATIC_REF(blink::Image, brokenImageHiRes,
339 (blink::Image::loadPlatformResource("missingImage@2x"))); 169 (blink::Image::loadPlatformResource("missingImage@2x")));
340 return std::make_pair(brokenImageHiRes, 2); 170 return std::make_pair(brokenImageHiRes, 2);
341 } 171 }
342 172
343 DEFINE_STATIC_REF(blink::Image, brokenImageLoRes, 173 DEFINE_STATIC_REF(blink::Image, brokenImageLoRes,
344 (blink::Image::loadPlatformResource("missingImage"))); 174 (blink::Image::loadPlatformResource("missingImage")));
345 return std::make_pair(brokenImageLoRes, 1); 175 return std::make_pair(brokenImageLoRes, 1);
346 } 176 }
347 177
348 bool ImageResource::willPaintBrokenImage() const { 178 blink::Image* ImageResourceContent::getImage() const {
349 return errorOccurred();
350 }
351
352 blink::Image* ImageResource::getImage() {
353 if (errorOccurred()) { 179 if (errorOccurred()) {
354 // Returning the 1x broken image is non-ideal, but we cannot reliably access 180 // Returning the 1x broken image is non-ideal, but we cannot reliably access
355 // the appropriate deviceScaleFactor from here. It is critical that callers 181 // the appropriate deviceScaleFactor from here. It is critical that callers
356 // use ImageResource::brokenImage() when they need the real, 182 // use ImageResourceContent::brokenImage() when they need the real,
357 // deviceScaleFactor-appropriate broken image icon. 183 // deviceScaleFactor-appropriate broken image icon.
358 return brokenImage(1).first; 184 return brokenImage(1).first;
359 } 185 }
360 186
361 if (m_image) 187 if (m_image)
362 return m_image.get(); 188 return m_image.get();
363 189
364 return blink::Image::nullImage(); 190 return blink::Image::nullImage();
365 } 191 }
366 192
367 bool ImageResource::usesImageContainerSize() const { 193 bool ImageResourceContent::usesImageContainerSize() const {
368 if (m_image) 194 if (m_image)
369 return m_image->usesContainerSize(); 195 return m_image->usesContainerSize();
370 196
371 return false; 197 return false;
372 } 198 }
373 199
374 bool ImageResource::imageHasRelativeSize() const { 200 bool ImageResourceContent::imageHasRelativeSize() const {
375 if (m_image) 201 if (m_image)
376 return m_image->hasRelativeSize(); 202 return m_image->hasRelativeSize();
377 203
378 return false; 204 return false;
379 } 205 }
380 206
381 LayoutSize ImageResource::imageSize( 207 LayoutSize ImageResourceContent::imageSize(
382 RespectImageOrientationEnum shouldRespectImageOrientation, 208 RespectImageOrientationEnum shouldRespectImageOrientation,
383 float multiplier, 209 float multiplier,
384 SizeType sizeType) { 210 SizeType sizeType) {
385 if (!m_image) 211 if (!m_image)
386 return LayoutSize(); 212 return LayoutSize();
387 213
388 LayoutSize size; 214 LayoutSize size;
389 215
390 if (m_image->isBitmapImage() && 216 if (m_image->isBitmapImage() &&
391 shouldRespectImageOrientation == RespectImageOrientation) { 217 shouldRespectImageOrientation == RespectImageOrientation) {
392 size = 218 size =
393 LayoutSize(toBitmapImage(m_image.get())->sizeRespectingOrientation()); 219 LayoutSize(toBitmapImage(m_image.get())->sizeRespectingOrientation());
394 } else { 220 } else {
395 size = LayoutSize(m_image->size()); 221 size = LayoutSize(m_image->size());
396 } 222 }
397 223
398 if (sizeType == IntrinsicCorrectedToDPR && m_hasDevicePixelRatioHeaderValue && 224 if (sizeType == IntrinsicCorrectedToDPR && hasDevicePixelRatioHeaderValue() &&
399 m_devicePixelRatioHeaderValue > 0) 225 devicePixelRatioHeaderValue() > 0)
400 multiplier = 1 / m_devicePixelRatioHeaderValue; 226 multiplier = 1 / devicePixelRatioHeaderValue();
401 227
402 if (multiplier == 1 || m_image->hasRelativeSize()) 228 if (multiplier == 1 || m_image->hasRelativeSize())
403 return size; 229 return size;
404 230
405 // Don't let images that have a width/height >= 1 shrink below 1 when zoomed. 231 // Don't let images that have a width/height >= 1 shrink below 1 when zoomed.
406 LayoutSize minimumSize( 232 LayoutSize minimumSize(
407 size.width() > LayoutUnit() ? LayoutUnit(1) : LayoutUnit(), 233 size.width() > LayoutUnit() ? LayoutUnit(1) : LayoutUnit(),
408 LayoutUnit(size.height() > LayoutUnit() ? LayoutUnit(1) : LayoutUnit())); 234 LayoutUnit(size.height() > LayoutUnit() ? LayoutUnit(1) : LayoutUnit()));
409 size.scale(multiplier); 235 size.scale(multiplier);
410 size.clampToMinimumSize(minimumSize); 236 size.clampToMinimumSize(minimumSize);
411 return size; 237 return size;
412 } 238 }
413 239
414 void ImageResource::notifyObservers(NotifyFinishOption notifyingFinishOption, 240 void ImageResourceContent::notifyObservers(
415 const IntRect* changeRect) { 241 NotifyFinishOption notifyingFinishOption,
242 const IntRect* changeRect) {
416 for (auto* observer : m_finishedObservers.asVector()) { 243 for (auto* observer : m_finishedObservers.asVector()) {
417 if (m_finishedObservers.contains(observer)) 244 if (m_finishedObservers.contains(observer))
418 observer->imageChanged(this, changeRect); 245 observer->imageChanged(this, changeRect);
419 } 246 }
420 for (auto* observer : m_observers.asVector()) { 247 for (auto* observer : m_observers.asVector()) {
421 if (m_observers.contains(observer)) { 248 if (m_observers.contains(observer)) {
422 observer->imageChanged(this, changeRect); 249 observer->imageChanged(this, changeRect);
423 if (notifyingFinishOption == ShouldNotifyFinish && 250 if (notifyingFinishOption == ShouldNotifyFinish &&
424 m_observers.contains(observer) && !m_isSchedulingReload && 251 m_observers.contains(observer) &&
425 !shouldReloadBrokenPlaceholder()) { 252 !m_info->schedulingReloadOrShouldReloadBrokenPlaceholder()) {
426 markObserverFinished(observer); 253 markObserverFinished(observer);
427 observer->imageNotifyFinished(this); 254 observer->imageNotifyFinished(this);
428 } 255 }
429 } 256 }
430 } 257 }
431 } 258 }
432 259
433 void ImageResource::clear() { 260 inline PassRefPtr<Image> ImageResourceContent::createImage() {
434 clearImage(); 261 if (m_info->response().mimeType() == "image/svg+xml")
435 clearData(); 262 return SVGImage::create(this);
436 setEncodedSize(0); 263 return BitmapImage::create(this);
437 } 264 }
438 265
439 inline void ImageResource::createImage() { 266 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) 267 if (!m_image)
453 return; 268 return;
454 int64_t length = m_image->data() ? m_image->data()->size() : 0; 269 int64_t length = m_image->data() ? m_image->data()->size() : 0;
455 v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(-length); 270 v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(-length);
456 271
457 // If our Image has an observer, it's always us so we need to clear the back 272 // If our Image has an observer, it's always us so we need to clear the back
458 // pointer before dropping our reference. 273 // pointer before dropping our reference.
459 m_image->clearImageObserver(); 274 m_image->clearImageObserver();
460 m_image.clear(); 275 m_image.clear();
461 m_sizeAvailable = Image::SizeUnavailable; 276 m_sizeAvailable = Image::SizeUnavailable;
462 } 277 }
463 278
464 void ImageResource::updateImage(bool allDataReceived) { 279 void ImageResourceContent::updateImage(PassRefPtr<SharedBuffer> data,
465 TRACE_EVENT0("blink", "ImageResource::updateImage"); 280 ClearImageOption clearImageOption,
281 bool allDataReceived) {
282 TRACE_EVENT0("blink", "ImageResourceContent::updateImage");
466 283
467 if (data()) 284 if (clearImageOption == ImageResourceContent::ClearExistingImage) {
468 createImage(); 285 clearImage();
286 }
469 287
470 // Have the image update its data from its internal buffer. It will not do 288 // 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 289 // anything now, but will delay decoding until queried for info (like size or
472 // specific image frames). 290 // specific image frames).
473 if (data()) { 291 if (data) {
292 if (!m_image)
293 m_image = createImage();
474 DCHECK(m_image); 294 DCHECK(m_image);
475 m_sizeAvailable = m_image->setData(data(), allDataReceived); 295 m_sizeAvailable = m_image->setData(std::move(data), allDataReceived);
476 } 296 }
477 297
478 // Go ahead and tell our observers to try to draw if we have either received 298 // 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 299 // 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. 300 // observers to repaint, which will force that chunk to decode.
481 if (m_sizeAvailable == Image::SizeUnavailable && !allDataReceived) 301 if (m_sizeAvailable == Image::SizeUnavailable && !allDataReceived)
482 return; 302 return;
483 303
484 if (m_isPlaceholder && allDataReceived && m_image && !m_image->isNull()) { 304 if (m_info->isPlaceholder() && allDataReceived && m_image &&
305 !m_image->isNull()) {
485 if (m_sizeAvailable == Image::SizeAvailable) { 306 if (m_sizeAvailable == Image::SizeAvailable) {
486 // TODO(sclittle): Show the original image if the response consists of the 307 // 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 308 // entire image, such as if the entire image response body is smaller than
488 // the requested range. 309 // the requested range.
489 IntSize dimensions = m_image->size(); 310 IntSize dimensions = m_image->size();
311
490 clearImage(); 312 clearImage();
491 m_image = PlaceholderImage::create(this, dimensions); 313 m_image = PlaceholderImage::create(this, dimensions);
492 } else { 314 } else {
493 // Clear the image so that it gets treated like a decoding error, since 315 // Clear the image so that it gets treated like a decoding error, since
494 // the attempt to build a placeholder image failed. 316 // the attempt to build a placeholder image failed.
495 clearImage(); 317 clearImage();
496 } 318 }
497 } 319 }
498 320
499 if (!m_image || m_image->isNull()) { 321 if (!m_image || m_image->isNull()) {
500 size_t size = encodedSize(); 322 clearImage();
501 clear(); 323 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 } 324 }
509 325
510 // It would be nice to only redraw the decoded band of the image, but with the 326 // 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. 327 // current design (decoding delayed until painting) that seems hard.
512 notifyObservers(allDataReceived ? ShouldNotifyFinish : DoNotNotifyFinish); 328 notifyObservers(allDataReceived ? ShouldNotifyFinish : DoNotNotifyFinish);
513 } 329 }
514 330
515 void ImageResource::updateImageAndClearBuffer() { 331 void ImageResourceContent::decodedSizeChangedTo(const blink::Image* image,
516 clearImage(); 332 size_t newSize) {
517 updateImage(true); 333 if (!image || image != m_image)
518 clearData(); 334 return;
335 m_info->setDecodedSize(newSize);
519 } 336 }
520 337
521 void ImageResource::finish(double loadFinishTime) { 338 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) 339 if (!image || image != m_image)
580 return false; 340 return false;
581 341
582 for (auto* observer : m_finishedObservers.asVector()) { 342 for (auto* observer : m_finishedObservers.asVector()) {
583 if (m_finishedObservers.contains(observer) && observer->willRenderImage()) 343 if (m_finishedObservers.contains(observer) && observer->willRenderImage())
584 return false; 344 return false;
585 } 345 }
586 346
587 for (auto* observer : m_observers.asVector()) { 347 for (auto* observer : m_observers.asVector()) {
588 if (m_observers.contains(observer) && observer->willRenderImage()) 348 if (m_observers.contains(observer) && observer->willRenderImage())
589 return false; 349 return false;
590 } 350 }
591 351
592 return true; 352 return true;
593 } 353 }
594 354
595 void ImageResource::animationAdvanced(const blink::Image* image) { 355 void ImageResourceContent::animationAdvanced(const blink::Image* image) {
596 if (!image || image != m_image) 356 if (!image || image != m_image)
597 return; 357 return;
598 notifyObservers(DoNotNotifyFinish); 358 notifyObservers(DoNotNotifyFinish);
599 } 359 }
600 360
601 void ImageResource::updateImageAnimationPolicy() { 361 void ImageResourceContent::updateImageAnimationPolicy() {
602 if (!m_image) 362 if (!m_image)
603 return; 363 return;
604 364
605 ImageAnimationPolicy newPolicy = ImageAnimationPolicyAllowed; 365 ImageAnimationPolicy newPolicy = ImageAnimationPolicyAllowed;
606 for (auto* observer : m_finishedObservers.asVector()) { 366 for (auto* observer : m_finishedObservers.asVector()) {
607 if (m_finishedObservers.contains(observer) && 367 if (m_finishedObservers.contains(observer) &&
608 observer->getImageAnimationPolicy(newPolicy)) 368 observer->getImageAnimationPolicy(newPolicy))
609 break; 369 break;
610 } 370 }
611 for (auto* observer : m_observers.asVector()) { 371 for (auto* observer : m_observers.asVector()) {
612 if (m_observers.contains(observer) && 372 if (m_observers.contains(observer) &&
613 observer->getImageAnimationPolicy(newPolicy)) 373 observer->getImageAnimationPolicy(newPolicy))
614 break; 374 break;
615 } 375 }
616 376
617 if (m_image->animationPolicy() != newPolicy) { 377 if (m_image->animationPolicy() != newPolicy) {
618 m_image->resetAnimation(); 378 m_image->resetAnimation();
619 m_image->setAnimationPolicy(newPolicy); 379 m_image->setAnimationPolicy(newPolicy);
620 } 380 }
621 } 381 }
622 382
623 static bool isLoFiImage(const ImageResource& resource) { 383 void ImageResourceContent::changedInRect(const blink::Image* image,
624 if (resource.resourceRequest().loFiState() != WebURLRequest::LoFiOn) 384 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) 385 if (!image || image != m_image)
675 return; 386 return;
676 notifyObservers(DoNotNotifyFinish, &rect); 387 notifyObservers(DoNotNotifyFinish, &rect);
677 } 388 }
678 389
679 void ImageResource::onePartInMultipartReceived( 390 bool ImageResourceContent::isAccessAllowed(
680 const ResourceResponse& response) { 391 SecurityOrigin* securityOrigin) const {
681 DCHECK(m_multipartParser); 392 return m_info->isAccessAllowed(
682 393 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 and observers of finish in checkNotify() and
697 // updateImageAndClearBuffer(), respectively, and they will not be
698 // notified again in Resource::finish()/error().
699 checkNotify();
700 if (loader())
701 loader()->didFinishLoadingFirstPartInMultipart();
702 }
703 } 394 }
704 395
705 void ImageResource::multipartDataReceived(const char* bytes, size_t size) { 396 void ImageResourceContent::emulateLoadStartedForInspector(
706 DCHECK(m_multipartParser); 397 ResourceFetcher* fetcher,
707 Resource::appendData(bytes, size); 398 const KURL& url,
399 const AtomicString& initiatorName) {
400 m_info->emulateLoadStartedForInspector(fetcher, url, initiatorName);
708 } 401 }
709 402
710 bool ImageResource::isAccessAllowed(SecurityOrigin* securityOrigin) { 403 // TODO(hiroshige): Consider removing the following methods, or stoping
711 if (response().wasFetchedViaServiceWorker()) { 404 // redirecting to ImageResource.
712 return response().serviceWorkerResponseType() != 405 bool ImageResourceContent::isLoaded() const {
713 WebServiceWorkerResponseTypeOpaque; 406 return getStatus() > ResourceStatus::Pending;
714 } 407 }
715 if (!getImage()->currentFrameHasSingleSecurityOrigin()) 408
716 return false; 409 bool ImageResourceContent::isLoading() const {
717 if (passesAccessControlCheck(securityOrigin)) 410 return getStatus() == ResourceStatus::Pending;
718 return true; 411 }
719 return !securityOrigin->taintsCanvas(response().url()); 412
413 bool ImageResourceContent::errorOccurred() const {
414 return getStatus() == ResourceStatus::LoadError ||
415 getStatus() == ResourceStatus::DecodeError;
416 }
417
418 bool ImageResourceContent::loadFailedOrCanceled() const {
419 return getStatus() == ResourceStatus::LoadError;
420 }
421
422 ResourceStatus ImageResourceContent::getStatus() const {
423 return m_info->getStatus();
424 }
425
426 const KURL& ImageResourceContent::url() const {
427 return m_info->url();
428 }
429
430 bool ImageResourceContent::hasCacheControlNoStoreHeader() const {
431 return m_info->hasCacheControlNoStoreHeader();
432 }
433
434 float ImageResourceContent::devicePixelRatioHeaderValue() const {
435 return m_info->devicePixelRatioHeaderValue();
436 }
437
438 bool ImageResourceContent::hasDevicePixelRatioHeaderValue() const {
439 return m_info->hasDevicePixelRatioHeaderValue();
440 }
441
442 const ResourceResponse& ImageResourceContent::response() const {
443 return m_info->response();
444 }
445
446 const ResourceError& ImageResourceContent::resourceError() const {
447 return m_info->resourceError();
720 } 448 }
721 449
722 } // namespace blink 450 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698