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"
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
,
37 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFrameLoader
)
38 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowserElementAPI
)
39 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
41 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsGenericHTMLFrameElement
,
43 if (tmp
->mFrameLoader
) {
44 tmp
->mFrameLoader
->Destroy();
47 NS_IMPL_CYCLE_COLLECTION_UNLINK(mFrameLoader
)
48 NS_IMPL_CYCLE_COLLECTION_UNLINK(mBrowserElementAPI
)
49 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
51 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(
52 nsGenericHTMLFrameElement
, nsGenericHTMLElement
, nsFrameLoaderOwner
,
53 nsIDOMMozBrowserFrame
, nsIMozBrowserFrame
, nsGenericHTMLFrameElement
)
56 nsGenericHTMLFrameElement::GetMozbrowser(bool* aValue
) {
57 *aValue
= GetBoolAttr(nsGkAtoms::mozbrowser
);
61 nsGenericHTMLFrameElement::SetMozbrowser(bool aValue
) {
62 return SetBoolAttr(nsGkAtoms::mozbrowser
, aValue
);
65 int32_t nsGenericHTMLFrameElement::TabIndexDefault() { return 0; }
67 nsGenericHTMLFrameElement::~nsGenericHTMLFrameElement() {
69 mFrameLoader
->Destroy();
73 Document
* nsGenericHTMLFrameElement::GetContentDocument(
74 nsIPrincipal
& aSubjectPrincipal
) {
75 RefPtr
<BrowsingContext
> bc
= GetContentWindowInternal();
80 nsPIDOMWindowOuter
* window
= bc
->GetDOMWindow();
82 // Either our browsing context contents are out-of-process (in which case
83 // clearly this is a cross-origin call and we should return null), or our
84 // browsing context is torn-down enough to no longer have a window or a
85 // document, and we should still return null.
88 Document
* doc
= window
->GetDoc();
93 // Return null for cross-origin contentDocument.
94 if (!aSubjectPrincipal
.SubsumesConsideringDomain(doc
->NodePrincipal())) {
100 BrowsingContext
* nsGenericHTMLFrameElement::GetContentWindowInternal() {
107 if (mFrameLoader
->DepthTooGreat()) {
108 // Claim to have no contentWindow
112 RefPtr
<BrowsingContext
> bc
= mFrameLoader
->GetBrowsingContext();
116 Nullable
<WindowProxyHolder
> nsGenericHTMLFrameElement::GetContentWindow() {
117 RefPtr
<BrowsingContext
> bc
= GetContentWindowInternal();
121 return WindowProxyHolder(bc
);
124 void nsGenericHTMLFrameElement::EnsureFrameLoader() {
125 if (!IsInComposedDoc() || mFrameLoader
|| OwnerDoc()->IsStaticDocument()) {
126 // If frame loader is there, we just keep it around, cached
130 // Strangely enough, this method doesn't actually ensure that the
131 // frameloader exists. It's more of a best-effort kind of thing.
132 mFrameLoader
= nsFrameLoader::Create(this, mNetworkCreated
);
135 void nsGenericHTMLFrameElement::SwapFrameLoaders(
136 HTMLIFrameElement
& aOtherLoaderOwner
, ErrorResult
& rv
) {
137 if (&aOtherLoaderOwner
== this) {
142 aOtherLoaderOwner
.SwapFrameLoaders(this, rv
);
145 void nsGenericHTMLFrameElement::SwapFrameLoaders(
146 XULFrameElement
& aOtherLoaderOwner
, ErrorResult
& rv
) {
147 aOtherLoaderOwner
.SwapFrameLoaders(this, rv
);
150 void nsGenericHTMLFrameElement::SwapFrameLoaders(
151 nsFrameLoaderOwner
* aOtherLoaderOwner
, mozilla::ErrorResult
& rv
) {
152 if (RefPtr
<Document
> doc
= GetComposedDoc()) {
153 // SwapWithOtherLoader relies on frames being up-to-date.
154 doc
->FlushPendingNotifications(FlushType::Frames
);
157 RefPtr
<nsFrameLoader
> loader
= GetFrameLoader();
158 RefPtr
<nsFrameLoader
> otherLoader
= aOtherLoaderOwner
->GetFrameLoader();
159 if (!loader
|| !otherLoader
) {
160 rv
.Throw(NS_ERROR_NOT_IMPLEMENTED
);
164 rv
= loader
->SwapWithOtherLoader(otherLoader
, this, aOtherLoaderOwner
);
167 void nsGenericHTMLFrameElement::LoadSrc() {
168 // Waiting for lazy load, do nothing.
179 bool origSrc
= !mSrcLoadHappened
;
180 mSrcLoadHappened
= true;
181 mFrameLoader
->LoadFrame(origSrc
);
184 nsresult
nsGenericHTMLFrameElement::BindToTree(BindContext
& aContext
,
186 nsresult rv
= nsGenericHTMLElement::BindToTree(aContext
, aParent
);
187 NS_ENSURE_SUCCESS(rv
, rv
);
189 if (IsInComposedDoc()) {
190 NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
191 "Missing a script blocker!");
193 AUTO_PROFILER_LABEL("nsGenericHTMLFrameElement::BindToTree", OTHER
);
195 // We're in a document now. Kick off the frame load.
199 // We're now in document and scripts may move us, so clear
200 // the mNetworkCreated flag.
201 mNetworkCreated
= false;
205 void nsGenericHTMLFrameElement::UnbindFromTree(UnbindContext
& aContext
) {
207 // This iframe is being taken out of the document, destroy the
208 // iframe's frame loader (doing that will tear down the window in
210 // XXXbz we really want to only partially destroy the frame
211 // loader... we don't want to tear down the docshell. Food for
213 mFrameLoader
->Destroy();
214 mFrameLoader
= nullptr;
217 nsGenericHTMLElement::UnbindFromTree(aContext
);
221 ScrollbarPreference
nsGenericHTMLFrameElement::MapScrollingAttribute(
222 const nsAttrValue
* aValue
) {
223 if (aValue
&& aValue
->Type() == nsAttrValue::eEnum
) {
224 auto scrolling
= static_cast<ScrollingAttribute
>(aValue
->GetEnumValue());
225 if (scrolling
== ScrollingAttribute::Off
||
226 scrolling
== ScrollingAttribute::Noscroll
||
227 scrolling
== ScrollingAttribute::No
) {
228 return ScrollbarPreference::Never
;
231 return ScrollbarPreference::Auto
;
235 void nsGenericHTMLFrameElement::AfterSetAttr(
236 int32_t aNameSpaceID
, nsAtom
* aName
, const nsAttrValue
* aValue
,
237 const nsAttrValue
* aOldValue
, nsIPrincipal
* aMaybeScriptedPrincipal
,
240 nsAttrValueOrString
value(aValue
);
241 AfterMaybeChangeAttr(aNameSpaceID
, aName
, &value
, aMaybeScriptedPrincipal
,
244 AfterMaybeChangeAttr(aNameSpaceID
, aName
, nullptr, aMaybeScriptedPrincipal
,
248 if (aNameSpaceID
== kNameSpaceID_None
) {
249 if (aName
== nsGkAtoms::scrolling
) {
251 ScrollbarPreference pref
= MapScrollingAttribute(aValue
);
252 if (nsDocShell
* docshell
= mFrameLoader
->GetExistingDocShell()) {
253 docshell
->SetScrollbarPreference(pref
);
254 } else if (auto* child
= mFrameLoader
->GetBrowserBridgeChild()) {
255 // NOTE(emilio): We intentionally don't deal with the
256 // GetBrowserParent() case, and only deal with the fission iframe
257 // case. We could make it work, but it's a bit of boilerplate for
258 // something that we don't use, and we'd need to think how it
259 // interacts with the scrollbar window flags...
260 child
->SendScrollbarPreferenceChanged(pref
);
263 } else if (aName
== nsGkAtoms::mozbrowser
) {
264 mReallyIsBrowser
= !!aValue
&& XRE_IsParentProcess() &&
265 NodePrincipal()->IsSystemPrincipal();
269 return nsGenericHTMLElement::AfterSetAttr(
270 aNameSpaceID
, aName
, aValue
, aOldValue
, aMaybeScriptedPrincipal
, aNotify
);
273 void nsGenericHTMLFrameElement::OnAttrSetButNotChanged(
274 int32_t aNamespaceID
, nsAtom
* aName
, const nsAttrValueOrString
& aValue
,
276 AfterMaybeChangeAttr(aNamespaceID
, aName
, &aValue
, nullptr, aNotify
);
278 return nsGenericHTMLElement::OnAttrSetButNotChanged(aNamespaceID
, aName
,
282 void nsGenericHTMLFrameElement::AfterMaybeChangeAttr(
283 int32_t aNamespaceID
, nsAtom
* aName
, const nsAttrValueOrString
* aValue
,
284 nsIPrincipal
* aMaybeScriptedPrincipal
, bool aNotify
) {
285 if (aNamespaceID
== kNameSpaceID_None
) {
286 if (aName
== nsGkAtoms::src
) {
287 mSrcTriggeringPrincipal
= nsContentUtils::GetAttrTriggeringPrincipal(
288 this, aValue
? aValue
->String() : u
""_ns
, aMaybeScriptedPrincipal
);
289 if (!IsHTMLElement(nsGkAtoms::iframe
) || !HasAttr(nsGkAtoms::srcdoc
)) {
290 // Don't propagate error here. The attribute was successfully
291 // set or removed; that's what we should reflect.
294 } else if (aName
== nsGkAtoms::name
) {
295 // Propagate "name" to the browsing context per HTML5.
296 RefPtr
<BrowsingContext
> bc
=
297 mFrameLoader
? mFrameLoader
->GetExtantBrowsingContext() : nullptr;
299 MOZ_ALWAYS_SUCCEEDS(bc
->SetName(aValue
? aValue
->String() : u
""_ns
));
305 void nsGenericHTMLFrameElement::DestroyContent() {
307 mFrameLoader
->Destroy();
308 mFrameLoader
= nullptr;
311 nsGenericHTMLElement::DestroyContent();
314 nsresult
nsGenericHTMLFrameElement::CopyInnerTo(Element
* aDest
) {
315 nsresult rv
= nsGenericHTMLElement::CopyInnerTo(aDest
);
316 NS_ENSURE_SUCCESS(rv
, rv
);
318 Document
* doc
= aDest
->OwnerDoc();
319 if (doc
->IsStaticDocument() && mFrameLoader
) {
320 nsGenericHTMLFrameElement
* dest
=
321 static_cast<nsGenericHTMLFrameElement
*>(aDest
);
322 doc
->AddPendingFrameStaticClone(dest
, mFrameLoader
);
328 bool nsGenericHTMLFrameElement::IsHTMLFocusable(bool aWithMouse
,
330 int32_t* aTabIndex
) {
331 if (nsGenericHTMLElement::IsHTMLFocusable(aWithMouse
, aIsFocusable
,
336 *aIsFocusable
= true;
341 * Return true if this frame element really is a mozbrowser. (It
342 * needs to have the right attributes, and its creator must have the right
346 nsresult
nsGenericHTMLFrameElement::GetReallyIsBrowser(bool* aOut
) {
347 *aOut
= mReallyIsBrowser
;
352 nsGenericHTMLFrameElement::InitializeBrowserAPI() {
353 MOZ_ASSERT(mFrameLoader
);
354 InitBrowserElementAPI();
359 nsGenericHTMLFrameElement::DestroyBrowserFrameScripts() {
360 MOZ_ASSERT(mFrameLoader
);
361 DestroyBrowserElementFrameScripts();