nsGenericHTMLFrameElement.cpp (11112B)
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/. */ 6 7 #include "nsGenericHTMLFrameElement.h" 8 9 #include "mozilla/ErrorResult.h" 10 #include "mozilla/Preferences.h" 11 #include "mozilla/PresShell.h" 12 #include "mozilla/ProfilerLabels.h" 13 #include "mozilla/StaticPrefs_dom.h" 14 #include "mozilla/dom/BrowserBridgeChild.h" 15 #include "mozilla/dom/Document.h" 16 #include "mozilla/dom/HTMLIFrameElement.h" 17 #include "mozilla/dom/UnbindContext.h" 18 #include "mozilla/dom/WindowProxyHolder.h" 19 #include "mozilla/dom/XULFrameElement.h" 20 #include "nsAttrValueInlines.h" 21 #include "nsAttrValueOrString.h" 22 #include "nsContentUtils.h" 23 #include "nsIDocShell.h" 24 #include "nsIFrame.h" 25 #include "nsIInterfaceRequestorUtils.h" 26 #include "nsIPermissionManager.h" 27 #include "nsPresContext.h" 28 #include "nsServiceManagerUtils.h" 29 #include "nsSubDocumentFrame.h" 30 31 using namespace mozilla; 32 using namespace mozilla::dom; 33 34 NS_IMPL_CYCLE_COLLECTION_CLASS(nsGenericHTMLFrameElement) 35 36 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsGenericHTMLFrameElement, 37 nsGenericHTMLElement) 38 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFrameLoader) 39 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END 40 41 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsGenericHTMLFrameElement, 42 nsGenericHTMLElement) 43 if (tmp->mFrameLoader) { 44 tmp->mFrameLoader->Destroy(); 45 } 46 47 NS_IMPL_CYCLE_COLLECTION_UNLINK(mFrameLoader) 48 NS_IMPL_CYCLE_COLLECTION_UNLINK_END 49 50 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(nsGenericHTMLFrameElement, 51 nsGenericHTMLElement, 52 nsFrameLoaderOwner, 53 nsGenericHTMLFrameElement) 54 55 int32_t nsGenericHTMLFrameElement::TabIndexDefault() { return 0; } 56 57 nsGenericHTMLFrameElement::~nsGenericHTMLFrameElement() { 58 if (mFrameLoader) { 59 mFrameLoader->Destroy(); 60 } 61 } 62 63 Document* nsGenericHTMLFrameElement::GetContentDocument( 64 nsIPrincipal& aSubjectPrincipal) { 65 RefPtr<BrowsingContext> bc = GetContentWindowInternal(); 66 if (!bc) { 67 return nullptr; 68 } 69 70 nsPIDOMWindowOuter* window = bc->GetDOMWindow(); 71 if (!window) { 72 // Either our browsing context contents are out-of-process (in which case 73 // clearly this is a cross-origin call and we should return null), or our 74 // browsing context is torn-down enough to no longer have a window or a 75 // document, and we should still return null. 76 return nullptr; 77 } 78 Document* doc = window->GetDoc(); 79 if (!doc) { 80 return nullptr; 81 } 82 83 // Return null for cross-origin contentDocument. 84 if (!aSubjectPrincipal.SubsumesConsideringDomain(doc->NodePrincipal())) { 85 return nullptr; 86 } 87 return doc; 88 } 89 90 BrowsingContext* nsGenericHTMLFrameElement::GetContentWindowInternal() { 91 EnsureFrameLoader(); 92 93 if (!mFrameLoader) { 94 return nullptr; 95 } 96 97 if (mFrameLoader->DepthTooGreat()) { 98 // Claim to have no contentWindow 99 return nullptr; 100 } 101 102 RefPtr<BrowsingContext> bc = mFrameLoader->GetBrowsingContext(); 103 return bc; 104 } 105 106 Nullable<WindowProxyHolder> nsGenericHTMLFrameElement::GetContentWindow() { 107 RefPtr<BrowsingContext> bc = GetContentWindowInternal(); 108 if (!bc) { 109 return nullptr; 110 } 111 return WindowProxyHolder(bc); 112 } 113 114 void nsGenericHTMLFrameElement::EnsureFrameLoader() { 115 if (!IsInComposedDoc() || mFrameLoader || OwnerDoc()->IsStaticDocument()) { 116 // If frame loader is there, we just keep it around, cached 117 return; 118 } 119 120 // Strangely enough, this method doesn't actually ensure that the 121 // frameloader exists. It's more of a best-effort kind of thing. 122 mFrameLoader = nsFrameLoader::Create(this, mNetworkCreated); 123 } 124 125 void nsGenericHTMLFrameElement::SwapFrameLoaders( 126 HTMLIFrameElement& aOtherLoaderOwner, ErrorResult& rv) { 127 if (&aOtherLoaderOwner == this) { 128 // nothing to do 129 return; 130 } 131 132 aOtherLoaderOwner.SwapFrameLoaders(this, rv); 133 } 134 135 void nsGenericHTMLFrameElement::SwapFrameLoaders( 136 XULFrameElement& aOtherLoaderOwner, ErrorResult& rv) { 137 aOtherLoaderOwner.SwapFrameLoaders(this, rv); 138 } 139 140 void nsGenericHTMLFrameElement::SwapFrameLoaders( 141 nsFrameLoaderOwner* aOtherLoaderOwner, mozilla::ErrorResult& rv) { 142 if (RefPtr<Document> doc = GetComposedDoc()) { 143 // SwapWithOtherLoader relies on frames being up-to-date. 144 doc->FlushPendingNotifications(FlushType::Frames); 145 } 146 147 RefPtr<nsFrameLoader> loader = GetFrameLoader(); 148 RefPtr<nsFrameLoader> otherLoader = aOtherLoaderOwner->GetFrameLoader(); 149 if (!loader || !otherLoader) { 150 rv.Throw(NS_ERROR_NOT_IMPLEMENTED); 151 return; 152 } 153 154 rv = loader->SwapWithOtherLoader(otherLoader, this, aOtherLoaderOwner); 155 } 156 157 void nsGenericHTMLFrameElement::LoadSrc() { 158 EnsureFrameLoader(); 159 160 if (!mFrameLoader) { 161 return; 162 } 163 164 if (mLazyLoading) { 165 // Waiting for lazy load, do nothing. 166 if (!mFrameLoader->GetExtantBrowsingContext()) { 167 // We still want to initialize the frame loader for the browsing 168 // context to exist, so that it can be found by name and such. 169 nsContentUtils::AddScriptRunner( 170 NewRunnableMethod("InitializeLazyFrameLoader", mFrameLoader.get(), 171 &nsFrameLoader::GetBrowsingContext)); 172 } 173 return; 174 } 175 176 bool origSrc = !mSrcLoadHappened; 177 mSrcLoadHappened = true; 178 mFrameLoader->LoadFrame(origSrc, /* aShouldCheckForRecursion */ true); 179 } 180 181 nsresult nsGenericHTMLFrameElement::BindToTree(BindContext& aContext, 182 nsINode& aParent) { 183 nsresult rv = nsGenericHTMLElement::BindToTree(aContext, aParent); 184 NS_ENSURE_SUCCESS(rv, rv); 185 186 if (IsInComposedDoc() && !mFrameLoader) { 187 NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(), 188 "Missing a script blocker!"); 189 190 AUTO_PROFILER_LABEL("nsGenericHTMLFrameElement::BindToTree", OTHER); 191 192 // We're in a document now. Kick off the frame load. 193 LoadSrc(); 194 } 195 196 // We're now in document and scripts may move us, so clear 197 // the mNetworkCreated flag. 198 mNetworkCreated = false; 199 return rv; 200 } 201 202 void nsGenericHTMLFrameElement::UnbindFromTree(UnbindContext& aContext) { 203 if (mFrameLoader && !aContext.IsMove()) { 204 // This iframe is being taken out of the document, destroy the 205 // iframe's frame loader (doing that will tear down the window in 206 // this iframe). 207 // XXXbz we really want to only partially destroy the frame 208 // loader... we don't want to tear down the docshell. Food for 209 // later bug. 210 mFrameLoader->Destroy(); 211 mFrameLoader = nullptr; 212 } 213 214 nsGenericHTMLElement::UnbindFromTree(aContext); 215 } 216 217 /* static */ 218 ScrollbarPreference nsGenericHTMLFrameElement::MapScrollingAttribute( 219 const nsAttrValue* aValue) { 220 if (aValue && aValue->Type() == nsAttrValue::eEnum) { 221 auto scrolling = static_cast<ScrollingAttribute>(aValue->GetEnumValue()); 222 if (scrolling == ScrollingAttribute::Off || 223 scrolling == ScrollingAttribute::Noscroll || 224 scrolling == ScrollingAttribute::No) { 225 return ScrollbarPreference::Never; 226 } 227 } 228 return ScrollbarPreference::Auto; 229 } 230 231 /* virtual */ 232 void nsGenericHTMLFrameElement::AfterSetAttr( 233 int32_t aNameSpaceID, nsAtom* aName, const nsAttrValue* aValue, 234 const nsAttrValue* aOldValue, nsIPrincipal* aMaybeScriptedPrincipal, 235 bool aNotify) { 236 if (aValue) { 237 nsAttrValueOrString value(aValue); 238 AfterMaybeChangeAttr(aNameSpaceID, aName, &value, aMaybeScriptedPrincipal, 239 aNotify); 240 } else { 241 AfterMaybeChangeAttr(aNameSpaceID, aName, nullptr, aMaybeScriptedPrincipal, 242 aNotify); 243 } 244 245 if (aNameSpaceID == kNameSpaceID_None) { 246 if (aName == nsGkAtoms::scrolling) { 247 if (mFrameLoader) { 248 ScrollbarPreference pref = MapScrollingAttribute(aValue); 249 if (nsDocShell* docshell = mFrameLoader->GetExistingDocShell()) { 250 docshell->SetScrollbarPreference(pref); 251 } else if (auto* child = mFrameLoader->GetBrowserBridgeChild()) { 252 // NOTE(emilio): We intentionally don't deal with the 253 // GetBrowserParent() case, and only deal with the fission iframe 254 // case. We could make it work, but it's a bit of boilerplate for 255 // something that we don't use, and we'd need to think how it 256 // interacts with the scrollbar window flags... 257 child->SendScrollbarPreferenceChanged(pref); 258 } 259 } 260 } 261 } 262 263 return nsGenericHTMLElement::AfterSetAttr( 264 aNameSpaceID, aName, aValue, aOldValue, aMaybeScriptedPrincipal, aNotify); 265 } 266 267 void nsGenericHTMLFrameElement::OnAttrSetButNotChanged( 268 int32_t aNamespaceID, nsAtom* aName, const nsAttrValueOrString& aValue, 269 bool aNotify) { 270 AfterMaybeChangeAttr(aNamespaceID, aName, &aValue, nullptr, aNotify); 271 272 return nsGenericHTMLElement::OnAttrSetButNotChanged(aNamespaceID, aName, 273 aValue, aNotify); 274 } 275 276 void nsGenericHTMLFrameElement::AfterMaybeChangeAttr( 277 int32_t aNamespaceID, nsAtom* aName, const nsAttrValueOrString* aValue, 278 nsIPrincipal* aMaybeScriptedPrincipal, bool aNotify) { 279 if (aNamespaceID == kNameSpaceID_None) { 280 if (aName == nsGkAtoms::src) { 281 mSrcTriggeringPrincipal = nsContentUtils::GetAttrTriggeringPrincipal( 282 this, aValue ? aValue->String() : u""_ns, aMaybeScriptedPrincipal); 283 if (!IsHTMLElement(nsGkAtoms::iframe) || !HasAttr(nsGkAtoms::srcdoc)) { 284 // Don't propagate error here. The attribute was successfully 285 // set or removed; that's what we should reflect. 286 LoadSrc(); 287 } 288 } else if (aName == nsGkAtoms::name) { 289 // Propagate "name" to the browsing context per HTML5. 290 RefPtr<BrowsingContext> bc = 291 mFrameLoader ? mFrameLoader->GetExtantBrowsingContext() : nullptr; 292 if (bc) { 293 MOZ_ALWAYS_SUCCEEDS(bc->SetName(aValue ? aValue->String() : u""_ns)); 294 } 295 } 296 } 297 } 298 299 void nsGenericHTMLFrameElement::DestroyContent() { 300 if (mFrameLoader) { 301 mFrameLoader->Destroy(); 302 mFrameLoader = nullptr; 303 } 304 305 nsGenericHTMLElement::DestroyContent(); 306 } 307 308 nsresult nsGenericHTMLFrameElement::CopyInnerTo(Element* aDest) { 309 nsresult rv = nsGenericHTMLElement::CopyInnerTo(aDest); 310 NS_ENSURE_SUCCESS(rv, rv); 311 312 Document* doc = aDest->OwnerDoc(); 313 if (doc->IsStaticDocument() && mFrameLoader) { 314 nsGenericHTMLFrameElement* dest = 315 static_cast<nsGenericHTMLFrameElement*>(aDest); 316 doc->AddPendingFrameStaticClone(dest, mFrameLoader); 317 } 318 319 return rv; 320 } 321 322 bool nsGenericHTMLFrameElement::IsHTMLFocusable(IsFocusableFlags aFlags, 323 bool* aIsFocusable, 324 int32_t* aTabIndex) { 325 if (nsGenericHTMLElement::IsHTMLFocusable(aFlags, aIsFocusable, aTabIndex)) { 326 return true; 327 } 328 329 *aIsFocusable = true; 330 return false; 331 }