void HTMLImageElement::selectSourceURL(ImageLoader::UpdateFromElementBehavior behavior) { if (!document().isActive()) return; bool foundURL = false; ImageCandidate candidate = findBestFitImageFromPictureParent(); if (!candidate.isEmpty()) { setBestFitURLAndDPRFromImageCandidate(candidate); foundURL = true; } if (!foundURL) { candidate = bestFitSourceForImageAttributes(document().devicePixelRatio(), sourceSize(*this), fastGetAttribute(srcAttr), fastGetAttribute(srcsetAttr), &document()); setBestFitURLAndDPRFromImageCandidate(candidate); } if (m_intrinsicSizingViewportDependant && !m_listener) { m_listener = ViewportChangeListener::create(this); document().mediaQueryMatcher().addViewportListener(m_listener); } imageLoader().updateFromElement(behavior, m_referrerPolicy); if (imageLoader().image() || (imageLoader().hasPendingActivity() && !imageSourceURL().isEmpty())) ensurePrimaryContent(); else ensureFallbackContent(); }
// http://picture.responsiveimages.org/#update-source-set ImageCandidate HTMLImageElement::findBestFitImageFromPictureParent() { ASSERT(isMainThread()); Node* parent = parentNode(); if (!parent || !isHTMLPictureElement(*parent)) return ImageCandidate(); for (Node* child = parent->firstChild(); child; child = child->nextSibling()) { if (child == this) return ImageCandidate(); if (!isHTMLSourceElement(*child)) continue; HTMLSourceElement* source = toHTMLSourceElement(child); if (!source->fastGetAttribute(srcAttr).isNull()) UseCounter::countDeprecation(document(), UseCounter::PictureSourceSrc); String srcset = source->fastGetAttribute(srcsetAttr); if (srcset.isEmpty()) continue; String type = source->fastGetAttribute(typeAttr); if (!type.isEmpty() && !supportedImageType(type)) continue; if (!source->mediaQueryMatches()) continue; ImageCandidate candidate = bestFitSourceForSrcsetAttribute(document().devicePixelRatio(), sourceSize(*source), source->fastGetAttribute(srcsetAttr), &document()); if (candidate.isEmpty()) continue; return candidate; } return ImageCandidate(); }
void HTMLImageElement::selectSourceURL(ImageLoader::UpdateFromElementBehavior behavior) { if (!document().isActive()) return; bool foundURL = false; if (RuntimeEnabledFeatures::pictureEnabled()) { ImageCandidate candidate = findBestFitImageFromPictureParent(); if (!candidate.isEmpty()) { setBestFitURLAndDPRFromImageCandidate(candidate); foundURL = true; } } if (!foundURL) { float effectiveSize = 0; if (RuntimeEnabledFeatures::pictureSizesEnabled()) { String sizes = fastGetAttribute(sizesAttr); if (!sizes.isNull()) UseCounter::count(document(), UseCounter::Sizes); SizesAttributeParser parser = SizesAttributeParser(MediaValuesDynamic::create(document()), sizes); effectiveSize = parser.length(); } ImageCandidate candidate = bestFitSourceForImageAttributes(document().devicePixelRatio(), effectiveSize, fastGetAttribute(srcAttr), fastGetAttribute(srcsetAttr), &document()); setBestFitURLAndDPRFromImageCandidate(candidate); } if (m_intrinsicSizingViewportDependant && !m_listener) { m_listener = ViewportChangeListener::create(this); document().mediaQueryMatcher().addViewportListener(m_listener); } imageLoader().updateFromElement(behavior); }
void processAttributes(const HTMLToken::AttributeList& attributes, Document& document, Vector<bool>& pictureState) { ASSERT(isMainThread()); if (m_tagId >= TagId::Unknown) return; for (auto& attribute : attributes) { AtomicString attributeName(attribute.name); String attributeValue = StringImpl::create8BitIfPossible(attribute.value); processAttribute(attributeName, attributeValue, document, pictureState); } if (m_tagId == TagId::Source && !pictureState.isEmpty() && !pictureState.last() && m_mediaMatched && !m_srcSetAttribute.isEmpty()) { float sourceSize = parseSizesAttribute(m_sizesAttribute, document.renderView(), document.frame()); ImageCandidate imageCandidate = bestFitSourceForImageAttributes(m_deviceScaleFactor, m_urlToLoad, m_srcSetAttribute, sourceSize); if (!imageCandidate.isEmpty()) { pictureState.last() = true; setUrlToLoad(imageCandidate.string.toString(), true); } } // Resolve between src and srcSet if we have them and the tag is img. if (m_tagId == TagId::Img && !m_srcSetAttribute.isEmpty()) { float sourceSize = parseSizesAttribute(m_sizesAttribute, document.renderView(), document.frame()); ImageCandidate imageCandidate = bestFitSourceForImageAttributes(m_deviceScaleFactor, m_urlToLoad, m_srcSetAttribute, sourceSize); setUrlToLoad(imageCandidate.string.toString(), true); } if (m_metaIsViewport && !m_metaContent.isNull()) document.processViewport(m_metaContent, ViewportArguments::ViewportMeta); }
void HTMLImageElement::selectImageSource() { // First look for the best fit source from our <picture> parent if we have one. ImageCandidate candidate = bestFitSourceFromPictureElement(); if (candidate.isEmpty()) { // If we don't have a <picture> or didn't find a source, then we use our own attributes. float sourceSize = parseSizesAttribute(fastGetAttribute(sizesAttr).string(), document().renderView(), document().frame()); candidate = bestFitSourceForImageAttributes(document().deviceScaleFactor(), fastGetAttribute(srcAttr), fastGetAttribute(srcsetAttr), sourceSize); } setBestFitURLAndDPRFromImageCandidate(candidate); m_imageLoader.updateFromElementIgnoringPreviousError(); }
String bestFitSourceForImageAttributes(float deviceScaleFactor, unsigned sourceSize, const String& srcAttribute, ImageCandidate& srcsetImageCandidate) { if (srcsetImageCandidate.isEmpty()) return srcAttribute; Vector<ImageCandidate> imageCandidates; imageCandidates.append(srcsetImageCandidate); if (!srcAttribute.isEmpty()) imageCandidates.append(ImageCandidate(srcAttribute, 0, srcAttribute.length(), DescriptorParsingResult(), ImageCandidate::SrcOrigin)); return pickBestImageCandidate(deviceScaleFactor, sourceSize, imageCandidates).toString(); }
Node::InsertionNotificationRequest HTMLImageElement::insertedInto(ContainerNode* insertionPoint) { if (!m_formWasSetByParser || insertionPoint->highestAncestorOrSelf() != m_form->highestAncestorOrSelf()) resetFormOwner(); bool imageWasModified = false; if (RuntimeEnabledFeatures::pictureEnabled()) { ImageCandidate candidate = findBestFitImageFromPictureParent(); if (!candidate.isEmpty()) { setBestFitURLAndDPRFromImageCandidate(candidate); imageWasModified = true; } } // If we have been inserted from a renderer-less document, // our loader may have not fetched the image, so do it now. if ((insertionPoint->inDocument() && !imageLoader().image()) || imageWasModified) imageLoader().updateFromElement(m_elementCreatedByParser ? ImageLoader::ForceLoadImmediately : ImageLoader::LoadNormally); return HTMLElement::insertedInto(insertionPoint); }
ImageCandidate HTMLImageElement::bestFitSourceFromPictureElement() { auto* parent = parentNode(); if (!is<HTMLPictureElement>(parent)) return { }; auto* picture = downcast<HTMLPictureElement>(parent); picture->clearViewportDependentResults(); document().removeViewportDependentPicture(*picture); for (Node* child = parent->firstChild(); child && child != this; child = child->nextSibling()) { if (!is<HTMLSourceElement>(*child)) continue; auto& source = downcast<HTMLSourceElement>(*child); auto& srcset = source.fastGetAttribute(srcsetAttr); if (srcset.isEmpty()) continue; if (source.hasAttribute(typeAttr)) { String type = source.fastGetAttribute(typeAttr).string(); int indexOfSemicolon = type.find(';'); if (indexOfSemicolon >= 0) type.truncate(indexOfSemicolon); type = stripLeadingAndTrailingHTMLSpaces(type); type = type.lower(); if (!type.isEmpty() && !MIMETypeRegistry::isSupportedImageMIMEType(type) && type != "image/svg+xml") continue; } MediaQueryEvaluator evaluator(document().printing() ? "print" : "screen", document().frame(), computedStyle()); bool evaluation = evaluator.evalCheckingViewportDependentResults(source.mediaQuerySet(), picture->viewportDependentResults()); if (picture->hasViewportDependentResults()) document().addViewportDependentPicture(*picture); if (!evaluation) continue; float sourceSize = parseSizesAttribute(source.fastGetAttribute(sizesAttr).string(), document().renderView(), document().frame()); ImageCandidate candidate = bestFitSourceForImageAttributes(document().deviceScaleFactor(), nullAtom, source.fastGetAttribute(srcsetAttr), sourceSize); if (!candidate.isEmpty()) return candidate; } return { }; }
Node::InsertionNotificationRequest HTMLImageElement::insertedInto(ContainerNode* insertionPoint) { if (!m_formWasSetByParser || NodeTraversal::highestAncestorOrSelf(*insertionPoint) != NodeTraversal::highestAncestorOrSelf(*m_form.get())) resetFormOwner(); if (m_listener) document().mediaQueryMatcher().addViewportListener(m_listener); bool imageWasModified = false; if (document().isActive()) { ImageCandidate candidate = findBestFitImageFromPictureParent(); if (!candidate.isEmpty()) { setBestFitURLAndDPRFromImageCandidate(candidate); imageWasModified = true; } } // If we have been inserted from a layoutObject-less document, // our loader may have not fetched the image, so do it now. if ((insertionPoint->inDocument() && !imageLoader().image()) || imageWasModified) imageLoader().updateFromElement(ImageLoader::UpdateNormal, m_referrerPolicy); return HTMLElement::insertedInto(insertionPoint); }
void HTMLImageElement::selectSourceURL(UpdateFromElementBehavior behavior) { bool foundURL = false; if (RuntimeEnabledFeatures::pictureEnabled()) { ImageCandidate candidate = findBestFitImageFromPictureParent(); if (!candidate.isEmpty()) { setBestFitURLAndDPRFromImageCandidate(candidate); foundURL = true; } } if (!foundURL) { unsigned effectiveSize = 0; if (RuntimeEnabledFeatures::pictureSizesEnabled()) effectiveSize = SizesAttributeParser::findEffectiveSize(fastGetAttribute(sizesAttr), MediaValuesCached::create(document())); ImageCandidate candidate = bestFitSourceForImageAttributes(document().devicePixelRatio(), effectiveSize, fastGetAttribute(srcAttr), fastGetAttribute(srcsetAttr)); setBestFitURLAndDPRFromImageCandidate(candidate); } if (behavior == UpdateIgnorePreviousError) imageLoader().updateFromElementIgnoringPreviousError(); else imageLoader().updateFromElement(); }
// http://picture.responsiveimages.org/#update-source-set ImageCandidate HTMLImageElement::findBestFitImageFromPictureParent() { ASSERT(isMainThread()); Node* parent = parentNode(); if (!parent || !isHTMLPictureElement(*parent)) return ImageCandidate(); for (Node* child = parent->firstChild(); child; child = child->nextSibling()) { if (child == this) return ImageCandidate(); if (!isHTMLSourceElement(*child)) continue; HTMLSourceElement* source = toHTMLSourceElement(child); String srcset = source->fastGetAttribute(srcsetAttr); if (srcset.isEmpty()) continue; String type = source->fastGetAttribute(typeAttr); if (!type.isEmpty() && !supportedImageType(type)) continue; String media = source->fastGetAttribute(mediaAttr); if (!media.isEmpty()) { RefPtrWillBeRawPtr<MediaQuerySet> mediaQueries = MediaQuerySet::create(media); if (!document().mediaQueryMatcher().evaluate(mediaQueries.get())) continue; } unsigned effectiveSize = SizesAttributeParser::findEffectiveSize(source->fastGetAttribute(sizesAttr), MediaValuesCached::create(document())); ImageCandidate candidate = bestFitSourceForSrcsetAttribute(document().devicePixelRatio(), effectiveSize, source->fastGetAttribute(srcsetAttr)); if (candidate.isEmpty()) continue; return candidate; } return ImageCandidate(); }