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

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

Powered by Google App Engine
This is Rietveld 408576698