Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / third_party / WebKit / Source / core / html / HTMLImageElement.cpp
blobfdef0d1c1565fdaa67511ef26c0f642022a15324
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.
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.
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.
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.
23 #include "config.h"
24 #include "core/html/HTMLImageElement.h"
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/dom/shadow/ShadowRoot.h"
36 #include "core/fetch/ImageResource.h"
37 #include "core/frame/UseCounter.h"
38 #include "core/html/HTMLAnchorElement.h"
39 #include "core/html/HTMLCanvasElement.h"
40 #include "core/html/HTMLFormElement.h"
41 #include "core/html/HTMLImageFallbackHelper.h"
42 #include "core/html/HTMLSourceElement.h"
43 #include "core/html/parser/HTMLParserIdioms.h"
44 #include "core/html/parser/HTMLSrcsetParser.h"
45 #include "core/inspector/ConsoleMessage.h"
46 #include "core/layout/LayoutBlockFlow.h"
47 #include "core/layout/LayoutImage.h"
48 #include "core/page/Page.h"
49 #include "core/style/ContentData.h"
50 #include "platform/ContentType.h"
51 #include "platform/EventDispatchForbiddenScope.h"
52 #include "platform/MIMETypeRegistry.h"
53 #include "platform/RuntimeEnabledFeatures.h"
54 #include "platform/weborigin/SecurityPolicy.h"
56 namespace blink {
58 using namespace HTMLNames;
60 class HTMLImageElement::ViewportChangeListener final : public MediaQueryListListener {
61 public:
62 static RefPtrWillBeRawPtr<ViewportChangeListener> create(HTMLImageElement* element)
64 return adoptRefWillBeNoop(new ViewportChangeListener(element));
67 void notifyMediaQueryChanged() override
69 if (m_element)
70 m_element->notifyViewportChanged();
73 #if !ENABLE(OILPAN)
74 void clearElement() { m_element = nullptr; }
75 #endif
76 DEFINE_INLINE_VIRTUAL_TRACE()
78 visitor->trace(m_element);
79 MediaQueryListListener::trace(visitor);
81 private:
82 explicit ViewportChangeListener(HTMLImageElement* element) : m_element(element) { }
83 RawPtrWillBeMember<HTMLImageElement> m_element;
86 HTMLImageElement::HTMLImageElement(Document& document, HTMLFormElement* form, bool createdByParser)
87 : HTMLElement(imgTag, document)
88 , m_imageLoader(HTMLImageLoader::create(this))
89 , m_imageDevicePixelRatio(1.0f)
90 , m_formWasSetByParser(false)
91 , m_elementCreatedByParser(createdByParser)
92 , m_intrinsicSizingViewportDependant(false)
93 , m_useFallbackContent(false)
94 , m_isFallbackImage(false)
95 , m_referrerPolicy(ReferrerPolicyDefault)
97 setHasCustomStyleCallbacks();
98 if (form && form->inDocument()) {
99 #if ENABLE(OILPAN)
100 m_form = form;
101 #else
102 m_form = form->createWeakPtr();
103 #endif
104 m_formWasSetByParser = true;
105 m_form->associate(*this);
106 m_form->didAssociateByParser();
110 PassRefPtrWillBeRawPtr<HTMLImageElement> HTMLImageElement::create(Document& document)
112 return adoptRefWillBeNoop(new HTMLImageElement(document));
115 PassRefPtrWillBeRawPtr<HTMLImageElement> HTMLImageElement::create(Document& document, HTMLFormElement* form, bool createdByParser)
117 return adoptRefWillBeNoop(new HTMLImageElement(document, form, createdByParser));
120 HTMLImageElement::~HTMLImageElement()
122 #if !ENABLE(OILPAN)
123 if (m_listener) {
124 document().mediaQueryMatcher().removeViewportListener(m_listener.get());
125 m_listener->clearElement();
127 if (m_form)
128 m_form->disassociate(*this);
129 #endif
132 DEFINE_TRACE(HTMLImageElement)
134 visitor->trace(m_imageLoader);
135 visitor->trace(m_listener);
136 visitor->trace(m_form);
137 HTMLElement::trace(visitor);
140 void HTMLImageElement::notifyViewportChanged()
142 // Re-selecting the source URL in order to pick a more fitting resource
143 // And update the image's intrinsic dimensions when the viewport changes.
144 // Picking of a better fitting resource is UA dependant, not spec required.
145 selectSourceURL(ImageLoader::UpdateSizeChanged);
148 PassRefPtrWillBeRawPtr<HTMLImageElement> HTMLImageElement::createForJSConstructor(Document& document)
150 RefPtrWillBeRawPtr<HTMLImageElement> image = adoptRefWillBeNoop(new HTMLImageElement(document));
151 image->m_elementCreatedByParser = false;
152 return image.release();
155 PassRefPtrWillBeRawPtr<HTMLImageElement> HTMLImageElement::createForJSConstructor(Document& document, int width)
157 RefPtrWillBeRawPtr<HTMLImageElement> image = adoptRefWillBeNoop(new HTMLImageElement(document));
158 image->setWidth(width);
159 image->m_elementCreatedByParser = false;
160 return image.release();
163 PassRefPtrWillBeRawPtr<HTMLImageElement> HTMLImageElement::createForJSConstructor(Document& document, int width, int height)
165 RefPtrWillBeRawPtr<HTMLImageElement> image = adoptRefWillBeNoop(new HTMLImageElement(document));
166 image->setWidth(width);
167 image->setHeight(height);
168 image->m_elementCreatedByParser = false;
169 return image.release();
172 bool HTMLImageElement::isPresentationAttribute(const QualifiedName& name) const
174 if (name == widthAttr || name == heightAttr || name == borderAttr || name == vspaceAttr || name == hspaceAttr || name == alignAttr || name == valignAttr)
175 return true;
176 return HTMLElement::isPresentationAttribute(name);
179 void HTMLImageElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStylePropertySet* style)
181 if (name == widthAttr) {
182 addHTMLLengthToStyle(style, CSSPropertyWidth, value);
183 } else if (name == heightAttr) {
184 addHTMLLengthToStyle(style, CSSPropertyHeight, value);
185 } else if (name == borderAttr) {
186 applyBorderAttributeToStyle(value, style);
187 } else if (name == vspaceAttr) {
188 addHTMLLengthToStyle(style, CSSPropertyMarginTop, value);
189 addHTMLLengthToStyle(style, CSSPropertyMarginBottom, value);
190 } else if (name == hspaceAttr) {
191 addHTMLLengthToStyle(style, CSSPropertyMarginLeft, value);
192 addHTMLLengthToStyle(style, CSSPropertyMarginRight, value);
193 } else if (name == alignAttr) {
194 applyAlignmentAttributeToStyle(value, style);
195 } else if (name == valignAttr) {
196 addPropertyToPresentationAttributeStyle(style, CSSPropertyVerticalAlign, value);
197 } else {
198 HTMLElement::collectStyleForPresentationAttribute(name, value, style);
202 const AtomicString HTMLImageElement::imageSourceURL() const
204 return m_bestFitImageURL.isNull() ? fastGetAttribute(srcAttr) : m_bestFitImageURL;
207 HTMLFormElement* HTMLImageElement::formOwner() const
209 return m_form.get();
212 void HTMLImageElement::formRemovedFromTree(const Node& formRoot)
214 ASSERT(m_form);
215 if (NodeTraversal::highestAncestorOrSelf(*this) != formRoot)
216 resetFormOwner();
219 void HTMLImageElement::resetFormOwner()
221 m_formWasSetByParser = false;
222 HTMLFormElement* nearestForm = findFormAncestor();
223 if (m_form) {
224 if (nearestForm == m_form.get())
225 return;
226 m_form->disassociate(*this);
228 if (nearestForm) {
229 #if ENABLE(OILPAN)
230 m_form = nearestForm;
231 #else
232 m_form = nearestForm->createWeakPtr();
233 #endif
234 m_form->associate(*this);
235 } else {
236 #if ENABLE(OILPAN)
237 m_form = nullptr;
238 #else
239 m_form = WeakPtr<HTMLFormElement>();
240 #endif
244 void HTMLImageElement::setBestFitURLAndDPRFromImageCandidate(const ImageCandidate& candidate)
246 m_bestFitImageURL = candidate.url();
247 float candidateDensity = candidate.density();
248 if (candidateDensity >= 0)
249 m_imageDevicePixelRatio = 1.0 / candidateDensity;
250 if (candidate.resourceWidth() > 0) {
251 m_intrinsicSizingViewportDependant = true;
252 UseCounter::count(document(), UseCounter::SrcsetWDescriptor);
253 } else if (!candidate.srcOrigin()) {
254 UseCounter::count(document(), UseCounter::SrcsetXDescriptor);
256 if (layoutObject() && layoutObject()->isImage())
257 toLayoutImage(layoutObject())->setImageDevicePixelRatio(m_imageDevicePixelRatio);
260 void HTMLImageElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
262 if (name == altAttr || name == titleAttr) {
263 if (userAgentShadowRoot()) {
264 Element* text = userAgentShadowRoot()->getElementById("alttext");
265 String value = altText();
266 if (text && text->textContent() != value)
267 text->setTextContent(altText());
269 } else if (name == srcAttr || name == srcsetAttr || name == sizesAttr) {
270 selectSourceURL(ImageLoader::UpdateIgnorePreviousError);
271 } else if (name == usemapAttr) {
272 setIsLink(!value.isNull());
273 } else if (RuntimeEnabledFeatures::referrerPolicyAttributeEnabled() && name == referrerpolicyAttr) {
274 m_referrerPolicy = ReferrerPolicyDefault;
275 if (!value.isNull())
276 SecurityPolicy::referrerPolicyFromString(value, &m_referrerPolicy);
277 } else {
278 HTMLElement::parseAttribute(name, value);
282 String HTMLImageElement::altText() const
284 // lets figure out the alt text.. magic stuff
285 // http://www.w3.org/TR/1998/REC-html40-19980424/appendix/notes.html#altgen
286 // also heavily discussed by Hixie on bugzilla
287 const AtomicString& alt = fastGetAttribute(altAttr);
288 if (!alt.isNull())
289 return alt;
290 // fall back to title attribute
291 return fastGetAttribute(titleAttr);
294 static bool supportedImageType(const String& type)
296 String trimmedType = ContentType(type).type();
297 // An empty type attribute is implicitly supported.
298 if (trimmedType.isEmpty())
299 return true;
300 return MIMETypeRegistry::isSupportedImagePrefixedMIMEType(trimmedType);
303 // http://picture.responsiveimages.org/#update-source-set
304 ImageCandidate HTMLImageElement::findBestFitImageFromPictureParent()
306 ASSERT(isMainThread());
307 Node* parent = parentNode();
308 if (!parent || !isHTMLPictureElement(*parent))
309 return ImageCandidate();
310 for (Node* child = parent->firstChild(); child; child = child->nextSibling()) {
311 if (child == this)
312 return ImageCandidate();
314 if (!isHTMLSourceElement(*child))
315 continue;
317 HTMLSourceElement* source = toHTMLSourceElement(child);
318 if (!source->fastGetAttribute(srcAttr).isNull())
319 UseCounter::countDeprecation(document(), UseCounter::PictureSourceSrc);
320 String srcset = source->fastGetAttribute(srcsetAttr);
321 if (srcset.isEmpty())
322 continue;
323 String type = source->fastGetAttribute(typeAttr);
324 if (!type.isEmpty() && !supportedImageType(type))
325 continue;
327 if (!source->mediaQueryMatches())
328 continue;
330 ImageCandidate candidate = bestFitSourceForSrcsetAttribute(document().devicePixelRatio(), sourceSize(*source), source->fastGetAttribute(srcsetAttr), &document());
331 if (candidate.isEmpty())
332 continue;
333 return candidate;
335 return ImageCandidate();
338 LayoutObject* HTMLImageElement::createLayoutObject(const ComputedStyle& style)
340 const ContentData* contentData = style.contentData();
341 if (contentData && contentData->isImage()) {
342 const StyleImage* contentImage = toImageContentData(contentData)->image();
343 bool errorOccurred = contentImage && contentImage->cachedImage() && contentImage->cachedImage()->errorOccurred();
344 if (!errorOccurred)
345 return LayoutObject::createObject(this, style);
348 if (m_useFallbackContent)
349 return new LayoutBlockFlow(this);
351 LayoutImage* image = new LayoutImage(this);
352 image->setImageResource(LayoutImageResource::create());
353 image->setImageDevicePixelRatio(m_imageDevicePixelRatio);
354 return image;
357 void HTMLImageElement::attach(const AttachContext& context)
359 HTMLElement::attach(context);
361 if (layoutObject() && layoutObject()->isImage()) {
362 LayoutImage* layoutImage = toLayoutImage(layoutObject());
363 LayoutImageResource* layoutImageResource = layoutImage->imageResource();
364 if (m_isFallbackImage) {
365 float deviceScaleFactor = blink::deviceScaleFactor(layoutImage->frame());
366 pair<Image*, float> brokenImageAndImageScaleFactor = ImageResource::brokenImage(deviceScaleFactor);
367 ImageResource* newImageResource = new ImageResource(brokenImageAndImageScaleFactor.first);
368 layoutImage->imageResource()->setImageResource(newImageResource);
370 if (layoutImageResource->hasImage())
371 return;
373 if (!imageLoader().image() && !layoutImageResource->cachedImage())
374 return;
375 layoutImageResource->setImageResource(imageLoader().image());
379 Node::InsertionNotificationRequest HTMLImageElement::insertedInto(ContainerNode* insertionPoint)
381 if (!m_formWasSetByParser || NodeTraversal::highestAncestorOrSelf(*insertionPoint) != NodeTraversal::highestAncestorOrSelf(*m_form.get()))
382 resetFormOwner();
383 if (m_listener)
384 document().mediaQueryMatcher().addViewportListener(m_listener);
386 bool imageWasModified = false;
387 if (document().isActive()) {
388 ImageCandidate candidate = findBestFitImageFromPictureParent();
389 if (!candidate.isEmpty()) {
390 setBestFitURLAndDPRFromImageCandidate(candidate);
391 imageWasModified = true;
395 // If we have been inserted from a layoutObject-less document,
396 // our loader may have not fetched the image, so do it now.
397 if ((insertionPoint->inDocument() && !imageLoader().image()) || imageWasModified)
398 imageLoader().updateFromElement(ImageLoader::UpdateNormal, m_referrerPolicy);
400 return HTMLElement::insertedInto(insertionPoint);
403 void HTMLImageElement::removedFrom(ContainerNode* insertionPoint)
405 if (!m_form || NodeTraversal::highestAncestorOrSelf(*m_form.get()) != NodeTraversal::highestAncestorOrSelf(*this))
406 resetFormOwner();
407 if (m_listener)
408 document().mediaQueryMatcher().removeViewportListener(m_listener);
409 HTMLElement::removedFrom(insertionPoint);
412 int HTMLImageElement::width()
414 if (inActiveDocument())
415 document().updateLayoutIgnorePendingStylesheets();
417 if (!layoutObject()) {
418 // check the attribute first for an explicit pixel value
419 bool ok;
420 int width = getAttribute(widthAttr).toInt(&ok);
421 if (ok)
422 return width;
424 // if the image is available, use its width
425 if (imageLoader().image())
426 return imageLoader().image()->imageSizeForLayoutObject(layoutObject(), 1.0f).width();
429 LayoutBox* box = layoutBox();
430 return box ? adjustForAbsoluteZoom(box->contentBoxRect().pixelSnappedWidth(), box) : 0;
433 int HTMLImageElement::height()
435 if (inActiveDocument())
436 document().updateLayoutIgnorePendingStylesheets();
438 if (!layoutObject()) {
439 // check the attribute first for an explicit pixel value
440 bool ok;
441 int height = getAttribute(heightAttr).toInt(&ok);
442 if (ok)
443 return height;
445 // if the image is available, use its height
446 if (imageLoader().image())
447 return imageLoader().image()->imageSizeForLayoutObject(layoutObject(), 1.0f).height();
450 LayoutBox* box = layoutBox();
451 return box ? adjustForAbsoluteZoom(box->contentBoxRect().pixelSnappedHeight(), box) : 0;
454 int HTMLImageElement::naturalWidth() const
456 if (!imageLoader().image())
457 return 0;
459 return imageLoader().image()->imageSizeForLayoutObject(layoutObject(), m_imageDevicePixelRatio, ImageResource::IntrinsicCorrectedToDPR).width();
462 int HTMLImageElement::naturalHeight() const
464 if (!imageLoader().image())
465 return 0;
467 return imageLoader().image()->imageSizeForLayoutObject(layoutObject(), m_imageDevicePixelRatio, ImageResource::IntrinsicCorrectedToDPR).height();
470 const String& HTMLImageElement::currentSrc() const
472 // http://www.whatwg.org/specs/web-apps/current-work/multipage/edits.html#dom-img-currentsrc
473 // The currentSrc IDL attribute must return the img element's current request's current URL.
474 // Initially, the pending request turns into current request when it is either available or broken.
475 // We use the image's dimensions as a proxy to it being in any of these states.
476 if (!imageLoader().image() || !imageLoader().image()->image() || !imageLoader().image()->image()->width())
477 return emptyAtom;
479 return imageLoader().image()->url().string();
482 bool HTMLImageElement::isURLAttribute(const Attribute& attribute) const
484 return attribute.name() == srcAttr
485 || attribute.name() == lowsrcAttr
486 || attribute.name() == longdescAttr
487 || (attribute.name() == usemapAttr && attribute.value()[0] != '#')
488 || HTMLElement::isURLAttribute(attribute);
491 bool HTMLImageElement::hasLegalLinkAttribute(const QualifiedName& name) const
493 return name == srcAttr || HTMLElement::hasLegalLinkAttribute(name);
496 const QualifiedName& HTMLImageElement::subResourceAttributeName() const
498 return srcAttr;
501 bool HTMLImageElement::draggable() const
503 // Image elements are draggable by default.
504 return !equalIgnoringCase(getAttribute(draggableAttr), "false");
507 void HTMLImageElement::setHeight(int value)
509 setIntegralAttribute(heightAttr, value);
512 KURL HTMLImageElement::src() const
514 return document().completeURL(getAttribute(srcAttr));
517 void HTMLImageElement::setSrc(const String& value)
519 setAttribute(srcAttr, AtomicString(value));
522 void HTMLImageElement::setWidth(int value)
524 setIntegralAttribute(widthAttr, value);
527 int HTMLImageElement::x() const
529 document().updateLayoutIgnorePendingStylesheets();
530 LayoutObject* r = layoutObject();
531 if (!r)
532 return 0;
534 // FIXME: This doesn't work correctly with transforms.
535 FloatPoint absPos = r->localToAbsolute();
536 return absPos.x();
539 int HTMLImageElement::y() const
541 document().updateLayoutIgnorePendingStylesheets();
542 LayoutObject* r = layoutObject();
543 if (!r)
544 return 0;
546 // FIXME: This doesn't work correctly with transforms.
547 FloatPoint absPos = r->localToAbsolute();
548 return absPos.y();
551 bool HTMLImageElement::complete() const
553 return imageLoader().imageComplete();
556 void HTMLImageElement::didMoveToNewDocument(Document& oldDocument)
558 selectSourceURL(ImageLoader::UpdateIgnorePreviousError);
559 imageLoader().elementDidMoveToNewDocument();
560 HTMLElement::didMoveToNewDocument(oldDocument);
563 bool HTMLImageElement::isServerMap() const
565 if (!fastHasAttribute(ismapAttr))
566 return false;
568 const AtomicString& usemap = fastGetAttribute(usemapAttr);
570 // If the usemap attribute starts with '#', it refers to a map element in the document.
571 if (usemap[0] == '#')
572 return false;
574 return document().completeURL(stripLeadingAndTrailingHTMLSpaces(usemap)).isEmpty();
577 Image* HTMLImageElement::imageContents()
579 if (!imageLoader().imageComplete())
580 return nullptr;
582 return imageLoader().image()->image();
585 bool HTMLImageElement::isInteractiveContent() const
587 return fastHasAttribute(usemapAttr);
590 PassRefPtr<Image> HTMLImageElement::getSourceImageForCanvas(SourceImageStatus* status) const
592 if (!complete() || !cachedImage()) {
593 *status = IncompleteSourceImageStatus;
594 return nullptr;
597 if (cachedImage()->errorOccurred()) {
598 *status = UndecodableSourceImageStatus;
599 return nullptr;
602 RefPtr<Image> sourceImage = cachedImage()->imageForLayoutObject(layoutObject());
604 // We need to synthesize a container size if a layoutObject is not available to provide one.
605 if (!layoutObject() && sourceImage->usesContainerSize())
606 sourceImage->setContainerSize(sourceImage->size());
608 *status = NormalSourceImageStatus;
609 return sourceImage->imageForDefaultFrame();
612 bool HTMLImageElement::wouldTaintOrigin(SecurityOrigin* destinationSecurityOrigin) const
614 ImageResource* image = cachedImage();
615 if (!image)
616 return false;
617 return !image->isAccessAllowed(destinationSecurityOrigin);
620 FloatSize HTMLImageElement::elementSize() const
622 ImageResource* image = cachedImage();
623 if (!image)
624 return FloatSize();
626 return FloatSize(image->imageSizeForLayoutObject(layoutObject(), 1.0f));
629 FloatSize HTMLImageElement::defaultDestinationSize() const
631 ImageResource* image = cachedImage();
632 if (!image)
633 return FloatSize();
634 LayoutSize size;
635 size = image->imageSizeForLayoutObject(layoutObject(), 1.0f);
636 if (layoutObject() && layoutObject()->isLayoutImage() && image->image() && !image->image()->hasRelativeWidth())
637 size.scale(toLayoutImage(layoutObject())->imageDevicePixelRatio());
638 return FloatSize(size);
641 static bool sourceSizeValue(Element& element, Document& currentDocument, float& sourceSize)
643 String sizes = element.fastGetAttribute(sizesAttr);
644 bool exists = !sizes.isNull();
645 if (exists)
646 UseCounter::count(currentDocument, UseCounter::Sizes);
647 sourceSize = SizesAttributeParser(MediaValuesDynamic::create(currentDocument), sizes).length();
648 return exists;
651 FetchRequest::ResourceWidth HTMLImageElement::resourceWidth()
653 FetchRequest::ResourceWidth resourceWidth;
654 resourceWidth.isSet = sourceSizeValue(*this, document(), resourceWidth.width);
655 return resourceWidth;
658 float HTMLImageElement::sourceSize(Element& element)
660 float value;
661 // We don't care here if the sizes attribute exists, so we ignore the return value.
662 // If it doesn't exist, we just return the default.
663 sourceSizeValue(element, document(), value);
664 return value;
667 void HTMLImageElement::forceReload() const
669 imageLoader().updateFromElement(ImageLoader::UpdateForcedReload, m_referrerPolicy);
672 void HTMLImageElement::selectSourceURL(ImageLoader::UpdateFromElementBehavior behavior)
674 if (!document().isActive())
675 return;
677 bool foundURL = false;
678 ImageCandidate candidate = findBestFitImageFromPictureParent();
679 if (!candidate.isEmpty()) {
680 setBestFitURLAndDPRFromImageCandidate(candidate);
681 foundURL = true;
684 if (!foundURL) {
685 candidate = bestFitSourceForImageAttributes(document().devicePixelRatio(), sourceSize(*this), fastGetAttribute(srcAttr), fastGetAttribute(srcsetAttr), &document());
686 setBestFitURLAndDPRFromImageCandidate(candidate);
688 if (m_intrinsicSizingViewportDependant && !m_listener) {
689 m_listener = ViewportChangeListener::create(this);
690 document().mediaQueryMatcher().addViewportListener(m_listener);
692 imageLoader().updateFromElement(behavior, m_referrerPolicy);
694 if (imageLoader().image() || (imageLoader().hasPendingActivity() && !imageSourceURL().isEmpty()))
695 ensurePrimaryContent();
696 else
697 ensureFallbackContent();
700 const KURL& HTMLImageElement::sourceURL() const
702 return cachedImage()->response().url();
705 void HTMLImageElement::didAddUserAgentShadowRoot(ShadowRoot&)
707 HTMLImageFallbackHelper::createAltTextShadowTree(*this);
710 void HTMLImageElement::ensureFallbackForGeneratedContent()
712 setUseFallbackContent();
713 reattachFallbackContent();
716 void HTMLImageElement::ensureFallbackContent()
718 if (m_useFallbackContent || m_isFallbackImage)
719 return;
720 setUseFallbackContent();
721 reattachFallbackContent();
724 void HTMLImageElement::ensurePrimaryContent()
726 if (!m_useFallbackContent)
727 return;
728 m_useFallbackContent = false;
729 reattachFallbackContent();
732 void HTMLImageElement::reattachFallbackContent()
734 // This can happen inside of attach() in the middle of a recalcStyle so we need to
735 // reattach synchronously here.
736 if (document().inStyleRecalc())
737 reattach();
738 else
739 lazyReattachIfAttached();
742 PassRefPtr<ComputedStyle> HTMLImageElement::customStyleForLayoutObject()
744 RefPtr<ComputedStyle> newStyle = originalStyleForLayoutObject();
746 if (!m_useFallbackContent)
747 return newStyle;
749 RefPtr<ComputedStyle> style = ComputedStyle::clone(*newStyle);
750 return HTMLImageFallbackHelper::customStyleForAltText(*this, style);
753 void HTMLImageElement::setUseFallbackContent()
755 m_useFallbackContent = true;
756 if (document().inStyleRecalc())
757 return;
758 EventDispatchForbiddenScope::AllowUserAgentEvents allowEvents;
759 ensureUserAgentShadowRoot();
762 bool HTMLImageElement::isOpaque() const
764 Image* image = const_cast<HTMLImageElement*>(this)->imageContents();
765 return image && image->currentFrameKnownToBeOpaque();