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

Side by Side Diff: Source/core/fetch/ImageResource.cpp

Issue 1167583003: Move Resource subclasses out of fetch/ (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 5 years, 6 months 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 | Annotate | Revision Log
« no previous file with comments | « Source/core/fetch/ImageResource.h ('k') | Source/core/fetch/ImageResourceClient.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 Copyright (C) 1998 Lars Knoll (knoll@mpi-hd.mpg.de)
3 Copyright (C) 2001 Dirk Mueller (mueller@kde.org)
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
8 This library is free software; you can redistribute it and/or
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
24 #include "config.h"
25 #include "core/fetch/ImageResource.h"
26
27 #include "core/fetch/ImageResourceClient.h"
28 #include "core/fetch/MemoryCache.h"
29 #include "core/fetch/ResourceClient.h"
30 #include "core/fetch/ResourceClientWalker.h"
31 #include "core/fetch/ResourceFetcher.h"
32 #include "core/fetch/ResourceLoader.h"
33 #include "core/html/HTMLImageElement.h"
34 #include "core/layout/LayoutObject.h"
35 #include "core/svg/graphics/SVGImage.h"
36 #include "core/svg/graphics/SVGImageForContainer.h"
37 #include "platform/Logging.h"
38 #include "platform/RuntimeEnabledFeatures.h"
39 #include "platform/SharedBuffer.h"
40 #include "platform/TraceEvent.h"
41 #include "platform/graphics/BitmapImage.h"
42 #include "public/platform/Platform.h"
43 #include "wtf/CurrentTime.h"
44 #include "wtf/StdLibExtras.h"
45
46 namespace blink {
47
48 void ImageResource::preCacheDataURIImage(const FetchRequest& request, ResourceFe tcher* fetcher)
49 {
50 const KURL& url = request.resourceRequest().url();
51 ASSERT(url.protocolIsData());
52
53 const String cacheIdentifier = fetcher->getCacheIdentifier();
54 if (memoryCache()->resourceForURL(url, cacheIdentifier))
55 return;
56
57 WebString mimetype;
58 WebString charset;
59 RefPtr<SharedBuffer> data = PassRefPtr<SharedBuffer>(Platform::current()->pa rseDataURL(url, mimetype, charset));
60 if (!data)
61 return;
62 ResourceResponse response(url, mimetype, data->size(), charset, String());
63
64 Resource* resource = new ImageResource(request.resourceRequest());
65 resource->setOptions(request.options());
66 // FIXME: We should provide a body stream here.
67 resource->responseReceived(response, nullptr);
68 if (data->size())
69 resource->setResourceBuffer(data);
70 resource->setCacheIdentifier(cacheIdentifier);
71 resource->finish();
72 memoryCache()->add(resource);
73 fetcher->scheduleDocumentResourcesGC();
74 }
75
76 ResourcePtr<ImageResource> ImageResource::fetch(FetchRequest& request, ResourceF etcher* fetcher)
77 {
78 if (request.resourceRequest().requestContext() == WebURLRequest::RequestCont extUnspecified)
79 request.mutableResourceRequest().setRequestContext(WebURLRequest::Reques tContextImage);
80 if (fetcher->context().pageDismissalEventBeingDispatched()) {
81 KURL requestURL = request.resourceRequest().url();
82 if (requestURL.isValid() && fetcher->context().canRequest(Resource::Imag e, request.resourceRequest(), requestURL, request.options(), request.forPreload( ), request.originRestriction()))
83 fetcher->context().sendImagePing(requestURL);
84 return 0;
85 }
86
87 if (request.resourceRequest().url().protocolIsData())
88 ImageResource::preCacheDataURIImage(request, fetcher);
89
90 if (fetcher->clientDefersImage(request.resourceRequest().url()))
91 request.setDefer(FetchRequest::DeferredByClient);
92
93 return toImageResource(fetcher->requestResource(request, ImageResourceFactor y()));
94 }
95
96 ImageResource::ImageResource(const ResourceRequest& resourceRequest)
97 : Resource(resourceRequest, Image)
98 , m_devicePixelRatioHeaderValue(1.0)
99 , m_image(nullptr)
100 , m_hasDevicePixelRatioHeaderValue(false)
101 {
102 WTF_LOG(Timers, "new ImageResource(ResourceRequest) %p", this);
103 setStatus(Unknown);
104 setCustomAcceptHeader();
105 }
106
107 ImageResource::ImageResource(blink::Image* image)
108 : Resource(ResourceRequest(""), Image)
109 , m_devicePixelRatioHeaderValue(1.0)
110 , m_image(image)
111 , m_hasDevicePixelRatioHeaderValue(false)
112 {
113 WTF_LOG(Timers, "new ImageResource(Image) %p", this);
114 setStatus(Cached);
115 setLoading(false);
116 setCustomAcceptHeader();
117 }
118
119 ImageResource::ImageResource(const ResourceRequest& resourceRequest, blink::Imag e* image)
120 : Resource(resourceRequest, Image)
121 , m_image(image)
122 {
123 WTF_LOG(Timers, "new ImageResource(ResourceRequest, Image) %p", this);
124 setStatus(Cached);
125 setLoading(false);
126 setCustomAcceptHeader();
127 }
128
129 ImageResource::~ImageResource()
130 {
131 WTF_LOG(Timers, "~ImageResource %p", this);
132 clearImage();
133 }
134
135 void ImageResource::load(ResourceFetcher* fetcher, const ResourceLoaderOptions& options)
136 {
137 if (!fetcher || fetcher->autoLoadImages())
138 Resource::load(fetcher, options);
139 else
140 setLoading(false);
141 }
142
143 void ImageResource::didAddClient(ResourceClient* c)
144 {
145 if (m_data && !m_image && !errorOccurred()) {
146 createImage();
147 m_image->setData(m_data, true);
148 }
149
150 ASSERT(c->resourceClientType() == ImageResourceClient::expectedType());
151 if (m_image && !m_image->isNull())
152 static_cast<ImageResourceClient*>(c)->imageChanged(this);
153
154 Resource::didAddClient(c);
155 }
156
157 void ImageResource::didRemoveClient(ResourceClient* c)
158 {
159 ASSERT(c);
160 ASSERT(c->resourceClientType() == ImageResourceClient::expectedType());
161 if (m_imageForContainerMap)
162 m_imageForContainerMap->remove(static_cast<ImageResourceClient*>(c));
163
164 Resource::didRemoveClient(c);
165 }
166
167 bool ImageResource::isSafeToUnlock() const
168 {
169 // Note that |m_image| holds a reference to |m_data| in addition to the one held by the Resource parent class.
170 return !m_image || (m_image->hasOneRef() && m_data->refCount() == 2);
171 }
172
173 void ImageResource::destroyDecodedDataIfPossible()
174 {
175 if (!hasClients() && !isLoading() && (!m_image || (m_image->hasOneRef() && m _image->isBitmapImage()))) {
176 m_image = nullptr;
177 setDecodedSize(0);
178 } else if (m_image && !errorOccurred()) {
179 m_image->destroyDecodedData(true);
180 }
181 }
182
183 void ImageResource::allClientsRemoved()
184 {
185 if (m_image && !errorOccurred())
186 m_image->resetAnimation();
187 Resource::allClientsRemoved();
188 }
189
190 pair<blink::Image*, float> ImageResource::brokenImage(float deviceScaleFactor)
191 {
192 if (deviceScaleFactor >= 2) {
193 DEFINE_STATIC_REF(blink::Image, brokenImageHiRes, (blink::Image::loadPla tformResource("missingImage@2x")));
194 return std::make_pair(brokenImageHiRes, 2);
195 }
196
197 DEFINE_STATIC_REF(blink::Image, brokenImageLoRes, (blink::Image::loadPlatfor mResource("missingImage")));
198 return std::make_pair(brokenImageLoRes, 1);
199 }
200
201 bool ImageResource::willPaintBrokenImage() const
202 {
203 return errorOccurred();
204 }
205
206 blink::Image* ImageResource::image()
207 {
208 ASSERT(!isPurgeable());
209
210 if (errorOccurred()) {
211 // Returning the 1x broken image is non-ideal, but we cannot reliably ac cess the appropriate
212 // deviceScaleFactor from here. It is critical that callers use ImageRes ource::brokenImage()
213 // when they need the real, deviceScaleFactor-appropriate broken image i con.
214 return brokenImage(1).first;
215 }
216
217 if (m_image)
218 return m_image.get();
219
220 return blink::Image::nullImage();
221 }
222
223 blink::Image* ImageResource::imageForLayoutObject(const LayoutObject* layoutObje ct)
224 {
225 ASSERT(!isPurgeable());
226
227 if (errorOccurred()) {
228 // Returning the 1x broken image is non-ideal, but we cannot reliably ac cess the appropriate
229 // deviceScaleFactor from here. It is critical that callers use ImageRes ource::brokenImage()
230 // when they need the real, deviceScaleFactor-appropriate broken image i con.
231 return brokenImage(1).first;
232 }
233
234 if (!m_image)
235 return blink::Image::nullImage();
236
237 if (m_image->isSVGImage()) {
238 blink::Image* image = svgImageForLayoutObject(layoutObject);
239 if (image != blink::Image::nullImage())
240 return image;
241 }
242
243 return m_image.get();
244 }
245
246 void ImageResource::setContainerSizeForLayoutObject(const ImageResourceClient* l ayoutObject, const IntSize& containerSize, float containerZoom)
247 {
248 if (containerSize.isEmpty())
249 return;
250 ASSERT(layoutObject);
251 ASSERT(containerZoom);
252 if (!m_image)
253 return;
254 if (!m_image->isSVGImage()) {
255 m_image->setContainerSize(containerSize);
256 return;
257 }
258
259 FloatSize containerSizeWithoutZoom(containerSize);
260 containerSizeWithoutZoom.scale(1 / containerZoom);
261 m_imageForContainerMap->set(layoutObject, SVGImageForContainer::create(toSVG Image(m_image.get()), containerSizeWithoutZoom, containerZoom));
262 }
263
264 bool ImageResource::usesImageContainerSize() const
265 {
266 if (m_image)
267 return m_image->usesContainerSize();
268
269 return false;
270 }
271
272 bool ImageResource::imageHasRelativeWidth() const
273 {
274 if (m_image)
275 return m_image->hasRelativeWidth();
276
277 return false;
278 }
279
280 bool ImageResource::imageHasRelativeHeight() const
281 {
282 if (m_image)
283 return m_image->hasRelativeHeight();
284
285 return false;
286 }
287
288 LayoutSize ImageResource::imageSizeForLayoutObject(const LayoutObject* layoutObj ect, float multiplier, SizeType sizeType)
289 {
290 ASSERT(!isPurgeable());
291
292 if (!m_image)
293 return LayoutSize();
294
295 LayoutSize imageSize;
296
297 if (m_image->isBitmapImage() && (layoutObject && layoutObject->shouldRespect ImageOrientation() == RespectImageOrientation))
298 imageSize = LayoutSize(toBitmapImage(m_image.get())->sizeRespectingOrien tation());
299 else if (m_image->isSVGImage() && sizeType == NormalSize)
300 imageSize = LayoutSize(svgImageSizeForLayoutObject(layoutObject));
301 else
302 imageSize = LayoutSize(m_image->size());
303
304 if (multiplier == 1.0f)
305 return imageSize;
306
307 // Don't let images that have a width/height >= 1 shrink below 1 when zoomed .
308 float widthScale = m_image->hasRelativeWidth() ? 1.0f : multiplier;
309 float heightScale = m_image->hasRelativeHeight() ? 1.0f : multiplier;
310 LayoutSize minimumSize(imageSize.width() > 0 ? 1 : 0, imageSize.height() > 0 ? 1 : 0);
311 imageSize.scale(widthScale, heightScale);
312 imageSize.clampToMinimumSize(minimumSize);
313 ASSERT(multiplier != 1.0f || (imageSize.width().fraction() == 0.0f && imageS ize.height().fraction() == 0.0f));
314 return imageSize;
315 }
316
317 void ImageResource::computeIntrinsicDimensions(Length& intrinsicWidth, Length& i ntrinsicHeight, FloatSize& intrinsicRatio)
318 {
319 if (m_image)
320 m_image->computeIntrinsicDimensions(intrinsicWidth, intrinsicHeight, int rinsicRatio);
321 }
322
323 void ImageResource::notifyObservers(const IntRect* changeRect)
324 {
325 ResourceClientWalker<ImageResourceClient> w(m_clients);
326 while (ImageResourceClient* c = w.next())
327 c->imageChanged(this, changeRect);
328 }
329
330 void ImageResource::clear()
331 {
332 prune();
333 clearImage();
334 setEncodedSize(0);
335 }
336
337 void ImageResource::setCustomAcceptHeader()
338 {
339 DEFINE_STATIC_LOCAL(const AtomicString, acceptImages, ("image/webp,image/*,* /*;q=0.8", AtomicString::ConstructFromLiteral));
340 setAccept(acceptImages);
341 }
342
343 inline void ImageResource::createImage()
344 {
345 // Create the image if it doesn't yet exist.
346 if (m_image)
347 return;
348
349 if (m_response.mimeType() == "image/svg+xml") {
350 m_image = SVGImage::create(this);
351 m_imageForContainerMap = adoptPtr(new ImageForContainerMap);
352 } else {
353 m_image = BitmapImage::create(this);
354 }
355 }
356
357 inline void ImageResource::clearImage()
358 {
359 // If our Image has an observer, it's always us so we need to clear the back pointer
360 // before dropping our reference.
361 if (m_image)
362 m_image->setImageObserver(nullptr);
363 m_image.clear();
364 }
365
366 void ImageResource::appendData(const char* data, unsigned length)
367 {
368 Resource::appendData(data, length);
369 if (!loadingMultipartContent())
370 updateImage(false);
371 }
372
373 void ImageResource::updateImage(bool allDataReceived)
374 {
375 TRACE_EVENT0("blink", "ImageResource::updateImage");
376
377 if (m_data)
378 createImage();
379
380 bool sizeAvailable = false;
381
382 // Have the image update its data from its internal buffer.
383 // It will not do anything now, but will delay decoding until
384 // queried for info (like size or specific image frames).
385 if (m_image)
386 sizeAvailable = m_image->setData(m_data, allDataReceived);
387
388 // Go ahead and tell our observers to try to draw if we have either
389 // received all the data or the size is known. Each chunk from the
390 // network causes observers to repaint, which will force that chunk
391 // to decode.
392 if (sizeAvailable || allDataReceived) {
393 if (!m_image || m_image->isNull()) {
394 error(errorOccurred() ? status() : DecodeError);
395 if (memoryCache()->contains(this))
396 memoryCache()->remove(this);
397 return;
398 }
399
400 // It would be nice to only redraw the decoded band of the image, but wi th the current design
401 // (decoding delayed until painting) that seems hard.
402 notifyObservers();
403 }
404 }
405
406 void ImageResource::finishOnePart()
407 {
408 if (loadingMultipartContent())
409 clear();
410 updateImage(true);
411 if (loadingMultipartContent())
412 m_data.clear();
413 Resource::finishOnePart();
414 }
415
416 void ImageResource::error(Resource::Status status)
417 {
418 clear();
419 Resource::error(status);
420 notifyObservers();
421 }
422
423 void ImageResource::responseReceived(const ResourceResponse& response, PassOwnPt r<WebDataConsumerHandle> handle)
424 {
425 if (loadingMultipartContent() && m_data)
426 finishOnePart();
427 if (RuntimeEnabledFeatures::clientHintsEnabled()) {
428 m_devicePixelRatioHeaderValue = response.httpHeaderField("content-dpr"). toFloat(&m_hasDevicePixelRatioHeaderValue);
429 if (!m_hasDevicePixelRatioHeaderValue || m_devicePixelRatioHeaderValue < = 0.0) {
430 m_devicePixelRatioHeaderValue = 1.0;
431 m_hasDevicePixelRatioHeaderValue = false;
432 }
433 }
434 Resource::responseReceived(response, handle);
435 }
436
437 void ImageResource::decodedSizeChanged(const blink::Image* image, int delta)
438 {
439 if (!image || image != m_image)
440 return;
441
442 setDecodedSize(decodedSize() + delta);
443 }
444
445 void ImageResource::didDraw(const blink::Image* image)
446 {
447 if (!image || image != m_image)
448 return;
449 // decodedSize() == 0 indicates that the image is decoded into DiscardableMe mory,
450 // not in MemoryCache. So we don't need to call Resource::didAccessDecodedDa ta()
451 // to update MemoryCache.
452 if (decodedSize() != 0)
453 Resource::didAccessDecodedData();
454 }
455
456 bool ImageResource::shouldPauseAnimation(const blink::Image* image)
457 {
458 if (!image || image != m_image)
459 return false;
460
461 ResourceClientWalker<ImageResourceClient> w(m_clients);
462 while (ImageResourceClient* c = w.next()) {
463 if (c->willRenderImage(this))
464 return false;
465 }
466
467 return true;
468 }
469
470 void ImageResource::animationAdvanced(const blink::Image* image)
471 {
472 if (!image || image != m_image)
473 return;
474 notifyObservers();
475 }
476
477 void ImageResource::updateImageAnimationPolicy()
478 {
479 if (!m_image)
480 return;
481
482 ImageAnimationPolicy newPolicy = ImageAnimationPolicyAllowed;
483 ResourceClientWalker<ImageResourceClient> w(m_clients);
484 while (ImageResourceClient* c = w.next()) {
485 if (c->getImageAnimationPolicy(this, newPolicy))
486 break;
487 }
488
489 if (m_image->animationPolicy() != newPolicy) {
490 m_image->resetAnimation();
491 m_image->setAnimationPolicy(newPolicy);
492 }
493 }
494
495 void ImageResource::changedInRect(const blink::Image* image, const IntRect& rect )
496 {
497 if (!image || image != m_image)
498 return;
499 notifyObservers(&rect);
500 }
501
502 bool ImageResource::currentFrameKnownToBeOpaque(const LayoutObject* layoutObject )
503 {
504 blink::Image* image = imageForLayoutObject(layoutObject);
505 if (image->isBitmapImage()) {
506 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "PaintImage ", "data", InspectorPaintImageEvent::data(layoutObject, *this));
507 SkBitmap dummy;
508 if (!image->bitmapForCurrentFrame(&dummy)) { // force decode
509 // We don't care about failures here, since we don't use "dummy"
510 }
511 }
512 return image->currentFrameKnownToBeOpaque();
513 }
514
515 bool ImageResource::isAccessAllowed(SecurityOrigin* securityOrigin)
516 {
517 if (response().wasFetchedViaServiceWorker())
518 return response().serviceWorkerResponseType() != WebServiceWorkerRespons eTypeOpaque;
519 if (!image()->currentFrameHasSingleSecurityOrigin())
520 return false;
521 if (passesAccessControlCheck(securityOrigin))
522 return true;
523 return !securityOrigin->taintsCanvas(response().url());
524 }
525
526 IntSize ImageResource::svgImageSizeForLayoutObject(const LayoutObject* layoutObj ect) const
527 {
528 IntSize imageSize = m_image->size();
529 if (!layoutObject)
530 return imageSize;
531
532 ImageForContainerMap::const_iterator it = m_imageForContainerMap->find(layou tObject);
533 if (it == m_imageForContainerMap->end())
534 return imageSize;
535
536 RefPtr<SVGImageForContainer> imageForContainer = it->value;
537 ASSERT(!imageForContainer->size().isEmpty());
538 return imageForContainer->size();
539 }
540
541 // FIXME: This doesn't take into account the animation timeline so animations wi ll not
542 // restart on page load, nor will two animations in different pages have differe nt timelines.
543 Image* ImageResource::svgImageForLayoutObject(const LayoutObject* layoutObject)
544 {
545 if (!layoutObject)
546 return Image::nullImage();
547
548 ImageForContainerMap::iterator it = m_imageForContainerMap->find(layoutObjec t);
549 if (it == m_imageForContainerMap->end())
550 return Image::nullImage();
551
552 RefPtr<SVGImageForContainer> imageForContainer = it->value;
553 ASSERT(!imageForContainer->size().isEmpty());
554
555 Node* node = layoutObject->node();
556 if (node && isHTMLImageElement(node)) {
557 const AtomicString& urlString = toHTMLImageElement(node)->imageSourceURL ();
558 KURL url = node->document().completeURL(urlString);
559 imageForContainer->setURL(url);
560 }
561
562 return imageForContainer.get();
563 }
564
565 bool ImageResource::loadingMultipartContent() const
566 {
567 return m_loader && m_loader->loadingMultipartContent();
568 }
569
570 } // namespace blink
OLDNEW
« no previous file with comments | « Source/core/fetch/ImageResource.h ('k') | Source/core/fetch/ImageResourceClient.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698