Bug 1880216 - Migrate Fenix docs into Sphinx. r=owlish,geckoview-reviewers,android...
[gecko.git] / dom / html / nsGenericHTMLFrameElement.cpp
blob92591d7b72eefdecfa28c614a530bbffd743475f
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 file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "nsGenericHTMLFrameElement.h"
9 #include "mozilla/dom/Document.h"
10 #include "mozilla/dom/HTMLIFrameElement.h"
11 #include "mozilla/dom/XULFrameElement.h"
12 #include "mozilla/dom/BrowserBridgeChild.h"
13 #include "mozilla/dom/WindowProxyHolder.h"
14 #include "mozilla/Preferences.h"
15 #include "mozilla/PresShell.h"
16 #include "mozilla/ProfilerLabels.h"
17 #include "mozilla/StaticPrefs_dom.h"
18 #include "mozilla/ErrorResult.h"
19 #include "nsAttrValueInlines.h"
20 #include "nsContentUtils.h"
21 #include "nsIDocShell.h"
22 #include "nsIFrame.h"
23 #include "nsIInterfaceRequestorUtils.h"
24 #include "nsIPermissionManager.h"
25 #include "nsPresContext.h"
26 #include "nsServiceManagerUtils.h"
27 #include "nsSubDocumentFrame.h"
28 #include "nsAttrValueOrString.h"
30 using namespace mozilla;
31 using namespace mozilla::dom;
33 NS_IMPL_CYCLE_COLLECTION_CLASS(nsGenericHTMLFrameElement)
35 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsGenericHTMLFrameElement,
36 nsGenericHTMLElement)
37 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFrameLoader)
38 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
40 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsGenericHTMLFrameElement,
41 nsGenericHTMLElement)
42 if (tmp->mFrameLoader) {
43 tmp->mFrameLoader->Destroy();
46 NS_IMPL_CYCLE_COLLECTION_UNLINK(mFrameLoader)
47 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
49 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(nsGenericHTMLFrameElement,
50 nsGenericHTMLElement,
51 nsFrameLoaderOwner,
52 nsGenericHTMLFrameElement)
54 int32_t nsGenericHTMLFrameElement::TabIndexDefault() { return 0; }
56 nsGenericHTMLFrameElement::~nsGenericHTMLFrameElement() {
57 if (mFrameLoader) {
58 mFrameLoader->Destroy();
62 Document* nsGenericHTMLFrameElement::GetContentDocument(
63 nsIPrincipal& aSubjectPrincipal) {
64 RefPtr<BrowsingContext> bc = GetContentWindowInternal();
65 if (!bc) {
66 return nullptr;
69 nsPIDOMWindowOuter* window = bc->GetDOMWindow();
70 if (!window) {
71 // Either our browsing context contents are out-of-process (in which case
72 // clearly this is a cross-origin call and we should return null), or our
73 // browsing context is torn-down enough to no longer have a window or a
74 // document, and we should still return null.
75 return nullptr;
77 Document* doc = window->GetDoc();
78 if (!doc) {
79 return nullptr;
82 // Return null for cross-origin contentDocument.
83 if (!aSubjectPrincipal.SubsumesConsideringDomain(doc->NodePrincipal())) {
84 return nullptr;
86 return doc;
89 BrowsingContext* nsGenericHTMLFrameElement::GetContentWindowInternal() {
90 EnsureFrameLoader();
92 if (!mFrameLoader) {
93 return nullptr;
96 if (mFrameLoader->DepthTooGreat()) {
97 // Claim to have no contentWindow
98 return nullptr;
101 RefPtr<BrowsingContext> bc = mFrameLoader->GetBrowsingContext();
102 return bc;
105 Nullable<WindowProxyHolder> nsGenericHTMLFrameElement::GetContentWindow() {
106 RefPtr<BrowsingContext> bc = GetContentWindowInternal();
107 if (!bc) {
108 return nullptr;
110 return WindowProxyHolder(bc);
113 void nsGenericHTMLFrameElement::EnsureFrameLoader() {
114 if (!IsInComposedDoc() || mFrameLoader || OwnerDoc()->IsStaticDocument()) {
115 // If frame loader is there, we just keep it around, cached
116 return;
119 // Strangely enough, this method doesn't actually ensure that the
120 // frameloader exists. It's more of a best-effort kind of thing.
121 mFrameLoader = nsFrameLoader::Create(this, mNetworkCreated);
124 void nsGenericHTMLFrameElement::SwapFrameLoaders(
125 HTMLIFrameElement& aOtherLoaderOwner, ErrorResult& rv) {
126 if (&aOtherLoaderOwner == this) {
127 // nothing to do
128 return;
131 aOtherLoaderOwner.SwapFrameLoaders(this, rv);
134 void nsGenericHTMLFrameElement::SwapFrameLoaders(
135 XULFrameElement& aOtherLoaderOwner, ErrorResult& rv) {
136 aOtherLoaderOwner.SwapFrameLoaders(this, rv);
139 void nsGenericHTMLFrameElement::SwapFrameLoaders(
140 nsFrameLoaderOwner* aOtherLoaderOwner, mozilla::ErrorResult& rv) {
141 if (RefPtr<Document> doc = GetComposedDoc()) {
142 // SwapWithOtherLoader relies on frames being up-to-date.
143 doc->FlushPendingNotifications(FlushType::Frames);
146 RefPtr<nsFrameLoader> loader = GetFrameLoader();
147 RefPtr<nsFrameLoader> otherLoader = aOtherLoaderOwner->GetFrameLoader();
148 if (!loader || !otherLoader) {
149 rv.Throw(NS_ERROR_NOT_IMPLEMENTED);
150 return;
153 rv = loader->SwapWithOtherLoader(otherLoader, this, aOtherLoaderOwner);
156 void nsGenericHTMLFrameElement::LoadSrc() {
157 // Waiting for lazy load, do nothing.
158 if (mLazyLoading) {
159 return;
162 EnsureFrameLoader();
164 if (!mFrameLoader) {
165 return;
168 bool origSrc = !mSrcLoadHappened;
169 mSrcLoadHappened = true;
170 mFrameLoader->LoadFrame(origSrc);
173 nsresult nsGenericHTMLFrameElement::BindToTree(BindContext& aContext,
174 nsINode& aParent) {
175 nsresult rv = nsGenericHTMLElement::BindToTree(aContext, aParent);
176 NS_ENSURE_SUCCESS(rv, rv);
178 if (IsInComposedDoc()) {
179 NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
180 "Missing a script blocker!");
182 AUTO_PROFILER_LABEL("nsGenericHTMLFrameElement::BindToTree", OTHER);
184 // We're in a document now. Kick off the frame load.
185 LoadSrc();
188 // We're now in document and scripts may move us, so clear
189 // the mNetworkCreated flag.
190 mNetworkCreated = false;
191 return rv;
194 void nsGenericHTMLFrameElement::UnbindFromTree(UnbindContext& aContext) {
195 if (mFrameLoader) {
196 // This iframe is being taken out of the document, destroy the
197 // iframe's frame loader (doing that will tear down the window in
198 // this iframe).
199 // XXXbz we really want to only partially destroy the frame
200 // loader... we don't want to tear down the docshell. Food for
201 // later bug.
202 mFrameLoader->Destroy();
203 mFrameLoader = nullptr;
206 nsGenericHTMLElement::UnbindFromTree(aContext);
209 /* static */
210 ScrollbarPreference nsGenericHTMLFrameElement::MapScrollingAttribute(
211 const nsAttrValue* aValue) {
212 if (aValue && aValue->Type() == nsAttrValue::eEnum) {
213 auto scrolling = static_cast<ScrollingAttribute>(aValue->GetEnumValue());
214 if (scrolling == ScrollingAttribute::Off ||
215 scrolling == ScrollingAttribute::Noscroll ||
216 scrolling == ScrollingAttribute::No) {
217 return ScrollbarPreference::Never;
220 return ScrollbarPreference::Auto;
223 /* virtual */
224 void nsGenericHTMLFrameElement::AfterSetAttr(
225 int32_t aNameSpaceID, nsAtom* aName, const nsAttrValue* aValue,
226 const nsAttrValue* aOldValue, nsIPrincipal* aMaybeScriptedPrincipal,
227 bool aNotify) {
228 if (aValue) {
229 nsAttrValueOrString value(aValue);
230 AfterMaybeChangeAttr(aNameSpaceID, aName, &value, aMaybeScriptedPrincipal,
231 aNotify);
232 } else {
233 AfterMaybeChangeAttr(aNameSpaceID, aName, nullptr, aMaybeScriptedPrincipal,
234 aNotify);
237 if (aNameSpaceID == kNameSpaceID_None) {
238 if (aName == nsGkAtoms::scrolling) {
239 if (mFrameLoader) {
240 ScrollbarPreference pref = MapScrollingAttribute(aValue);
241 if (nsDocShell* docshell = mFrameLoader->GetExistingDocShell()) {
242 docshell->SetScrollbarPreference(pref);
243 } else if (auto* child = mFrameLoader->GetBrowserBridgeChild()) {
244 // NOTE(emilio): We intentionally don't deal with the
245 // GetBrowserParent() case, and only deal with the fission iframe
246 // case. We could make it work, but it's a bit of boilerplate for
247 // something that we don't use, and we'd need to think how it
248 // interacts with the scrollbar window flags...
249 child->SendScrollbarPreferenceChanged(pref);
255 return nsGenericHTMLElement::AfterSetAttr(
256 aNameSpaceID, aName, aValue, aOldValue, aMaybeScriptedPrincipal, aNotify);
259 void nsGenericHTMLFrameElement::OnAttrSetButNotChanged(
260 int32_t aNamespaceID, nsAtom* aName, const nsAttrValueOrString& aValue,
261 bool aNotify) {
262 AfterMaybeChangeAttr(aNamespaceID, aName, &aValue, nullptr, aNotify);
264 return nsGenericHTMLElement::OnAttrSetButNotChanged(aNamespaceID, aName,
265 aValue, aNotify);
268 void nsGenericHTMLFrameElement::AfterMaybeChangeAttr(
269 int32_t aNamespaceID, nsAtom* aName, const nsAttrValueOrString* aValue,
270 nsIPrincipal* aMaybeScriptedPrincipal, bool aNotify) {
271 if (aNamespaceID == kNameSpaceID_None) {
272 if (aName == nsGkAtoms::src) {
273 mSrcTriggeringPrincipal = nsContentUtils::GetAttrTriggeringPrincipal(
274 this, aValue ? aValue->String() : u""_ns, aMaybeScriptedPrincipal);
275 if (!IsHTMLElement(nsGkAtoms::iframe) || !HasAttr(nsGkAtoms::srcdoc)) {
276 // Don't propagate error here. The attribute was successfully
277 // set or removed; that's what we should reflect.
278 LoadSrc();
280 } else if (aName == nsGkAtoms::name) {
281 // Propagate "name" to the browsing context per HTML5.
282 RefPtr<BrowsingContext> bc =
283 mFrameLoader ? mFrameLoader->GetExtantBrowsingContext() : nullptr;
284 if (bc) {
285 MOZ_ALWAYS_SUCCEEDS(bc->SetName(aValue ? aValue->String() : u""_ns));
291 void nsGenericHTMLFrameElement::DestroyContent() {
292 if (mFrameLoader) {
293 mFrameLoader->Destroy();
294 mFrameLoader = nullptr;
297 nsGenericHTMLElement::DestroyContent();
300 nsresult nsGenericHTMLFrameElement::CopyInnerTo(Element* aDest) {
301 nsresult rv = nsGenericHTMLElement::CopyInnerTo(aDest);
302 NS_ENSURE_SUCCESS(rv, rv);
304 Document* doc = aDest->OwnerDoc();
305 if (doc->IsStaticDocument() && mFrameLoader) {
306 nsGenericHTMLFrameElement* dest =
307 static_cast<nsGenericHTMLFrameElement*>(aDest);
308 doc->AddPendingFrameStaticClone(dest, mFrameLoader);
311 return rv;
314 bool nsGenericHTMLFrameElement::IsHTMLFocusable(bool aWithMouse,
315 bool* aIsFocusable,
316 int32_t* aTabIndex) {
317 if (nsGenericHTMLElement::IsHTMLFocusable(aWithMouse, aIsFocusable,
318 aTabIndex)) {
319 return true;
322 *aIsFocusable = true;
323 return false;