Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / html / HTMLImageElement.cpp
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:
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 }