Merge backout of changeset 4e7a2d27d636: relanding part of bug 433616 to test the theory that it was the cause of the regression, and something else caused an equal regression when we backed it out.

This commit is contained in:
L. David Baron 2008-10-04 13:00:50 -07:00
commit 04df678063
11 changed files with 847 additions and 35 deletions

View File

@ -52,13 +52,13 @@
#include "nsCompatibility.h"
#include "nsTObserverArray.h"
#include "nsNodeInfoManager.h"
#include "nsIStreamListener.h"
#include "nsIObserver.h"
class nsIContent;
class nsPresContext;
class nsIPresShell;
class nsIDocShell;
class nsIStreamListener;
class nsIStreamObserver;
class nsStyleSet;
class nsIStyleSheet;
class nsIStyleRule;
@ -77,7 +77,6 @@ class nsIChannel;
class nsIPrincipal;
class nsIDOMDocument;
class nsIDOMDocumentType;
class nsIObserver;
class nsScriptLoader;
class nsIContentSink;
class nsIScriptEventManager;
@ -97,8 +96,8 @@ class nsFrameLoader;
// IID for the nsIDocument interface
#define NS_IDOCUMENT_IID \
{ 0xd5b1e3c5, 0x85dc, 0x403e, \
{ 0xbb, 0x4a, 0x54, 0x66, 0xdc, 0xbe, 0x15, 0x69 } }
{ 0x189ebc9e, 0x779b, 0x4c49, \
{ 0x90, 0x8b, 0x9a, 0x80, 0x25, 0x9b, 0xaf, 0xa7 } }
// Flag for AddStyleSheet().
#define NS_STYLESHEET_FROM_CATALOG (1 << 0)
@ -1004,6 +1003,98 @@ public:
virtual void TryCancelFrameLoaderInitialization(nsIDocShell* aShell) = 0;
// Returns true if the frame loader of aShell is in the finalization list.
virtual PRBool FrameLoaderScheduledToBeFinalized(nsIDocShell* aShell) = 0;
/**
* Check whether this document is a root document that is not an
* external resource.
*/
PRBool IsRootDisplayDocument() const
{
return !mParentDocument && !mDisplayDocument;
}
/**
* Get the document for which this document is an external resource. This
* will be null if this document is not an external resource. Otherwise,
* GetDisplayDocument() will return a non-null document, and
* GetDisplayDocument()->GetDisplayDocument() is guaranteed to be null.
*/
nsIDocument* GetDisplayDocument() const
{
return mDisplayDocument;
}
/**
* Set the display document for this document. aDisplayDocument must not be
* null.
*/
void SetDisplayDocument(nsIDocument* aDisplayDocument)
{
NS_PRECONDITION(!GetPrimaryShell() &&
!nsCOMPtr<nsISupports>(GetContainer()) &&
!GetWindow() &&
!GetScriptGlobalObject(),
"Shouldn't set mDisplayDocument on documents that already "
"have a presentation or a docshell or a window");
NS_PRECONDITION(aDisplayDocument != this, "Should be different document");
NS_PRECONDITION(!aDisplayDocument->GetDisplayDocument(),
"Display documents should not nest");
mDisplayDocument = aDisplayDocument;
}
/**
* A class that represents an external resource load that has begun but
* doesn't have a document yet. Observers can be registered on this object,
* and will be notified after the document is created. Observers registered
* after the document has been created will NOT be notified. When observers
* are notified, the subject will be the newly-created document, the topic
* will be "external-resource-document-created", and the data will be null.
* If document creation fails for some reason, observers will still be
* notified, with a null document pointer.
*/
class ExternalResourceLoad : public nsISupports
{
public:
virtual ~ExternalResourceLoad() {}
void AddObserver(nsIObserver* aObserver) {
NS_PRECONDITION(aObserver, "Must have observer");
mObservers.AppendElement(aObserver);
}
const nsTArray< nsCOMPtr<nsIObserver> > & Observers() {
return mObservers;
}
protected:
nsAutoTArray< nsCOMPtr<nsIObserver>, 8 > mObservers;
};
/**
* Request an external resource document for aURI. This will return the
* resource document if available. If one is not available yet, it will
* start loading as needed, and the pending load object will be returned in
* aPendingLoad so that the caller can register an observer to wait for the
* load. If this function returns null and doesn't return a pending load,
* that means that there is no resource document for this URI and won't be
* one in the future.
*
* @param aURI the URI to get
* @param aRequestingNode the node making the request
* @param aPendingLoad the pending load for this request, if any
*/
virtual nsIDocument*
RequestExternalResource(nsIURI* aURI,
nsINode* aRequestingNode,
ExternalResourceLoad** aPendingLoad) = 0;
/**
* Enumerate the external resource documents associated with this document.
* The enumerator callback should return PR_TRUE to continue enumerating, or
* PR_FALSE to stop.
*/
virtual void EnumerateExternalResources(nsSubDocEnumFunc aCallback,
void* aData) = 0;
protected:
~nsIDocument()
{
@ -1100,6 +1191,11 @@ protected:
nsCOMArray<nsINode> mSubtreeModifiedTargets;
PRUint32 mSubtreeModifiedDepth;
// If we're an external resource document, this will be non-null and will
// point to our "display document": the one that all resource lookups should
// go to.
nsCOMPtr<nsIDocument> mDisplayDocument;
private:
// JSObject cache. Only to be used for performance
// optimizations. This will be set once this document is touched

View File

@ -2911,6 +2911,10 @@ nsContentUtils::IsInChromeDocshell(nsIDocument *aDocument)
return PR_FALSE;
}
if (aDocument->GetDisplayDocument()) {
return IsInChromeDocshell(aDocument->GetDisplayDocument());
}
nsCOMPtr<nsISupports> docContainer = aDocument->GetContainer();
nsCOMPtr<nsIDocShellTreeItem> docShell(do_QueryInterface(docContainer));
PRInt32 itemType = nsIDocShellTreeItem::typeContent;

