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