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

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: style 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"
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 DoesCurrentFrameHaveSingleSecurityOrigin) const override {
50 return true;
51 }
52 bool hasCacheControlNoStoreHeader() const override { return false; }
53 const ResourceError& resourceError() const override { return m_error; }
54
55 void decodeError(bool allDataReceived) override {}
56 void setDecodedSize(size_t) override {}
57 void willAddClientOrObserver() override {}
58 void didRemoveClientOrObserver() override {}
59 void emulateLoadStartedForInspector(
60 ResourceFetcher*,
61 const KURL&,
62 const AtomicString& initiatorName) override {}
63
64 const KURL m_url;
65 const ResourceResponse m_response;
66 const ResourceError m_error;
67 };
68
55 } // namespace 69 } // namespace
56 70
57 class ImageResource::ImageResourceFactory : public ResourceFactory { 71 ImageResourceContent::ImageResourceContent(PassRefPtr<blink::Image> image)
58 STACK_ALLOCATED(); 72 : m_image(image), m_isRefetchableDataFromDiskCache(true) {
59 73 DEFINE_STATIC_LOCAL(NullImageResourceInfo, nullInfo,
60 public: 74 (new NullImageResourceInfo()));
61 ImageResourceFactory(const FetchRequest& fetchRequest) 75 m_info = &nullInfo;
62 : ResourceFactory(Resource::Image), m_fetchRequest(&fetchRequest) {}
63
64 Resource* create(const ResourceRequest& request,
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 ResourceRequestBlockedReason blockReason = fetcher->context().canRequest(
88 Resource::Image, request.resourceRequest(), requestURL,
89 request.options(), request.forPreload(),
90 request.getOriginRestriction());
91 if (blockReason == ResourceRequestBlockedReason::None)
92 fetcher->context().sendImagePing(requestURL);
93 }
94 return nullptr;
95 }
96
97 ImageResource* resource = toImageResource(
98 fetcher->requestResource(request, ImageResourceFactory(request)));
99 if (resource &&
100 request.placeholderImageRequestType() != FetchRequest::AllowPlaceholder &&
101 resource->m_isPlaceholder) {
102 // If the image is a placeholder, but this fetch doesn't allow a
103 // placeholder, then load the original image. Note that the cache is not
104 // bypassed here - it should be fine to use a cached copy if possible.
105 resource->reloadIfLoFiOrPlaceholder(fetcher,
106 ReloadCachePolicy::UseExistingPolicy);
107 }
108 return resource;
109 } 76 }
110 77
111 ImageResource::ImageResource(const ResourceRequest& resourceRequest, 78 ImageResourceContent* ImageResourceContent::fetch(FetchRequest& request,
112 const ResourceLoaderOptions& options, 79 ResourceFetcher* fetcher) {
113 bool isPlaceholder) 80 // TODO(hiroshige): Remove direct references to ImageResource by making
114 : Resource(resourceRequest, Image, options), 81 // the dependencies around ImageResource and ImageResourceContent cleaner.
115 m_devicePixelRatioHeaderValue(1.0), 82 ImageResource* resource = ImageResource::fetch(request, fetcher);
116 m_image(nullptr), 83 if (!resource)
117 m_hasDevicePixelRatioHeaderValue(false), 84 return nullptr;
118 m_isSchedulingReload(false), 85 return resource->getContent();
119 m_isPlaceholder(isPlaceholder),
120 m_flushTimer(this, &ImageResource::flushImageIfNeeded),
121 m_isRefetchableDataFromDiskCache(true) {
122 RESOURCE_LOADING_DVLOG(1) << "new ImageResource(ResourceRequest) " << this;
123 } 86 }
124 87
125 ImageResource::ImageResource(blink::Image* image, 88 void ImageResourceContent::setImageResourceInfo(ImageResourceInfo* info) {
126 const ResourceLoaderOptions& options) 89 m_info = info;
127 : Resource(ResourceRequest(""), Image, options),
128 m_devicePixelRatioHeaderValue(1.0),
129 m_image(image),
130 m_hasDevicePixelRatioHeaderValue(false),
131 m_isSchedulingReload(false),
132 m_isPlaceholder(false),
133 m_flushTimer(this, &ImageResource::flushImageIfNeeded),
134 m_isRefetchableDataFromDiskCache(true) {
135 RESOURCE_LOADING_DVLOG(1) << "new ImageResource(Image) " << this;
136 setStatus(Cached);
137 } 90 }
138 91
139 ImageResource::~ImageResource() { 92 DEFINE_TRACE(ImageResourceContent) {
140 RESOURCE_LOADING_DVLOG(1) << "~ImageResource " << this; 93 visitor->trace(m_info);
141 clearImage(); 94 ImageObserver::trace(visitor);
142 } 95 }
143 96
144 DEFINE_TRACE(ImageResource) { 97 void ImageResourceContent::markObserverFinished(
145 visitor->trace(m_multipartParser); 98 ImageResourceObserver* observer) {
146 Resource::trace(visitor);
147 ImageObserver::trace(visitor);
148 MultipartImageResourceParser::Client::trace(visitor);
149 }
150
151 void ImageResource::checkNotify() {
152 // Don't notify clients of completion if this ImageResource is
153 // about to be reloaded.
154 if (m_isSchedulingReload || shouldReloadBrokenPlaceholder())
155 return;
156
157 Resource::checkNotify();
158 }
159
160 void ImageResource::markObserverFinished(ImageResourceObserver* observer) {
161 auto it = m_observers.find(observer); 99 auto it = m_observers.find(observer);
162 if (it == m_observers.end()) 100 if (it == m_observers.end())
163 return; 101 return;
164 m_observers.remove(it); 102 m_observers.remove(it);
165 m_finishedObservers.add(observer); 103 m_finishedObservers.add(observer);
166 } 104 }
167 105
168 void ImageResource::didAddClient(ResourceClient* client) { 106 void ImageResourceContent::addObserver(ImageResourceObserver* observer) {
169 DCHECK((m_multipartParser && isLoading()) || !data() || m_image); 107 m_info->willAddClientOrObserver();
170
171 // Don't notify observers and clients of completion if this ImageResource is
172 // about to be reloaded.
173 if (m_isSchedulingReload || shouldReloadBrokenPlaceholder())
174 return;
175
176 Resource::didAddClient(client);
177 }
178
179 void ImageResource::addObserver(ImageResourceObserver* observer) {
180 willAddClientOrObserver(MarkAsReferenced);
181 108
182 m_observers.add(observer); 109 m_observers.add(observer);
183 110
184 if (isCacheValidator()) 111 if (m_info->isCacheValidator())
185 return; 112 return;
186 113
187 // When the response is not multipart, if |data()| exists, |m_image| must be
188 // created. This is assured that |updateImage()| is called when |appendData()|
189 // is called.
190 //
191 // On the other hand, when the response is multipart, |updateImage()| is not
192 // called in |appendData()|, which means |m_image| might not be created even
193 // when |data()| exists. This is intentional since creating a |m_image| on
194 // receiving data might destroy an existing image in a previous part.
195 DCHECK((m_multipartParser && isLoading()) || !data() || m_image);
196
197 if (m_image && !m_image->isNull()) { 114 if (m_image && !m_image->isNull()) {
198 observer->imageChanged(this); 115 observer->imageChanged(this);
199 } 116 }
200 117
201 if (isLoaded() && m_observers.contains(observer) && !m_isSchedulingReload && 118 if (isLoaded() && m_observers.contains(observer) &&
202 !shouldReloadBrokenPlaceholder()) { 119 !m_info->schedulingReloadOrShouldReloadBrokenPlaceholder()) {
203 markObserverFinished(observer); 120 markObserverFinished(observer);
204 observer->imageNotifyFinished(this); 121 observer->imageNotifyFinished(this);
205 } 122 }
206 } 123 }
207 124
208 void ImageResource::removeObserver(ImageResourceObserver* observer) { 125 void ImageResourceContent::removeObserver(ImageResourceObserver* observer) {
209 DCHECK(observer); 126 DCHECK(observer);
210 127
211 auto it = m_observers.find(observer); 128 auto it = m_observers.find(observer);
212 if (it != m_observers.end()) { 129 if (it != m_observers.end()) {
213 m_observers.remove(it); 130 m_observers.remove(it);
214 } else { 131 } else {
215 it = m_finishedObservers.find(observer); 132 it = m_finishedObservers.find(observer);
216 DCHECK(it != m_finishedObservers.end()); 133 DCHECK(it != m_finishedObservers.end());
217 m_finishedObservers.remove(it); 134 m_finishedObservers.remove(it);
218 } 135 }
219 didRemoveClientOrObserver(); 136 m_info->didRemoveClientOrObserver();
220 } 137 }
221 138
222 static void priorityFromObserver(const ImageResourceObserver* observer, 139 static void priorityFromObserver(const ImageResourceObserver* observer,
223 ResourcePriority& priority) { 140 ResourcePriority& priority) {
224 ResourcePriority nextPriority = observer->computeResourcePriority(); 141 ResourcePriority nextPriority = observer->computeResourcePriority();
225 if (nextPriority.visibility == ResourcePriority::NotVisible) 142 if (nextPriority.visibility == ResourcePriority::NotVisible)
226 return; 143 return;
227 priority.visibility = ResourcePriority::Visible; 144 priority.visibility = ResourcePriority::Visible;
228 priority.intraPriorityValue += nextPriority.intraPriorityValue; 145 priority.intraPriorityValue += nextPriority.intraPriorityValue;
229 } 146 }
230 147
231 ResourcePriority ImageResource::priorityFromObservers() { 148 ResourcePriority ImageResourceContent::priorityFromObservers() const {
232 ResourcePriority priority; 149 ResourcePriority priority;
233 150
234 for (const auto& it : m_finishedObservers) 151 for (const auto& it : m_finishedObservers)
235 priorityFromObserver(it.key, priority); 152 priorityFromObserver(it.key, priority);
236 for (const auto& it : m_observers) 153 for (const auto& it : m_observers)
237 priorityFromObserver(it.key, priority); 154 priorityFromObserver(it.key, priority);
238 155
239 return priority; 156 return priority;
240 } 157 }
241 158
242 void ImageResource::destroyDecodedDataForFailedRevalidation() { 159 void ImageResourceContent::destroyDecodedData() {
243 clearImage();
244 setDecodedSize(0);
245 }
246
247 void ImageResource::destroyDecodedDataIfPossible() {
248 if (!m_image) 160 if (!m_image)
249 return; 161 return;
250 CHECK(!errorOccurred()); 162 CHECK(!errorOccurred());
251 m_image->destroyDecodedData(); 163 m_image->destroyDecodedData();
252 if (!isPreloaded() && m_isRefetchableDataFromDiskCache) {
253 UMA_HISTOGRAM_MEMORY_KB("Memory.Renderer.EstimatedDroppableEncodedSize",
254 encodedSize() / 1024);
255 }
256 } 164 }
257 165
258 void ImageResource::doResetAnimation() { 166 void ImageResourceContent::doResetAnimation() {
259 if (m_image) 167 if (m_image)
260 m_image->resetAnimation(); 168 m_image->resetAnimation();
261 } 169 }
262 170
263 void ImageResource::allClientsAndObserversRemoved() { 171 PassRefPtr<const SharedBuffer> ImageResourceContent::resourceBuffer() const {
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) 172 if (m_image)
286 return m_image->data(); 173 return m_image->data();
287 return nullptr; 174 return nullptr;
288 } 175 }
289 176
290 void ImageResource::appendData(const char* data, size_t length) { 177 bool ImageResourceContent::shouldUpdateImageImmediately() const {
291 v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(length); 178 // If we don't have the size available yet, then update immediately since
292 if (m_multipartParser) { 179 // we need to know the image size as soon as possible. Likewise for
293 m_multipartParser->appendData(data, length); 180 // animated images, update right away since we shouldn't throttle animated
294 } else { 181 // images.
295 Resource::appendData(data, length); 182 return m_sizeAvailable == Image::SizeUnavailable ||
296 183 (m_image && m_image->maybeAnimated());
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 } 184 }
325 185
326 void ImageResource::flushImageIfNeeded(TimerBase*) { 186 std::pair<blink::Image*, float> ImageResourceContent::brokenImage(
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) { 187 float deviceScaleFactor) {
337 if (deviceScaleFactor >= 2) { 188 if (deviceScaleFactor >= 2) {
338 DEFINE_STATIC_REF(blink::Image, brokenImageHiRes, 189 DEFINE_STATIC_REF(blink::Image, brokenImageHiRes,
339 (blink::Image::loadPlatformResource("missingImage@2x"))); 190 (blink::Image::loadPlatformResource("missingImage@2x")));
340 return std::make_pair(brokenImageHiRes, 2); 191 return std::make_pair(brokenImageHiRes, 2);
341 } 192 }
342 193
343 DEFINE_STATIC_REF(blink::Image, brokenImageLoRes, 194 DEFINE_STATIC_REF(blink::Image, brokenImageLoRes,
344 (blink::Image::loadPlatformResource("missingImage"))); 195 (blink::Image::loadPlatformResource("missingImage")));
345 return std::make_pair(brokenImageLoRes, 1); 196 return std::make_pair(brokenImageLoRes, 1);
346 } 197 }
347 198
348 bool ImageResource::willPaintBrokenImage() const { 199 blink::Image* ImageResourceContent::getImage() {
349 return errorOccurred();
350 }
351
352 blink::Image* ImageResource::getImage() {
353 if (errorOccurred()) { 200 if (errorOccurred()) {
354 // Returning the 1x broken image is non-ideal, but we cannot reliably access 201 // Returning the 1x broken image is non-ideal, but we cannot reliably access
355 // the appropriate deviceScaleFactor from here. It is critical that callers 202 // the appropriate deviceScaleFactor from here. It is critical that callers
356 // use ImageResource::brokenImage() when they need the real, 203 // use ImageResourceContent::brokenImage() when they need the real,
357 // deviceScaleFactor-appropriate broken image icon. 204 // deviceScaleFactor-appropriate broken image icon.
358 return brokenImage(1).first; 205 return brokenImage(1).first;
359 } 206 }
360 207
361 if (m_image) 208 if (m_image)
362 return m_image.get(); 209 return m_image.get();
363 210
364 return blink::Image::nullImage(); 211 return blink::Image::nullImage();
365 } 212 }
366 213
367 bool ImageResource::usesImageContainerSize() const { 214 bool ImageResourceContent::usesImageContainerSize() const {
368 if (m_image) 215 if (m_image)
369 return m_image->usesContainerSize(); 216 return m_image->usesContainerSize();
370 217
371 return false; 218 return false;
372 } 219 }
373 220
374 bool ImageResource::imageHasRelativeSize() const { 221 bool ImageResourceContent::imageHasRelativeSize() const {
375 if (m_image) 222 if (m_image)
376 return m_image->hasRelativeSize(); 223 return m_image->hasRelativeSize();
377 224
378 return false; 225 return false;
379 } 226 }
380 227
381 LayoutSize ImageResource::imageSize( 228 LayoutSize ImageResourceContent::imageSize(
382 RespectImageOrientationEnum shouldRespectImageOrientation, 229 RespectImageOrientationEnum shouldRespectImageOrientation,
383 float multiplier, 230 float multiplier,
384 SizeType sizeType) { 231 SizeType sizeType) {
385 if (!m_image) 232 if (!m_image)
386 return LayoutSize(); 233 return LayoutSize();
387 234
388 LayoutSize size; 235 LayoutSize size;
389 236
390 if (m_image->isBitmapImage() && 237 if (m_image->isBitmapImage() &&
391 shouldRespectImageOrientation == RespectImageOrientation) { 238 shouldRespectImageOrientation == RespectImageOrientation) {
392 size = 239 size =
393 LayoutSize(toBitmapImage(m_image.get())->sizeRespectingOrientation()); 240 LayoutSize(toBitmapImage(m_image.get())->sizeRespectingOrientation());
394 } else { 241 } else {
395 size = LayoutSize(m_image->size()); 242 size = LayoutSize(m_image->size());
396 } 243 }
397 244
398 if (sizeType == IntrinsicCorrectedToDPR && m_hasDevicePixelRatioHeaderValue && 245 if (sizeType == IntrinsicCorrectedToDPR && hasDevicePixelRatioHeaderValue() &&
399 m_devicePixelRatioHeaderValue > 0) 246 devicePixelRatioHeaderValue() > 0)
400 multiplier = 1 / m_devicePixelRatioHeaderValue; 247 multiplier = 1 / devicePixelRatioHeaderValue();
401 248
402 if (multiplier == 1 || m_image->hasRelativeSize()) 249 if (multiplier == 1 || m_image->hasRelativeSize())
403 return size; 250 return size;
404 251
405 // Don't let images that have a width/height >= 1 shrink below 1 when zoomed. 252 // Don't let images that have a width/height >= 1 shrink below 1 when zoomed.
406 LayoutSize minimumSize( 253 LayoutSize minimumSize(
407 size.width() > LayoutUnit() ? LayoutUnit(1) : LayoutUnit(), 254 size.width() > LayoutUnit() ? LayoutUnit(1) : LayoutUnit(),
408 LayoutUnit(size.height() > LayoutUnit() ? LayoutUnit(1) : LayoutUnit())); 255 LayoutUnit(size.height() > LayoutUnit() ? LayoutUnit(1) : LayoutUnit()));
409 size.scale(multiplier); 256 size.scale(multiplier);
410 size.clampToMinimumSize(minimumSize); 257 size.clampToMinimumSize(minimumSize);
411 return size; 258 return size;
412 } 259 }
413 260
414 void ImageResource::notifyObservers(NotifyFinishOption notifyingFinishOption, 261 void ImageResourceContent::notifyObservers(
415 const IntRect* changeRect) { 262 NotifyFinishOption notifyingFinishOption,
263 const IntRect* changeRect) {
416 for (auto* observer : m_finishedObservers.asVector()) { 264 for (auto* observer : m_finishedObservers.asVector()) {
417 if (m_finishedObservers.contains(observer)) 265 if (m_finishedObservers.contains(observer))
418 observer->imageChanged(this, changeRect); 266 observer->imageChanged(this, changeRect);
419 } 267 }
420 for (auto* observer : m_observers.asVector()) { 268 for (auto* observer : m_observers.asVector()) {
421 if (m_observers.contains(observer)) { 269 if (m_observers.contains(observer)) {
422 observer->imageChanged(this, changeRect); 270 observer->imageChanged(this, changeRect);
423 if (notifyingFinishOption == ShouldNotifyFinish && 271 if (notifyingFinishOption == ShouldNotifyFinish &&
424 m_observers.contains(observer) && !m_isSchedulingReload && 272 m_observers.contains(observer) &&
425 !shouldReloadBrokenPlaceholder()) { 273 !m_info->schedulingReloadOrShouldReloadBrokenPlaceholder()) {
426 markObserverFinished(observer); 274 markObserverFinished(observer);
427 observer->imageNotifyFinished(this); 275 observer->imageNotifyFinished(this);
428 } 276 }
429 } 277 }
430 } 278 }
431 } 279 }
432 280
433 void ImageResource::clear() { 281 PassRefPtr<Image> ImageResourceContent::createImage() {
434 clearImage(); 282 if (m_info->response().mimeType() == "image/svg+xml")
435 clearData(); 283 return SVGImage::create(this);
436 setEncodedSize(0); 284 return BitmapImage::create(this);
437 } 285 }
438 286
439 inline void ImageResource::createImage() { 287 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) 288 if (!m_image)
453 return; 289 return;
454 int64_t length = m_image->data() ? m_image->data()->size() : 0; 290 int64_t length = m_image->data() ? m_image->data()->size() : 0;
455 v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(-length); 291 v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(-length);
456 292
457 // If our Image has an observer, it's always us so we need to clear the back 293 // If our Image has an observer, it's always us so we need to clear the back
458 // pointer before dropping our reference. 294 // pointer before dropping our reference.
459 m_image->clearImageObserver(); 295 m_image->clearImageObserver();
460 m_image.clear(); 296 m_image.clear();
461 m_sizeAvailable = Image::SizeUnavailable; 297 m_sizeAvailable = Image::SizeUnavailable;
462 } 298 }
463 299
464 void ImageResource::updateImage(bool allDataReceived) { 300 void ImageResourceContent::clearImageAndNotifyObservers(
465 TRACE_EVENT0("blink", "ImageResource::updateImage"); 301 NotifyFinishOption notifyingFinishOption) {
302 clearImage();
303 notifyObservers(notifyingFinishOption);
304 }
466 305
467 if (data()) 306 void ImageResourceContent::updateImage(PassRefPtr<SharedBuffer> data,
468 createImage(); 307 ClearImageOption clearImageOption,
308 bool allDataReceived) {
309 TRACE_EVENT0("blink", "ImageResourceContent::updateImage");
310
311 if (clearImageOption == ImageResourceContent::ClearExistingImage) {
312 clearImage();
313 }
469 314
470 // Have the image update its data from its internal buffer. It will not do 315 // 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 316 // anything now, but will delay decoding until queried for info (like size or
472 // specific image frames). 317 // specific image frames).
473 if (data()) { 318 if (data) {
319 if (!m_image)
320 m_image = createImage();
474 DCHECK(m_image); 321 DCHECK(m_image);
475 m_sizeAvailable = m_image->setData(data(), allDataReceived); 322 m_sizeAvailable = m_image->setData(std::move(data), allDataReceived);
476 } 323 }
477 324
478 // Go ahead and tell our observers to try to draw if we have either received 325 // 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 326 // 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. 327 // observers to repaint, which will force that chunk to decode.
481 if (m_sizeAvailable == Image::SizeUnavailable && !allDataReceived) 328 if (m_sizeAvailable == Image::SizeUnavailable && !allDataReceived)
482 return; 329 return;
483 330
484 if (m_isPlaceholder && allDataReceived && m_image && !m_image->isNull()) { 331 if (m_info->isPlaceholder() && allDataReceived && m_image &&
332 !m_image->isNull()) {
485 if (m_sizeAvailable == Image::SizeAvailable) { 333 if (m_sizeAvailable == Image::SizeAvailable) {
486 // TODO(sclittle): Show the original image if the response consists of the 334 // 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 335 // entire image, such as if the entire image response body is smaller than
488 // the requested range. 336 // the requested range.
489 IntSize dimensions = m_image->size(); 337 IntSize dimensions = m_image->size();
338
490 clearImage(); 339 clearImage();
491 m_image = PlaceholderImage::create(this, dimensions); 340 m_image = PlaceholderImage::create(this, dimensions);
492 } else { 341 } else {
493 // Clear the image so that it gets treated like a decoding error, since 342 // Clear the image so that it gets treated like a decoding error, since
494 // the attempt to build a placeholder image failed. 343 // the attempt to build a placeholder image failed.
495 clearImage(); 344 clearImage();
496 } 345 }
497 } 346 }
498 347
499 if (!m_image || m_image->isNull()) { 348 if (!m_image || m_image->isNull()) {
500 size_t size = encodedSize(); 349 clearImage();
501 clear(); 350 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 } 351 }
509 352
510 // It would be nice to only redraw the decoded band of the image, but with the 353 // 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. 354 // current design (decoding delayed until painting) that seems hard.
512 notifyObservers(allDataReceived ? ShouldNotifyFinish : DoNotNotifyFinish); 355 notifyObservers(allDataReceived ? ShouldNotifyFinish : DoNotNotifyFinish);
513 } 356 }
514 357
515 void ImageResource::updateImageAndClearBuffer() { 358 void ImageResourceContent::decodedSizeChangedTo(const blink::Image* image,
516 clearImage(); 359 size_t newSize) {
517 updateImage(true);
518 clearData();
519 }
520
521 void ImageResource::finish(double loadFinishTime) {
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) 360 if (!image || image != m_image)
573 return; 361 return;
574 362
575 setDecodedSize(newSize); 363 m_info->setDecodedSize(newSize);
576 } 364 }
577 365
578 bool ImageResource::shouldPauseAnimation(const blink::Image* image) { 366 bool ImageResourceContent::shouldPauseAnimation(const blink::Image* image) {
579 if (!image || image != m_image) 367 if (!image || image != m_image)
580 return false; 368 return false;
581 369
582 for (const auto& it : m_finishedObservers) 370 for (const auto& it : m_finishedObservers)
583 if (it.key->willRenderImage()) 371 if (it.key->willRenderImage())
584 return false; 372 return false;
585 373
586 for (const auto& it : m_observers) 374 for (const auto& it : m_observers)
587 if (it.key->willRenderImage()) 375 if (it.key->willRenderImage())
588 return false; 376 return false;
589 377
590 return true; 378 return true;
591 } 379 }
592 380
593 void ImageResource::animationAdvanced(const blink::Image* image) { 381 void ImageResourceContent::animationAdvanced(const blink::Image* image) {
594 if (!image || image != m_image) 382 if (!image || image != m_image)
595 return; 383 return;
596 notifyObservers(DoNotNotifyFinish); 384 notifyObservers(DoNotNotifyFinish);
597 } 385 }
598 386
599 void ImageResource::updateImageAnimationPolicy() { 387 void ImageResourceContent::updateImageAnimationPolicy() {
600 if (!m_image) 388 if (!m_image)
601 return; 389 return;
602 390
603 ImageAnimationPolicy newPolicy = ImageAnimationPolicyAllowed; 391 ImageAnimationPolicy newPolicy = ImageAnimationPolicyAllowed;
604 for (const auto& it : m_finishedObservers) { 392 for (const auto& it : m_finishedObservers) {
605 if (it.key->getImageAnimationPolicy(newPolicy)) 393 if (it.key->getImageAnimationPolicy(newPolicy))
606 break; 394 break;
607 } 395 }
608 for (const auto& it : m_observers) { 396 for (const auto& it : m_observers) {
609 if (it.key->getImageAnimationPolicy(newPolicy)) 397 if (it.key->getImageAnimationPolicy(newPolicy))
610 break; 398 break;
611 } 399 }
612 400
613 if (m_image->animationPolicy() != newPolicy) { 401 if (m_image->animationPolicy() != newPolicy) {
614 m_image->resetAnimation(); 402 m_image->resetAnimation();
615 m_image->setAnimationPolicy(newPolicy); 403 m_image->setAnimationPolicy(newPolicy);
616 } 404 }
617 } 405 }
618 406
619 static bool isLoFiImage(const ImageResource& resource) { 407 void ImageResourceContent::changedInRect(const blink::Image* image,
620 if (resource.resourceRequest().loFiState() != WebURLRequest::LoFiOn) 408 const IntRect& rect) {
621 return false;
622 return !resource.isLoaded() ||
623 resource.response()
624 .httpHeaderField("chrome-proxy-content-transform")
625 .contains("empty-image");
626 }
627
628 void ImageResource::reloadIfLoFiOrPlaceholder(
629 ResourceFetcher* fetcher,
630 ReloadCachePolicy reloadCachePolicy) {
631 if (!m_isPlaceholder && !isLoFiImage(*this))
632 return;
633
634 // Prevent clients and observers from being notified of completion while the
635 // reload is being scheduled, so that e.g. canceling an existing load in
636 // progress doesn't cause clients and observers to be notified of completion
637 // prematurely.
638 DCHECK(!m_isSchedulingReload);
639 m_isSchedulingReload = true;
640
641 if (reloadCachePolicy == ReloadCachePolicy::BypassCache)
642 setCachePolicyBypassingCache();
643 setLoFiStateOff();
644
645 if (m_isPlaceholder) {
646 m_isPlaceholder = false;
647 clearRangeRequestHeader();
648 }
649
650 if (isLoading()) {
651 loader()->cancel();
652 // Canceling the loader causes error() to be called, which in turn calls
653 // clear() and notifyObservers(), so there's no need to call these again
654 // here.
655 } else {
656 clear();
657 notifyObservers(DoNotNotifyFinish);
658 }
659
660 setStatus(NotStarted);
661
662 DCHECK(m_isSchedulingReload);
663 m_isSchedulingReload = false;
664
665 fetcher->startLoad(this);
666 }
667
668 void ImageResource::changedInRect(const blink::Image* image,
669 const IntRect& rect) {
670 if (!image || image != m_image) 409 if (!image || image != m_image)
671 return; 410 return;
672 notifyObservers(DoNotNotifyFinish, &rect); 411 notifyObservers(DoNotNotifyFinish, &rect);
673 } 412 }
674 413
675 void ImageResource::onePartInMultipartReceived( 414 bool ImageResourceContent::isAccessAllowed(SecurityOrigin* securityOrigin) {
676 const ResourceResponse& response) { 415 return m_info->isAccessAllowed(
677 DCHECK(m_multipartParser); 416 securityOrigin, getImage()->currentFrameHasSingleSecurityOrigin()
678 417 ? ImageResourceInfo::HasSingleSecurityOrigin
679 setResponse(response); 418 : ImageResourceInfo::HasMultipleSecurityOrigin);
680 if (m_multipartParsingState == MultipartParsingState::WaitingForFirstPart) {
681 // We have nothing to do because we don't have any data.
682 m_multipartParsingState = MultipartParsingState::ParsingFirstPart;
683 return;
684 }
685 updateImageAndClearBuffer();
686
687 if (m_multipartParsingState == MultipartParsingState::ParsingFirstPart) {
688 m_multipartParsingState = MultipartParsingState::FinishedParsingFirstPart;
689 // Notify finished when the first part ends.
690 if (!errorOccurred())
691 setStatus(Cached);
692 // We notify clients and observers of finish in checkNotify() and
693 // updateImageAndClearBuffer(), respectively, and they will not be
694 // notified again in Resource::finish()/error().
695 checkNotify();
696 if (loader())
697 loader()->didFinishLoadingFirstPartInMultipart();
698 }
699 } 419 }
700 420
701 void ImageResource::multipartDataReceived(const char* bytes, size_t size) { 421 void ImageResourceContent::emulateLoadStartedForInspector(
702 DCHECK(m_multipartParser); 422 ResourceFetcher* fetcher,
703 Resource::appendData(bytes, size); 423 const KURL& url,
424 const AtomicString& initiatorName) {
425 m_info->emulateLoadStartedForInspector(fetcher, url, initiatorName);
704 } 426 }
705 427
706 bool ImageResource::isAccessAllowed(SecurityOrigin* securityOrigin) { 428 // TODO(hiroshige): Consider removing the following methods, or stoping
707 if (response().wasFetchedViaServiceWorker()) { 429 // redirecting to ImageResource.
708 return response().serviceWorkerResponseType() != 430 bool ImageResourceContent::isLoaded() const {
709 WebServiceWorkerResponseTypeOpaque; 431 return getStatus() > ResourceStatus::Pending;
710 } 432 }
711 if (!getImage()->currentFrameHasSingleSecurityOrigin()) 433
712 return false; 434 bool ImageResourceContent::isLoading() const {
713 if (passesAccessControlCheck(securityOrigin)) 435 return getStatus() == ResourceStatus::Pending;
714 return true; 436 }
715 return !securityOrigin->taintsCanvas(response().url()); 437
438 bool ImageResourceContent::errorOccurred() const {
439 return getStatus() == ResourceStatus::LoadError ||
440 getStatus() == ResourceStatus::DecodeError;
441 }
442
443 bool ImageResourceContent::loadFailedOrCanceled() const {
444 return getStatus() == ResourceStatus::LoadError;
445 }
446
447 ResourceStatus ImageResourceContent::getStatus() const {
448 return m_info->getStatus();
449 }
450
451 const KURL& ImageResourceContent::url() const {
452 return m_info->url();
453 }
454
455 bool ImageResourceContent::hasCacheControlNoStoreHeader() const {
456 return m_info->hasCacheControlNoStoreHeader();
457 }
458
459 float ImageResourceContent::devicePixelRatioHeaderValue() const {
460 return m_info->devicePixelRatioHeaderValue();
461 }
462
463 bool ImageResourceContent::hasDevicePixelRatioHeaderValue() const {
464 return m_info->hasDevicePixelRatioHeaderValue();
465 }
466
467 const ResourceResponse& ImageResourceContent::response() const {
468 return m_info->response();
469 }
470
471 const ResourceError& ImageResourceContent::resourceError() const {
472 return m_info->resourceError();
716 } 473 }
717 474
718 } // namespace blink 475 } // namespace blink
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/core/fetch/ImageResourceContent.h ('k') | third_party/WebKit/Source/core/fetch/ImageResourceInfo.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698