Home | History | Annotate | Download | only in html
      1 /*
      2  * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org)
      3  *           (C) 1999 Antti Koivisto (koivisto (at) 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:
     55     static RefPtrWillBeRawPtr<ViewportChangeListener> create(HTMLImageElement* element)
     56     {
     57         return adoptRefWillBeNoop(new ViewportChangeListener(element));
     58     }
     59 
     60     virtual void notifyMediaQueryChanged() OVERRIDE
     61     {
     62         if (m_element)
     63             m_element->notifyViewportChanged();
     64     }
     65 
     66 #if !ENABLE(OILPAN)
     67     void clearElement() { m_element = nullptr; }
     68 #endif
     69     virtual void trace(Visitor* visitor) OVERRIDE
     70     {
     71         visitor->trace(m_element);
     72         MediaQueryListListener::trace(visitor);
     73     }
     74 private:
     75     explicit ViewportChangeListener(HTMLImageElement* element) : m_element(element) { }
     76     RawPtrWillBeMember<HTMLImageElement> m_element;
     77 };
     78 
     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 
    101 PassRefPtrWillBeRawPtr<HTMLImageElement> HTMLImageElement::create(Document& document)
    102 {
    103     return adoptRefWillBeNoop(new HTMLImageElement(document));
    104 }
    105 
    106 PassRefPtrWillBeRawPtr<HTMLImageElement> HTMLImageElement::create(Document& document, HTMLFormElement* form, bool createdByParser)
    107 {
    108     return adoptRefWillBeNoop(new HTMLImageElement(document, form, createdByParser));
    109 }
    110 
    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 
    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 
    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 
    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 
    150 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 
    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 
    179 const AtomicString HTMLImageElement::imageSourceURL() const
    180 {
    181     return m_bestFitImageURL.isNull() ? fastGetAttribute(srcAttr) : m_bestFitImageURL;
    182 }
    183 
    184 HTMLFormElement* HTMLImageElement::formOwner() const
    185 {
    186     return m_form.get();
    187 }
    188 
    189 void HTMLImageElement::formRemovedFromTree(const Node& formRoot)
    190 {
    191     ASSERT(m_form);
    192     if (NodeTraversal::highestAncestorOrSelf(*this) != formRoot)
    193         resetFormOwner();
    194 }
    195 
    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 
    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 
    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 
    257 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 
    269 static bool supportedImageType(const String& type)
    270 {
    271     return MIMETypeRegistry::isSupportedImagePrefixedMIMEType(type);
    272 }
    273 
    274 // http://picture.responsiveimages.org/#update-source-set
    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 
    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 
    326 bool HTMLImageElement::canStartSelection() const
    327 {
    328     if (shadow())
    329         return HTMLElement::canStartSelection();
    330 
    331     return false;
    332 }
    333 
    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 
    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 
    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 
    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 
    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 
    433 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 
    441 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 
    449 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 
    461 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 
    470 bool HTMLImageElement::hasLegalLinkAttribute(const QualifiedName& name) const
    471 {
    472     return name == srcAttr || HTMLElement::hasLegalLinkAttribute(name);
    473 }
    474 
    475 const QualifiedName& HTMLImageElement::subResourceAttributeName() const
    476 {
    477     return srcAttr;
    478 }
    479 
    480 bool HTMLImageElement::draggable() const
    481 {
    482     // Image elements are draggable by default.
    483     return !equalIgnoringCase(getAttribute(draggableAttr), "false");
    484 }
    485 
    486 void HTMLImageElement::setHeight(int value)
    487 {
    488     setIntegralAttribute(heightAttr, value);
    489 }
    490 
    491 KURL HTMLImageElement::src() const
    492 {
    493     return document().completeURL(getAttribute(srcAttr));
    494 }
    495 
    496 void HTMLImageElement::setSrc(const String& value)
    497 {
    498     setAttribute(srcAttr, AtomicString(value));
    499 }
    500 
    501 void HTMLImageElement::setWidth(int value)
    502 {
    503     setIntegralAttribute(widthAttr, value);
    504 }
    505 
    506 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 
    518 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 
    530 bool HTMLImageElement::complete() const
    531 {
    532     return imageLoader().imageComplete();
    533 }
    534 
    535 void HTMLImageElement::didMoveToNewDocument(Document& oldDocument)
    536 {
    537     imageLoader().elementDidMoveToNewDocument();
    538     HTMLElement::didMoveToNewDocument(oldDocument);
    539 }
    540 
    541 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 
    555 Image* HTMLImageElement::imageContents()
    556 {
    557     if (!imageLoader().imageComplete())
    558         return 0;
    559 
    560     return imageLoader().image()->image();
    561 }
    562 
    563 bool HTMLImageElement::isInteractiveContent() const
    564 {
    565     return fastHasAttribute(usemapAttr);
    566 }
    567 
    568 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 
    590 bool HTMLImageElement::wouldTaintOrigin(SecurityOrigin* destinationSecurityOrigin) const
    591 {
    592     ImageResource* image = cachedImage();
    593     if (!image)
    594         return false;
    595     return !image->isAccessAllowed(destinationSecurityOrigin);
    596 }
    597 
    598 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 
    609 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 
    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 
    652 const KURL& HTMLImageElement::sourceURL() const
    653 {
    654     return cachedImage()->response().url();
    655 }
    656 
    657 }
    658