Bug 1554951 [wpt PR 17043] - wake-lock: Fix invalid types test in wakelock-type.https...
[gecko.git] / dom / html / nsGenericHTMLFrameElement.cpp
blob028073d30c7e0c9f465230e6e32db0ca75e781ca
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"
20 #include "nsIFrame.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,
35 nsGenericHTMLElement)
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,
42 nsGenericHTMLElement)
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)
56 NS_IMETHODIMP
57 nsGenericHTMLFrameElement::GetMozbrowser(bool* aValue) {
58 *aValue = GetBoolAttr(nsGkAtoms::mozbrowser);
59 return NS_OK;
61 NS_IMETHODIMP
62 nsGenericHTMLFrameElement::SetMozbrowser(bool aValue) {
63 return SetBoolAttr(nsGkAtoms::mozbrowser, aValue);
66 int32_t nsGenericHTMLFrameElement::TabIndexDefault() { return 0; }
68 nsGenericHTMLFrameElement::~nsGenericHTMLFrameElement() {
69 if (mFrameLoader) {
70 mFrameLoader->Destroy();
74 Document* nsGenericHTMLFrameElement::GetContentDocument(
75 nsIPrincipal& aSubjectPrincipal) {
76 RefPtr<BrowsingContext> bc = GetContentWindowInternal();
77 if (!bc) {
78 return nullptr;
81 nsPIDOMWindowOuter* window = bc->GetDOMWindow();
82 if (!window) {
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.
87 return nullptr;
89 Document* doc = window->GetDoc();
90 if (!doc) {
91 return nullptr;
94 // Return null for cross-origin contentDocument.
95 if (!aSubjectPrincipal.SubsumesConsideringDomain(doc->NodePrincipal())) {
96 return nullptr;
98 return doc;
101 BrowsingContext* nsGenericHTMLFrameElement::GetContentWindowInternal() {
102 EnsureFrameLoader();
104 if (!mFrameLoader) {
105 return nullptr;
108 if (mFrameLoader->DepthTooGreat()) {
109 // Claim to have no contentWindow
110 return nullptr;
113 RefPtr<BrowsingContext> bc = mFrameLoader->GetBrowsingContext();
114 return bc;
117 Nullable<WindowProxyHolder> nsGenericHTMLFrameElement::GetContentWindow() {
118 RefPtr<BrowsingContext> bc = GetContentWindowInternal();
119 if (!bc) {
120 return nullptr;
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
128 return;
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);
151 EnsureFrameLoader();
152 if (NS_WARN_IF(!mFrameLoader)) {
153 return;
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);
169 mOpenerWindow =
170 aOpenerWindow.IsNull() ? nullptr : aOpenerWindow.Value().get();
173 void nsGenericHTMLFrameElement::SwapFrameLoaders(
174 HTMLIFrameElement& aOtherLoaderOwner, ErrorResult& rv) {
175 if (&aOtherLoaderOwner == this) {
176 // nothing to do
177 return;
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);
199 return;
202 rv = loader->SwapWithOtherLoader(otherLoader, this, aOtherLoaderOwner);
205 void nsGenericHTMLFrameElement::LoadSrc() {
206 EnsureFrameLoader();
208 if (!mFrameLoader) {
209 return;
212 bool origSrc = !mSrcLoadHappened;
213 mSrcLoadHappened = true;
214 mFrameLoader->LoadFrame(origSrc);
217 nsresult nsGenericHTMLFrameElement::BindToTree(BindContext& aContext,
218 nsINode& aParent) {
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.
229 LoadSrc();
232 // We're now in document and scripts may move us, so clear
233 // the mNetworkCreated flag.
234 mNetworkCreated = false;
235 return rv;
238 void nsGenericHTMLFrameElement::UnbindFromTree(bool aNullParent) {
239 if (mFrameLoader) {
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
242 // this iframe).
243 // XXXbz we really want to only partially destroy the frame
244 // loader... we don't want to tear down the docshell. Food for
245 // later bug.
246 mFrameLoader->Destroy();
247 mFrameLoader = nullptr;
250 nsGenericHTMLElement::UnbindFromTree(aNullParent);
253 /* static */
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;
263 break;
266 return mappedValue;
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;
280 /* virtual */
281 nsresult nsGenericHTMLFrameElement::AfterSetAttr(
282 int32_t aNameSpaceID, nsAtom* aName, const nsAttrValue* aValue,
283 const nsAttrValue* aOldValue, nsIPrincipal* aMaybeScriptedPrincipal,
284 bool aNotify) {
285 if (aValue) {
286 nsAttrValueOrString value(aValue);
287 AfterMaybeChangeAttr(aNameSpaceID, aName, &value, aMaybeScriptedPrincipal,
288 aNotify);
289 } else {
290 AfterMaybeChangeAttr(aNameSpaceID, aName, nullptr, aMaybeScriptedPrincipal,
291 aNotify);
294 if (aNameSpaceID == kNameSpaceID_None) {
295 if (aName == nsGkAtoms::scrolling) {
296 if (mFrameLoader) {
297 nsIDocShell* docshell = mFrameLoader->GetExistingDocShell();
298 nsCOMPtr<nsIScrollable> scrollable = do_QueryInterface(docshell);
299 if (scrollable) {
300 int32_t cur;
301 scrollable->GetDefaultScrollbarPreferences(
302 nsIScrollable::ScrollOrientation_X, &cur);
303 int32_t val = MapScrollingAttribute(aValue);
304 if (cur != val) {
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;
314 if (rootScroll) {
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,
334 bool aNotify) {
335 AfterMaybeChangeAttr(aNamespaceID, aName, &aValue, nullptr, aNotify);
337 return nsGenericHTMLElement::OnAttrSetButNotChanged(aNamespaceID, aName,
338 aValue, aNotify);
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.
353 LoadSrc();
355 } else if (aName == nsGkAtoms::name) {
356 // Propagate "name" to the docshell to make browsing context names live,
357 // per HTML5.
358 nsIDocShell* docShell =
359 mFrameLoader ? mFrameLoader->GetExistingDocShell() : nullptr;
360 if (docShell) {
361 if (aValue) {
362 docShell->SetName(aValue->String());
363 } else {
364 docShell->SetName(EmptyString());
371 void nsGenericHTMLFrameElement::DestroyContent() {
372 if (mFrameLoader) {
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);
389 NS_ENSURE_STATE(fl);
390 dest->mFrameLoader = fl;
391 mFrameLoader->CreateStaticClone(fl);
394 return rv;
397 bool nsGenericHTMLFrameElement::IsHTMLFocusable(bool aWithMouse,
398 bool* aIsFocusable,
399 int32_t* aTabIndex) {
400 if (nsGenericHTMLElement::IsHTMLFocusable(aWithMouse, aIsFocusable,
401 aTabIndex)) {
402 return true;
405 *aIsFocusable = nsContentUtils::IsSubDocumentTabbable(this);
407 if (!*aIsFocusable && aTabIndex) {
408 *aTabIndex = -1;
411 return false;
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
417 * permissions.)
419 /* [infallible] */
420 nsresult nsGenericHTMLFrameElement::GetReallyIsBrowser(bool* aOut) {
421 *aOut = mReallyIsBrowser;
422 return NS_OK;
425 /* [infallible] */
426 NS_IMETHODIMP nsGenericHTMLFrameElement::GetIsolated(bool* aOut) {
427 *aOut = true;
429 if (!nsContentUtils::IsSystemPrincipal(NodePrincipal())) {
430 return NS_OK;
433 // Isolation is only disabled if the attribute is present
434 *aOut = !HasAttr(kNameSpaceID_None, nsGkAtoms::noisolation);
435 return NS_OK;
438 NS_IMETHODIMP
439 nsGenericHTMLFrameElement::InitializeBrowserAPI() {
440 MOZ_ASSERT(mFrameLoader);
441 InitBrowserElementAPI();
442 return NS_OK;
445 NS_IMETHODIMP
446 nsGenericHTMLFrameElement::DestroyBrowserFrameScripts() {
447 MOZ_ASSERT(mFrameLoader);
448 DestroyBrowserElementFrameScripts();
449 return NS_OK;