Bug 1880216 - Migrate Fenix docs into Sphinx. r=owlish,geckoview-reviewers,android...
[gecko.git] / dom / html / HTMLIFrameElement.cpp
blob97363ccbff684470e3d9254175fd9dd1e41bb278
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/DOMIntersectionObserver.h"
8 #include "mozilla/dom/HTMLIFrameElement.h"
9 #include "mozilla/dom/ContentChild.h"
10 #include "mozilla/dom/Document.h"
11 #include "mozilla/dom/HTMLIFrameElementBinding.h"
12 #include "mozilla/dom/FeaturePolicy.h"
13 #include "mozilla/MappedDeclarationsBuilder.h"
14 #include "mozilla/NullPrincipal.h"
15 #include "mozilla/StaticPrefs_dom.h"
16 #include "nsSubDocumentFrame.h"
17 #include "nsError.h"
18 #include "nsContentUtils.h"
19 #include "nsSandboxFlags.h"
20 #include "nsNetUtil.h"
22 NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(IFrame)
24 namespace mozilla::dom {
26 NS_IMPL_CYCLE_COLLECTION_CLASS(HTMLIFrameElement)
28 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLIFrameElement,
29 nsGenericHTMLFrameElement)
30 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFeaturePolicy)
31 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSandbox)
32 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
34 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLIFrameElement,
35 nsGenericHTMLFrameElement)
36 NS_IMPL_CYCLE_COLLECTION_UNLINK(mFeaturePolicy)
37 NS_IMPL_CYCLE_COLLECTION_UNLINK(mSandbox)
38 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
40 NS_IMPL_ADDREF_INHERITED(HTMLIFrameElement, nsGenericHTMLFrameElement)
41 NS_IMPL_RELEASE_INHERITED(HTMLIFrameElement, nsGenericHTMLFrameElement)
43 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(HTMLIFrameElement)
44 NS_INTERFACE_MAP_END_INHERITING(nsGenericHTMLFrameElement)
46 // static
47 const DOMTokenListSupportedToken HTMLIFrameElement::sSupportedSandboxTokens[] =
49 #define SANDBOX_KEYWORD(string, atom, flags) string,
50 #include "IframeSandboxKeywordList.h"
51 #undef SANDBOX_KEYWORD
52 nullptr};
54 HTMLIFrameElement::HTMLIFrameElement(
55 already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
56 FromParser aFromParser)
57 : nsGenericHTMLFrameElement(std::move(aNodeInfo), aFromParser) {
58 // We always need a featurePolicy, even if not exposed.
59 mFeaturePolicy = new mozilla::dom::FeaturePolicy(this);
60 nsCOMPtr<nsIPrincipal> origin = GetFeaturePolicyDefaultOrigin();
61 MOZ_ASSERT(origin);
62 mFeaturePolicy->SetDefaultOrigin(origin);
65 HTMLIFrameElement::~HTMLIFrameElement() = default;
67 NS_IMPL_ELEMENT_CLONE(HTMLIFrameElement)
69 void HTMLIFrameElement::BindToBrowsingContext(BrowsingContext*) {
70 RefreshFeaturePolicy(true /* parse the feature policy attribute */);
73 bool HTMLIFrameElement::ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute,
74 const nsAString& aValue,
75 nsIPrincipal* aMaybeScriptedPrincipal,
76 nsAttrValue& aResult) {
77 if (aNamespaceID == kNameSpaceID_None) {
78 if (aAttribute == nsGkAtoms::marginwidth) {
79 return aResult.ParseNonNegativeIntValue(aValue);
81 if (aAttribute == nsGkAtoms::marginheight) {
82 return aResult.ParseNonNegativeIntValue(aValue);
84 if (aAttribute == nsGkAtoms::width) {
85 return aResult.ParseHTMLDimension(aValue);
87 if (aAttribute == nsGkAtoms::height) {
88 return aResult.ParseHTMLDimension(aValue);
90 if (aAttribute == nsGkAtoms::frameborder) {
91 return ParseFrameborderValue(aValue, aResult);
93 if (aAttribute == nsGkAtoms::scrolling) {
94 return ParseScrollingValue(aValue, aResult);
96 if (aAttribute == nsGkAtoms::align) {
97 return ParseAlignValue(aValue, aResult);
99 if (aAttribute == nsGkAtoms::sandbox) {
100 aResult.ParseAtomArray(aValue);
101 return true;
103 if (aAttribute == nsGkAtoms::loading) {
104 return ParseLoadingAttribute(aValue, aResult);
108 return nsGenericHTMLFrameElement::ParseAttribute(
109 aNamespaceID, aAttribute, aValue, aMaybeScriptedPrincipal, aResult);
112 void HTMLIFrameElement::MapAttributesIntoRule(
113 MappedDeclarationsBuilder& aBuilder) {
114 // frameborder: 0 | 1 (| NO | YES in quirks mode)
115 // If frameborder is 0 or No, set border to 0
116 // else leave it as the value set in html.css
117 const nsAttrValue* value = aBuilder.GetAttr(nsGkAtoms::frameborder);
118 if (value && value->Type() == nsAttrValue::eEnum) {
119 auto frameborder = static_cast<FrameBorderProperty>(value->GetEnumValue());
120 if (FrameBorderProperty::No == frameborder ||
121 FrameBorderProperty::Zero == frameborder) {
122 aBuilder.SetPixelValueIfUnset(eCSSProperty_border_top_width, 0.0f);
123 aBuilder.SetPixelValueIfUnset(eCSSProperty_border_right_width, 0.0f);
124 aBuilder.SetPixelValueIfUnset(eCSSProperty_border_bottom_width, 0.0f);
125 aBuilder.SetPixelValueIfUnset(eCSSProperty_border_left_width, 0.0f);
129 nsGenericHTMLElement::MapImageSizeAttributesInto(aBuilder);
130 nsGenericHTMLElement::MapImageAlignAttributeInto(aBuilder);
131 nsGenericHTMLElement::MapCommonAttributesInto(aBuilder);
134 NS_IMETHODIMP_(bool)
135 HTMLIFrameElement::IsAttributeMapped(const nsAtom* aAttribute) const {
136 static const MappedAttributeEntry attributes[] = {
137 {nsGkAtoms::width},
138 {nsGkAtoms::height},
139 {nsGkAtoms::frameborder},
140 {nullptr},
143 static const MappedAttributeEntry* const map[] = {
144 attributes,
145 sImageAlignAttributeMap,
146 sCommonAttributeMap,
149 return FindAttributeDependence(aAttribute, map);
152 nsMapRuleToAttributesFunc HTMLIFrameElement::GetAttributeMappingFunction()
153 const {
154 return &MapAttributesIntoRule;
157 void HTMLIFrameElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
158 const nsAttrValue* aValue,
159 const nsAttrValue* aOldValue,
160 nsIPrincipal* aMaybeScriptedPrincipal,
161 bool aNotify) {
162 AfterMaybeChangeAttr(aNameSpaceID, aName, aNotify);
164 if (aNameSpaceID == kNameSpaceID_None) {
165 if (aName == nsGkAtoms::loading) {
166 if (aValue && Loading(aValue->GetEnumValue()) == Loading::Lazy) {
167 SetLazyLoading();
168 } else if (aOldValue &&
169 Loading(aOldValue->GetEnumValue()) == Loading::Lazy) {
170 StopLazyLoading();
174 // If lazy loading and src set, set lazy loading again as we are doing a new
175 // load (lazy loading is unset after a load is complete).
176 if ((aName == nsGkAtoms::src || aName == nsGkAtoms::srcdoc) &&
177 LoadingState() == Loading::Lazy) {
178 SetLazyLoading();
181 if (aName == nsGkAtoms::sandbox) {
182 if (mFrameLoader) {
183 // If we have an nsFrameLoader, apply the new sandbox flags.
184 // Since this is called after the setter, the sandbox flags have
185 // alreay been updated.
186 mFrameLoader->ApplySandboxFlags(GetSandboxFlags());
190 if (aName == nsGkAtoms::allow || aName == nsGkAtoms::src ||
191 aName == nsGkAtoms::srcdoc || aName == nsGkAtoms::sandbox) {
192 RefreshFeaturePolicy(true /* parse the feature policy attribute */);
193 } else if (aName == nsGkAtoms::allowfullscreen) {
194 RefreshFeaturePolicy(false /* parse the feature policy attribute */);
198 return nsGenericHTMLFrameElement::AfterSetAttr(
199 aNameSpaceID, aName, aValue, aOldValue, aMaybeScriptedPrincipal, aNotify);
202 void HTMLIFrameElement::OnAttrSetButNotChanged(
203 int32_t aNamespaceID, nsAtom* aName, const nsAttrValueOrString& aValue,
204 bool aNotify) {
205 AfterMaybeChangeAttr(aNamespaceID, aName, aNotify);
207 return nsGenericHTMLFrameElement::OnAttrSetButNotChanged(aNamespaceID, aName,
208 aValue, aNotify);
211 void HTMLIFrameElement::AfterMaybeChangeAttr(int32_t aNamespaceID,
212 nsAtom* aName, bool aNotify) {
213 if (aNamespaceID == kNameSpaceID_None) {
214 if (aName == nsGkAtoms::srcdoc) {
215 // Don't propagate errors from LoadSrc. The attribute was successfully
216 // set/unset, that's what we should reflect.
217 LoadSrc();
222 uint32_t HTMLIFrameElement::GetSandboxFlags() const {
223 const nsAttrValue* sandboxAttr = GetParsedAttr(nsGkAtoms::sandbox);
224 // No sandbox attribute, no sandbox flags.
225 if (!sandboxAttr) {
226 return SANDBOXED_NONE;
228 return nsContentUtils::ParseSandboxAttributeToFlags(sandboxAttr);
231 JSObject* HTMLIFrameElement::WrapNode(JSContext* aCx,
232 JS::Handle<JSObject*> aGivenProto) {
233 return HTMLIFrameElement_Binding::Wrap(aCx, this, aGivenProto);
236 mozilla::dom::FeaturePolicy* HTMLIFrameElement::FeaturePolicy() const {
237 return mFeaturePolicy;
240 void HTMLIFrameElement::MaybeStoreCrossOriginFeaturePolicy() {
241 if (!mFrameLoader) {
242 return;
245 // If the browsingContext is not ready (because docshell is dead), don't try
246 // to create one.
247 if (!mFrameLoader->IsRemoteFrame() && !mFrameLoader->GetExistingDocShell()) {
248 return;
251 RefPtr<BrowsingContext> browsingContext = mFrameLoader->GetBrowsingContext();
253 if (!browsingContext || !browsingContext->IsContentSubframe()) {
254 return;
257 if (ContentChild* cc = ContentChild::GetSingleton()) {
258 Unused << cc->SendSetContainerFeaturePolicy(browsingContext,
259 mFeaturePolicy);
263 already_AddRefed<nsIPrincipal>
264 HTMLIFrameElement::GetFeaturePolicyDefaultOrigin() const {
265 nsCOMPtr<nsIPrincipal> principal;
267 if (HasAttr(nsGkAtoms::srcdoc)) {
268 principal = NodePrincipal();
269 return principal.forget();
272 nsCOMPtr<nsIURI> nodeURI;
273 if (GetURIAttr(nsGkAtoms::src, nullptr, getter_AddRefs(nodeURI)) && nodeURI) {
274 principal = BasePrincipal::CreateContentPrincipal(
275 nodeURI, BasePrincipal::Cast(NodePrincipal())->OriginAttributesRef());
278 if (!principal) {
279 principal = NodePrincipal();
282 return principal.forget();
285 void HTMLIFrameElement::RefreshFeaturePolicy(bool aParseAllowAttribute) {
286 if (aParseAllowAttribute) {
287 mFeaturePolicy->ResetDeclaredPolicy();
289 // The origin can change if 'src' and 'srcdoc' attributes change.
290 nsCOMPtr<nsIPrincipal> origin = GetFeaturePolicyDefaultOrigin();
291 MOZ_ASSERT(origin);
292 mFeaturePolicy->SetDefaultOrigin(origin);
294 nsAutoString allow;
295 GetAttr(nsGkAtoms::allow, allow);
297 if (!allow.IsEmpty()) {
298 // Set or reset the FeaturePolicy directives.
299 mFeaturePolicy->SetDeclaredPolicy(OwnerDoc(), allow, NodePrincipal(),
300 origin);
304 if (AllowFullscreen()) {
305 mFeaturePolicy->MaybeSetAllowedPolicy(u"fullscreen"_ns);
308 mFeaturePolicy->InheritPolicy(OwnerDoc()->FeaturePolicy());
309 MaybeStoreCrossOriginFeaturePolicy();
312 void HTMLIFrameElement::UpdateLazyLoadState() {
313 // Store current base URI and referrer policy in the lazy load state.
314 mLazyLoadState.mBaseURI = GetBaseURI();
315 mLazyLoadState.mReferrerPolicy = GetReferrerPolicyAsEnum();
318 nsresult HTMLIFrameElement::BindToTree(BindContext& aContext,
319 nsINode& aParent) {
320 // Update lazy load state on bind to tree again if lazy loading, as the
321 // loading attribute could be set before others.
322 if (mLazyLoading) {
323 UpdateLazyLoadState();
326 return nsGenericHTMLFrameElement::BindToTree(aContext, aParent);
329 void HTMLIFrameElement::SetLazyLoading() {
330 if (mLazyLoading) {
331 return;
334 if (!StaticPrefs::dom_iframe_lazy_loading_enabled()) {
335 return;
338 // https://html.spec.whatwg.org/multipage/urls-and-fetching.html#will-lazy-load-element-steps
339 // "If scripting is disabled for element, then return false."
340 Document* doc = OwnerDoc();
341 if (!doc->IsScriptEnabled() || doc->IsStaticDocument()) {
342 return;
345 doc->EnsureLazyLoadObserver().Observe(*this);
346 mLazyLoading = true;
348 UpdateLazyLoadState();
351 void HTMLIFrameElement::StopLazyLoading() {
352 if (!mLazyLoading) {
353 return;
356 mLazyLoading = false;
358 Document* doc = OwnerDoc();
359 if (auto* obs = doc->GetLazyLoadObserver()) {
360 obs->Unobserve(*this);
363 LoadSrc();
365 mLazyLoadState.Clear();
366 if (nsSubDocumentFrame* ourFrame = do_QueryFrame(GetPrimaryFrame())) {
367 ourFrame->ResetFrameLoader(nsSubDocumentFrame::RetainPaintData::No);
371 void HTMLIFrameElement::NodeInfoChanged(Document* aOldDoc) {
372 nsGenericHTMLElement::NodeInfoChanged(aOldDoc);
374 if (mLazyLoading) {
375 aOldDoc->GetLazyLoadObserver()->Unobserve(*this);
376 mLazyLoading = false;
377 SetLazyLoading();
381 } // namespace mozilla::dom