From fbe086cd70c2d3f1bfd32fe6b4b9f4ef79f07fd6 Mon Sep 17 00:00:00 2001 From: "jst%netscape.com" Date: Tue, 29 Jan 2002 06:27:27 +0000 Subject: [PATCH] WIP for a new frame and iframe loader. Not part of the build yet. git-svn-id: svn://10.0.0.236/trunk@113102 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/content/base/src/nsFrameLoader.cpp | 533 +++++++++++++++++++++ 1 file changed, 533 insertions(+) create mode 100644 mozilla/content/base/src/nsFrameLoader.cpp diff --git a/mozilla/content/base/src/nsFrameLoader.cpp b/mozilla/content/base/src/nsFrameLoader.cpp new file mode 100644 index 00000000000..1a4e5c9f97d --- /dev/null +++ b/mozilla/content/base/src/nsFrameLoader.cpp @@ -0,0 +1,533 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: NPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Netscape Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Johnny Stenback (original author) + * + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the NPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the NPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsIFrameLoader.h" +#include "nsIDOMHTMLIFrameElement.h" +#include "nsIDOMHTMLFrameElement.h" +#include "nsIDOMEventListener.h" +#include "nsIDOMEventTarget.h" +#include "nsIDOMWindow.h" +#include "nsIPresContext.h" +#include "nsIPresShell.h" +#include "nsIDocument.h" +#include "nsIDOMDocument.h" +#include "nsIWebNavigation.h" +#include "nsIChromeEventHandler.h" +#include "nsIDocShell.h" +#include "nsIDocShellTreeItem.h" +#include "nsIDocShellTreeNode.h" +#include "nsIDocShellTreeOwner.h" +#include "nsIDocShellLoadInfo.h" +#include "nsIBaseWindow.h" +#include "nsIWebShell.h" +#include "nsIWebProgressListener.h" +#include "nsIWebProgress.h" +#include "nsWeakReference.h" + +#include "nsIScriptSecurityManager.h" +#include "nsICodebasePrincipal.h" + +#include "nsIURI.h" +#include "nsNetUtil.h" + +class nsFrameLoader : public nsIFrameLoader, + public nsIDOMEventListener, + public nsIWebProgressListener, + public nsSupportsWeakReference +{ +public: + nsFrameLoader(); + virtual ~nsFrameLoader(); + + // nsISupports + NS_DECL_ISUPPORTS + + // nsIFrameLoader + NS_IMETHOD Init(nsIDOMElement *aOwner); + NS_IMETHOD LoadURI(nsIURI *aURI); + NS_IMETHOD GetDocShell(nsIDocShell **aDocShell); + NS_IMETHOD Destroy(); + + // nsIDOMEventListener + NS_DECL_NSIDOMEVENTLISTENER + + // nsIWebProgressListener + NS_DECL_NSIWEBPROGRESSLISTENER + +protected: + nsresult GetPresContext(nsIPresContext **aPresContext); + nsresult EnsureDocShell(); + + nsCOMPtr mDocShell; + + nsCOMPtr mOwnerElement; + + nsCOMPtr mURI; +}; + +nsresult +NS_NewFrameLoader(nsIFrameLoader **aFrameLoader) +{ + *aFrameLoader = new nsFrameLoader(); + NS_ENSURE_TRUE(*aFrameLoader, NS_ERROR_OUT_OF_MEMORY); + + NS_ADDREF(*aFrameLoader); + + return NS_OK; +} + + +nsFrameLoader::nsFrameLoader() +{ + NS_INIT_ISUPPORTS(); +} + +nsFrameLoader::~nsFrameLoader() +{ + nsCOMPtr treeOwnerAsWin(do_QueryInterface(mDocShell)); + + if (treeOwnerAsWin) { + treeOwnerAsWin->Destroy(); + } +} + + +// QueryInterface implementation for nsFrameLoader +NS_INTERFACE_MAP_BEGIN(nsFrameLoader) + NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) + NS_INTERFACE_MAP_ENTRY(nsIFrameLoader) +NS_INTERFACE_MAP_END + + +NS_IMPL_ADDREF(nsFrameLoader); +NS_IMPL_RELEASE(nsFrameLoader); + +NS_IMETHODIMP +nsFrameLoader::Init(nsIDOMElement *aOwner) +{ + mOwnerElement = aOwner; + + return NS_OK; +} + +NS_IMETHODIMP +nsFrameLoader::LoadURI(nsIURI *aURI) +{ + mURI = aURI; + + nsresult rv = EnsureDocShell(); + + + // Prevent recursion + + + + // mCreatingViewer=PR_TRUE; + + + // Check for security + nsCOMPtr secMan = + do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr loadInfo; + mDocShell->CreateLoadInfo(getter_AddRefs(loadInfo)); + NS_ENSURE_TRUE(loadInfo, NS_ERROR_FAILURE); + + // Get referring URL + nsCOMPtr referrer; + nsCOMPtr principal; + rv = secMan->GetSubjectPrincipal(getter_AddRefs(principal)); + NS_ENSURE_SUCCESS(rv, rv); + + // If we were called from script, get the referring URL from the script + + if (principal) { + nsCOMPtr codebase(do_QueryInterface(principal)); + + if (codebase) { + rv = codebase->GetURI(getter_AddRefs(referrer)); + NS_ENSURE_SUCCESS(rv, rv); + } + + // Pass the script principal to the docshell + + loadInfo->SetOwner(principal); + } + + if (!referrer) { + // We're not being called form script, tell the docshell + // to inherit an owner from the current document. + + loadInfo->SetInheritOwner(PR_TRUE); + + nsCOMPtr dom_doc; + mOwnerElement->GetOwnerDocument(getter_AddRefs(dom_doc)); + nsCOMPtr doc(do_QueryInterface(dom_doc)); + + if (doc) { + doc->GetBaseURL(*getter_AddRefs(referrer)); + } + } + + loadInfo->SetReferrer(referrer); + + // Check if we are allowed to load absURL + rv = secMan->CheckLoadURI(referrer, mURI, + nsIScriptSecurityManager::STANDARD); + if (NS_FAILED(rv)) { + return rv; // We're not + } + + nsCOMPtr webProgress(do_GetInterface(mDocShell)); + + if (webProgress) { + webProgress->AddProgressListener(this); + } + + rv = mDocShell->LoadURI(mURI, loadInfo, nsIWebNavigation::LOAD_FLAGS_NONE); + NS_ASSERTION(NS_SUCCEEDED(rv), "failed to load URL"); + + return rv; +} + +NS_IMETHODIMP +nsFrameLoader::GetDocShell(nsIDocShell **aDocShell) +{ + EnsureDocShell(); + + *aDocShell = mDocShell; + NS_IF_ADDREF(*aDocShell); + + return NS_OK; +} + +NS_IMETHODIMP +nsFrameLoader::Destroy() +{ + return NS_OK; +} + +NS_IMETHODIMP +nsFrameLoader::HandleEvent(nsIDOMEvent *aEvent) +{ + + return NS_OK; +} + +nsresult +nsFrameLoader::GetPresContext(nsIPresContext **aPresContext) +{ + *aPresContext = nsnull; + + nsCOMPtr dom_doc; + mOwnerElement->GetOwnerDocument(getter_AddRefs(dom_doc)); + + nsCOMPtr doc(do_QueryInterface(dom_doc)); + + while (doc) { + nsCOMPtr presShell; + doc->GetShellAt(0, getter_AddRefs(presShell)); + + if (presShell) { + presShell->GetPresContext(aPresContext); + + return NS_OK; + } + + nsCOMPtr parent; + doc->GetParentDocument(getter_AddRefs(parent)); + + doc = parent; + } + + return NS_OK; +} + +nsresult +nsFrameLoader::EnsureDocShell() +{ + if (mDocShell) { + return NS_OK; + } + +#if 0 + + + + + // Bug 8065: Don't exceed some maximum depth in content frames + // (MAX_DEPTH_CONTENT_FRAMES) + PRInt32 depth = 0; + nsCOMPtr parentAsSupports; + aPresContext->GetContainer(getter_AddRefs(parentAsSupports)); + + if (parentAsSupports) { + nsCOMPtr parentAsItem = + do_QueryInterface(parentAsSupports); + + while (parentAsItem) { + ++depth; + + if (MAX_DEPTH_CONTENT_FRAMES < depth) + return NS_ERROR_UNEXPECTED; // Too deep, give up! (silently?) + + // Only count depth on content, not chrome. + // If we wanted to limit total depth, skip the following check: + PRInt32 parentType; + parentAsItem->GetItemType(&parentType); + + if (nsIDocShellTreeItem::typeContent == parentType) { + nsIDocShellTreeItem* temp = parentAsItem; + temp->GetParent(getter_AddRefs(parentAsItem)); + } else { + break; // we have exited content, stop counting, depth is OK! + } + } + } +#endif + + mDocShell = do_CreateInstance("@mozilla.org/webshell;1"); + NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE); + +#if 0 + // notify the pres shell that a docshell has been created + nsCOMPtr presShell; + aPresContext->GetShell(getter_AddRefs(presShell)); + + if (presShell) { + nsCOMPtr subShellAsSupports(do_QueryInterface(mDocShell)); + NS_ENSURE_TRUE(subShellAsSupports, NS_ERROR_FAILURE); + + presShell->SetSubShellFor(mContent, subShellAsSupports); + + // We need to be able to get back to the presShell to unset the + // subshell at destruction + mPresShellWeak = getter_AddRefs(NS_GetWeakReference(presShell)); + } +#endif + + nsCOMPtr docShellAsItem(do_QueryInterface(mDocShell)); + NS_ENSURE_TRUE(docShellAsItem, NS_ERROR_FAILURE); + nsAutoString frameName; + mOwnerElement->GetAttribute(NS_LITERAL_STRING("name"), frameName); + + if (!frameName.IsEmpty()) { + docShellAsItem->SetName(frameName.get()); + } + + // If our container is a web-shell, inform it that it has a new + // child. If it's not a web-shell then some things will not operate + // properly. + + + nsCOMPtr presContext; + GetPresContext(getter_AddRefs(presContext)); + + + + + + + + + + + + // what if !presContext ? + + + + + + + + + + nsCOMPtr container; + presContext->GetContainer(getter_AddRefs(container)); + + if (container) { + nsCOMPtr parentAsNode(do_QueryInterface(container)); + if (parentAsNode) { + nsCOMPtr parentAsItem = + do_QueryInterface(parentAsNode); + + PRInt32 parentType; + parentAsItem->GetItemType(&parentType); + + nsAutoString value, valuePiece; + PRBool isContent; + + isContent = PR_FALSE; + mOwnerElement->GetAttribute(NS_LITERAL_STRING("type"), value); + + if (!value.IsEmpty()) { + // we accept "content" and "content-xxx" values. + // at time of writing, we expect "xxx" to be "primary", but + // someday it might be an integer expressing priority + + + + + // string iterators! + + + value.Left(valuePiece, 7); + if (valuePiece.EqualsIgnoreCase("content") && + (value.Length() == 7 || + value.Mid(valuePiece, 7, 1) == 1 && + valuePiece.EqualsWithConversion("-"))) { + isContent = PR_TRUE; + } + } + + if (isContent) { + // The web shell's type is content. + docShellAsItem->SetItemType(nsIDocShellTreeItem::typeContent); + } else { + // Inherit our type from our parent webshell. If it is + // chrome, we'll be chrome. If it is content, we'll be + // content. + docShellAsItem->SetItemType(parentType); + } + + parentAsNode->AddChild(docShellAsItem); + + if (isContent) { + nsCOMPtr parentTreeOwner; + parentAsItem->GetTreeOwner(getter_AddRefs(parentTreeOwner)); + if(parentTreeOwner) { + PRBool is_primary = value.EqualsIgnoreCase("content-primary"); + + parentTreeOwner->ContentShellAdded(docShellAsItem, is_primary, + value.get()); + } + } + + // connect the container... + nsCOMPtr webShell(do_QueryInterface(mDocShell)); + nsCOMPtr outerContainer = + do_QueryInterface(container); + + if (outerContainer) { + webShell->SetContainer(outerContainer); + } + + // Make sure all shells have links back to the content element + // in the nearest enclosing chrome shell. + nsCOMPtr chromeEventHandler; + + if (parentType == nsIDocShellTreeItem::typeChrome) { + // Our parent shell is a chrome shell. It is therefore our nearest + // enclosing chrome shell. + chromeEventHandler = do_QueryInterface(mOwnerElement); + NS_WARN_IF_FALSE(chromeEventHandler, + "This mContent should implement this."); + } else { + nsCOMPtr parentShell(do_QueryInterface(parentAsNode)); + + // Our parent shell is a content shell. Get the chrome info from + // it and use that for our shell as well. + parentShell->GetChromeEventHandler(getter_AddRefs(chromeEventHandler)); + } + + + + // Should this be in the layout code? + + mDocShell->SetChromeEventHandler(chromeEventHandler); + } + } + + return NS_OK; +} + +NS_IMETHODIMP +nsFrameLoader::OnStateChange(nsIWebProgress *aWebProgress, + nsIRequest *aRequest, + PRInt32 aStateFlags, PRUint32 aStatus) +{ + if (!((~aStateFlags) & (nsIWebProgressListener::STATE_IS_DOCUMENT | + nsIWebProgressListener::STATE_TRANSFERRING))) { + nsCOMPtr win(do_GetInterface(mDocShell)); + nsCOMPtr eventTarget(do_QueryInterface(win)); + + if (eventTarget) { + eventTarget->AddEventListener(NS_LITERAL_STRING("load"), this, + PR_FALSE); + } + } + + return NS_OK; +} + +NS_IMETHODIMP +nsFrameLoader::OnProgressChange(nsIWebProgress *aWebProgress, + nsIRequest *aRequest, + PRInt32 aCurSelfProgress, + PRInt32 aMaxSelfProgress, + PRInt32 aCurTotalProgress, + PRInt32 aMaxTotalProgress) +{ + return NS_OK; +} + +NS_IMETHODIMP +nsFrameLoader::OnLocationChange(nsIWebProgress *aWebProgress, + nsIRequest *aRequest, nsIURI *location) +{ + return NS_OK; +} + +NS_IMETHODIMP +nsFrameLoader::OnStatusChange(nsIWebProgress *aWebProgress, + nsIRequest *aRequest, nsresult aStatus, + const PRUnichar *aMessage) +{ + return NS_OK; +} + +NS_IMETHODIMP +nsFrameLoader::OnSecurityChange(nsIWebProgress *aWebProgress, + nsIRequest *aRequest, PRInt32 state) +{ + return NS_OK; +} +