summaryrefslogtreecommitdiffstats
path: root/dom/html/nsGenericHTMLFrameElement.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/html/nsGenericHTMLFrameElement.cpp')
-rw-r--r--dom/html/nsGenericHTMLFrameElement.cpp359
1 files changed, 359 insertions, 0 deletions
diff --git a/dom/html/nsGenericHTMLFrameElement.cpp b/dom/html/nsGenericHTMLFrameElement.cpp
new file mode 100644
index 0000000000..2a015d2c6c
--- /dev/null
+++ b/dom/html/nsGenericHTMLFrameElement.cpp
@@ -0,0 +1,359 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsGenericHTMLFrameElement.h"
+
+#include "mozilla/dom/Document.h"
+#include "mozilla/dom/HTMLIFrameElement.h"
+#include "mozilla/dom/XULFrameElement.h"
+#include "mozilla/dom/BrowserBridgeChild.h"
+#include "mozilla/dom/WindowProxyHolder.h"
+#include "mozilla/Preferences.h"
+#include "mozilla/PresShell.h"
+#include "mozilla/ProfilerLabels.h"
+#include "mozilla/StaticPrefs_dom.h"
+#include "mozilla/ErrorResult.h"
+#include "nsAttrValueInlines.h"
+#include "nsContentUtils.h"
+#include "nsIDocShell.h"
+#include "nsIFrame.h"
+#include "nsIInterfaceRequestorUtils.h"
+#include "nsIPermissionManager.h"
+#include "nsPresContext.h"
+#include "nsServiceManagerUtils.h"
+#include "nsSubDocumentFrame.h"
+#include "nsAttrValueOrString.h"
+
+using namespace mozilla;
+using namespace mozilla::dom;
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(nsGenericHTMLFrameElement)
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsGenericHTMLFrameElement,
+ nsGenericHTMLElement)
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFrameLoader)
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowserElementAPI)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsGenericHTMLFrameElement,
+ nsGenericHTMLElement)
+ if (tmp->mFrameLoader) {
+ tmp->mFrameLoader->Destroy();
+ }
+
+ NS_IMPL_CYCLE_COLLECTION_UNLINK(mFrameLoader)
+ NS_IMPL_CYCLE_COLLECTION_UNLINK(mBrowserElementAPI)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(
+ nsGenericHTMLFrameElement, nsGenericHTMLElement, nsFrameLoaderOwner,
+ nsIDOMMozBrowserFrame, nsIMozBrowserFrame, nsGenericHTMLFrameElement)
+
+NS_IMETHODIMP
+nsGenericHTMLFrameElement::GetMozbrowser(bool* aValue) {
+ *aValue = GetBoolAttr(nsGkAtoms::mozbrowser);
+ return NS_OK;
+}
+NS_IMETHODIMP
+nsGenericHTMLFrameElement::SetMozbrowser(bool aValue) {
+ return SetBoolAttr(nsGkAtoms::mozbrowser, aValue);
+}
+
+int32_t nsGenericHTMLFrameElement::TabIndexDefault() { return 0; }
+
+nsGenericHTMLFrameElement::~nsGenericHTMLFrameElement() {
+ if (mFrameLoader) {
+ mFrameLoader->Destroy();
+ }
+}
+
+Document* nsGenericHTMLFrameElement::GetContentDocument(
+ nsIPrincipal& aSubjectPrincipal) {
+ RefPtr<BrowsingContext> bc = GetContentWindowInternal();
+ if (!bc) {
+ return nullptr;
+ }
+
+ nsPIDOMWindowOuter* window = bc->GetDOMWindow();
+ if (!window) {
+ // Either our browsing context contents are out-of-process (in which case
+ // clearly this is a cross-origin call and we should return null), or our
+ // browsing context is torn-down enough to no longer have a window or a
+ // document, and we should still return null.
+ return nullptr;
+ }
+ Document* doc = window->GetDoc();
+ if (!doc) {
+ return nullptr;
+ }
+
+ // Return null for cross-origin contentDocument.
+ if (!aSubjectPrincipal.SubsumesConsideringDomain(doc->NodePrincipal())) {
+ return nullptr;
+ }
+ return doc;
+}
+
+BrowsingContext* nsGenericHTMLFrameElement::GetContentWindowInternal() {
+ EnsureFrameLoader();
+
+ if (!mFrameLoader) {
+ return nullptr;
+ }
+
+ if (mFrameLoader->DepthTooGreat()) {
+ // Claim to have no contentWindow
+ return nullptr;
+ }
+
+ RefPtr<BrowsingContext> bc = mFrameLoader->GetBrowsingContext();
+ return bc;
+}
+
+Nullable<WindowProxyHolder> nsGenericHTMLFrameElement::GetContentWindow() {
+ RefPtr<BrowsingContext> bc = GetContentWindowInternal();
+ if (!bc) {
+ return nullptr;
+ }
+ return WindowProxyHolder(bc);
+}
+
+void nsGenericHTMLFrameElement::EnsureFrameLoader() {
+ if (!IsInComposedDoc() || mFrameLoader || OwnerDoc()->IsStaticDocument()) {
+ // If frame loader is there, we just keep it around, cached
+ return;
+ }
+
+ // Strangely enough, this method doesn't actually ensure that the
+ // frameloader exists. It's more of a best-effort kind of thing.
+ mFrameLoader = nsFrameLoader::Create(this, mNetworkCreated);
+}
+
+void nsGenericHTMLFrameElement::SwapFrameLoaders(
+ HTMLIFrameElement& aOtherLoaderOwner, ErrorResult& rv) {
+ if (&aOtherLoaderOwner == this) {
+ // nothing to do
+ return;
+ }
+
+ aOtherLoaderOwner.SwapFrameLoaders(this, rv);
+}
+
+void nsGenericHTMLFrameElement::SwapFrameLoaders(
+ XULFrameElement& aOtherLoaderOwner, ErrorResult& rv) {
+ aOtherLoaderOwner.SwapFrameLoaders(this, rv);
+}
+
+void nsGenericHTMLFrameElement::SwapFrameLoaders(
+ nsFrameLoaderOwner* aOtherLoaderOwner, mozilla::ErrorResult& rv) {
+ if (RefPtr<Document> doc = GetComposedDoc()) {
+ // SwapWithOtherLoader relies on frames being up-to-date.
+ doc->FlushPendingNotifications(FlushType::Frames);
+ }
+
+ RefPtr<nsFrameLoader> loader = GetFrameLoader();
+ RefPtr<nsFrameLoader> otherLoader = aOtherLoaderOwner->GetFrameLoader();
+ if (!loader || !otherLoader) {
+ rv.Throw(NS_ERROR_NOT_IMPLEMENTED);
+ return;
+ }
+
+ rv = loader->SwapWithOtherLoader(otherLoader, this, aOtherLoaderOwner);
+}
+
+void nsGenericHTMLFrameElement::LoadSrc() {
+ EnsureFrameLoader();
+
+ if (!mFrameLoader) {
+ return;
+ }
+
+ bool origSrc = !mSrcLoadHappened;
+ mSrcLoadHappened = true;
+ mFrameLoader->LoadFrame(origSrc);
+}
+
+nsresult nsGenericHTMLFrameElement::BindToTree(BindContext& aContext,
+ nsINode& aParent) {
+ nsresult rv = nsGenericHTMLElement::BindToTree(aContext, aParent);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ if (IsInComposedDoc()) {
+ NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
+ "Missing a script blocker!");
+
+ AUTO_PROFILER_LABEL("nsGenericHTMLFrameElement::BindToTree", OTHER);
+
+ // We're in a document now. Kick off the frame load.
+ LoadSrc();
+ }
+
+ // We're now in document and scripts may move us, so clear
+ // the mNetworkCreated flag.
+ mNetworkCreated = false;
+ return rv;
+}
+
+void nsGenericHTMLFrameElement::UnbindFromTree(bool aNullParent) {
+ if (mFrameLoader) {
+ // This iframe is being taken out of the document, destroy the
+ // iframe's frame loader (doing that will tear down the window in
+ // this iframe).
+ // XXXbz we really want to only partially destroy the frame
+ // loader... we don't want to tear down the docshell. Food for
+ // later bug.
+ mFrameLoader->Destroy();
+ mFrameLoader = nullptr;
+ }
+
+ nsGenericHTMLElement::UnbindFromTree(aNullParent);
+}
+
+/* static */
+ScrollbarPreference nsGenericHTMLFrameElement::MapScrollingAttribute(
+ const nsAttrValue* aValue) {
+ if (aValue && aValue->Type() == nsAttrValue::eEnum) {
+ auto scrolling = static_cast<ScrollingAttribute>(aValue->GetEnumValue());
+ if (scrolling == ScrollingAttribute::Off ||
+ scrolling == ScrollingAttribute::Noscroll ||
+ scrolling == ScrollingAttribute::No) {
+ return ScrollbarPreference::Never;
+ }
+ }
+ return ScrollbarPreference::Auto;
+}
+
+/* virtual */
+void nsGenericHTMLFrameElement::AfterSetAttr(
+ int32_t aNameSpaceID, nsAtom* aName, const nsAttrValue* aValue,
+ const nsAttrValue* aOldValue, nsIPrincipal* aMaybeScriptedPrincipal,
+ bool aNotify) {
+ if (aValue) {
+ nsAttrValueOrString value(aValue);
+ AfterMaybeChangeAttr(aNameSpaceID, aName, &value, aMaybeScriptedPrincipal,
+ aNotify);
+ } else {
+ AfterMaybeChangeAttr(aNameSpaceID, aName, nullptr, aMaybeScriptedPrincipal,
+ aNotify);
+ }
+
+ if (aNameSpaceID == kNameSpaceID_None) {
+ if (aName == nsGkAtoms::scrolling) {
+ if (mFrameLoader) {
+ ScrollbarPreference pref = MapScrollingAttribute(aValue);
+ if (nsDocShell* docshell = mFrameLoader->GetExistingDocShell()) {
+ docshell->SetScrollbarPreference(pref);
+ } else if (auto* child = mFrameLoader->GetBrowserBridgeChild()) {
+ // NOTE(emilio): We intentionally don't deal with the
+ // GetBrowserParent() case, and only deal with the fission iframe
+ // case. We could make it work, but it's a bit of boilerplate for
+ // something that we don't use, and we'd need to think how it
+ // interacts with the scrollbar window flags...
+ child->SendScrollbarPreferenceChanged(pref);
+ }
+ }
+ } else if (aName == nsGkAtoms::mozbrowser) {
+ mReallyIsBrowser = !!aValue && XRE_IsParentProcess() &&
+ NodePrincipal()->IsSystemPrincipal();
+ }
+ }
+
+ return nsGenericHTMLElement::AfterSetAttr(
+ aNameSpaceID, aName, aValue, aOldValue, aMaybeScriptedPrincipal, aNotify);
+}
+
+void nsGenericHTMLFrameElement::OnAttrSetButNotChanged(
+ int32_t aNamespaceID, nsAtom* aName, const nsAttrValueOrString& aValue,
+ bool aNotify) {
+ AfterMaybeChangeAttr(aNamespaceID, aName, &aValue, nullptr, aNotify);
+
+ return nsGenericHTMLElement::OnAttrSetButNotChanged(aNamespaceID, aName,
+ aValue, aNotify);
+}
+
+void nsGenericHTMLFrameElement::AfterMaybeChangeAttr(
+ int32_t aNamespaceID, nsAtom* aName, const nsAttrValueOrString* aValue,
+ nsIPrincipal* aMaybeScriptedPrincipal, bool aNotify) {
+ if (aNamespaceID == kNameSpaceID_None) {
+ if (aName == nsGkAtoms::src) {
+ mSrcTriggeringPrincipal = nsContentUtils::GetAttrTriggeringPrincipal(
+ this, aValue ? aValue->String() : u""_ns, aMaybeScriptedPrincipal);
+ if (!IsHTMLElement(nsGkAtoms::iframe) ||
+ !HasAttr(kNameSpaceID_None, nsGkAtoms::srcdoc)) {
+ // Don't propagate error here. The attribute was successfully
+ // set or removed; that's what we should reflect.
+ LoadSrc();
+ }
+ } else if (aName == nsGkAtoms::name) {
+ // Propagate "name" to the browsing context per HTML5.
+ RefPtr<BrowsingContext> bc =
+ mFrameLoader ? mFrameLoader->GetExtantBrowsingContext() : nullptr;
+ if (bc) {
+ MOZ_ALWAYS_SUCCEEDS(bc->SetName(aValue ? aValue->String() : u""_ns));
+ }
+ }
+ }
+}
+
+void nsGenericHTMLFrameElement::DestroyContent() {
+ if (mFrameLoader) {
+ mFrameLoader->Destroy();
+ mFrameLoader = nullptr;
+ }
+
+ nsGenericHTMLElement::DestroyContent();
+}
+
+nsresult nsGenericHTMLFrameElement::CopyInnerTo(Element* aDest) {
+ nsresult rv = nsGenericHTMLElement::CopyInnerTo(aDest);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ Document* doc = aDest->OwnerDoc();
+ if (doc->IsStaticDocument() && mFrameLoader) {
+ nsGenericHTMLFrameElement* dest =
+ static_cast<nsGenericHTMLFrameElement*>(aDest);
+ doc->AddPendingFrameStaticClone(dest, mFrameLoader);
+ }
+
+ return rv;
+}
+
+bool nsGenericHTMLFrameElement::IsHTMLFocusable(bool aWithMouse,
+ bool* aIsFocusable,
+ int32_t* aTabIndex) {
+ if (nsGenericHTMLElement::IsHTMLFocusable(aWithMouse, aIsFocusable,
+ aTabIndex)) {
+ return true;
+ }
+
+ *aIsFocusable = true;
+ return false;
+}
+
+/**
+ * Return true if this frame element really is a mozbrowser. (It
+ * needs to have the right attributes, and its creator must have the right
+ * permissions.)
+ */
+/* [infallible] */
+nsresult nsGenericHTMLFrameElement::GetReallyIsBrowser(bool* aOut) {
+ *aOut = mReallyIsBrowser;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsGenericHTMLFrameElement::InitializeBrowserAPI() {
+ MOZ_ASSERT(mFrameLoader);
+ InitBrowserElementAPI();
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsGenericHTMLFrameElement::DestroyBrowserFrameScripts() {
+ MOZ_ASSERT(mFrameLoader);
+ DestroyBrowserElementFrameScripts();
+ return NS_OK;
+}