Backed out changeset 1d9301697aa0 (bug 1887752) for causing failures on browser_all_f...
[gecko.git] / dom / html / HTMLSourceElement.cpp
blob1bff67274e0424ec1bd05c53c6bf1d3de1d04f48
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "mozilla/dom/HTMLSourceElement.h"
8 #include "mozilla/dom/HTMLSourceElementBinding.h"
10 #include "mozilla/dom/DocumentInlines.h"
11 #include "mozilla/dom/HTMLImageElement.h"
12 #include "mozilla/dom/HTMLMediaElement.h"
13 #include "mozilla/dom/ResponsiveImageSelector.h"
14 #include "mozilla/dom/MediaList.h"
15 #include "mozilla/dom/MediaSource.h"
17 #include "mozilla/dom/BlobURLProtocolHandler.h"
18 #include "mozilla/AttributeStyles.h"
19 #include "mozilla/MappedDeclarationsBuilder.h"
20 #include "mozilla/Preferences.h"
22 #include "nsGkAtoms.h"
24 NS_IMPL_NS_NEW_HTML_ELEMENT(Source)
26 namespace mozilla::dom {
28 HTMLSourceElement::HTMLSourceElement(
29 already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo)
30 : nsGenericHTMLElement(std::move(aNodeInfo)) {}
32 HTMLSourceElement::~HTMLSourceElement() = default;
34 NS_IMPL_CYCLE_COLLECTION_INHERITED(HTMLSourceElement, nsGenericHTMLElement,
35 mSrcMediaSource)
37 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(HTMLSourceElement,
38 nsGenericHTMLElement)
40 NS_IMPL_ELEMENT_CLONE(HTMLSourceElement)
42 bool HTMLSourceElement::MatchesCurrentMedia() {
43 if (mMediaList) {
44 return mMediaList->Matches(*OwnerDoc());
47 // No media specified
48 return true;
51 /* static */
52 bool HTMLSourceElement::WouldMatchMediaForDocument(const nsAString& aMedia,
53 const Document* aDocument) {
54 if (aMedia.IsEmpty()) {
55 return true;
58 RefPtr<MediaList> mediaList =
59 MediaList::Create(NS_ConvertUTF16toUTF8(aMedia));
60 return mediaList->Matches(*aDocument);
63 void HTMLSourceElement::UpdateMediaList(const nsAttrValue* aValue) {
64 mMediaList = nullptr;
65 if (!aValue) {
66 return;
69 NS_ConvertUTF16toUTF8 mediaStr(aValue->GetStringValue());
70 mMediaList = MediaList::Create(mediaStr);
73 bool HTMLSourceElement::ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute,
74 const nsAString& aValue,
75 nsIPrincipal* aMaybeScriptedPrincipal,
76 nsAttrValue& aResult) {
77 if (aNamespaceID == kNameSpaceID_None &&
78 (aAttribute == nsGkAtoms::width || aAttribute == nsGkAtoms::height)) {
79 return aResult.ParseHTMLDimension(aValue);
82 return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
83 aMaybeScriptedPrincipal, aResult);
86 void HTMLSourceElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
87 const nsAttrValue* aValue,
88 const nsAttrValue* aOldValue,
89 nsIPrincipal* aMaybeScriptedPrincipal,
90 bool aNotify) {
91 if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::srcset) {
92 mSrcsetTriggeringPrincipal = nsContentUtils::GetAttrTriggeringPrincipal(
93 this, aValue ? aValue->GetStringValue() : EmptyString(),
94 aMaybeScriptedPrincipal);
96 // If we are associated with a <picture> with a valid <img>, notify it of
97 // responsive parameter changes
98 if (aNameSpaceID == kNameSpaceID_None &&
99 (aName == nsGkAtoms::srcset || aName == nsGkAtoms::sizes ||
100 aName == nsGkAtoms::media || aName == nsGkAtoms::type) &&
101 IsInPicture()) {
102 if (aName == nsGkAtoms::media) {
103 UpdateMediaList(aValue);
106 nsString strVal = aValue ? aValue->GetStringValue() : EmptyString();
107 // Find all img siblings after this <source> and notify them of the change
108 nsCOMPtr<nsIContent> sibling = AsContent();
109 while ((sibling = sibling->GetNextSibling())) {
110 if (auto* img = HTMLImageElement::FromNode(sibling)) {
111 if (aName == nsGkAtoms::srcset) {
112 img->PictureSourceSrcsetChanged(this, strVal, aNotify);
113 } else if (aName == nsGkAtoms::sizes) {
114 img->PictureSourceSizesChanged(this, strVal, aNotify);
115 } else if (aName == nsGkAtoms::media || aName == nsGkAtoms::type) {
116 img->PictureSourceMediaOrTypeChanged(this, aNotify);
120 } else if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::media) {
121 UpdateMediaList(aValue);
122 } else if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::src) {
123 mSrcTriggeringPrincipal = nsContentUtils::GetAttrTriggeringPrincipal(
124 this, aValue ? aValue->GetStringValue() : EmptyString(),
125 aMaybeScriptedPrincipal);
126 mSrcMediaSource = nullptr;
127 if (aValue) {
128 nsString srcStr = aValue->GetStringValue();
129 nsCOMPtr<nsIURI> uri;
130 NewURIFromString(srcStr, getter_AddRefs(uri));
131 if (uri && IsMediaSourceURI(uri)) {
132 NS_GetSourceForMediaSourceURI(uri, getter_AddRefs(mSrcMediaSource));
135 } else if (aNameSpaceID == kNameSpaceID_None &&
136 IsAttributeMappedToImages(aName) && IsInPicture()) {
137 BuildMappedAttributesForImage();
139 nsCOMPtr<nsIContent> sibling = AsContent();
140 while ((sibling = sibling->GetNextSibling())) {
141 if (auto* img = HTMLImageElement::FromNode(sibling)) {
142 img->PictureSourceDimensionChanged(this, aNotify);
147 return nsGenericHTMLElement::AfterSetAttr(
148 aNameSpaceID, aName, aValue, aOldValue, aMaybeScriptedPrincipal, aNotify);
151 nsresult HTMLSourceElement::BindToTree(BindContext& aContext,
152 nsINode& aParent) {
153 nsresult rv = nsGenericHTMLElement::BindToTree(aContext, aParent);
154 NS_ENSURE_SUCCESS(rv, rv);
156 if (auto* media = HTMLMediaElement::FromNode(aParent)) {
157 media->NotifyAddedSource();
160 if (aParent.IsHTMLElement(nsGkAtoms::picture)) {
161 BuildMappedAttributesForImage();
162 } else {
163 mMappedAttributesForImage = nullptr;
166 return NS_OK;
169 void HTMLSourceElement::UnbindFromTree(UnbindContext& aContext) {
170 mMappedAttributesForImage = nullptr;
171 nsGenericHTMLElement::UnbindFromTree(aContext);
174 JSObject* HTMLSourceElement::WrapNode(JSContext* aCx,
175 JS::Handle<JSObject*> aGivenProto) {
176 return HTMLSourceElement_Binding::Wrap(aCx, this, aGivenProto);
180 * Helper to map the image source attributes.
181 * Note: This will override the declaration created by the presentation
182 * attributes of HTMLImageElement (i.e. mapped by MapImageSizeAttributeInto).
183 * https://html.spec.whatwg.org/multipage/embedded-content.html#the-source-element
185 void HTMLSourceElement::BuildMappedAttributesForImage() {
186 MOZ_ASSERT(NS_IsMainThread());
188 mMappedAttributesForImage = nullptr;
190 Document* document = GetComposedDoc();
191 if (!document) {
192 return;
195 const nsAttrValue* width = mAttrs.GetAttr(nsGkAtoms::width);
196 const nsAttrValue* height = mAttrs.GetAttr(nsGkAtoms::height);
197 if (!width && !height) {
198 return;
201 MappedDeclarationsBuilder builder(*this, *document);
202 // We should set the missing property values with auto value to make sure it
203 // overrides the declaration created by the presentation attributes of
204 // HTMLImageElement. This can make sure we compute the ratio-dependent axis
205 // size properly by the natural aspect-ratio of the image.
207 // Note: The spec doesn't specify this, so we follow the implementation in
208 // other browsers.
209 // Spec issue: https://github.com/whatwg/html/issues/8178.
210 if (width) {
211 MapDimensionAttributeInto(builder, eCSSProperty_width, *width);
212 } else {
213 builder.SetAutoValue(eCSSProperty_width);
216 if (height) {
217 MapDimensionAttributeInto(builder, eCSSProperty_height, *height);
218 } else {
219 builder.SetAutoValue(eCSSProperty_height);
222 if (width && height) {
223 DoMapAspectRatio(*width, *height, builder);
224 } else {
225 builder.SetAutoValue(eCSSProperty_aspect_ratio);
227 mMappedAttributesForImage = builder.TakeDeclarationBlock();
230 } // namespace mozilla::dom