View File

@ -72,7 +72,28 @@ nsDataDocumentContentPolicy::ShouldLoad(PRUint32 aContentType,
doc = do_QueryInterface(domDoc);
}
}
if (aContentType != nsIContentPolicy::TYPE_DTD && doc && doc->IsLoadedAsData()) {
// DTDs are always OK to load
if (!doc || aContentType == nsIContentPolicy::TYPE_DTD) {
return NS_OK;
}
// Nothing else is OK to load for data documents
if (doc->IsLoadedAsData()) {
*aDecision = nsIContentPolicy::REJECT_TYPE;
return NS_OK;
}
// Allow all loads for non-external-resource documents
if (!doc->GetDisplayDocument()) {
return NS_OK;
}
// For external resources, blacklist some load types
if (aContentType == nsIContentPolicy::TYPE_OBJECT ||
aContentType == nsIContentPolicy::TYPE_DOCUMENT ||
aContentType == nsIContentPolicy::TYPE_SUBDOCUMENT ||
aContentType == nsIContentPolicy::TYPE_SCRIPT) {
*aDecision = nsIContentPolicy::REJECT_TYPE;
}

View File

@ -157,11 +157,23 @@ static NS_DEFINE_CID(kDOMEventGroupCID, NS_DOMEVENTGROUP_CID);
#include "nsCycleCollector.h"
#include "nsCCUncollectableMarker.h"
#include "nsIContentPolicy.h"
#include "nsContentPolicyUtils.h"
#include "nsICategoryManager.h"
#include "nsIDocumentLoaderFactory.h"
#include "nsIContentViewer.h"
#include "nsIXMLContentSink.h"
#include "nsIChannelEventSink.h"
#include "nsContentErrors.h"
#include "nsIXULDocument.h"
#include "nsIProgressEventSink.h"
#include "nsISecurityEventSink.h"
#include "nsIPrompt.h"
#include "nsFrameLoader.h"
#include "mozAutoDocUpdate.h"
#ifdef MOZ_LOGGING
// so we can get logging even in release builds
#define FORCE_PR_LOG 1
@ -718,6 +730,433 @@ nsOnloadBlocker::SetLoadFlags(nsLoadFlags aLoadFlags)
return NS_OK;
}
// ==================================================================
nsExternalResourceMap::nsExternalResourceMap()
: mHaveShutDown(PR_FALSE)
{
mMap.Init();
mPendingLoads.Init();
}
nsIDocument*
nsExternalResourceMap::RequestResource(nsIURI* aURI,
nsINode* aRequestingNode,
nsDocument* aDisplayDocument,
ExternalResourceLoad** aPendingLoad)
{
// If we ever start allowing non-same-origin loads here, we might need to do
// something interesting with aRequestingPrincipal even for the hashtable
// gets.
NS_PRECONDITION(aURI, "Must have a URI");
NS_PRECONDITION(aRequestingNode, "Must have a node");
*aPendingLoad = nsnull;
if (mHaveShutDown) {
return nsnull;
}
// First, make sure we strip the ref from aURI.
nsCOMPtr<nsIURI> clone;
aURI->Clone(getter_AddRefs(clone));
if (!clone) {
return nsnull;
}
nsCOMPtr<nsIURL> url(do_QueryInterface(clone));
if (url) {
url->SetRef(EmptyCString());
}
ExternalResource* resource;
mMap.Get(clone, &resource);
if (resource) {
return resource->mDocument;
}
nsRefPtr<PendingLoad> load;
mPendingLoads.Get(clone, getter_AddRefs(load));
if (load) {
NS_ADDREF(*aPendingLoad = load);
return nsnull;
}
load = new PendingLoad(aDisplayDocument);
if (!load) {
return nsnull;
}
if (!mPendingLoads.Put(clone, load)) {
return nsnull;
}
if (NS_FAILED(load->StartLoad(clone, aRequestingNode))) {
// Make sure we don't thrash things by trying this load again, since
// chances are it failed for good reasons (security check, etc).
AddExternalResource(clone, nsnull, nsnull, aDisplayDocument);
} else {
NS_ADDREF(*aPendingLoad = load);
}
return nsnull;
}
struct
nsExternalResourceEnumArgs
{
nsIDocument::nsSubDocEnumFunc callback;
void *data;
};
PR_STATIC_CALLBACK(PLDHashOperator)
ExternalResourceEnumerator(nsIURI* aKey,
nsExternalResourceMap::ExternalResource* aData,
void* aClosure)
{
nsExternalResourceEnumArgs* args =
static_cast<nsExternalResourceEnumArgs*>(aClosure);
PRBool next = args->callback(aData->mDocument, args->data);
return next ? PL_DHASH_NEXT : PL_DHASH_STOP;
}
void
nsExternalResourceMap::EnumerateResources(nsIDocument::nsSubDocEnumFunc aCallback,
void* aData)
{
nsExternalResourceEnumArgs args = { aCallback, aData };
mMap.EnumerateRead(ExternalResourceEnumerator, &args);
}
PR_STATIC_CALLBACK(PLDHashOperator)
ExternalResourceTraverser(nsIURI* aKey,
nsExternalResourceMap::ExternalResource* aData,
void* aClosure)
{
nsCycleCollectionTraversalCallback *cb =
static_cast<nsCycleCollectionTraversalCallback*>(aClosure);
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb,
"mExternalResourceMap.mMap entry"
"->mDocument");
cb->NoteXPCOMChild(aData->mDocument);
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb,
"mExternalResourceMap.mMap entry"
"->mViewer");
cb->NoteXPCOMChild(aData->mViewer);
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb,
"mExternalResourceMap.mMap entry"
"->mLoadGroup");
cb->NoteXPCOMChild(aData->mLoadGroup);
return PL_DHASH_NEXT;
}
void
nsExternalResourceMap::Traverse(nsCycleCollectionTraversalCallback* aCallback) const
{
// mPendingLoads will get cleared out as the requests complete, so
// no need to worry about those here.
mMap.EnumerateRead(ExternalResourceTraverser, aCallback);
}
nsresult
nsExternalResourceMap::AddExternalResource(nsIURI* aURI,
nsIDocumentViewer* aViewer,
nsILoadGroup* aLoadGroup,
nsIDocument* aDisplayDocument)
{
NS_PRECONDITION(aURI, "Unexpected call");
NS_PRECONDITION((aViewer && aLoadGroup) || (!aViewer && !aLoadGroup),
"Must have both or neither");
nsRefPtr<PendingLoad> load;
mPendingLoads.Get(aURI, getter_AddRefs(load));
mPendingLoads.Remove(aURI);
nsresult rv = NS_OK;
nsCOMPtr<nsIDocument> doc;
if (aViewer) {
aViewer->GetDocument(getter_AddRefs(doc));
NS_ASSERTION(doc, "Must have a document");
nsCOMPtr<nsIXULDocument> xulDoc = do_QueryInterface(doc);
if (xulDoc) {
// We don't handle XUL stuff here yet.
rv = NS_ERROR_NOT_AVAILABLE;
} else {
doc->SetDisplayDocument(aDisplayDocument);
rv = aViewer->Init(nsnull, nsRect(0, 0, 0, 0));
if (NS_SUCCEEDED(rv)) {
rv = aViewer->Open(nsnull, nsnull);
}
}
if (NS_FAILED(rv)) {
doc = nsnull;
aViewer = nsnull;
aLoadGroup = nsnull;
}
}
ExternalResource* newResource = new ExternalResource();
if (newResource && !mMap.Put(aURI, newResource)) {
delete newResource;
newResource = nsnull;
if (NS_SUCCEEDED(rv)) {
rv = NS_ERROR_OUT_OF_MEMORY;
}
}
if (newResource) {
newResource->mDocument = doc;
newResource->mViewer = aViewer;
newResource->mLoadGroup = aLoadGroup;
}
const nsTArray< nsCOMPtr<nsIObserver> > & obs = load->Observers();
for (PRUint32 i = 0; i < obs.Length(); ++i) {
obs[i]->Observe(doc, "external-resource-document-created", nsnull);
}
return rv;
}
NS_IMPL_ISUPPORTS2(nsExternalResourceMap::PendingLoad,
nsIStreamListener,
nsIRequestObserver)
NS_IMETHODIMP
nsExternalResourceMap::PendingLoad::OnStartRequest(nsIRequest *aRequest,
nsISupports *aContext)
{
nsExternalResourceMap& map = mDisplayDocument->ExternalResourceMap();
if (map.HaveShutDown()) {
return NS_BINDING_ABORTED;
}
nsCOMPtr<nsIDocumentViewer> viewer;
nsCOMPtr<nsILoadGroup> loadGroup;
nsresult rv = SetupViewer(aRequest, getter_AddRefs(viewer),
getter_AddRefs(loadGroup));
// Make sure to do this no matter what
nsresult rv2 = map.AddExternalResource(mURI, viewer, loadGroup,
mDisplayDocument);
if (NS_FAILED(rv)) {
return rv;
}
if (NS_FAILED(rv2)) {
mTargetListener = nsnull;
return rv2;
}
return mTargetListener->OnStartRequest(aRequest, aContext);
}
nsresult
nsExternalResourceMap::PendingLoad::SetupViewer(nsIRequest* aRequest,
nsIDocumentViewer** aViewer,
nsILoadGroup** aLoadGroup)
{
NS_PRECONDITION(!mTargetListener, "Unexpected call to OnStartRequest");
*aViewer = nsnull;
*aLoadGroup = nsnull;
nsCOMPtr<nsIChannel> chan(do_QueryInterface(aRequest));
NS_ENSURE_TRUE(chan, NS_ERROR_UNEXPECTED);
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aRequest));
if (httpChannel) {
PRBool requestSucceeded;
if (NS_FAILED(httpChannel->GetRequestSucceeded(&requestSucceeded)) ||
!requestSucceeded) {
// Bail out on this load, since it looks like we have an HTTP error page
return NS_BINDING_ABORTED;
}
}
nsCAutoString type;
chan->GetContentType(type);
nsCOMPtr<nsILoadGroup> loadGroup;
chan->GetLoadGroup(getter_AddRefs(loadGroup));
// Give this document its own loadgroup
nsCOMPtr<nsILoadGroup> newLoadGroup =
do_CreateInstance(NS_LOADGROUP_CONTRACTID);
NS_ENSURE_TRUE(newLoadGroup, NS_ERROR_OUT_OF_MEMORY);
newLoadGroup->SetLoadGroup(loadGroup);
nsCOMPtr<nsIInterfaceRequestor> callbacks;
loadGroup->GetNotificationCallbacks(getter_AddRefs(callbacks));
nsCOMPtr<nsIInterfaceRequestor> newCallbacks =
new LoadgroupCallbacks(callbacks);
newLoadGroup->SetNotificationCallbacks(newCallbacks);
// This is some serious hackery cribbed from docshell
nsCOMPtr<nsICategoryManager> catMan =
do_GetService(NS_CATEGORYMANAGER_CONTRACTID);
NS_ENSURE_TRUE(catMan, NS_ERROR_NOT_AVAILABLE);
nsXPIDLCString contractId;
nsresult rv = catMan->GetCategoryEntry("Gecko-Content-Viewers", type.get(),
getter_Copies(contractId));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDocumentLoaderFactory> docLoaderFactory =
do_GetService(contractId);
NS_ENSURE_TRUE(docLoaderFactory, NS_ERROR_NOT_AVAILABLE);
nsCOMPtr<nsIContentViewer> viewer;
nsCOMPtr<nsIStreamListener> listener;
rv = docLoaderFactory->CreateInstance("external-resource", chan, newLoadGroup,
type.get(), nsnull, nsnull,
getter_AddRefs(listener),
getter_AddRefs(viewer));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDocumentViewer> docViewer = do_QueryInterface(viewer);
NS_ENSURE_TRUE(docViewer, NS_ERROR_UNEXPECTED);
nsCOMPtr<nsIParser> parser = do_QueryInterface(listener);
if (!parser) {
/// We don't want to deal with the various fake documents yet
return NS_ERROR_NOT_IMPLEMENTED;
}
// We can't handle HTML and other weird things here yet.
nsIContentSink* sink = parser->GetContentSink();
nsCOMPtr<nsIXMLContentSink> xmlSink = do_QueryInterface(sink);
if (!xmlSink) {
return NS_ERROR_NOT_IMPLEMENTED;
}
listener.swap(mTargetListener);
docViewer.swap(*aViewer);
newLoadGroup.swap(*aLoadGroup);
return NS_OK;
}
NS_IMETHODIMP
nsExternalResourceMap::PendingLoad::OnDataAvailable(nsIRequest* aRequest,
nsISupports* aContext,
nsIInputStream* aStream,
PRUint32 aOffset,
PRUint32 aCount)
{
NS_PRECONDITION(mTargetListener, "Shouldn't be getting called!");
if (mDisplayDocument->ExternalResourceMap().HaveShutDown()) {
return NS_BINDING_ABORTED;
}
return mTargetListener->OnDataAvailable(aRequest, aContext, aStream, aOffset,
aCount);
}
NS_IMETHODIMP
nsExternalResourceMap::PendingLoad::OnStopRequest(nsIRequest* aRequest,
nsISupports* aContext,
nsresult aStatus)
{
// mTargetListener might be null if SetupViewer or AddExternalResource failed
if (mTargetListener) {
nsCOMPtr<nsIStreamListener> listener;
mTargetListener.swap(listener);
return listener->OnStopRequest(aRequest, aContext, aStatus);
}
return NS_OK;
}
nsresult
nsExternalResourceMap::PendingLoad::StartLoad(nsIURI* aURI,
nsINode* aRequestingNode)
{
NS_PRECONDITION(aURI, "Must have a URI");
NS_PRECONDITION(aRequestingNode, "Must have a node");
// Time to start a load. First, the security checks.
nsIPrincipal* requestingPrincipal = aRequestingNode->NodePrincipal();
nsresult rv = nsContentUtils::GetSecurityManager()->
CheckLoadURIWithPrincipal(requestingPrincipal, aURI,
nsIScriptSecurityManager::STANDARD);
NS_ENSURE_SUCCESS(rv, rv);
rv = requestingPrincipal->CheckMayLoad(aURI, PR_TRUE);
NS_ENSURE_SUCCESS(rv, rv);
PRInt16 shouldLoad = nsIContentPolicy::ACCEPT;
rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_OTHER,
aURI,
requestingPrincipal,
aRequestingNode,
EmptyCString(), //mime guess
nsnull, //extra
&shouldLoad,
nsContentUtils::GetContentPolicy(),
nsContentUtils::GetSecurityManager());
if (NS_FAILED(rv)) return rv;
if (NS_CP_REJECTED(shouldLoad)) {
// Disallowed by content policy
return NS_ERROR_CONTENT_BLOCKED;
}
nsIDocument* doc = aRequestingNode->GetOwnerDoc();
if (!doc) {
return NS_ERROR_NOT_AVAILABLE;
}
nsCOMPtr<nsILoadGroup> loadGroup = doc->GetDocumentLoadGroup();
nsCOMPtr<nsIChannel> channel;
rv = NS_NewChannel(getter_AddRefs(channel), aURI, nsnull, loadGroup);
NS_ENSURE_SUCCESS(rv, rv);
mURI = aURI;
nsCOMPtr<nsIInterfaceRequestor> req = nsContentUtils::GetSameOriginChecker();
NS_ENSURE_TRUE(req, NS_ERROR_OUT_OF_MEMORY);
channel->SetNotificationCallbacks(req);
return channel->AsyncOpen(this, nsnull);
}
NS_IMPL_ISUPPORTS1(nsExternalResourceMap::LoadgroupCallbacks,
nsIInterfaceRequestor)
NS_IMETHODIMP
nsExternalResourceMap::LoadgroupCallbacks::GetInterface(const nsIID & aIID,
void **aSink)
{
#define IID_IS(_i) aIID.Equals(NS_GET_IID(_i))
if (mCallbacks &&
(IID_IS(nsIProgressEventSink) ||
IID_IS(nsIChannelEventSink) ||
IID_IS(nsISecurityEventSink) ||
IID_IS(nsIPrompt) ||
IID_IS(nsIAuthPrompt) ||
IID_IS(nsIAuthPrompt2) ||
IID_IS(nsIApplicationCacheContainer) ||
// XXXbz evil hack for cookies for now
IID_IS(nsIDOMWindow) ||
IID_IS(nsIDocShellTreeItem))) {
return mCallbacks->GetInterface(aIID, aSink);
}
#undef IID_IS
*aSink = nsnull;
return NS_NOINTERFACE;
}
nsExternalResourceMap::ExternalResource::~ExternalResource()
{
if (mViewer) {
mViewer->Close(nsnull);
mViewer->Destroy();
}
}
// ==================================================================
// =
// ==================================================================
@ -1194,7 +1633,8 @@ SubDocTraverser(PLDHashTable *table, PLDHashEntryHdr *hdr, PRUint32 number,
}
PR_STATIC_CALLBACK(PLDHashOperator)
RadioGroupsTraverser(const nsAString& aKey, nsAutoPtr<nsRadioGroupStruct>& aData, void* aClosure)
RadioGroupsTraverser(const nsAString& aKey, nsRadioGroupStruct* aData,
void* aClosure)
{
nsCycleCollectionTraversalCallback *cb =
static_cast<nsCycleCollectionTraversalCallback*>(aClosure);
@ -1261,6 +1701,8 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDocument)
tmp->mIdentifierMap.EnumerateEntries(IdentifierMapEntryTraverse, &cb);
tmp->mExternalResourceMap.Traverse(&cb);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mNodeInfo)
// Traverse the mChildren nsAttrAndChildArray.
@ -1276,6 +1718,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDocument)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_MEMBER(mNodeInfoManager,
nsNodeInfoManager)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mSecurityInfo)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDisplayDocument)
// Traverse all nsDocument nsCOMPtrs.
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mParser)
@ -1284,7 +1727,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDocument)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDOMStyleSheets)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mScriptLoader)
tmp->mRadioGroups.Enumerate(RadioGroupsTraverser, &cb);
tmp->mRadioGroups.EnumerateRead(RadioGroupsTraverser, &cb);
// The boxobject for an element will only exist as long as it's in the
// document, so we'll traverse the table here instead of from the element.
@ -1326,6 +1769,9 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDocument)
// from the doc.
tmp->DestroyLinkMap();
// Clear out our external resources
tmp->mExternalResourceMap.Shutdown();
nsAutoScriptBlocker scriptBlocker;
// Unlink the mChildren nsAttrAndChildArray.
@ -1336,6 +1782,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDocument)
}
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mCachedRootContent)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDisplayDocument)
NS_IMPL_CYCLE_COLLECTION_UNLINK_USERDATA
@ -1711,6 +2158,9 @@ nsDocument::StartDocumentLoad(const char* aCommand, nsIChannel* aChannel,
// styles
CSSLoader()->SetEnabled(PR_FALSE); // Do not load/process styles when loading as data
} else if (nsCRT::strcmp("external-resource", aCommand) == 0) {
// Allow CSS, but not scripts
ScriptLoader()->SetEnabled(PR_FALSE);
}
mMayStartLayout = PR_FALSE;
@ -4703,6 +5153,29 @@ nsDocument::FrameLoaderScheduledToBeFinalized(nsIDocShell* aShell)
return PR_FALSE;
}
nsIDocument*
nsDocument::RequestExternalResource(nsIURI* aURI,
nsINode* aRequestingNode,
ExternalResourceLoad** aPendingLoad)
{
NS_PRECONDITION(aURI, "Must have a URI");
NS_PRECONDITION(aRequestingNode, "Must have a node");
if (mDisplayDocument) {
return mDisplayDocument->RequestExternalResource(aURI,
aRequestingNode,
aPendingLoad);
}
return mExternalResourceMap.RequestResource(aURI, aRequestingNode,
this, aPendingLoad);
}
void
nsDocument::EnumerateExternalResources(nsSubDocEnumFunc aCallback, void* aData)
{
mExternalResourceMap.EnumerateResources(aCallback, aData);
}
struct DirTable {
const char* mName;
PRUint8 mValue;
@ -5860,20 +6333,20 @@ PRBool
nsDocument::IsScriptEnabled()
{
nsCOMPtr<nsIScriptSecurityManager> sm(do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID));
NS_ENSURE_TRUE(sm, PR_TRUE);
NS_ENSURE_TRUE(sm, PR_FALSE);
nsIScriptGlobalObject* globalObject = GetScriptGlobalObject();
NS_ENSURE_TRUE(globalObject, PR_TRUE);
NS_ENSURE_TRUE(globalObject, PR_FALSE);
nsIScriptContext *scriptContext = globalObject->GetContext();
NS_ENSURE_TRUE(scriptContext, PR_TRUE);
NS_ENSURE_TRUE(scriptContext, PR_FALSE);
JSContext* cx = (JSContext *) scriptContext->GetNativeContext();
NS_ENSURE_TRUE(cx, PR_TRUE);
NS_ENSURE_TRUE(cx, PR_FALSE);
PRBool enabled;
nsresult rv = sm->CanExecuteScripts(cx, NodePrincipal(), &enabled);
NS_ENSURE_SUCCESS(rv, PR_TRUE);
NS_ENSURE_SUCCESS(rv, PR_FALSE);
return enabled;
}
@ -6396,6 +6869,11 @@ nsDocument::Destroy()
nsContentList::OnDocumentDestroy(this);
// Shut down our external resource map. We might not need this for
// leak-fixing if we fix DocumentViewerImpl to do cycle-collection, but
// tearing down all those frame trees right now is the right thing to do.
mExternalResourceMap.Shutdown();
// XXX We really should let cycle collection do this, but that currently still
// leaks (see https://bugzilla.mozilla.org/show_bug.cgi?id=406684).
// When we start relying on cycle collection again we should remove the
@ -6437,6 +6915,11 @@ nsDocument::GetLayoutHistoryState() const
void
nsDocument::BlockOnload()
{
if (mDisplayDocument) {
mDisplayDocument->BlockOnload();
return;
}
// If mScriptGlobalObject is null, we shouldn't be messing with the loadgroup
// -- it's not ours.
if (mOnloadBlockCount == 0 && mScriptGlobalObject) {
@ -6451,6 +6934,11 @@ nsDocument::BlockOnload()
void
nsDocument::UnblockOnload(PRBool aFireSync)
{
if (mDisplayDocument) {
mDisplayDocument->UnblockOnload(aFireSync);
return;
}
if (mOnloadBlockCount == 0) {
NS_NOTREACHED("More UnblockOnload() calls than BlockOnload() calls; dropping call");
return;
@ -6498,12 +6986,14 @@ nsDocument::PostUnblockOnloadEvent()
void
nsDocument::DoUnblockOnload()
{
NS_ASSERTION(mOnloadBlockCount != 0,
"Shouldn't have a count of zero here, since we stabilized in "
"PostUnblockOnloadEvent");
NS_PRECONDITION(!mDisplayDocument,
"Shouldn't get here for resource document");
NS_PRECONDITION(mOnloadBlockCount != 0,
"Shouldn't have a count of zero here, since we stabilized in "
"PostUnblockOnloadEvent");
--mOnloadBlockCount;
if (mOnloadBlockCount != 0) {
// We blocked again after the last unblock. Nothing to do here. We'll
// post a new event when we unblock again.

View File

@ -108,6 +108,8 @@
#include "nsPresShellIterator.h"
#include "nsContentUtils.h"
#include "nsThreadUtils.h"
#include "nsIDocumentViewer.h"
#include "nsIInterfaceRequestor.h"
#define XML_DECLARATION_BITS_DECLARATION_EXISTS (1 << 0)
#define XML_DECLARATION_BITS_ENCODING_EXISTS (1 << 1)
@ -383,6 +385,117 @@ private:
~nsOnloadBlocker() {}
};
class nsExternalResourceMap
{
public:
typedef nsIDocument::ExternalResourceLoad ExternalResourceLoad;
nsExternalResourceMap();
/**
* Request an external resource document. This does exactly what
* nsIDocument::RequestExternalResource is documented to do.
*/
nsIDocument* RequestResource(nsIURI* aURI,
nsINode* aRequestingNode,
nsDocument* aDisplayDocument,
ExternalResourceLoad** aPendingLoad);
/**
* Enumerate the resource documents. See
* nsIDocument::EnumerateExternalResources.
*/
void EnumerateResources(nsIDocument::nsSubDocEnumFunc aCallback, void* aData);
/**
* Traverse ourselves for cycle-collection
*/
void Traverse(nsCycleCollectionTraversalCallback* aCallback) const;
/**
* Shut ourselves down (used for cycle-collection unlink), as well
* as for document destruction.
*/
void Shutdown()
{
mPendingLoads.Clear();
mMap.Clear();
mHaveShutDown = PR_TRUE;
}
PRBool HaveShutDown() const
{
return mHaveShutDown;
}
// Needs to be public so we can traverse them sanely
struct ExternalResource
{
~ExternalResource();
nsCOMPtr<nsIDocument> mDocument;
nsCOMPtr<nsIContentViewer> mViewer;
nsCOMPtr<nsILoadGroup> mLoadGroup;
};
protected:
class PendingLoad : public ExternalResourceLoad,
public nsIStreamListener
{
public:
PendingLoad(nsDocument* aDisplayDocument) :
mDisplayDocument(aDisplayDocument)
{}
NS_DECL_ISUPPORTS
NS_DECL_NSISTREAMLISTENER
NS_DECL_NSIREQUESTOBSERVER
/**
* Start aURI loading. This will perform the necessary security checks and
* so forth.
*/
nsresult StartLoad(nsIURI* aURI, nsINode* aRequestingNode);
/**
* Set up an nsIDocumentViewer based on aRequest. This is guaranteed to
* put null in *aViewer and *aLoadGroup on all failures.
*/
nsresult SetupViewer(nsIRequest* aRequest, nsIDocumentViewer** aViewer,
nsILoadGroup** aLoadGroup);
private:
nsRefPtr<nsDocument> mDisplayDocument;
nsCOMPtr<nsIStreamListener> mTargetListener;
nsCOMPtr<nsIURI> mURI;
};
friend class PendingLoad;
class LoadgroupCallbacks : public nsIInterfaceRequestor
{
public:
LoadgroupCallbacks(nsIInterfaceRequestor* aOtherCallbacks)
: mCallbacks(aOtherCallbacks)
{}
NS_DECL_ISUPPORTS
NS_DECL_NSIINTERFACEREQUESTOR
private:
nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
};
/**
* Add an ExternalResource for aURI. aViewer and aLoadGroup might be null
* when this is called if the URI didn't result in an XML document. This
* function makes sure to remove the pending load for aURI, if any, from our
* hashtable, and to notify its observers, if any.
*/
nsresult AddExternalResource(nsIURI* aURI, nsIDocumentViewer* aViewer,
nsILoadGroup* aLoadGroup,
nsIDocument* aDisplayDocument);
nsClassHashtable<nsURIHashKey, ExternalResource> mMap;
nsRefPtrHashtable<nsURIHashKey, PendingLoad> mPendingLoads;
PRPackedBool mHaveShutDown;
};
// Base class for our document implementations.
//
// Note that this class *implements* nsIDOMXMLDocument, but it's not
@ -802,6 +915,12 @@ public:
virtual NS_HIDDEN_(nsresult) FinalizeFrameLoader(nsFrameLoader* aLoader);
virtual NS_HIDDEN_(void) TryCancelFrameLoaderInitialization(nsIDocShell* aShell);
virtual NS_HIDDEN_(PRBool) FrameLoaderScheduledToBeFinalized(nsIDocShell* aShell);
virtual NS_HIDDEN_(nsIDocument*)
RequestExternalResource(nsIURI* aURI,
nsINode* aRequestingNode,
ExternalResourceLoad** aPendingLoad);
virtual NS_HIDDEN_(void)
EnumerateExternalResources(nsSubDocEnumFunc aCallback, void* aData);
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsDocument, nsIDocument)
@ -815,6 +934,11 @@ public:
void DoNotifyPossibleTitleChange();
nsExternalResourceMap& ExternalResourceMap()
{
return mExternalResourceMap;
}
void SetLoadedAsData(PRBool aLoadedAsData) { mLoadedAsData = aLoadedAsData; }
nsresult CloneDocHelper(nsDocument* clone) const;
@ -1087,6 +1211,8 @@ private:
nsTArray<nsRefPtr<nsFrameLoader> > mFinalizableFrameLoaders;
nsRevocableEventPtr<nsRunnableMethod<nsDocument> > mPendingTitleChangeEvent;
nsExternalResourceMap mExternalResourceMap;
};
#endif /* nsDocument_h___ */

View File

@ -727,6 +727,11 @@ nsFrameLoader::EnsureDocShell()
return NS_ERROR_UNEXPECTED;
}
if (doc->GetDisplayDocument()) {
// Don't allow subframe loads in external reference documents
return NS_ERROR_NOT_AVAILABLE;
}
nsCOMPtr<nsIWebNavigation> parentAsWebNav =
do_GetInterface(doc->GetScriptGlobalObject());

View File

@ -54,6 +54,7 @@ REQUIRES = \
thebes \
dom \
webshell \
docshell \
htmlparser \
necko \
pref \

View File

@ -2488,7 +2488,7 @@ nsXULElement::HideWindowChrome(PRBool aShouldHide)
return NS_ERROR_UNEXPECTED;
// only top level chrome documents can hide the window chrome
if (doc->GetParentDocument())
if (!doc->IsRootDisplayDocument())
return NS_OK;
nsIPresShell *shell = doc->GetPrimaryShell();
@ -2522,7 +2522,7 @@ nsXULElement::SetTitlebarColor(nscolor aColor, PRBool aActive)
}
// only top level chrome documents can set the titlebar color
if (!doc->GetParentDocument()) {
if (doc->IsRootDisplayDocument()) {
nsCOMPtr<nsISupports> container = doc->GetContainer();
nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(container);
if (baseWindow) {

View File

@ -817,7 +817,11 @@ DocumentViewerImpl::InitInternal(nsIWidget* aParentWidget,
PRBool makeCX = PR_FALSE;
if (aDoCreation) {
if (aParentWidget && !mPresContext) {
// XXXbz this is a nasty hack to do with the fact that we create
// presentations both in Init() and in Show()... Ideally we would only do
// it in one place (Show()) and require that callers call init(), open(),
// show() in that order or something.
if ((aParentWidget || mDocument->GetDisplayDocument()) && !mPresContext) {
// Create presentation context
if (mIsPageMode) {
//Presentation context already created in SetPageMode which is calling this method
@ -1241,12 +1245,12 @@ DocumentViewerImpl::Open(nsISupports *aState, nsISHEntry *aSHEntry)
nsRect bounds;
mWindow->GetBounds(bounds);
nsresult rv = InitInternal(mParentWidget, aState, bounds, PR_FALSE, PR_FALSE);
NS_ENSURE_SUCCESS(rv, rv);
if (mDocument)
mDocument->SetContainer(nsCOMPtr<nsISupports>(do_QueryReferent(mContainer)));
nsresult rv = InitInternal(mParentWidget, aState, bounds, PR_FALSE, PR_FALSE);
NS_ENSURE_SUCCESS(rv, rv);
if (mPresShell)
mPresShell->SetForwardingContainer(nsnull);
@ -2101,13 +2105,14 @@ DocumentViewerImpl::CreateStyleSet(nsIDocument* aDocument,
// The document will fill in the document sheets when we create the presshell
// Handle the user sheets.
PRInt32 shellType = nsIDocShellTreeItem::typeContent;;
nsCOMPtr<nsIDocShellTreeItem> docShell(do_QueryReferent(mContainer));
if (docShell) {
docShell->GetItemType(&shellType);
}
#ifdef DEBUG
nsCOMPtr<nsISupports> debugDocContainer = aDocument->GetContainer();
nsCOMPtr<nsIDocShellTreeItem> debugDocShell(do_QueryReferent(mContainer));
NS_ASSERTION(SameCOMIdentity(debugDocContainer, debugDocShell),
"Unexpected containers");
#endif
nsICSSStyleSheet* sheet = nsnull;
if (shellType == nsIDocShellTreeItem::typeChrome) {
if (nsContentUtils::IsInChromeDocshell(aDocument)) {
sheet = nsLayoutStylesheetCache::UserChromeSheet();
}
else {
@ -2119,7 +2124,9 @@ DocumentViewerImpl::CreateStyleSet(nsIDocument* aDocument,
// Append chrome sheets (scrollbars + forms).
PRBool shouldOverride = PR_FALSE;
nsCOMPtr<nsIDocShell> ds(do_QueryInterface(docShell));
// We don't want a docshell here for external resource docs, so just
// look at mContainer.
nsCOMPtr<nsIDocShell> ds(do_QueryReferent(mContainer));
nsCOMPtr<nsIDOMEventTarget> chromeHandler;
nsCOMPtr<nsIURI> uri;
nsCOMPtr<nsICSSStyleSheet> csssheet;
@ -2296,6 +2303,23 @@ DocumentViewerImpl::CreateDeviceContext(nsIWidget* aWidget)
{
NS_PRECONDITION(!mPresShell && !mPresContext && !mWindow,
"This will screw up our existing presentation");
NS_PRECONDITION(mDocument, "Gotta have a document here");
nsIDocument* doc = mDocument->GetDisplayDocument();
if (doc) {
NS_ASSERTION(!aWidget, "Shouldn't have a widget here");
// We want to use our display document's device context if possible
nsIPresShell* shell = doc->GetPrimaryShell();
if (shell) {
nsPresContext* ctx = shell->GetPresContext();
if (ctx) {
mDeviceContext = ctx->DeviceContext();
return NS_OK;
}
}
}
// Create a device context even if we already have one, since our widget
// might have changed.
mDeviceContext = do_CreateInstance(kDeviceContextCID);
@ -2684,6 +2708,38 @@ SetChildFullZoom(nsIMarkupDocumentViewer* aChild, void* aClosure)
aChild->SetFullZoom(ZoomInfo->mZoom);
}
PR_STATIC_CALLBACK(PRBool)
SetExtResourceTextZoom(nsIDocument* aDocument, void* aClosure)
{
// Would it be better to enumerate external resource viewers instead?
nsIPresShell* shell = aDocument->GetPrimaryShell();
if (shell) {
nsPresContext* ctxt = shell->GetPresContext();
if (ctxt) {
struct ZoomInfo* ZoomInfo = static_cast<struct ZoomInfo*>(aClosure);
ctxt->SetTextZoom(ZoomInfo->mZoom);
}
}
return PR_TRUE;
}
PR_STATIC_CALLBACK(PRBool)
SetExtResourceFullZoom(nsIDocument* aDocument, void* aClosure)
{
// Would it be better to enumerate external resource viewers instead?
nsIPresShell* shell = aDocument->GetPrimaryShell();
if (shell) {
nsPresContext* ctxt = shell->GetPresContext();
if (ctxt) {
struct ZoomInfo* ZoomInfo = static_cast<struct ZoomInfo*>(aClosure);
ctxt->SetFullZoom(ZoomInfo->mZoom);
}
}
return PR_TRUE;
}
NS_IMETHODIMP
DocumentViewerImpl::SetTextZoom(float aTextZoom)
{
@ -2706,6 +2762,9 @@ DocumentViewerImpl::SetTextZoom(float aTextZoom)
pc->SetTextZoom(aTextZoom);
}
// And do the external resources
mDocument->EnumerateExternalResources(SetExtResourceTextZoom, &ZoomInfo);
batch.EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC);
return NS_OK;
@ -2737,6 +2796,9 @@ DocumentViewerImpl::SetFullZoom(float aFullZoom)
pc->SetFullZoom(aFullZoom);
}
// And do the external resources
mDocument->EnumerateExternalResources(SetExtResourceFullZoom, &ZoomInfo);
batch.EndUpdateViewBatch(NS_VMREFRESH_NO_SYNC);
return NS_OK;

View File

@ -555,9 +555,11 @@ nsSubDocumentFrame::Reflow(nsPresContext* aPresContext,
innerSize.height -= aReflowState.mComputedBorderPadding.TopBottom();
}
nsIViewManager* vm = mInnerView->GetViewManager();
vm->MoveViewTo(mInnerView, offset.x, offset.y);
vm->ResizeView(mInnerView, nsRect(nsPoint(0, 0), innerSize), PR_TRUE);
if (mInnerView) {
nsIViewManager* vm = mInnerView->GetViewManager();
vm->MoveViewTo(mInnerView, offset.x, offset.y);
vm->ResizeView(mInnerView, nsRect(nsPoint(0, 0), innerSize), PR_TRUE);
}
// Determine if we need to repaint our border, background or outline
CheckInvalidateSizeChange(aDesiredSize);

View File

@ -609,7 +609,9 @@ nsObjectFrame::Init(nsIContent* aContent,
nsIFrame* aParent,
nsIFrame* aPrevInFlow)
{
mPreventInstantiation = PR_FALSE;
NS_PRECONDITION(aContent, "How did that happen?");
mPreventInstantiation =
(aContent->GetCurrentDoc()->GetDisplayDocument() != nsnull);
PR_LOG(nsObjectFrameLM, PR_LOG_DEBUG,
("Initializing nsObjectFrame %p for content %p\n", this, aContent));
@ -620,7 +622,9 @@ nsObjectFrame::Init(nsIContent* aContent,
void
nsObjectFrame::Destroy()
{
NS_ASSERTION(!mPreventInstantiation, "about to crash due to bug 136927");
NS_ASSERTION(!mPreventInstantiation ||
mContent && mContent->GetCurrentDoc()->GetDisplayDocument(),
"about to crash due to bug 136927");
// we need to finish with the plugin before native window is destroyed
// doing this in the destructor is too late.
@ -1718,6 +1722,7 @@ nsObjectFrame::Instantiate(const char* aMimeType, nsIURI* aURI)
return rv;
mInstanceOwner->SetPluginHost(pluginHost);
NS_ASSERTION(!mPreventInstantiation, "Say what?");
mPreventInstantiation = PR_TRUE;
rv = InstantiatePlugin(pluginHost, aMimeType, aURI);