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/HTMLIFrameElement.h"
10 #include "mozilla/dom/XULFrameElement.h"
11 #include "mozilla/dom/WindowProxyHolder.h"
12 #include "mozilla/Preferences.h"
13 #include "mozilla/PresShell.h"
14 #include "mozilla/StaticPrefs.h"
15 #include "mozilla/ErrorResult.h"
16 #include "GeckoProfiler.h"
17 #include "nsAttrValueInlines.h"
18 #include "nsContentUtils.h"
19 #include "nsIDocShell.h"
21 #include "nsIInterfaceRequestorUtils.h"
22 #include "nsIPermissionManager.h"
23 #include "nsIScrollable.h"
24 #include "nsPresContext.h"
25 #include "nsServiceManagerUtils.h"
26 #include "nsSubDocumentFrame.h"
27 #include "nsAttrValueOrString.h"
29 using namespace mozilla
;
30 using namespace mozilla::dom
;
32 NS_IMPL_CYCLE_COLLECTION_CLASS(nsGenericHTMLFrameElement
)
34 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsGenericHTMLFrameElement
,
36 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFrameLoader
)
37 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOpenerWindow
)
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(mOpenerWindow
)
49 NS_IMPL_CYCLE_COLLECTION_UNLINK(mBrowserElementAPI
)
50 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
52 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(
53 nsGenericHTMLFrameElement
, nsGenericHTMLElement
, nsFrameLoaderOwner
,
54 nsIDOMMozBrowserFrame
, nsIMozBrowserFrame
, nsGenericHTMLFrameElement
)
57 nsGenericHTMLFrameElement::GetMozbrowser(bool* aValue
) {
58 *aValue
= GetBoolAttr(nsGkAtoms::mozbrowser
);
62 nsGenericHTMLFrameElement::SetMozbrowser(bool aValue
) {
63 return SetBoolAttr(nsGkAtoms::mozbrowser
, aValue
);
66 int32_t nsGenericHTMLFrameElement::TabIndexDefault() { return 0; }
68 nsGenericHTMLFrameElement::~nsGenericHTMLFrameElement() {
70 mFrameLoader
->Destroy();
74 Document
* nsGenericHTMLFrameElement::GetContentDocument(
75 nsIPrincipal
& aSubjectPrincipal
) {
76 RefPtr
<BrowsingContext
> bc
= GetContentWindowInternal();
81 nsPIDOMWindowOuter
* window
= bc
->GetDOMWindow();
83 // Either our browsing context contents are out-of-process (in which case
84 // clearly this is a cross-origin call and we should return null), or our
85 // browsing context is torn-down enough to no longer have a window or a
86 // document, and we should still return null.
89 Document
* doc
= window
->GetDoc();
94 // Return null for cross-origin contentDocument.
95 if (!aSubjectPrincipal
.SubsumesConsideringDomain(doc
->NodePrincipal())) {
101 BrowsingContext
* nsGenericHTMLFrameElement::GetContentWindowInternal() {
108 if (mFrameLoader
->DepthTooGreat()) {
109 // Claim to have no contentWindow
113 RefPtr
<BrowsingContext
> bc
= mFrameLoader
->GetBrowsingContext();
117 Nullable
<WindowProxyHolder
> nsGenericHTMLFrameElement::GetContentWindow() {
118 RefPtr
<BrowsingContext
> bc
= GetContentWindowInternal();
122 return WindowProxyHolder(bc
);
125 void nsGenericHTMLFrameElement::EnsureFrameLoader() {
126 if (!IsInComposedDoc() || mFrameLoader
|| mFrameLoaderCreationDisallowed
) {
127 // If frame loader is there, we just keep it around, cached
131 // Strangely enough, this method doesn't actually ensure that the
132 // frameloader exists. It's more of a best-effort kind of thing.
133 mFrameLoader
= nsFrameLoader::Create(this, mOpenerWindow
, mNetworkCreated
);
136 void nsGenericHTMLFrameElement::DisallowCreateFrameLoader() {
137 MOZ_ASSERT(!mFrameLoader
);
138 MOZ_ASSERT(!mFrameLoaderCreationDisallowed
);
139 mFrameLoaderCreationDisallowed
= true;
142 void nsGenericHTMLFrameElement::AllowCreateFrameLoader() {
143 MOZ_ASSERT(!mFrameLoader
);
144 MOZ_ASSERT(mFrameLoaderCreationDisallowed
);
145 mFrameLoaderCreationDisallowed
= false;
148 void nsGenericHTMLFrameElement::CreateRemoteFrameLoader(
149 BrowserParent
* aBrowserParent
) {
150 MOZ_ASSERT(!mFrameLoader
);
152 if (NS_WARN_IF(!mFrameLoader
)) {
155 mFrameLoader
->InitializeFromBrowserParent(aBrowserParent
);
157 if (nsSubDocumentFrame
* subdocFrame
= do_QueryFrame(GetPrimaryFrame())) {
158 // The reflow for this element already happened while we were waiting
159 // for the iframe creation. Therefore the subdoc frame didn't have a
160 // frameloader when UpdatePositionAndSize was supposed to be called in
161 // ReflowFinished, and we need to do it properly now.
162 mFrameLoader
->UpdatePositionAndSize(subdocFrame
);
166 void nsGenericHTMLFrameElement::PresetOpenerWindow(
167 const Nullable
<WindowProxyHolder
>& aOpenerWindow
, ErrorResult
& aRv
) {
168 MOZ_ASSERT(!mFrameLoader
);
170 aOpenerWindow
.IsNull() ? nullptr : aOpenerWindow
.Value().get();
173 void nsGenericHTMLFrameElement::SwapFrameLoaders(
174 HTMLIFrameElement
& aOtherLoaderOwner
, ErrorResult
& rv
) {
175 if (&aOtherLoaderOwner
== this) {
180 aOtherLoaderOwner
.SwapFrameLoaders(this, rv
);
183 void nsGenericHTMLFrameElement::SwapFrameLoaders(
184 XULFrameElement
& aOtherLoaderOwner
, ErrorResult
& rv
) {
185 aOtherLoaderOwner
.SwapFrameLoaders(this, rv
);
188 void nsGenericHTMLFrameElement::SwapFrameLoaders(
189 nsFrameLoaderOwner
* aOtherLoaderOwner
, mozilla::ErrorResult
& rv
) {
190 if (RefPtr
<Document
> doc
= GetComposedDoc()) {
191 // SwapWithOtherLoader relies on frames being up-to-date.
192 doc
->FlushPendingNotifications(FlushType::Frames
);
195 RefPtr
<nsFrameLoader
> loader
= GetFrameLoader();
196 RefPtr
<nsFrameLoader
> otherLoader
= aOtherLoaderOwner
->GetFrameLoader();
197 if (!loader
|| !otherLoader
) {
198 rv
.Throw(NS_ERROR_NOT_IMPLEMENTED
);
202 rv
= loader
->SwapWithOtherLoader(otherLoader
, this, aOtherLoaderOwner
);
205 void nsGenericHTMLFrameElement::LoadSrc() {
212 bool origSrc
= !mSrcLoadHappened
;
213 mSrcLoadHappened
= true;
214 mFrameLoader
->LoadFrame(origSrc
);
217 nsresult
nsGenericHTMLFrameElement::BindToTree(BindContext
& aContext
,
219 nsresult rv
= nsGenericHTMLElement::BindToTree(aContext
, aParent
);
220 NS_ENSURE_SUCCESS(rv
, rv
);
222 if (IsInComposedDoc()) {
223 NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
224 "Missing a script blocker!");
226 AUTO_PROFILER_LABEL("nsGenericHTMLFrameElement::BindToTree", OTHER
);
228 // We're in a document now. Kick off the frame load.
232 // We're now in document and scripts may move us, so clear
233 // the mNetworkCreated flag.
234 mNetworkCreated
= false;
238 void nsGenericHTMLFrameElement::UnbindFromTree(bool aNullParent
) {
240 // This iframe is being taken out of the document, destroy the
241 // iframe's frame loader (doing that will tear down the window in
243 // XXXbz we really want to only partially destroy the frame
244 // loader... we don't want to tear down the docshell. Food for
246 mFrameLoader
->Destroy();
247 mFrameLoader
= nullptr;
250 nsGenericHTMLElement::UnbindFromTree(aNullParent
);
254 int32_t nsGenericHTMLFrameElement::MapScrollingAttribute(
255 const nsAttrValue
* aValue
) {
256 int32_t mappedValue
= nsIScrollable::Scrollbar_Auto
;
257 if (aValue
&& aValue
->Type() == nsAttrValue::eEnum
) {
258 switch (aValue
->GetEnumValue()) {
259 case NS_STYLE_FRAME_OFF
:
260 case NS_STYLE_FRAME_NOSCROLL
:
261 case NS_STYLE_FRAME_NO
:
262 mappedValue
= nsIScrollable::Scrollbar_Never
;
269 static bool PrincipalAllowsBrowserFrame(nsIPrincipal
* aPrincipal
) {
270 nsCOMPtr
<nsIPermissionManager
> permMgr
=
271 mozilla::services::GetPermissionManager();
272 NS_ENSURE_TRUE(permMgr
, false);
273 uint32_t permission
= nsIPermissionManager::DENY_ACTION
;
274 nsresult rv
= permMgr
->TestPermissionFromPrincipal(
275 aPrincipal
, NS_LITERAL_CSTRING("browser"), &permission
);
276 NS_ENSURE_SUCCESS(rv
, false);
277 return permission
== nsIPermissionManager::ALLOW_ACTION
;
281 nsresult
nsGenericHTMLFrameElement::AfterSetAttr(
282 int32_t aNameSpaceID
, nsAtom
* aName
, const nsAttrValue
* aValue
,
283 const nsAttrValue
* aOldValue
, nsIPrincipal
* aMaybeScriptedPrincipal
,
286 nsAttrValueOrString
value(aValue
);
287 AfterMaybeChangeAttr(aNameSpaceID
, aName
, &value
, aMaybeScriptedPrincipal
,
290 AfterMaybeChangeAttr(aNameSpaceID
, aName
, nullptr, aMaybeScriptedPrincipal
,
294 if (aNameSpaceID
== kNameSpaceID_None
) {
295 if (aName
== nsGkAtoms::scrolling
) {
297 nsIDocShell
* docshell
= mFrameLoader
->GetExistingDocShell();
298 nsCOMPtr
<nsIScrollable
> scrollable
= do_QueryInterface(docshell
);
301 scrollable
->GetDefaultScrollbarPreferences(
302 nsIScrollable::ScrollOrientation_X
, &cur
);
303 int32_t val
= MapScrollingAttribute(aValue
);
305 scrollable
->SetDefaultScrollbarPreferences(
306 nsIScrollable::ScrollOrientation_X
, val
);
307 scrollable
->SetDefaultScrollbarPreferences(
308 nsIScrollable::ScrollOrientation_Y
, val
);
309 RefPtr
<nsPresContext
> presContext
= docshell
->GetPresContext();
310 PresShell
* presShell
=
311 presContext
? presContext
->GetPresShell() : nullptr;
312 nsIFrame
* rootScroll
=
313 presShell
? presShell
->GetRootScrollFrame() : nullptr;
315 presShell
->FrameNeedsReflow(
316 rootScroll
, IntrinsicDirty::StyleChange
, NS_FRAME_IS_DIRTY
);
321 } else if (aName
== nsGkAtoms::mozbrowser
) {
322 mReallyIsBrowser
= !!aValue
&&
323 StaticPrefs::dom_mozBrowserFramesEnabled() &&
324 PrincipalAllowsBrowserFrame(NodePrincipal());
328 return nsGenericHTMLElement::AfterSetAttr(
329 aNameSpaceID
, aName
, aValue
, aOldValue
, aMaybeScriptedPrincipal
, aNotify
);
332 nsresult
nsGenericHTMLFrameElement::OnAttrSetButNotChanged(
333 int32_t aNamespaceID
, nsAtom
* aName
, const nsAttrValueOrString
& aValue
,
335 AfterMaybeChangeAttr(aNamespaceID
, aName
, &aValue
, nullptr, aNotify
);
337 return nsGenericHTMLElement::OnAttrSetButNotChanged(aNamespaceID
, aName
,
341 void nsGenericHTMLFrameElement::AfterMaybeChangeAttr(
342 int32_t aNamespaceID
, nsAtom
* aName
, const nsAttrValueOrString
* aValue
,
343 nsIPrincipal
* aMaybeScriptedPrincipal
, bool aNotify
) {
344 if (aNamespaceID
== kNameSpaceID_None
) {
345 if (aName
== nsGkAtoms::src
) {
346 mSrcTriggeringPrincipal
= nsContentUtils::GetAttrTriggeringPrincipal(
347 this, aValue
? aValue
->String() : EmptyString(),
348 aMaybeScriptedPrincipal
);
349 if (!IsHTMLElement(nsGkAtoms::iframe
) ||
350 !HasAttr(kNameSpaceID_None
, nsGkAtoms::srcdoc
)) {
351 // Don't propagate error here. The attribute was successfully
352 // set or removed; that's what we should reflect.
355 } else if (aName
== nsGkAtoms::name
) {
356 // Propagate "name" to the docshell to make browsing context names live,
358 nsIDocShell
* docShell
=
359 mFrameLoader
? mFrameLoader
->GetExistingDocShell() : nullptr;
362 docShell
->SetName(aValue
->String());
364 docShell
->SetName(EmptyString());
371 void nsGenericHTMLFrameElement::DestroyContent() {
373 mFrameLoader
->Destroy();
374 mFrameLoader
= nullptr;
377 nsGenericHTMLElement::DestroyContent();
380 nsresult
nsGenericHTMLFrameElement::CopyInnerTo(Element
* aDest
) {
381 nsresult rv
= nsGenericHTMLElement::CopyInnerTo(aDest
);
382 NS_ENSURE_SUCCESS(rv
, rv
);
384 Document
* doc
= aDest
->OwnerDoc();
385 if (doc
->IsStaticDocument() && mFrameLoader
) {
386 nsGenericHTMLFrameElement
* dest
=
387 static_cast<nsGenericHTMLFrameElement
*>(aDest
);
388 nsFrameLoader
* fl
= nsFrameLoader::Create(dest
, nullptr, false);
390 dest
->mFrameLoader
= fl
;
391 mFrameLoader
->CreateStaticClone(fl
);
397 bool nsGenericHTMLFrameElement::IsHTMLFocusable(bool aWithMouse
,
399 int32_t* aTabIndex
) {
400 if (nsGenericHTMLElement::IsHTMLFocusable(aWithMouse
, aIsFocusable
,
405 *aIsFocusable
= nsContentUtils::IsSubDocumentTabbable(this);
407 if (!*aIsFocusable
&& aTabIndex
) {
415 * Return true if this frame element really is a mozbrowser. (It
416 * needs to have the right attributes, and its creator must have the right
420 nsresult
nsGenericHTMLFrameElement::GetReallyIsBrowser(bool* aOut
) {
421 *aOut
= mReallyIsBrowser
;
426 NS_IMETHODIMP
nsGenericHTMLFrameElement::GetIsolated(bool* aOut
) {
429 if (!nsContentUtils::IsSystemPrincipal(NodePrincipal())) {
433 // Isolation is only disabled if the attribute is present
434 *aOut
= !HasAttr(kNameSpaceID_None
, nsGkAtoms::noisolation
);
439 nsGenericHTMLFrameElement::InitializeBrowserAPI() {
440 MOZ_ASSERT(mFrameLoader
);
441 InitBrowserElementAPI();
446 nsGenericHTMLFrameElement::DestroyBrowserFrameScripts() {
447 MOZ_ASSERT(mFrameLoader
);
448 DestroyBrowserElementFrameScripts();