peterv%netscape.com 718f5bc984 Fix for bug 73936 (xsl:include/xsl:import/document() doesn't work). r=Pike/sicking, sr=jst.
git-svn-id: svn://10.0.0.236/trunk@100223 18797224-902f-48f8-a5cc-f745e15eee43
2001-08-02 20:29:20 +00:00

340 lines
9.2 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* 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.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Peter Van der Beken, peterv@netscape.com
* -- original author.
*
*/
#include "nsSyncLoader.h"
#include "nsAppShellCIDs.h"
#include "nsIDocument.h"
#include "nsIDOMDocument.h"
#include "nsIDOMDOMImplementation.h"
#include "nsIDOMEventReceiver.h"
#include "nsIEventQueueService.h"
#include "nsIScriptSecurityManager.h"
#include "nsLayoutCID.h"
#include "nsNetUtil.h"
static const char* kLoadAsData = "loadAsData";
static NS_DEFINE_CID(kIDOMDOMImplementationCID, NS_DOM_IMPLEMENTATION_CID);
static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
static NS_DEFINE_CID(kAppShellServiceCID, NS_APPSHELL_SERVICE_CID);
/*
* This class exists to prevent a circular reference between
* the loaded document and the nsSyncloader instance. The
* request owns the document. While the document is loading,
* the request is a load listener, held onto by the document.
* The proxy class breaks the circularity by filling in as the
* load listener and holding a weak reference to the request
* object.
*/
class txLoadListenerProxy : public nsIDOMLoadListener {
public:
txLoadListenerProxy(nsWeakPtr aParent);
virtual ~txLoadListenerProxy();
NS_DECL_ISUPPORTS
// nsIDOMEventListener
NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent);
// nsIDOMLoadListener
NS_IMETHOD Load(nsIDOMEvent* aEvent);
NS_IMETHOD Unload(nsIDOMEvent* aEvent);
NS_IMETHOD Abort(nsIDOMEvent* aEvent);
NS_IMETHOD Error(nsIDOMEvent* aEvent);
protected:
nsWeakPtr mParent;
};
txLoadListenerProxy::txLoadListenerProxy(nsWeakPtr aParent)
{
NS_INIT_ISUPPORTS();
mParent = aParent;
}
txLoadListenerProxy::~txLoadListenerProxy()
{
}
NS_IMPL_ISUPPORTS1(txLoadListenerProxy, nsIDOMLoadListener)
NS_IMETHODIMP
txLoadListenerProxy::HandleEvent(nsIDOMEvent* aEvent)
{
nsCOMPtr<nsIDOMLoadListener> listener = do_QueryReferent(mParent);
if (listener) {
return listener->HandleEvent(aEvent);
}
return NS_OK;
}
NS_IMETHODIMP
txLoadListenerProxy::Load(nsIDOMEvent* aEvent)
{
nsCOMPtr<nsIDOMLoadListener> listener = do_QueryReferent(mParent);
if (listener) {
return listener->Load(aEvent);
}
return NS_OK;
}
NS_IMETHODIMP
txLoadListenerProxy::Unload(nsIDOMEvent* aEvent)
{
nsCOMPtr<nsIDOMLoadListener> listener = do_QueryReferent(mParent);
if (listener) {
return listener->Unload(aEvent);
}
return NS_OK;
}
NS_IMETHODIMP
txLoadListenerProxy::Abort(nsIDOMEvent* aEvent)
{
nsCOMPtr<nsIDOMLoadListener> listener = do_QueryReferent(mParent);
if (listener) {
return listener->Abort(aEvent);
}
return NS_OK;
}
NS_IMETHODIMP
txLoadListenerProxy::Error(nsIDOMEvent* aEvent)
{
nsCOMPtr<nsIDOMLoadListener> listener = do_QueryReferent(mParent);
if (listener) {
return listener->Error(aEvent);
}
return NS_OK;
}
nsSyncLoader::nsSyncLoader()
{
NS_INIT_ISUPPORTS();
}
nsSyncLoader::~nsSyncLoader()
{
if (mLoading && mChannel) {
mChannel->Cancel(NS_BINDING_ABORTED);
}
}
NS_IMPL_ISUPPORTS3(nsSyncLoader, nsISyncLoader, nsIDOMLoadListener, nsISupportsWeakReference)
NS_IMETHODIMP
nsSyncLoader::LoadDocument(nsIURI* documentURI, nsIDocument *aLoader, nsIDOMDocument **_retval)
{
nsresult rv = NS_OK;
nsCOMPtr<nsIURI> loaderURI;
aLoader->GetDocumentURL(getter_AddRefs(loaderURI));
nsCOMPtr<nsIScriptSecurityManager> securityManager =
do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = securityManager->CheckLoadURI(loaderURI, documentURI,
nsIScriptSecurityManager::STANDARD);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsILoadGroup> loadGroup;
rv = aLoader->GetDocumentLoadGroup(getter_AddRefs(loadGroup));
NS_ENSURE_SUCCESS(rv, rv);
// Get and initialize a DOMImplementation
nsCOMPtr<nsIDOMDOMImplementation> implementation =
do_CreateInstance(kIDOMDOMImplementationCID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
// Create an empty document from it
nsString emptyStr;
nsCOMPtr<nsIDOMDocument> DOMDocument;
rv = implementation->CreateDocument(emptyStr,
emptyStr,
nsnull,
getter_AddRefs(DOMDocument));
NS_ENSURE_SUCCESS(rv, rv);
rv = NS_OpenURI(getter_AddRefs(mChannel), documentURI, nsnull, loadGroup);
NS_ENSURE_SUCCESS(rv, rv);
// Make sure we've been opened
if (!mChannel) {
return NS_ERROR_NOT_INITIALIZED;
}
// Tell the document to start loading
nsCOMPtr<nsIDocument> document = do_QueryInterface(DOMDocument, &rv);
NS_ENSURE_SUCCESS(rv, rv);
// Partial Reset
document->SetDocumentURL(documentURI);
document->SetBaseURL(documentURI);
document->SetBaseTarget(NS_LITERAL_STRING(""));
nsCOMPtr<nsIEventQueueService> service =
do_GetService(NS_EVENTQUEUESERVICE_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIEventQueue> currentThreadQ;
rv = service->PushThreadEventQueue(getter_AddRefs(currentThreadQ));
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
// Register as a load listener on the document
nsCOMPtr<nsIDOMEventReceiver> target = do_QueryInterface(DOMDocument);
txLoadListenerProxy* proxy;
if (target) {
nsWeakPtr requestWeak = getter_AddRefs(NS_GetWeakReference(NS_STATIC_CAST(nsIDOMLoadListener*, this)));
proxy = new txLoadListenerProxy(requestWeak);
if (!proxy) {
service->PopThreadEventQueue(currentThreadQ);
return NS_ERROR_OUT_OF_MEMORY;
}
// This will addref the proxy
rv = target->AddEventListenerByIID(NS_STATIC_CAST(nsIDOMEventListener*,
proxy),
NS_GET_IID(nsIDOMLoadListener));
if (NS_FAILED(rv)) {
service->PopThreadEventQueue(currentThreadQ);
return rv;
}
}
mLoadSuccess = PR_FALSE;
nsCOMPtr<nsIStreamListener> listener;
rv = document->StartDocumentLoad(kLoadAsData, mChannel,
loadGroup, nsnull,
getter_AddRefs(listener),
PR_FALSE);
if (NS_SUCCEEDED(rv)) {
// Start reading from the channel
rv = mChannel->AsyncOpen(listener, nsnull);
if (NS_SUCCEEDED(rv)) {
mLoading = PR_TRUE;
// process events until we're finished.
PLEvent *event;
while (mLoading && NS_SUCCEEDED(rv)) {
rv = currentThreadQ->WaitForEvent(&event);
NS_ASSERTION(NS_SUCCEEDED(rv), ": currentThreadQ->WaitForEvent failed...\n");
if (NS_SUCCEEDED(rv)) {
rv = currentThreadQ->HandleEvent(event);
NS_ASSERTION(NS_SUCCEEDED(rv), ": currentThreadQ->HandleEvent failed...\n");
}
}
}
}
mChannel = 0;
if (NS_FAILED(rv)) {
service->PopThreadEventQueue(currentThreadQ);
// This will release the proxy
target->RemoveEventListenerByIID(NS_STATIC_CAST(nsIDOMEventListener*,
proxy),
NS_GET_IID(nsIDOMLoadListener));
return rv;
}
// This will release the proxy
rv = target->RemoveEventListenerByIID(NS_STATIC_CAST(nsIDOMEventListener*,
proxy),
NS_GET_IID(nsIDOMLoadListener));
if (NS_FAILED(rv)) {
return rv;
}
if (mLoadSuccess) {
*_retval = DOMDocument;
NS_ADDREF(*_retval);
}
rv = service->PopThreadEventQueue(currentThreadQ);
return rv;
}
// nsIDOMEventListener
nsresult
nsSyncLoader::HandleEvent(nsIDOMEvent* aEvent)
{
return NS_OK;
}
// nsIDOMLoadListener
nsresult
nsSyncLoader::Load(nsIDOMEvent* aEvent)
{
if (mLoading) {
mLoading = PR_FALSE;
mLoadSuccess = PR_TRUE;
}
return NS_OK;
}
nsresult
nsSyncLoader::Unload(nsIDOMEvent* aEvent)
{
return NS_OK;
}
nsresult
nsSyncLoader::Abort(nsIDOMEvent* aEvent)
{
if (mLoading) {
mLoading = PR_FALSE;
}
return NS_OK;
}
nsresult
nsSyncLoader::Error(nsIDOMEvent* aEvent)
{
if (mLoading) {
mLoading = PR_FALSE;
}
return NS_OK;
}