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/. */
6 
7 #include "nsCOMPtr.h"
8 #include "nsIBrowser.h"
9 #include "nsIContent.h"
10 #include "nsIOpenWindowInfo.h"
11 #include "nsFrameLoader.h"
12 #include "mozilla/AsyncEventDispatcher.h"
13 #include "mozilla/dom/HTMLIFrameElement.h"
14 #include "mozilla/dom/WindowProxyHolder.h"
15 #include "mozilla/dom/XULFrameElement.h"
16 #include "mozilla/dom/XULFrameElementBinding.h"
17 
18 namespace mozilla {
19 namespace dom {
20 
21 NS_IMPL_CYCLE_COLLECTION_CLASS(XULFrameElement)
22 
23 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(XULFrameElement, nsXULElement)
24   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFrameLoader)
25   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOpenWindowInfo)
26 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
27 
28 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(XULFrameElement, nsXULElement)
29   if (tmp->mFrameLoader) {
30     tmp->mFrameLoader->Destroy();
31   }
NS_IMPL_CYCLE_COLLECTION_UNLINK(mOpenWindowInfo)32   NS_IMPL_CYCLE_COLLECTION_UNLINK(mOpenWindowInfo)
33 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
34 
35 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(XULFrameElement, nsXULElement,
36                                              nsFrameLoaderOwner)
37 
38 JSObject* XULFrameElement::WrapNode(JSContext* aCx,
39                                     JS::Handle<JSObject*> aGivenProto) {
40   return XULFrameElement_Binding::Wrap(aCx, this, aGivenProto);
41 }
42 
GetDocShell()43 nsDocShell* XULFrameElement::GetDocShell() {
44   RefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
45   return frameLoader ? frameLoader->GetDocShell(IgnoreErrors()) : nullptr;
46 }
47 
GetWebNavigation()48 already_AddRefed<nsIWebNavigation> XULFrameElement::GetWebNavigation() {
49   nsCOMPtr<nsIDocShell> docShell = GetDocShell();
50   nsCOMPtr<nsIWebNavigation> webnav = do_QueryInterface(docShell);
51   return webnav.forget();
52 }
53 
GetContentWindow()54 Nullable<WindowProxyHolder> XULFrameElement::GetContentWindow() {
55   RefPtr<nsDocShell> docShell = GetDocShell();
56   if (docShell) {
57     return docShell->GetWindowProxy();
58   }
59 
60   return nullptr;
61 }
62 
GetContentDocument()63 Document* XULFrameElement::GetContentDocument() {
64   nsCOMPtr<nsIDocShell> docShell = GetDocShell();
65   if (docShell) {
66     nsCOMPtr<nsPIDOMWindowOuter> win = docShell->GetWindow();
67     if (win) {
68       return win->GetDoc();
69     }
70   }
71   return nullptr;
72 }
73 
BrowserId()74 uint64_t XULFrameElement::BrowserId() {
75   if (mFrameLoader) {
76     if (auto* bc = mFrameLoader->GetExtantBrowsingContext()) {
77       return bc->GetBrowserId();
78     }
79   }
80   return 0;
81 }
82 
GetOpenWindowInfo() const83 nsIOpenWindowInfo* XULFrameElement::GetOpenWindowInfo() const {
84   return mOpenWindowInfo;
85 }
86 
SetOpenWindowInfo(nsIOpenWindowInfo * aInfo)87 void XULFrameElement::SetOpenWindowInfo(nsIOpenWindowInfo* aInfo) {
88   mOpenWindowInfo = aInfo;
89 }
90 
LoadSrc()91 void XULFrameElement::LoadSrc() {
92   if (!IsInUncomposedDoc() || !OwnerDoc()->GetRootElement()) {
93     return;
94   }
95   RefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
96   if (!frameLoader) {
97     // We may have had a nsIOpenWindowInfo set on us by browser chrome, due to
98     // being used as the target for a `window.open` call. Fetch that information
99     // if it's available, and clear it out so we don't read it again.
100     nsCOMPtr<nsIOpenWindowInfo> openWindowInfo = mOpenWindowInfo.forget();
101 
102     // false as the networkCreated parameter so that xul:iframe/browser/editor
103     // session history handling works like dynamic html:iframes. Usually xul
104     // elements are used in chrome, which doesn't have session history at all.
105     mFrameLoader = nsFrameLoader::Create(this, false, openWindowInfo);
106     if (NS_WARN_IF(!mFrameLoader)) {
107       return;
108     }
109 
110     (new AsyncEventDispatcher(this, u"XULFrameLoaderCreated"_ns,
111                               CanBubble::eYes))
112         ->RunDOMEventWhenSafe();
113   }
114 
115   mFrameLoader->LoadFrame(false);
116 }
117 
SwapFrameLoaders(HTMLIFrameElement & aOtherLoaderOwner,ErrorResult & rv)118 void XULFrameElement::SwapFrameLoaders(HTMLIFrameElement& aOtherLoaderOwner,
119                                        ErrorResult& rv) {
120   aOtherLoaderOwner.SwapFrameLoaders(this, rv);
121 }
122 
SwapFrameLoaders(XULFrameElement & aOtherLoaderOwner,ErrorResult & rv)123 void XULFrameElement::SwapFrameLoaders(XULFrameElement& aOtherLoaderOwner,
124                                        ErrorResult& rv) {
125   if (&aOtherLoaderOwner == this) {
126     // nothing to do
127     return;
128   }
129 
130   aOtherLoaderOwner.SwapFrameLoaders(this, rv);
131 }
132 
SwapFrameLoaders(nsFrameLoaderOwner * aOtherLoaderOwner,mozilla::ErrorResult & rv)133 void XULFrameElement::SwapFrameLoaders(nsFrameLoaderOwner* aOtherLoaderOwner,
134                                        mozilla::ErrorResult& rv) {
135   if (RefPtr<Document> doc = GetComposedDoc()) {
136     // SwapWithOtherLoader relies on frames being up-to-date.
137     doc->FlushPendingNotifications(FlushType::Frames);
138   }
139 
140   RefPtr<nsFrameLoader> loader = GetFrameLoader();
141   RefPtr<nsFrameLoader> otherLoader = aOtherLoaderOwner->GetFrameLoader();
142   if (!loader || !otherLoader) {
143     rv.Throw(NS_ERROR_NOT_IMPLEMENTED);
144     return;
145   }
146 
147   rv = loader->SwapWithOtherLoader(otherLoader, this, aOtherLoaderOwner);
148 }
149 
BindToTree(BindContext & aContext,nsINode & aParent)150 nsresult XULFrameElement::BindToTree(BindContext& aContext, nsINode& aParent) {
151   nsresult rv = nsXULElement::BindToTree(aContext, aParent);
152   NS_ENSURE_SUCCESS(rv, rv);
153 
154   if (IsInUncomposedDoc()) {
155     NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
156                  "Missing a script blocker!");
157     // We're in a document now.  Kick off the frame load.
158     LoadSrc();
159   }
160 
161   return NS_OK;
162 }
163 
UnbindFromTree(bool aNullParent)164 void XULFrameElement::UnbindFromTree(bool aNullParent) {
165   if (RefPtr<nsFrameLoader> frameLoader = GetFrameLoader()) {
166     frameLoader->Destroy();
167   }
168   mFrameLoader = nullptr;
169 
170   nsXULElement::UnbindFromTree(aNullParent);
171 }
172 
DestroyContent()173 void XULFrameElement::DestroyContent() {
174   RefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
175   if (frameLoader) {
176     frameLoader->Destroy();
177   }
178   mFrameLoader = nullptr;
179 
180   nsXULElement::DestroyContent();
181 }
182 
AfterSetAttr(int32_t aNamespaceID,nsAtom * aName,const nsAttrValue * aValue,const nsAttrValue * aOldValue,nsIPrincipal * aSubjectPrincipal,bool aNotify)183 nsresult XULFrameElement::AfterSetAttr(int32_t aNamespaceID, nsAtom* aName,
184                                        const nsAttrValue* aValue,
185                                        const nsAttrValue* aOldValue,
186                                        nsIPrincipal* aSubjectPrincipal,
187                                        bool aNotify) {
188   if (aNamespaceID == kNameSpaceID_None) {
189     if (aName == nsGkAtoms::src && aValue) {
190       LoadSrc();
191     } else if (aName == nsGkAtoms::disablefullscreen && mFrameLoader) {
192       if (auto* bc = mFrameLoader->GetExtantBrowsingContext()) {
193         MOZ_ALWAYS_SUCCEEDS(bc->SetFullscreenAllowedByOwner(!aValue));
194       }
195     }
196   }
197 
198   return nsXULElement::AfterSetAttr(aNamespaceID, aName, aValue, aOldValue,
199                                     aSubjectPrincipal, aNotify);
200 }
201 
202 }  // namespace dom
203 }  // namespace mozilla
204