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

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

Issue 2558033002: Loading: move ImageResource and related classes to core/loader/resource (Closed)
Patch Set: rebase and format 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
(Empty)
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "core/fetch/ImageResourceContent.h"
6
7 #include "core/fetch/ImageResource.h"
8 #include "core/fetch/ImageResourceInfo.h"
9 #include "core/fetch/ImageResourceObserver.h"
10 #include "core/svg/graphics/SVGImage.h"
11 #include "platform/Histogram.h"
12 #include "platform/RuntimeEnabledFeatures.h"
13 #include "platform/SharedBuffer.h"
14 #include "platform/geometry/IntSize.h"
15 #include "platform/graphics/BitmapImage.h"
16 #include "platform/graphics/PlaceholderImage.h"
17 #include "platform/tracing/TraceEvent.h"
18 #include "wtf/StdLibExtras.h"
19 #include "wtf/Vector.h"
20 #include <memory>
21 #include <v8.h>
22
23 namespace blink {
24 namespace {
25 class NullImageResourceInfo final
26 : public GarbageCollectedFinalized<NullImageResourceInfo>,
27 public ImageResourceInfo {
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
69 } // namespace
70
71 ImageResourceContent::ImageResourceContent(PassRefPtr<blink::Image> image)
72 : m_image(image), m_isRefetchableDataFromDiskCache(true) {
73 DEFINE_STATIC_LOCAL(NullImageResourceInfo, nullInfo,
74 (new NullImageResourceInfo()));
75 m_info = &nullInfo;
76 }
77
78 ImageResourceContent* ImageResourceContent::fetch(FetchRequest& request,
79 ResourceFetcher* fetcher) {
80 // TODO(hiroshige): Remove direct references to ImageResource by making
81 // the dependencies around ImageResource and ImageResourceContent cleaner.
82 ImageResource* resource = ImageResource::fetch(request, fetcher);
83 if (!resource)
84 return nullptr;
85 return resource->getContent();
86 }
87
88 void ImageResourceContent::setImageResourceInfo(ImageResourceInfo* info) {
89 m_info = info;
90 }
91
92 DEFINE_TRACE(ImageResourceContent) {
93 visitor->trace(m_info);
94 ImageObserver::trace(visitor);
95 }
96
97 void ImageResourceContent::markObserverFinished(
98 ImageResourceObserver* observer) {
99 auto it = m_observers.find(observer);
100 if (it == m_observers.end())
101 return;
102 m_observers.remove(it);
103 m_finishedObservers.add(observer);
104 }
105
106 void ImageResourceContent::addObserver(ImageResourceObserver* observer) {
107 m_info->willAddClientOrObserver();
108
109 m_observers.add(observer);
110
111 if (m_info->isCacheValidator())
112 return;
113
114 if (m_image && !m_image->isNull()) {
115 observer->imageChanged(this);
116 }
117
118 if (isLoaded() && m_observers.contains(observer) &&
119 !m_info->schedulingReloadOrShouldReloadBrokenPlaceholder()) {
120 markObserverFinished(observer);
121 observer->imageNotifyFinished(this);
122 }
123 }
124
125 void ImageResourceContent::removeObserver(ImageResourceObserver* observer) {
126 DCHECK(observer);
127
128 auto it = m_observers.find(observer);
129 if (it != m_observers.end()) {
130 m_observers.remove(it);
131 } else {
132 it = m_finishedObservers.find(observer);
133 DCHECK(it != m_finishedObservers.end());
134 m_finishedObservers.remove(it);
135 }
136 m_info->didRemoveClientOrObserver();
137 }
138
139 static void priorityFromObserver(const ImageResourceObserver* observer,
140 ResourcePriority& priority) {
141 ResourcePriority nextPriority = observer->computeResourcePriority();
142 if (nextPriority.visibility == ResourcePriority::NotVisible)
143 return;
144 priority.visibility = ResourcePriority::Visible;
145 priority.intraPriorityValue += nextPriority.intraPriorityValue;
146 }
147
148 ResourcePriority ImageResourceContent::priorityFromObservers() const {
149 ResourcePriority priority;
150
151 for (const auto& it : m_finishedObservers)
152 priorityFromObserver(it.key, priority);
153 for (const auto& it : m_observers)
154 priorityFromObserver(it.key, priority);
155
156 return priority;
157 }
158
159 void ImageResourceContent::destroyDecodedData() {
160 if (!m_image)
161 return;
162 CHECK(!errorOccurred());
163 m_image->destroyDecodedData();
164 }
165
166 void ImageResourceContent::doResetAnimation() {
167 if (m_image)
168 m_image->resetAnimation();
169 }
170
171 PassRefPtr<const SharedBuffer> ImageResourceContent::resourceBuffer() const {
172 if (m_image)
173 return m_image->data();
174 return nullptr;
175 }
176
177 bool ImageResourceContent::shouldUpdateImageImmediately() const {
178 // If we don't have the size available yet, then update immediately since
179 // we need to know the image size as soon as possible. Likewise for
180 // animated images, update right away since we shouldn't throttle animated
181 // images.
182 return m_sizeAvailable == Image::SizeUnavailable ||
183 (m_image && m_image->maybeAnimated());
184 }
185
186 std::pair<blink::Image*, float> ImageResourceContent::brokenImage(
187 float deviceScaleFactor) {
188 if (deviceScaleFactor >= 2) {
189 DEFINE_STATIC_REF(blink::Image, brokenImageHiRes,
190 (blink::Image::loadPlatformResource("missingImage@2x")));
191 return std::make_pair(brokenImageHiRes, 2);
192 }
193
194 DEFINE_STATIC_REF(blink::Image, brokenImageLoRes,
195 (blink::Image::loadPlatformResource("missingImage")));
196 return std::make_pair(brokenImageLoRes, 1);
197 }
198
199 blink::Image* ImageResourceContent::getImage() {
200 if (errorOccurred()) {
201 // Returning the 1x broken image is non-ideal, but we cannot reliably access
202 // the appropriate deviceScaleFactor from here. It is critical that callers
203 // use ImageResourceContent::brokenImage() when they need the real,
204 // deviceScaleFactor-appropriate broken image icon.
205 return brokenImage(1).first;
206 }
207
208 if (m_image)
209 return m_image.get();
210
211 return blink::Image::nullImage();
212 }
213
214 bool ImageResourceContent::usesImageContainerSize() const {
215 if (m_image)
216 return m_image->usesContainerSize();
217
218 return false;
219 }
220
221 bool ImageResourceContent::imageHasRelativeSize() const {
222 if (m_image)
223 return m_image->hasRelativeSize();
224
225 return false;
226 }
227
228 LayoutSize ImageResourceContent::imageSize(
229 RespectImageOrientationEnum shouldRespectImageOrientation,
230 float multiplier,
231 SizeType sizeType) {
232 if (!m_image)
233 return LayoutSize();
234
235 LayoutSize size;
236
237 if (m_image->isBitmapImage() &&
238 shouldRespectImageOrientation == RespectImageOrientation) {
239 size =
240 LayoutSize(toBitmapImage(m_image.get())->sizeRespectingOrientation());
241 } else {
242 size = LayoutSize(m_image->size());
243 }
244
245 if (sizeType == IntrinsicCorrectedToDPR && hasDevicePixelRatioHeaderValue() &&
246 devicePixelRatioHeaderValue() > 0)
247 multiplier = 1 / devicePixelRatioHeaderValue();
248
249 if (multiplier == 1 || m_image->hasRelativeSize())
250 return size;
251
252 // Don't let images that have a width/height >= 1 shrink below 1 when zoomed.
253 LayoutSize minimumSize(
254 size.width() > LayoutUnit() ? LayoutUnit(1) : LayoutUnit(),
255 LayoutUnit(size.height() > LayoutUnit() ? LayoutUnit(1) : LayoutUnit()));
256 size.scale(multiplier);
257 size.clampToMinimumSize(minimumSize);
258 return size;
259 }
260
261 void ImageResourceContent::notifyObservers(
262 NotifyFinishOption notifyingFinishOption,
263 const IntRect* changeRect) {
264 for (auto* observer : m_finishedObservers.asVector()) {
265 if (m_finishedObservers.contains(observer))
266 observer->imageChanged(this, changeRect);
267 }
268 for (auto* observer : m_observers.asVector()) {
269 if (m_observers.contains(observer)) {
270 observer->imageChanged(this, changeRect);
271 if (notifyingFinishOption == ShouldNotifyFinish &&
272 m_observers.contains(observer) &&
273 !m_info->schedulingReloadOrShouldReloadBrokenPlaceholder()) {
274 markObserverFinished(observer);
275 observer->imageNotifyFinished(this);
276 }
277 }
278 }
279 }
280
281 PassRefPtr<Image> ImageResourceContent::createImage() {
282 if (m_info->response().mimeType() == "image/svg+xml")
283 return SVGImage::create(this);
284 return BitmapImage::create(this);
285 }
286
287 void ImageResourceContent::clearImage() {
288 if (!m_image)
289 return;
290 int64_t length = m_image->data() ? m_image->data()->size() : 0;
291 v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(-length);
292
293 // If our Image has an observer, it's always us so we need to clear the back
294 // pointer before dropping our reference.
295 m_image->clearImageObserver();
296 m_image.clear();
297 m_sizeAvailable = Image::SizeUnavailable;
298 }
299
300 void ImageResourceContent::clearImageAndNotifyObservers(
301 NotifyFinishOption notifyingFinishOption) {
302 clearImage();
303 notifyObservers(notifyingFinishOption);
304 }
305
306 void ImageResourceContent::updateImage(PassRefPtr<SharedBuffer> data,
307 ClearImageOption clearImageOption,
308 bool allDataReceived) {
309 TRACE_EVENT0("blink", "ImageResourceContent::updateImage");
310
311 if (clearImageOption == ImageResourceContent::ClearExistingImage) {
312 clearImage();
313 }
314
315 // Have the image update its data from its internal buffer. It will not do
316 // anything now, but will delay decoding until queried for info (like size or
317 // specific image frames).
318 if (data) {
319 if (!m_image)
320 m_image = createImage();
321 DCHECK(m_image);
322 m_sizeAvailable = m_image->setData(std::move(data), allDataReceived);
323 }
324
325 // Go ahead and tell our observers to try to draw if we have either received
326 // all the data or the size is known. Each chunk from the network causes
327 // observers to repaint, which will force that chunk to decode.
328 if (m_sizeAvailable == Image::SizeUnavailable && !allDataReceived)
329 return;
330
331 if (m_info->isPlaceholder() && allDataReceived && m_image &&
332 !m_image->isNull()) {
333 if (m_sizeAvailable == Image::SizeAvailable) {
334 // TODO(sclittle): Show the original image if the response consists of the
335 // entire image, such as if the entire image response body is smaller than
336 // the requested range.
337 IntSize dimensions = m_image->size();
338
339 clearImage();
340 m_image = PlaceholderImage::create(this, dimensions);
341 } else {
342 // Clear the image so that it gets treated like a decoding error, since
343 // the attempt to build a placeholder image failed.
344 clearImage();
345 }
346 }
347
348 if (!m_image || m_image->isNull()) {
349 clearImage();
350 m_info->decodeError(allDataReceived);
351 }
352
353 // It would be nice to only redraw the decoded band of the image, but with the
354 // current design (decoding delayed until painting) that seems hard.
355 notifyObservers(allDataReceived ? ShouldNotifyFinish : DoNotNotifyFinish);
356 }
357
358 void ImageResourceContent::decodedSizeChangedTo(const blink::Image* image,
359 size_t newSize) {
360 if (!image || image != m_image)
361 return;
362
363 m_info->setDecodedSize(newSize);
364 }
365
366 bool ImageResourceContent::shouldPauseAnimation(const blink::Image* image) {
367 if (!image || image != m_image)
368 return false;
369
370 for (const auto& it : m_finishedObservers)
371 if (it.key->willRenderImage())
372 return false;
373
374 for (const auto& it : m_observers)
375 if (it.key->willRenderImage())
376 return false;
377
378 return true;
379 }
380
381 void ImageResourceContent::animationAdvanced(const blink::Image* image) {
382 if (!image || image != m_image)
383 return;
384 notifyObservers(DoNotNotifyFinish);
385 }
386
387 void ImageResourceContent::updateImageAnimationPolicy() {
388 if (!m_image)
389 return;
390
391 ImageAnimationPolicy newPolicy = ImageAnimationPolicyAllowed;
392 for (const auto& it : m_finishedObservers) {
393 if (it.key->getImageAnimationPolicy(newPolicy))
394 break;
395 }
396 for (const auto& it : m_observers) {
397 if (it.key->getImageAnimationPolicy(newPolicy))
398 break;
399 }
400
401 if (m_image->animationPolicy() != newPolicy) {
402 m_image->resetAnimation();
403 m_image->setAnimationPolicy(newPolicy);
404 }
405 }
406
407 void ImageResourceContent::changedInRect(const blink::Image* image,
408 const IntRect& rect) {
409 if (!image || image != m_image)
410 return;
411 notifyObservers(DoNotNotifyFinish, &rect);
412 }
413
414 bool ImageResourceContent::isAccessAllowed(SecurityOrigin* securityOrigin) {
415 return m_info->isAccessAllowed(
416 securityOrigin, getImage()->currentFrameHasSingleSecurityOrigin()
417 ? ImageResourceInfo::HasSingleSecurityOrigin
418 : ImageResourceInfo::HasMultipleSecurityOrigin);
419 }
420
421 void ImageResourceContent::emulateLoadStartedForInspector(
422 ResourceFetcher* fetcher,
423 const KURL& url,
424 const AtomicString& initiatorName) {
425 m_info->emulateLoadStartedForInspector(fetcher, url, initiatorName);
426 }
427
428 // TODO(hiroshige): Consider removing the following methods, or stoping
429 // redirecting to ImageResource.
430 bool ImageResourceContent::isLoaded() const {
431 return getStatus() > ResourceStatus::Pending;
432 }
433
434 bool ImageResourceContent::isLoading() const {
435 return getStatus() == ResourceStatus::Pending;
436 }
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();
473 }
474
475 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698