1 /*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2010 Apple Inc. All rights reserved.
5 * Copyright (C) 2010 Google Inc. All rights reserved.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public License
18 * along with this library; see the file COPYING.LIB. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 */
22
23 #include "config.h"
24 #include "core/html/HTMLImageElement.h"
25
26 #include "bindings/core/v8/ScriptEventListener.h"
27 #include "core/CSSPropertyNames.h"
28 #include "core/HTMLNames.h"
29 #include "core/MediaTypeNames.h"
30 #include "core/css/MediaQueryMatcher.h"
31 #include "core/css/MediaValuesDynamic.h"
32 #include "core/css/parser/SizesAttributeParser.h"
33 #include "core/dom/Attribute.h"
34 #include "core/dom/NodeTraversal.h"
35 #include "core/fetch/ImageResource.h"
36 #include "core/frame/UseCounter.h"
37 #include "core/html/HTMLAnchorElement.h"
38 #include "core/html/HTMLCanvasElement.h"
39 #include "core/html/HTMLFormElement.h"
40 #include "core/html/HTMLSourceElement.h"
41 #include "core/html/canvas/CanvasRenderingContext.h"
42 #include "core/html/parser/HTMLParserIdioms.h"
43 #include "core/html/parser/HTMLSrcsetParser.h"
44 #include "core/inspector/ConsoleMessage.h"
45 #include "core/rendering/RenderImage.h"
46 #include "platform/MIMETypeRegistry.h"
47 #include "platform/RuntimeEnabledFeatures.h"
48
49 namespace blink {
50
51 using namespace HTMLNames;
52
53 class HTMLImageElement::ViewportChangeListener FINAL : public MediaQueryListListener {
54 public:
create(HTMLImageElement * element)55 static RefPtrWillBeRawPtr<ViewportChangeListener> create(HTMLImageElement* element)
56 {
57 return adoptRefWillBeNoop(new ViewportChangeListener(element));
58 }
59
notifyMediaQueryChanged()60 virtual void notifyMediaQueryChanged() OVERRIDE
61 {
62 if (m_element)
63 m_element->notifyViewportChanged();
64 }
65
66 #if !ENABLE(OILPAN)
clearElement()67 void clearElement() { m_element = nullptr; }
68 #endif
trace(Visitor * visitor)69 virtual void trace(Visitor* visitor) OVERRIDE
70 {
71 visitor->trace(m_element);
72 MediaQueryListListener::trace(visitor);
73 }
74 private:
ViewportChangeListener(HTMLImageElement * element)75 explicit ViewportChangeListener(HTMLImageElement* element) : m_element(element) { }
76 RawPtrWillBeMember<HTMLImageElement> m_element;
77 };
78
HTMLImageElement(Document & document,HTMLFormElement * form,bool createdByParser)79 HTMLImageElement::HTMLImageElement(Document& document, HTMLFormElement* form, bool createdByParser)
80 : HTMLElement(imgTag, document)
81 , m_imageLoader(HTMLImageLoader::create(this))
82 , m_compositeOperator(CompositeSourceOver)
83 , m_imageDevicePixelRatio(1.0f)
84 , m_formWasSetByParser(false)
85 , m_elementCreatedByParser(createdByParser)
86 , m_intrinsicSizingViewportDependant(false)
87 , m_effectiveSizeViewportDependant(false)
88 {
89 if (form && form->inDocument()) {
90 #if ENABLE(OILPAN)
91 m_form = form;
92 #else
93 m_form = form->createWeakPtr();
94 #endif
95 m_formWasSetByParser = true;
96 m_form->associate(*this);
97 m_form->didAssociateByParser();
98 }
99 }
100
create(Document & document)101 PassRefPtrWillBeRawPtr<HTMLImageElement> HTMLImageElement::create(Document& document)
102 {
103 return adoptRefWillBeNoop(new HTMLImageElement(document));
104 }
105
create(Document & document,HTMLFormElement * form,bool createdByParser)106 PassRefPtrWillBeRawPtr<HTMLImageElement> HTMLImageElement::create(Document& document, HTMLFormElement* form, bool createdByParser)
107 {
108 return adoptRefWillBeNoop(new HTMLImageElement(document, form, createdByParser));
109 }
110
~HTMLImageElement()111 HTMLImageElement::~HTMLImageElement()
112 {
113 #if !ENABLE(OILPAN)
114 if (m_listener) {
115 document().mediaQueryMatcher().removeViewportListener(m_listener.get());
116 m_listener->clearElement();
117 }
118 if (m_form)
119 m_form->disassociate(*this);
120 #endif
121 }
122
trace(Visitor * visitor)123 void HTMLImageElement::trace(Visitor* visitor)
124 {
125 visitor->trace(m_imageLoader);
126 visitor->trace(m_listener);
127 visitor->trace(m_form);
128 HTMLElement::trace(visitor);
129 }
130
notifyViewportChanged()131 void HTMLImageElement::notifyViewportChanged()
132 {
133 // Re-selecting the source URL in order to pick a more fitting resource
134 // And update the image's intrinsic dimensions when the viewport changes.
135 // Picking of a better fitting resource is UA dependant, not spec required.
136 selectSourceURL(ImageLoader::UpdateSizeChanged);
137 }
138
createForJSConstructor(Document & document,int width,int height)139 PassRefPtrWillBeRawPtr<HTMLImageElement> HTMLImageElement::createForJSConstructor(Document& document, int width, int height)
140 {
141 RefPtrWillBeRawPtr<HTMLImageElement> image = adoptRefWillBeNoop(new HTMLImageElement(document));
142 if (width)
143 image->setWidth(width);
144 if (height)
145 image->setHeight(height);
146 image->m_elementCreatedByParser = false;
147 return image.release();
148 }
149
isPresentationAttribute(const QualifiedName & name) const150 bool HTMLImageElement::isPresentationAttribute(const QualifiedName& name) const
151 {
152 if (name == widthAttr || name == heightAttr || name == borderAttr || name == vspaceAttr || name == hspaceAttr || name == alignAttr || name == valignAttr)
153 return true;
154 return HTMLElement::isPresentationAttribute(name);
155 }
156
collectStyleForPresentationAttribute(const QualifiedName & name,const AtomicString & value,MutableStylePropertySet * style)157 void HTMLImageElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStylePropertySet* style)
158 {
159 if (name == widthAttr)
160 addHTMLLengthToStyle(style, CSSPropertyWidth, value);
161 else if (name == heightAttr)
162 addHTMLLengthToStyle(style, CSSPropertyHeight, value);
163 else if (name == borderAttr)
164 applyBorderAttributeToStyle(value, style);
165 else if (name == vspaceAttr) {
166 addHTMLLengthToStyle(style, CSSPropertyMarginTop, value);
167 addHTMLLengthToStyle(style, CSSPropertyMarginBottom, value);
168 } else if (name == hspaceAttr) {
169 addHTMLLengthToStyle(style, CSSPropertyMarginLeft, value);
170 addHTMLLengthToStyle(style, CSSPropertyMarginRight, value);
171 } else if (name == alignAttr)
172 applyAlignmentAttributeToStyle(value, style);
173 else if (name == valignAttr)
174 addPropertyToPresentationAttributeStyle(style, CSSPropertyVerticalAlign, value);
175 else
176 HTMLElement::collectStyleForPresentationAttribute(name, value, style);
177 }
178
imageSourceURL() const179 const AtomicString HTMLImageElement::imageSourceURL() const
180 {
181 return m_bestFitImageURL.isNull() ? fastGetAttribute(srcAttr) : m_bestFitImageURL;
182 }
183
formOwner() const184 HTMLFormElement* HTMLImageElement::formOwner() const
185 {
186 return m_form.get();
187 }
188
formRemovedFromTree(const Node & formRoot)189 void HTMLImageElement::formRemovedFromTree(const Node& formRoot)
190 {
191 ASSERT(m_form);
192 if (NodeTraversal::highestAncestorOrSelf(*this) != formRoot)
193 resetFormOwner();
194 }
195
resetFormOwner()196 void HTMLImageElement::resetFormOwner()
197 {
198 m_formWasSetByParser = false;
199 HTMLFormElement* nearestForm = findFormAncestor();
200 if (m_form) {
201 if (nearestForm == m_form.get())
202 return;
203 m_form->disassociate(*this);
204 }
205 if (nearestForm) {
206 #if ENABLE(OILPAN)
207 m_form = nearestForm;
208 #else
209 m_form = nearestForm->createWeakPtr();
210 #endif
211 m_form->associate(*this);
212 } else {
213 #if ENABLE(OILPAN)
214 m_form = nullptr;
215 #else
216 m_form = WeakPtr<HTMLFormElement>();
217 #endif
218 }
219 }
220
setBestFitURLAndDPRFromImageCandidate(const ImageCandidate & candidate)221 void HTMLImageElement::setBestFitURLAndDPRFromImageCandidate(const ImageCandidate& candidate)
222 {
223 m_bestFitImageURL = candidate.url();
224 float candidateDensity = candidate.density();
225 if (candidateDensity >= 0)
226 m_imageDevicePixelRatio = 1.0 / candidateDensity;
227 if (candidate.resourceWidth() > 0) {
228 m_intrinsicSizingViewportDependant = true;
229 UseCounter::count(document(), UseCounter::SrcsetWDescriptor);
230 } else if (!candidate.srcOrigin()) {
231 UseCounter::count(document(), UseCounter::SrcsetXDescriptor);
232 }
233 if (renderer() && renderer()->isImage())
234 toRenderImage(renderer())->setImageDevicePixelRatio(m_imageDevicePixelRatio);
235 }
236
parseAttribute(const QualifiedName & name,const AtomicString & value)237 void HTMLImageElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
238 {
239 if (name == altAttr) {
240 if (renderer() && renderer()->isImage())
241 toRenderImage(renderer())->updateAltText();
242 } else if (name == srcAttr || name == srcsetAttr || name == sizesAttr) {
243 selectSourceURL(ImageLoader::UpdateIgnorePreviousError);
244 } else if (name == usemapAttr) {
245 setIsLink(!value.isNull());
246 } else if (name == compositeAttr) {
247 blink::WebBlendMode blendOp = blink::WebBlendModeNormal;
248 if (!parseCompositeAndBlendOperator(value, m_compositeOperator, blendOp))
249 m_compositeOperator = CompositeSourceOver;
250 else if (m_compositeOperator != CompositeSourceOver)
251 UseCounter::count(document(), UseCounter::HTMLImageElementComposite);
252 } else {
253 HTMLElement::parseAttribute(name, value);
254 }
255 }
256
altText() const257 const AtomicString& HTMLImageElement::altText() const
258 {
259 // lets figure out the alt text.. magic stuff
260 // http://www.w3.org/TR/1998/REC-html40-19980424/appendix/notes.html#altgen
261 // also heavily discussed by Hixie on bugzilla
262 const AtomicString& alt = fastGetAttribute(altAttr);
263 if (!alt.isNull())
264 return alt;
265 // fall back to title attribute
266 return fastGetAttribute(titleAttr);
267 }
268
supportedImageType(const String & type)269 static bool supportedImageType(const String& type)
270 {
271 return MIMETypeRegistry::isSupportedImagePrefixedMIMEType(type);
272 }
273
274 // http://picture.responsiveimages.org/#update-source-set
findBestFitImageFromPictureParent()275 ImageCandidate HTMLImageElement::findBestFitImageFromPictureParent()
276 {
277 ASSERT(isMainThread());
278 Node* parent = parentNode();
279 if (!parent || !isHTMLPictureElement(*parent))
280 return ImageCandidate();
281 for (Node* child = parent->firstChild(); child; child = child->nextSibling()) {
282 if (child == this)
283 return ImageCandidate();
284
285 if (!isHTMLSourceElement(*child))
286 continue;
287
288 HTMLSourceElement* source = toHTMLSourceElement(child);
289 if (!source->fastGetAttribute(srcAttr).isNull())
290 UseCounter::countDeprecation(document(), UseCounter::PictureSourceSrc);
291 String srcset = source->fastGetAttribute(srcsetAttr);
292 if (srcset.isEmpty())
293 continue;
294 String type = source->fastGetAttribute(typeAttr);
295 if (!type.isEmpty() && !supportedImageType(type))
296 continue;
297
298 if (!source->mediaQueryMatches())
299 continue;
300
301 String sizes = source->fastGetAttribute(sizesAttr);
302 if (!sizes.isNull())
303 UseCounter::count(document(), UseCounter::Sizes);
304 SizesAttributeParser parser = SizesAttributeParser(MediaValuesDynamic::create(document()), sizes);
305 unsigned effectiveSize = parser.length();
306 m_effectiveSizeViewportDependant = parser.viewportDependant();
307 ImageCandidate candidate = bestFitSourceForSrcsetAttribute(document().devicePixelRatio(), effectiveSize, source->fastGetAttribute(srcsetAttr));
308 if (candidate.isEmpty())
309 continue;
310 return candidate;
311 }
312 return ImageCandidate();
313 }
314
createRenderer(RenderStyle * style)315 RenderObject* HTMLImageElement::createRenderer(RenderStyle* style)
316 {
317 if (style->hasContent())
318 return RenderObject::createObject(this, style);
319
320 RenderImage* image = new RenderImage(this);
321 image->setImageResource(RenderImageResource::create());
322 image->setImageDevicePixelRatio(m_imageDevicePixelRatio);
323 return image;
324 }
325
canStartSelection() const326 bool HTMLImageElement::canStartSelection() const
327 {
328 if (shadow())
329 return HTMLElement::canStartSelection();
330
331 return false;
332 }
333
attach(const AttachContext & context)334 void HTMLImageElement::attach(const AttachContext& context)
335 {
336 HTMLElement::attach(context);
337
338 if (renderer() && renderer()->isImage()) {
339 RenderImage* renderImage = toRenderImage(renderer());
340 RenderImageResource* renderImageResource = renderImage->imageResource();
341 if (renderImageResource->hasImage())
342 return;
343
344 // If we have no image at all because we have no src attribute, set
345 // image height and width for the alt text instead.
346 if (!imageLoader().image() && !renderImageResource->cachedImage())
347 renderImage->setImageSizeForAltText();
348 else
349 renderImageResource->setImageResource(imageLoader().image());
350
351 }
352 }
353
insertedInto(ContainerNode * insertionPoint)354 Node::InsertionNotificationRequest HTMLImageElement::insertedInto(ContainerNode* insertionPoint)
355 {
356 if (!m_formWasSetByParser || NodeTraversal::highestAncestorOrSelf(*insertionPoint) != NodeTraversal::highestAncestorOrSelf(*m_form.get()))
357 resetFormOwner();
358 if (m_listener)
359 document().mediaQueryMatcher().addViewportListener(m_listener);
360
361 bool imageWasModified = false;
362 if (RuntimeEnabledFeatures::pictureEnabled()) {
363 ImageCandidate candidate = findBestFitImageFromPictureParent();
364 if (!candidate.isEmpty()) {
365 setBestFitURLAndDPRFromImageCandidate(candidate);
366 imageWasModified = true;
367 }
368 }
369
370 // If we have been inserted from a renderer-less document,
371 // our loader may have not fetched the image, so do it now.
372 if ((insertionPoint->inDocument() && !imageLoader().image()) || imageWasModified)
373 imageLoader().updateFromElement(ImageLoader::UpdateNormal, m_elementCreatedByParser ? ImageLoader::ForceLoadImmediately : ImageLoader::LoadNormally);
374
375 return HTMLElement::insertedInto(insertionPoint);
376 }
377
removedFrom(ContainerNode * insertionPoint)378 void HTMLImageElement::removedFrom(ContainerNode* insertionPoint)
379 {
380 if (!m_form || NodeTraversal::highestAncestorOrSelf(*m_form.get()) != NodeTraversal::highestAncestorOrSelf(*this))
381 resetFormOwner();
382 if (m_listener)
383 document().mediaQueryMatcher().removeViewportListener(m_listener);
384 HTMLElement::removedFrom(insertionPoint);
385 }
386
width(bool ignorePendingStylesheets)387 int HTMLImageElement::width(bool ignorePendingStylesheets)
388 {
389 if (!renderer()) {
390 // check the attribute first for an explicit pixel value
391 bool ok;
392 int width = getAttribute(widthAttr).toInt(&ok);
393 if (ok)
394 return width;
395
396 // if the image is available, use its width
397 if (imageLoader().image())
398 return imageLoader().image()->imageSizeForRenderer(renderer(), 1.0f).width();
399 }
400
401 if (ignorePendingStylesheets)
402 document().updateLayoutIgnorePendingStylesheets();
403 else
404 document().updateLayout();
405
406 RenderBox* box = renderBox();
407 return box ? adjustForAbsoluteZoom(box->contentBoxRect().pixelSnappedWidth(), box) : 0;
408 }
409
height(bool ignorePendingStylesheets)410 int HTMLImageElement::height(bool ignorePendingStylesheets)
411 {
412 if (!renderer()) {
413 // check the attribute first for an explicit pixel value
414 bool ok;
415 int height = getAttribute(heightAttr).toInt(&ok);
416 if (ok)
417 return height;
418
419 // if the image is available, use its height
420 if (imageLoader().image())
421 return imageLoader().image()->imageSizeForRenderer(renderer(), 1.0f).height();
422 }
423
424 if (ignorePendingStylesheets)
425 document().updateLayoutIgnorePendingStylesheets();
426 else
427 document().updateLayout();
428
429 RenderBox* box = renderBox();
430 return box ? adjustForAbsoluteZoom(box->contentBoxRect().pixelSnappedHeight(), box) : 0;
431 }
432
naturalWidth() const433 int HTMLImageElement::naturalWidth() const
434 {
435 if (!imageLoader().image())
436 return 0;
437
438 return imageLoader().image()->imageSizeForRenderer(renderer(), 1.0f, ImageResource::IntrinsicSize).width();
439 }
440
naturalHeight() const441 int HTMLImageElement::naturalHeight() const
442 {
443 if (!imageLoader().image())
444 return 0;
445
446 return imageLoader().image()->imageSizeForRenderer(renderer(), 1.0f, ImageResource::IntrinsicSize).height();
447 }
448
currentSrc() const449 const String& HTMLImageElement::currentSrc() const
450 {
451 // http://www.whatwg.org/specs/web-apps/current-work/multipage/edits.html#dom-img-currentsrc
452 // The currentSrc IDL attribute must return the img element's current request's current URL.
453 // Initially, the pending request turns into current request when it is either available or broken.
454 // We use the image's dimensions as a proxy to it being in any of these states.
455 if (!imageLoader().image() || !imageLoader().image()->image() || !imageLoader().image()->image()->width())
456 return emptyAtom;
457
458 return imageLoader().image()->url().string();
459 }
460
isURLAttribute(const Attribute & attribute) const461 bool HTMLImageElement::isURLAttribute(const Attribute& attribute) const
462 {
463 return attribute.name() == srcAttr
464 || attribute.name() == lowsrcAttr
465 || attribute.name() == longdescAttr
466 || (attribute.name() == usemapAttr && attribute.value()[0] != '#')
467 || HTMLElement::isURLAttribute(attribute);
468 }
469
hasLegalLinkAttribute(const QualifiedName & name) const470 bool HTMLImageElement::hasLegalLinkAttribute(const QualifiedName& name) const
471 {
472 return name == srcAttr || HTMLElement::hasLegalLinkAttribute(name);
473 }
474
subResourceAttributeName() const475 const QualifiedName& HTMLImageElement::subResourceAttributeName() const
476 {
477 return srcAttr;
478 }
479
draggable() const480 bool HTMLImageElement::draggable() const
481 {
482 // Image elements are draggable by default.
483 return !equalIgnoringCase(getAttribute(draggableAttr), "false");
484 }
485
setHeight(int value)486 void HTMLImageElement::setHeight(int value)
487 {
488 setIntegralAttribute(heightAttr, value);
489 }
490
src() const491 KURL HTMLImageElement::src() const
492 {
493 return document().completeURL(getAttribute(srcAttr));
494 }
495
setSrc(const String & value)496 void HTMLImageElement::setSrc(const String& value)
497 {
498 setAttribute(srcAttr, AtomicString(value));
499 }
500
setWidth(int value)501 void HTMLImageElement::setWidth(int value)
502 {
503 setIntegralAttribute(widthAttr, value);
504 }
505
x() const506 int HTMLImageElement::x() const
507 {
508 document().updateLayoutIgnorePendingStylesheets();
509 RenderObject* r = renderer();
510 if (!r)
511 return 0;
512
513 // FIXME: This doesn't work correctly with transforms.
514 FloatPoint absPos = r->localToAbsolute();
515 return absPos.x();
516 }
517
y() const518 int HTMLImageElement::y() const
519 {
520 document().updateLayoutIgnorePendingStylesheets();
521 RenderObject* r = renderer();
522 if (!r)
523 return 0;
524
525 // FIXME: This doesn't work correctly with transforms.
526 FloatPoint absPos = r->localToAbsolute();
527 return absPos.y();
528 }
529
complete() const530 bool HTMLImageElement::complete() const
531 {
532 return imageLoader().imageComplete();
533 }
534
didMoveToNewDocument(Document & oldDocument)535 void HTMLImageElement::didMoveToNewDocument(Document& oldDocument)
536 {
537 imageLoader().elementDidMoveToNewDocument();
538 HTMLElement::didMoveToNewDocument(oldDocument);
539 }
540
isServerMap() const541 bool HTMLImageElement::isServerMap() const
542 {
543 if (!fastHasAttribute(ismapAttr))
544 return false;
545
546 const AtomicString& usemap = fastGetAttribute(usemapAttr);
547
548 // If the usemap attribute starts with '#', it refers to a map element in the document.
549 if (usemap[0] == '#')
550 return false;
551
552 return document().completeURL(stripLeadingAndTrailingHTMLSpaces(usemap)).isEmpty();
553 }
554
imageContents()555 Image* HTMLImageElement::imageContents()
556 {
557 if (!imageLoader().imageComplete())
558 return 0;
559
560 return imageLoader().image()->image();
561 }
562
isInteractiveContent() const563 bool HTMLImageElement::isInteractiveContent() const
564 {
565 return fastHasAttribute(usemapAttr);
566 }
567
getSourceImageForCanvas(SourceImageMode,SourceImageStatus * status) const568 PassRefPtr<Image> HTMLImageElement::getSourceImageForCanvas(SourceImageMode, SourceImageStatus* status) const
569 {
570 if (!complete() || !cachedImage()) {
571 *status = IncompleteSourceImageStatus;
572 return nullptr;
573 }
574
575 if (cachedImage()->errorOccurred()) {
576 *status = UndecodableSourceImageStatus;
577 return nullptr;
578 }
579
580 RefPtr<Image> sourceImage = cachedImage()->imageForRenderer(renderer());
581
582 // We need to synthesize a container size if a renderer is not available to provide one.
583 if (!renderer() && sourceImage->usesContainerSize())
584 sourceImage->setContainerSize(sourceImage->size());
585
586 *status = NormalSourceImageStatus;
587 return sourceImage->imageForDefaultFrame();
588 }
589
wouldTaintOrigin(SecurityOrigin * destinationSecurityOrigin) const590 bool HTMLImageElement::wouldTaintOrigin(SecurityOrigin* destinationSecurityOrigin) const
591 {
592 ImageResource* image = cachedImage();
593 if (!image)
594 return false;
595 return !image->isAccessAllowed(destinationSecurityOrigin);
596 }
597
sourceSize() const598 FloatSize HTMLImageElement::sourceSize() const
599 {
600 ImageResource* image = cachedImage();
601 if (!image)
602 return FloatSize();
603 LayoutSize size;
604 size = image->imageSizeForRenderer(renderer(), 1.0f); // FIXME: Not sure about this.
605
606 return size;
607 }
608
defaultDestinationSize() const609 FloatSize HTMLImageElement::defaultDestinationSize() const
610 {
611 ImageResource* image = cachedImage();
612 if (!image)
613 return FloatSize();
614 LayoutSize size;
615 size = image->imageSizeForRenderer(renderer(), 1.0f); // FIXME: Not sure about this.
616 if (renderer() && renderer()->isRenderImage() && image->image() && !image->image()->hasRelativeWidth())
617 size.scale(toRenderImage(renderer())->imageDevicePixelRatio());
618 return size;
619 }
620
selectSourceURL(ImageLoader::UpdateFromElementBehavior behavior)621 void HTMLImageElement::selectSourceURL(ImageLoader::UpdateFromElementBehavior behavior)
622 {
623 bool foundURL = false;
624 if (RuntimeEnabledFeatures::pictureEnabled()) {
625 ImageCandidate candidate = findBestFitImageFromPictureParent();
626 if (!candidate.isEmpty()) {
627 setBestFitURLAndDPRFromImageCandidate(candidate);
628 foundURL = true;
629 }
630 }
631
632 if (!foundURL) {
633 unsigned effectiveSize = 0;
634 if (RuntimeEnabledFeatures::pictureSizesEnabled()) {
635 String sizes = fastGetAttribute(sizesAttr);
636 if (!sizes.isNull())
637 UseCounter::count(document(), UseCounter::Sizes);
638 SizesAttributeParser parser = SizesAttributeParser(MediaValuesDynamic::create(document()), sizes);
639 effectiveSize = parser.length();
640 m_effectiveSizeViewportDependant = parser.viewportDependant();
641 }
642 ImageCandidate candidate = bestFitSourceForImageAttributes(document().devicePixelRatio(), effectiveSize, fastGetAttribute(srcAttr), fastGetAttribute(srcsetAttr));
643 setBestFitURLAndDPRFromImageCandidate(candidate);
644 }
645 if (m_intrinsicSizingViewportDependant && m_effectiveSizeViewportDependant && !m_listener) {
646 m_listener = ViewportChangeListener::create(this);
647 document().mediaQueryMatcher().addViewportListener(m_listener);
648 }
649 imageLoader().updateFromElement(behavior);
650 }
651
sourceURL() const652 const KURL& HTMLImageElement::sourceURL() const
653 {
654 return cachedImage()->response().url();
655 }
656
657 }
658