[Chrome FastLoad]
Implement XUL Prototype Document and Prototype Element serialization/deserialization scheme for FastLoad of chrome documents. r=brendan, sr=hyatt git-svn-id: svn://10.0.0.236/trunk@120648 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
parent
521dde6f78
commit
989514f6c4
@ -246,6 +246,8 @@ Shutdown(nsIModule* aSelf)
|
||||
nsXULContentUtils::Finish();
|
||||
nsXULAtoms::ReleaseAtoms();
|
||||
nsXULElement::ReleaseGlobals();
|
||||
nsXULPrototypeElement::ReleaseGlobals();
|
||||
nsXULPrototypeScript::ReleaseGlobals();
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_SVG
|
||||
|
||||
@ -55,8 +55,6 @@
|
||||
#include "nsXBLProtoImplMethod.h"
|
||||
#include "nsXBLProtoImplField.h"
|
||||
|
||||
static NS_DEFINE_CID(kCSSParserCID, NS_CSSPARSER_CID);
|
||||
|
||||
nsresult
|
||||
NS_NewXBLContentSink(nsIXMLContentSink** aResult,
|
||||
nsIDocument* aDoc,
|
||||
|
||||
@ -23,6 +23,7 @@
|
||||
* Peter Annema <disttsc@bart.nl>
|
||||
* Brendan Eich <brendan@mozilla.org>
|
||||
* Mike Shaver <shaver@mozilla.org>
|
||||
* Ben Goodger <ben@netscape.com>
|
||||
*
|
||||
* This Original Code has been modified by IBM Corporation.
|
||||
* Modifications made by IBM described herein are
|
||||
@ -81,6 +82,7 @@
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIEventListenerManager.h"
|
||||
#include "nsIEventStateManager.h"
|
||||
#include "nsIFastLoadService.h"
|
||||
#include "nsIHTMLContentContainer.h"
|
||||
#include "nsIHTMLStyleSheet.h"
|
||||
#include "nsIStyleContext.h"
|
||||
@ -152,6 +154,9 @@
|
||||
class nsIWebShell;
|
||||
|
||||
// Global object maintenance
|
||||
nsINodeInfoManager* nsXULPrototypeElement::sNodeInfoManager = nsnull;
|
||||
nsICSSParser* nsXULPrototypeElement::sCSSParser = nsnull;
|
||||
nsIXULPrototypeCache* nsXULPrototypeScript::sXULPrototypeCache = nsnull;
|
||||
nsIXBLService * nsXULElement::gXBLService = nsnull;
|
||||
|
||||
// XXX This is sure to change. Copied from mozilla/layout/xul/content/src/nsXULAtoms.cpp
|
||||
@ -445,25 +450,6 @@ PRUint32 nsXULPrototypeAttribute::gNumCacheSets;
|
||||
PRUint32 nsXULPrototypeAttribute::gNumCacheFills;
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsXULNode
|
||||
// XXXbe temporary, make 'em pure when all subclasses implement
|
||||
|
||||
nsresult
|
||||
nsXULPrototypeNode::Serialize(nsIObjectOutputStream* aStream,
|
||||
nsIScriptContext* aContext)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsXULPrototypeNode::Deserialize(nsIObjectInputStream* aStream,
|
||||
nsIScriptContext* aContext)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsXULElement
|
||||
//
|
||||
@ -4932,38 +4918,182 @@ nsXULPrototypeElement::Serialize(nsIObjectOutputStream* aStream,
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
#if 0
|
||||
// XXXbe partial deserializer is not ready for this yet
|
||||
rv = aStream->Write32(PRUint32(mNumChildren));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
#endif
|
||||
// Write basic prototype data
|
||||
rv = aStream->Write32(mType);
|
||||
rv |= aStream->Write32(mLineNo);
|
||||
|
||||
// XXXbe check for failure once all elements have been taught to serialize
|
||||
for (PRInt32 i = 0; i < mNumChildren; i++) {
|
||||
rv = mChildren[i]->Serialize(aStream, aContext);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv) || rv == NS_ERROR_NOT_IMPLEMENTED,
|
||||
"can't serialize!");
|
||||
// Write Node Info
|
||||
nsAutoString namespaceURI;
|
||||
rv |= mNodeInfo->GetNamespaceURI(namespaceURI);
|
||||
rv |= aStream->WriteWStringZ(namespaceURI.get());
|
||||
|
||||
nsAutoString qualifiedName;
|
||||
rv |= mNodeInfo->GetQualifiedName(qualifiedName);
|
||||
rv |= aStream->WriteWStringZ(qualifiedName.get());
|
||||
|
||||
// Write Attributes
|
||||
rv |= aStream->Write32(mNumAttributes);
|
||||
|
||||
nsAutoString attributeValue, attributeNamespaceURI, attributeName;
|
||||
PRInt32 i;
|
||||
for (i = 0; i < mNumAttributes; ++i) {
|
||||
rv |= mAttributes[i].mNodeInfo->GetNamespaceURI(attributeNamespaceURI);
|
||||
rv |= aStream->WriteWStringZ(attributeNamespaceURI.get());
|
||||
|
||||
rv |= mAttributes[i].mNodeInfo->GetQualifiedName(attributeName);
|
||||
rv |= aStream->WriteWStringZ(attributeName.get());
|
||||
|
||||
rv |= mAttributes[i].mValue.GetValue(attributeValue);
|
||||
rv |= aStream->WriteWStringZ(attributeValue.get());
|
||||
}
|
||||
return NS_OK;
|
||||
|
||||
// Now write children
|
||||
rv |= aStream->Write32(PRUint32(mNumChildren));
|
||||
for (i = 0; i < mNumChildren; i++) {
|
||||
nsXULPrototypeNode* child = mChildren[i];
|
||||
switch (child->mType) {
|
||||
case eType_Element:
|
||||
case eType_Text:
|
||||
rv |= child->Serialize(aStream, aContext);
|
||||
break;
|
||||
case eType_Script:
|
||||
rv |= aStream->Write32(child->mType);
|
||||
nsXULPrototypeScript* script = NS_STATIC_CAST(nsXULPrototypeScript*, child);
|
||||
|
||||
if (script) {
|
||||
rv |= aStream->WriteBoolean(script->mOutOfLine);
|
||||
if (! script->mOutOfLine)
|
||||
rv |= script->Serialize(aStream, aContext);
|
||||
else
|
||||
rv |= aStream->WriteCompoundObject(script->mSrcURI,
|
||||
NS_GET_IID(nsIURI),
|
||||
PR_TRUE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsXULPrototypeElement::Deserialize(nsIObjectInputStream* aStream,
|
||||
nsIScriptContext* aContext)
|
||||
nsIScriptContext* aContext,
|
||||
nsIURI* aDocumentURI)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
PRUint32 numChildren;
|
||||
rv = aStream->Read32(&numChildren);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
PRUint32 number;
|
||||
rv = aStream->Read32(&number);
|
||||
mLineNo = (PRInt32)number;
|
||||
|
||||
// XXXbe temporary until we stop parsing tags when deserializing
|
||||
NS_ASSERTION(PRInt32(numChildren) == mNumChildren, "XUL/FastLoad mismatch");
|
||||
// Read Node Info
|
||||
nsXPIDLString namespaceURI;
|
||||
rv |= aStream->ReadWStringZ(getter_Copies(namespaceURI));
|
||||
|
||||
nsXPIDLString qualifiedName;
|
||||
rv |= aStream->ReadWStringZ(getter_Copies(qualifiedName));
|
||||
|
||||
// XXXbe check for failure once all elements have been taught to serialize
|
||||
for (PRInt32 i = 0; i < mNumChildren; i++)
|
||||
(void) mChildren[i]->Deserialize(aStream, aContext);
|
||||
return NS_OK;
|
||||
nsINodeInfoManager* nimgr = GetNodeInfoManager();
|
||||
rv |= nimgr->GetNodeInfo(qualifiedName, namespaceURI, *getter_AddRefs(mNodeInfo));
|
||||
|
||||
// Read Attributes
|
||||
rv |= aStream->Read32(&number);
|
||||
mNumAttributes = PRInt32(number);
|
||||
|
||||
PRInt32 i;
|
||||
if (mNumAttributes > 0) {
|
||||
mAttributes = new nsXULPrototypeAttribute[mNumAttributes];
|
||||
if (! mAttributes)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
nsXPIDLString attributeValue, attributeNamespaceURI, attributeName;
|
||||
for (i = 0; i < mNumAttributes; ++i) {
|
||||
rv |= aStream->ReadWStringZ(getter_Copies(attributeNamespaceURI));
|
||||
rv |= aStream->ReadWStringZ(getter_Copies(attributeName));
|
||||
|
||||
rv |= nimgr->GetNodeInfo(attributeName, attributeNamespaceURI,
|
||||
*getter_AddRefs(mAttributes[i].mNodeInfo));
|
||||
|
||||
rv |= aStream->ReadWStringZ(getter_Copies(attributeValue));
|
||||
mAttributes[i].mValue.SetValue(attributeValue);
|
||||
}
|
||||
|
||||
// Compute the element's class list if the element has a 'class' attribute.
|
||||
nsAutoString value;
|
||||
if (NS_SUCCEEDED(GetAttr(kNameSpaceID_None, nsXULAtoms::clazz, value)))
|
||||
rv |= nsClassList::ParseClasses(&mClassList, value);
|
||||
|
||||
// Parse the element's 'style' attribute
|
||||
if (NS_SUCCEEDED(GetAttr(kNameSpaceID_None, nsXULAtoms::style, value))) {
|
||||
nsICSSParser* parser = GetCSSParser();
|
||||
|
||||
rv |= parser->ParseStyleAttribute(value, aDocumentURI,
|
||||
getter_AddRefs(mInlineStyleRule));
|
||||
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "unable to parse style rule");
|
||||
}
|
||||
}
|
||||
|
||||
rv |= aStream->Read32(&number);
|
||||
mNumChildren = PRInt32(number);
|
||||
|
||||
if (mNumChildren > 0) {
|
||||
mChildren = new nsXULPrototypeNode*[mNumChildren];
|
||||
if (! mChildren)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
|
||||
for (i = 0; i < mNumChildren; i++) {
|
||||
rv |= aStream->Read32(&number);
|
||||
Type childType = (Type)number;
|
||||
|
||||
nsXULPrototypeNode* child = nsnull;
|
||||
|
||||
switch (childType) {
|
||||
case eType_Element:
|
||||
child = new nsXULPrototypeElement(-1);
|
||||
if (! child)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
child->mType = childType;
|
||||
|
||||
rv |= child->Deserialize(aStream, aContext, aDocumentURI);
|
||||
break;
|
||||
case eType_Text:
|
||||
child = new nsXULPrototypeText(-1);
|
||||
if (! child)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
child->mType = childType;
|
||||
|
||||
rv |= child->Deserialize(aStream, aContext, aDocumentURI);
|
||||
break;
|
||||
case eType_Script:
|
||||
// language version obtained during deserialization.
|
||||
child = new nsXULPrototypeScript(-1, nsnull);
|
||||
if (! child)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
child->mType = childType;
|
||||
|
||||
nsXULPrototypeScript* script = NS_STATIC_CAST(nsXULPrototypeScript*, child);
|
||||
if (script) {
|
||||
rv |= aStream->ReadBoolean(&script->mOutOfLine);
|
||||
if (! script->mOutOfLine)
|
||||
rv |= script->Deserialize(aStream, aContext, aDocumentURI);
|
||||
else {
|
||||
rv |= aStream->ReadObject(PR_TRUE, getter_AddRefs(script->mSrcURI));
|
||||
|
||||
rv |= script->DeserializeOutOfLineScript(aStream, aContext);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
mChildren[i] = child;
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
@ -4989,6 +5119,7 @@ nsXULPrototypeElement::GetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, nsAString&
|
||||
nsXULPrototypeScript::nsXULPrototypeScript(PRInt32 aLineNo, const char *aVersion)
|
||||
: nsXULPrototypeNode(eType_Script, aLineNo),
|
||||
mSrcLoading(PR_FALSE),
|
||||
mOutOfLine(PR_TRUE),
|
||||
mSrcLoadWaiters(nsnull),
|
||||
mJSObject(nsnull),
|
||||
mLangVersion(aVersion)
|
||||
@ -5011,16 +5142,11 @@ nsXULPrototypeScript::Serialize(nsIObjectOutputStream* aStream,
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
// Write basic prototype data
|
||||
aStream->Write32(mLineNo);
|
||||
|
||||
NS_ASSERTION(!mSrcLoading || mSrcLoadWaiters != nsnull || !mJSObject,
|
||||
"script source still loading when serializing?!");
|
||||
|
||||
#if 0
|
||||
// XXXbe redundant while we're still parsing XUL instead of deserializing it
|
||||
// XXXbe also, we should serialize mType and mLineNo first.
|
||||
rv = NS_WriteOptionalCompoundObject(aStream, mSrcURI, NS_GET_IID(nsIURI),
|
||||
PR_TRUE);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
#endif
|
||||
|
||||
JSContext* cx = NS_REINTERPRET_CAST(JSContext*,
|
||||
aContext->GetNativeContext());
|
||||
@ -5072,21 +5198,20 @@ nsXULPrototypeScript::Serialize(nsIObjectOutputStream* aStream,
|
||||
|
||||
nsresult
|
||||
nsXULPrototypeScript::Deserialize(nsIObjectInputStream* aStream,
|
||||
nsIScriptContext* aContext)
|
||||
nsIScriptContext* aContext,
|
||||
nsIURI* aDocumentURI)
|
||||
{
|
||||
NS_TIMELINE_MARK_FUNCTION("chrome js deserialize");
|
||||
nsresult rv;
|
||||
|
||||
// Read basic prototype data
|
||||
PRUint32 number;
|
||||
aStream->Read32(&number);
|
||||
mLineNo = (PRInt32)number;
|
||||
|
||||
NS_ASSERTION(!mSrcLoading || mSrcLoadWaiters != nsnull || !mJSObject,
|
||||
"prototype script not well-initialized when deserializing?!");
|
||||
|
||||
#if 0
|
||||
// XXXbe redundant while we're still parsing XUL instead of deserializing it
|
||||
// XXXbe also, we should deserialize mType and mLineNo first.
|
||||
rv = NS_ReadOptionalObject(aStream, PR_TRUE, getter_AddRefs(mSrcURI));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
#endif
|
||||
|
||||
PRUint32 size;
|
||||
rv = aStream->Read32(&size);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
@ -5157,8 +5282,106 @@ nsXULPrototypeScript::Deserialize(nsIObjectInputStream* aStream,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// XXXbe temporary, goes away when we serialize entire XUL prototype document
|
||||
#include "nsIFastLoadService.h"
|
||||
|
||||
nsresult
|
||||
nsXULPrototypeScript::DeserializeOutOfLineScript(nsIObjectInputStream* aInput,
|
||||
nsIScriptContext* aContext)
|
||||
{
|
||||
nsIXULPrototypeCache* cache = GetXULCache();
|
||||
nsCOMPtr<nsIFastLoadService> fastLoadService;
|
||||
cache->GetFastLoadService(getter_AddRefs(fastLoadService));
|
||||
|
||||
nsCOMPtr<nsIObjectInputStream> objectInput;
|
||||
if (fastLoadService)
|
||||
fastLoadService->GetInputStream(getter_AddRefs(objectInput));
|
||||
|
||||
if (objectInput) {
|
||||
PRBool useXULCache = PR_TRUE;
|
||||
if (mSrcURI) {
|
||||
// NB: we must check the XUL script cache early, to avoid
|
||||
// multiple deserialization attempts for a given script, which
|
||||
// would exhaust the multiplexed stream containing the singly
|
||||
// serialized script. Note that nsXULDocument::LoadScript
|
||||
// checks the XUL script cache too, in order to handle the
|
||||
// serialization case.
|
||||
//
|
||||
// We need do this only for <script src='strres.js'> and the
|
||||
// like, i.e., out-of-line scripts that are included by several
|
||||
// different XUL documents multiplexed in the FastLoad file.
|
||||
cache->GetEnabled(&useXULCache);
|
||||
|
||||
if (useXULCache) {
|
||||
cache->GetScript(mSrcURI, NS_REINTERPRET_CAST(void**, &mJSObject));
|
||||
}
|
||||
}
|
||||
|
||||
if (! mJSObject) {
|
||||
// Keep track of FastLoad failure via rv, so we can
|
||||
// AbortFastLoads if things look bad.
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
nsCOMPtr<nsIURI> oldURI;
|
||||
|
||||
if (mSrcURI) {
|
||||
nsCAutoString spec;
|
||||
mSrcURI->GetAsciiSpec(spec);
|
||||
rv = fastLoadService->StartMuxedDocument(mSrcURI, spec.get(),
|
||||
nsIFastLoadService::NS_FASTLOAD_READ);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
rv = fastLoadService->SelectMuxedDocument(mSrcURI, getter_AddRefs(oldURI));
|
||||
} else {
|
||||
// An inline script: check FastLoad multiplexing direction
|
||||
// and skip Deserialize if we're not reading from a
|
||||
// muxed stream to get inline objects that are contained in
|
||||
// the current document.
|
||||
PRInt32 direction;
|
||||
fastLoadService->GetDirection(&direction);
|
||||
if (direction != nsIFastLoadService::NS_FASTLOAD_READ)
|
||||
rv = NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
// Don't reflect errors into rv: mJSObject will be null
|
||||
// after any error, which suffices to cause the script to
|
||||
// be reloaded (from the src= URI, if any) and recompiled.
|
||||
// We're better off slow-loading than bailing out due to a
|
||||
// FastLoad error.
|
||||
if (NS_SUCCEEDED(rv))
|
||||
rv = Deserialize(objectInput, aContext, nsnull);
|
||||
|
||||
if (NS_SUCCEEDED(rv) && mSrcURI) {
|
||||
rv = fastLoadService->EndMuxedDocument(mSrcURI);
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
nsCOMPtr<nsIURI> tempURI;
|
||||
rv = fastLoadService->SelectMuxedDocument(oldURI, getter_AddRefs(tempURI));
|
||||
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv) && (!tempURI || tempURI == mSrcURI),
|
||||
"not currently deserializing into the script we thought we were!");
|
||||
}
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
if (useXULCache && mSrcURI) {
|
||||
PRBool isChrome = PR_FALSE;
|
||||
mSrcURI->SchemeIs("chrome", &isChrome);
|
||||
if (isChrome) {
|
||||
nsIXULPrototypeCache* cache = GetXULCache();
|
||||
cache->PutScript(mSrcURI, NS_REINTERPRET_CAST(void*, mJSObject));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// If mSrcURI is not in the FastLoad multiplex,
|
||||
// rv will be NS_ERROR_NOT_AVAILABLE and we'll try to
|
||||
// update the FastLoad file to hold a serialization of
|
||||
// this script, once it has finished loading.
|
||||
if (rv != NS_ERROR_NOT_AVAILABLE)
|
||||
cache->AbortFastLoads();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsXULPrototypeScript::Compile(const PRUnichar* aText,
|
||||
@ -5229,7 +5452,7 @@ nsXULPrototypeScript::Compile(const PRUnichar* aText,
|
||||
(void**)&mJSObject);
|
||||
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
|
||||
if (mJSObject) {
|
||||
// Root the compiled prototype script object.
|
||||
JSContext* cx = NS_REINTERPRET_CAST(JSContext*,
|
||||
@ -5237,18 +5460,64 @@ nsXULPrototypeScript::Compile(const PRUnichar* aText,
|
||||
if (!cx)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
// XXXbe temporary, until we serialize/deserialize everything from the
|
||||
// nsXULPrototypeDocument on down...
|
||||
nsCOMPtr<nsIFastLoadService> fastLoadService(do_GetFastLoadService());
|
||||
nsCOMPtr<nsIObjectOutputStream> objectOutput;
|
||||
fastLoadService->GetOutputStream(getter_AddRefs(objectOutput));
|
||||
if (objectOutput) {
|
||||
rv = Serialize(objectOutput, context);
|
||||
if (NS_FAILED(rv))
|
||||
nsXULDocument::AbortFastLoads();
|
||||
|
||||
if (mOutOfLine) {
|
||||
nsCOMPtr<nsIFastLoadService> fastLoadService;
|
||||
|
||||
nsIXULPrototypeCache* cache = GetXULCache();
|
||||
cache->GetFastLoadService(getter_AddRefs(fastLoadService));
|
||||
|
||||
if (fastLoadService) {
|
||||
nsCOMPtr<nsIObjectOutputStream> objectOutput;
|
||||
fastLoadService->GetOutputStream(getter_AddRefs(objectOutput));
|
||||
if (objectOutput) {
|
||||
rv = Serialize(objectOutput, context);
|
||||
if (NS_FAILED(rv))
|
||||
cache->AbortFastLoads();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
//
|
||||
// nsXULPrototypeText
|
||||
//
|
||||
|
||||
nsresult
|
||||
nsXULPrototypeText::Serialize(nsIObjectOutputStream* aStream,
|
||||
nsIScriptContext* aContext)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
// Write basic prototype data
|
||||
rv = aStream->Write32(mType);
|
||||
rv |= aStream->Write32(mLineNo);
|
||||
|
||||
rv |= aStream->WriteWStringZ(mValue.get());
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsXULPrototypeText::Deserialize(nsIObjectInputStream* aStream,
|
||||
nsIScriptContext* aContext,
|
||||
nsIURI* aDocumentURI)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
// Write basic prototype data
|
||||
PRUint32 number;
|
||||
rv = aStream->Read32(&number);
|
||||
mLineNo = (PRInt32)number;
|
||||
|
||||
PRUnichar* str = nsnull;
|
||||
rv |= aStream->ReadWStringZ(&str);
|
||||
mValue.Adopt(str);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -23,6 +23,7 @@
|
||||
* Chris Waterson <waterson@netscape.com>
|
||||
* Peter Annema <disttsc@bart.nl>
|
||||
* Mike Shaver <shaver@mozilla.org>
|
||||
* Ben Goodger <ben@netscape.com>
|
||||
*
|
||||
* 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
|
||||
@ -54,6 +55,7 @@
|
||||
#include "nsIAtom.h"
|
||||
#include "nsINodeInfo.h"
|
||||
#include "nsIControllers.h"
|
||||
#include "nsICSSParser.h"
|
||||
#include "nsIDOMElement.h"
|
||||
#include "nsIDOMEventReceiver.h"
|
||||
#include "nsIDOMXULElement.h"
|
||||
@ -69,12 +71,14 @@
|
||||
#include "nsIXBLBinding.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsIXULContent.h"
|
||||
#include "nsIXULPrototypeCache.h"
|
||||
#include "nsIXULTemplateBuilder.h"
|
||||
#include "nsIBoxObject.h"
|
||||
#include "nsXULAttributes.h"
|
||||
#include "nsIChromeEventHandler.h"
|
||||
#include "nsXULAttributeValue.h"
|
||||
#include "nsIXBLService.h"
|
||||
#include "nsLayoutCID.h"
|
||||
|
||||
#include "nsGenericElement.h" // for nsCheapVoidArray
|
||||
|
||||
@ -94,6 +98,8 @@ class nsIWebShell;
|
||||
class nsIObjectInputStream;
|
||||
class nsIObjectOutputStream;
|
||||
|
||||
static NS_DEFINE_CID(kCSSParserCID, NS_CSSPARSER_CID);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef XUL_PROTOTYPE_ATTRIBUTE_METERING
|
||||
@ -195,9 +201,10 @@ public:
|
||||
|
||||
virtual ~nsXULPrototypeNode() {}
|
||||
virtual nsresult Serialize(nsIObjectOutputStream* aStream,
|
||||
nsIScriptContext* aContext);
|
||||
nsIScriptContext* aContext) = 0;
|
||||
virtual nsresult Deserialize(nsIObjectInputStream* aStream,
|
||||
nsIScriptContext* aContext);
|
||||
nsIScriptContext* aContext,
|
||||
nsIURI* aDocumentURI) = 0;
|
||||
|
||||
void AddRef() { mRefCnt++; };
|
||||
void Release()
|
||||
@ -249,7 +256,8 @@ public:
|
||||
virtual nsresult Serialize(nsIObjectOutputStream* aStream,
|
||||
nsIScriptContext* aContext);
|
||||
virtual nsresult Deserialize(nsIObjectInputStream* aStream,
|
||||
nsIScriptContext* aContext);
|
||||
nsIScriptContext* aContext,
|
||||
nsIURI* aDocumentURI);
|
||||
|
||||
PRInt32 mNumChildren;
|
||||
nsXULPrototypeNode** mChildren; // [OWNER]
|
||||
@ -263,6 +271,36 @@ public:
|
||||
nsClassList* mClassList;
|
||||
|
||||
nsresult GetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, nsAString& aValue);
|
||||
|
||||
|
||||
static void ReleaseGlobals()
|
||||
{
|
||||
NS_IF_RELEASE(sNodeInfoManager);
|
||||
NS_IF_RELEASE(sCSSParser);
|
||||
}
|
||||
|
||||
protected:
|
||||
static nsINodeInfoManager* GetNodeInfoManager()
|
||||
{
|
||||
if (!sNodeInfoManager) {
|
||||
CallCreateInstance(NS_NODEINFOMANAGER_CONTRACTID, &sNodeInfoManager);
|
||||
|
||||
nsCOMPtr<nsINameSpaceManager> nsmgr;
|
||||
NS_NewNameSpaceManager(getter_AddRefs(nsmgr));
|
||||
|
||||
sNodeInfoManager->Init(nsnull, nsmgr);
|
||||
}
|
||||
return sNodeInfoManager;
|
||||
}
|
||||
static nsINodeInfoManager* sNodeInfoManager;
|
||||
|
||||
static nsICSSParser* GetCSSParser()
|
||||
{
|
||||
if (!sCSSParser)
|
||||
CallCreateInstance(kCSSParserCID, &sCSSParser);
|
||||
return sCSSParser;
|
||||
}
|
||||
static nsICSSParser* sCSSParser;
|
||||
};
|
||||
|
||||
struct JSRuntime;
|
||||
@ -278,7 +316,10 @@ public:
|
||||
virtual nsresult Serialize(nsIObjectOutputStream* aStream,
|
||||
nsIScriptContext* aContext);
|
||||
virtual nsresult Deserialize(nsIObjectInputStream* aStream,
|
||||
nsIScriptContext* aContext);
|
||||
nsIScriptContext* aContext,
|
||||
nsIURI* aDocumentURI);
|
||||
virtual nsresult DeserializeOutOfLineScript(nsIObjectInputStream* aInput,
|
||||
nsIScriptContext* aContext);
|
||||
|
||||
nsresult Compile(const PRUnichar* aText, PRInt32 aTextLength,
|
||||
nsIURI* aURI, PRInt32 aLineNo,
|
||||
@ -287,9 +328,25 @@ public:
|
||||
|
||||
nsCOMPtr<nsIURI> mSrcURI;
|
||||
PRBool mSrcLoading;
|
||||
PRBool mOutOfLine;
|
||||
nsXULDocument* mSrcLoadWaiters; // [OWNER] but not COMPtr
|
||||
JSObject* mJSObject;
|
||||
const char* mLangVersion;
|
||||
|
||||
static void ReleaseGlobals()
|
||||
{
|
||||
NS_IF_RELEASE(sXULPrototypeCache);
|
||||
}
|
||||
|
||||
protected:
|
||||
static nsIXULPrototypeCache* GetXULCache()
|
||||
{
|
||||
if (!sXULPrototypeCache)
|
||||
CallGetService("@mozilla.org/xul/xul-prototype-cache;1", &sXULPrototypeCache);
|
||||
|
||||
return sXULPrototypeCache;
|
||||
}
|
||||
static nsIXULPrototypeCache* sXULPrototypeCache;
|
||||
};
|
||||
|
||||
class nsXULPrototypeText : public nsXULPrototypeNode
|
||||
@ -306,6 +363,12 @@ public:
|
||||
MOZ_COUNT_DTOR(nsXULPrototypeText);
|
||||
}
|
||||
|
||||
virtual nsresult Serialize(nsIObjectOutputStream* aStream,
|
||||
nsIScriptContext* aContext);
|
||||
virtual nsresult Deserialize(nsIObjectInputStream* aStream,
|
||||
nsIScriptContext* aContext,
|
||||
nsIURI* aDocumentURI);
|
||||
|
||||
nsString mValue;
|
||||
};
|
||||
|
||||
|
||||
@ -161,11 +161,6 @@ public:
|
||||
*/
|
||||
NS_IMETHOD OnPrototypeLoadDone() = 0;
|
||||
|
||||
/**
|
||||
* Callback from the content sink upon resumption from the parser.
|
||||
*/
|
||||
NS_IMETHOD OnResumeContentSink() = 0;
|
||||
|
||||
/**
|
||||
* Notify the XUL document that it's being hidden
|
||||
*/
|
||||
|
||||
@ -20,6 +20,7 @@
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Ben Goodger <ben@netscape.com>
|
||||
*
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
@ -49,9 +50,11 @@
|
||||
class nsICSSStyleSheet;
|
||||
class nsIURI;
|
||||
class nsIXULPrototypeDocument;
|
||||
class nsIXULDocument;
|
||||
class nsCString;
|
||||
class nsIDocument;
|
||||
class nsIXBLDocumentInfo;
|
||||
class nsIFastLoadService;
|
||||
|
||||
// {3A0A0FC1-8349-11d3-BE47-00104BDE6048}
|
||||
#define NS_XULPROTOTYPECACHE_CID \
|
||||
@ -105,10 +108,34 @@ public:
|
||||
* Stop the FastLoad process abruptly, removing the FastLoad file.
|
||||
*/
|
||||
NS_IMETHOD AbortFastLoads() = 0;
|
||||
|
||||
/**
|
||||
* Retrieve the FastLoad service
|
||||
*/
|
||||
NS_IMETHOD GetFastLoadService(nsIFastLoadService** aResult) = 0;
|
||||
|
||||
/**
|
||||
* Remove a XULDocument from the set of loading documents
|
||||
*/
|
||||
NS_IMETHOD RemoveFromFastLoadSet(nsIURI* aDocumentURI) = 0;
|
||||
|
||||
/**
|
||||
* Write Prototype Document to FastLoad file
|
||||
*/
|
||||
NS_IMETHOD WritePrototype(nsIXULPrototypeDocument* aDocument) = 0;
|
||||
};
|
||||
|
||||
|
||||
extern NS_IMETHODIMP
|
||||
NS_NewXULPrototypeCache(nsISupports* aOuter, REFNSIID aIID, void** aResult);
|
||||
|
||||
|
||||
const char XUL_FASTLOAD_FILE_BASENAME[] = "XUL";
|
||||
|
||||
#define XUL_FASTLOAD_FILE_VERSION (0xfeedbeef - 4)
|
||||
|
||||
#define XUL_SERIALIZATION_BUFFER_SIZE (64 * 1024)
|
||||
#define XUL_DESERIALIZATION_BUFFER_SIZE (8 * 1024)
|
||||
|
||||
|
||||
#endif // nsIXULPrototypeCache_h__
|
||||
|
||||
@ -56,6 +56,7 @@ class nsString;
|
||||
class nsVoidArray;
|
||||
class nsXULPrototypeElement;
|
||||
class nsIXULDocument;
|
||||
class nsIScriptGlobalObject;
|
||||
|
||||
// {187A63D0-8337-11d3-BE47-00104BDE6048}
|
||||
#define NS_IXULPROTOTYPEDOCUMENT_IID \
|
||||
|
||||
@ -52,6 +52,9 @@ REQUIRES = xpcom \
|
||||
|
||||
DEFINES=-D_IMPL_NS_HTML -DWIN32_LEAN_AND_MEAN
|
||||
|
||||
EXPORTS = \
|
||||
$(NULL)
|
||||
|
||||
CPP_OBJS= \
|
||||
.\$(OBJDIR)\nsElementMap.obj \
|
||||
.\$(OBJDIR)\nsXULCommandDispatcher.obj \
|
||||
|
||||
@ -42,10 +42,7 @@
|
||||
/*
|
||||
|
||||
An implementation for a Gecko-style content sink that knows how
|
||||
to build an RDF content model from XUL.
|
||||
|
||||
For each container tag, an RDF Sequence object is created that
|
||||
contains the order set of children of that container.
|
||||
to build a content model from XUL.
|
||||
|
||||
For more information on XUL, see http://www.mozilla.org/xpfe
|
||||
|
||||
@ -74,8 +71,6 @@
|
||||
#include "nsINodeInfo.h"
|
||||
#include "nsIParser.h"
|
||||
#include "nsIPresShell.h"
|
||||
#include "nsIRDFCompositeDataSource.h"
|
||||
#include "nsIRDFService.h"
|
||||
#include "nsIScriptContext.h"
|
||||
#include "nsIScriptGlobalObject.h"
|
||||
#include "nsIScriptGlobalObjectOwner.h"
|
||||
@ -120,7 +115,6 @@ static PRLogModuleInfo* gLog;
|
||||
static const char kXULNameSpaceURI[] = XUL_NAMESPACE_URI;
|
||||
|
||||
|
||||
static NS_DEFINE_CID(kCSSParserCID, NS_CSSPARSER_CID);
|
||||
static NS_DEFINE_CID(kNameSpaceManagerCID, NS_NAMESPACEMANAGER_CID);
|
||||
static NS_DEFINE_CID(kXULPrototypeCacheCID, NS_XULPROTOTYPECACHE_CID);
|
||||
|
||||
@ -553,10 +547,6 @@ XULContentSinkImpl::WillInterrupt(void)
|
||||
NS_IMETHODIMP
|
||||
XULContentSinkImpl::WillResume(void)
|
||||
{
|
||||
nsCOMPtr<nsIXULDocument> xuldoc(do_QueryReferent(mDocument));
|
||||
if (xuldoc)
|
||||
xuldoc->OnResumeContentSink();
|
||||
|
||||
// XXX Notify the webshell, if necessary
|
||||
return NS_OK;
|
||||
}
|
||||
@ -951,6 +941,8 @@ XULContentSinkImpl::HandleEndElement(const PRUnichar *aName)
|
||||
if (! script->mSrcURI && ! script->mJSObject) {
|
||||
nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument);
|
||||
|
||||
script->mOutOfLine = PR_FALSE;
|
||||
|
||||
rv = script->Compile(mText, mTextLength, mDocumentURL,
|
||||
script->mLineNo, doc, mPrototype);
|
||||
}
|
||||
@ -1487,109 +1479,6 @@ XULContentSinkImpl::OpenScript(const PRUnichar** aAttributes,
|
||||
}
|
||||
}
|
||||
|
||||
// XXXbe temporary, until we serialize/deserialize everything from
|
||||
// the nsXULPrototypeDocument on down...
|
||||
nsCOMPtr<nsIFastLoadService> fastLoadService;
|
||||
nsCOMPtr<nsIObjectInputStream> objectInput;
|
||||
nsXULDocument::GetFastLoadService(getter_AddRefs(fastLoadService));
|
||||
if (fastLoadService)
|
||||
fastLoadService->GetInputStream(getter_AddRefs(objectInput));
|
||||
|
||||
if (objectInput) {
|
||||
PRBool useXULCache = PR_TRUE;
|
||||
if (script->mSrcURI) {
|
||||
// NB: we must check the XUL script cache early, to avoid
|
||||
// multiple deserialization attempts for a given script, which
|
||||
// would exhaust the multiplexed stream containing the singly
|
||||
// serialized script. Note that nsXULDocument::LoadScript
|
||||
// checks the XUL script cache too, in order to handle the
|
||||
// serialization case.
|
||||
//
|
||||
// We need do this only for <script src='strres.js'> and the
|
||||
// like, i.e., out-of-line scripts that are included by several
|
||||
// different XUL documents multiplexed in the FastLoad file.
|
||||
gXULCache->GetEnabled(&useXULCache);
|
||||
|
||||
if (useXULCache) {
|
||||
gXULCache->GetScript(script->mSrcURI,
|
||||
NS_REINTERPRET_CAST(void**, &script->mJSObject));
|
||||
}
|
||||
}
|
||||
|
||||
if (! script->mJSObject) {
|
||||
nsCOMPtr<nsIScriptGlobalObjectOwner> globalOwner(do_QueryInterface(mPrototype));
|
||||
nsCOMPtr<nsIScriptGlobalObject> globalObject;
|
||||
globalOwner->GetScriptGlobalObject(getter_AddRefs(globalObject));
|
||||
NS_ASSERTION(globalObject != nsnull, "no prototype global object!");
|
||||
|
||||
nsCOMPtr<nsIScriptContext> scriptContext;
|
||||
globalObject->GetContext(getter_AddRefs(scriptContext));
|
||||
NS_ASSERTION(scriptContext != nsnull,
|
||||
"no prototype script context!");
|
||||
|
||||
// Keep track of FastLoad failure via rv2, so we can
|
||||
// AbortFastLoads if things look bad.
|
||||
nsresult rv2 = NS_OK;
|
||||
if (script->mSrcURI) {
|
||||
nsCAutoString spec;
|
||||
script->mSrcURI->GetAsciiSpec(spec);
|
||||
rv2 = fastLoadService->StartMuxedDocument(script->mSrcURI,
|
||||
spec.get(),
|
||||
nsIFastLoadService::NS_FASTLOAD_READ);
|
||||
if (NS_SUCCEEDED(rv2))
|
||||
rv2 = fastLoadService->SelectMuxedDocument(script->mSrcURI);
|
||||
} else {
|
||||
// An inline script: check FastLoad multiplexing direction
|
||||
// and skip script->Deserialize if we're not reading from a
|
||||
// muxed stream to get inline objects that are contained in
|
||||
// the current document.
|
||||
PRInt32 direction;
|
||||
fastLoadService->GetDirection(&direction);
|
||||
if (direction != nsIFastLoadService::NS_FASTLOAD_READ)
|
||||
rv2 = NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
// Don't reflect errors into rv: mJSObject will be null
|
||||
// after any error, which suffices to cause the script to
|
||||
// be reloaded (from the src= URI, if any) and recompiled.
|
||||
// We're better off slow-loading than bailing out due to a
|
||||
// FastLoad error.
|
||||
if (NS_SUCCEEDED(rv2))
|
||||
rv2 = script->Deserialize(objectInput, scriptContext);
|
||||
|
||||
if (NS_SUCCEEDED(rv2) && script->mSrcURI) {
|
||||
rv2 = fastLoadService->EndMuxedDocument(script->mSrcURI);
|
||||
if (NS_SUCCEEDED(rv2)) {
|
||||
// We must reselect the including XUL document now,
|
||||
// in case the next script in it is an inline one
|
||||
// whose data comes from its stream, not from the
|
||||
// now-exhausted document that was multiplexed for
|
||||
// script->mSrcURI. Inline scripts are compiled in
|
||||
// XULContentSinkImpl::CloseContainer.
|
||||
rv2 = fastLoadService->SelectMuxedDocument(mDocumentURL);
|
||||
}
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(rv2)) {
|
||||
if (useXULCache && script->mSrcURI) {
|
||||
PRBool isChrome = PR_FALSE;
|
||||
script->mSrcURI->SchemeIs("chrome", &isChrome);
|
||||
if (isChrome) {
|
||||
gXULCache->PutScript(script->mSrcURI,
|
||||
NS_REINTERPRET_CAST(void*, script->mJSObject));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// If script->mSrcURI is not in the FastLoad multiplex,
|
||||
// rv2 will be NS_ERROR_NOT_AVAILABLE and we'll try to
|
||||
// update the FastLoad file to hold a serialization of
|
||||
// this script, once it has finished loading.
|
||||
if (rv2 != NS_ERROR_NOT_AVAILABLE)
|
||||
nsXULDocument::AbortFastLoads();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsVoidArray* children;
|
||||
rv = mContextStack.GetTopChildren(&children);
|
||||
if (NS_FAILED(rv)) {
|
||||
|
||||
@ -48,7 +48,7 @@
|
||||
Notes
|
||||
-----
|
||||
|
||||
1. We do some monkey business in the document observer methods to
|
||||
1. We do some monkey business in the document observer methods to`
|
||||
keep the element map in sync for HTML elements. Why don't we just
|
||||
do it for _all_ elements? Well, in the case of XUL elements,
|
||||
which may be lazily created during frame construction, the
|
||||
@ -156,8 +156,6 @@
|
||||
#include "nsMimeTypes.h"
|
||||
#include "nsISelectionController.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsAppDirectoryServiceDefs.h"
|
||||
#include "nsIFastLoadFileControl.h"
|
||||
#include "nsIFastLoadService.h"
|
||||
#include "nsIObjectInputStream.h"
|
||||
#include "nsIObjectOutputStream.h"
|
||||
@ -193,7 +191,7 @@ static NS_DEFINE_IID(kIParserIID, NS_IPARSER_IID);
|
||||
static PRBool IsChromeURI(nsIURI* aURI)
|
||||
{
|
||||
// why is this check a member function of nsXULDocument? -gagan
|
||||
PRBool isChrome=PR_FALSE;
|
||||
PRBool isChrome = PR_FALSE;
|
||||
if (NS_SUCCEEDED(aURI->SchemeIs("chrome", &isChrome)) && isChrome)
|
||||
return PR_TRUE;
|
||||
return PR_FALSE;
|
||||
@ -422,9 +420,8 @@ nsXULDocument::nsXULDocument(void)
|
||||
mNextSrcLoadWaiter(nsnull),
|
||||
mDisplaySelection(PR_FALSE),
|
||||
mIsPopup(PR_FALSE),
|
||||
mIsFastLoad(PR_FALSE),
|
||||
mApplyingPersistedAttrs(PR_FALSE),
|
||||
mNextFastLoad(nsnull),
|
||||
mIsWritingFastLoad(PR_FALSE),
|
||||
mBoxObjectTable(nsnull),
|
||||
mTemplateBuilderTable(nsnull),
|
||||
mResolutionPhase(nsForwardReference::eStart),
|
||||
@ -449,10 +446,6 @@ nsXULDocument::nsXULDocument(void)
|
||||
mSubDocuments = nsnull;
|
||||
}
|
||||
|
||||
nsIFastLoadService* nsXULDocument::gFastLoadService = nsnull;
|
||||
nsIFile* nsXULDocument::gFastLoadFile = nsnull;
|
||||
nsXULDocument* nsXULDocument::gFastLoadList = nsnull;
|
||||
|
||||
nsXULDocument::~nsXULDocument()
|
||||
{
|
||||
NS_ASSERTION(mNextSrcLoadWaiter == nsnull,
|
||||
@ -531,20 +524,21 @@ nsXULDocument::~nsXULDocument()
|
||||
}
|
||||
|
||||
if (gXULCache) {
|
||||
// Remove the current document here from the FastLoad table in
|
||||
// case the document did not make it past StartLayout in
|
||||
// ResumeWalk. The FastLoad table must be clear of entries so
|
||||
// that the FastLoad file footer can be properly written.
|
||||
gXULCache->RemoveFromFastLoadSet(mDocumentURL);
|
||||
|
||||
nsServiceManager::ReleaseService(kXULPrototypeCacheCID, gXULCache);
|
||||
gXULCache = nsnull;
|
||||
}
|
||||
|
||||
NS_IF_RELEASE(gFastLoadService); // don't need ReleaseService nowadays!
|
||||
NS_IF_RELEASE(gFastLoadFile);
|
||||
}
|
||||
|
||||
if (mNodeInfoManager) {
|
||||
mNodeInfoManager->DropDocumentReference();
|
||||
}
|
||||
|
||||
if (mIsFastLoad)
|
||||
RemoveFromFastLoadList();
|
||||
}
|
||||
|
||||
|
||||
@ -732,26 +726,28 @@ nsXULDocument::StartDocumentLoad(const char* aCommand,
|
||||
rv = PrepareStyleSheets(mDocumentURL);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// Get the content type, if possible, to see if it's a cached XUL
|
||||
// load. We explicitly ignore failure at this point, because
|
||||
// certain hacks (cough, the directory viewer) need to be able to
|
||||
// StartDocumentLoad() before the channel's content type has been
|
||||
// detected.
|
||||
|
||||
nsCAutoString contentType;
|
||||
aChannel->GetContentType(contentType);
|
||||
|
||||
if (contentType.Equals(NS_LITERAL_CSTRING("mozilla.application/cached-xul"))) {
|
||||
// Look in the chrome cache: we've got this puppy loaded
|
||||
// already.
|
||||
nsCOMPtr<nsIXULPrototypeDocument> proto;
|
||||
rv = gXULCache->GetPrototype(mDocumentURL, getter_AddRefs(proto));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
NS_ASSERTION(proto != nsnull, "no prototype on cached load");
|
||||
if (! proto)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
// Look in the chrome cache: we've got this puppy loaded
|
||||
// already.
|
||||
nsCOMPtr<nsIXULPrototypeDocument> proto;
|
||||
gXULCache->GetPrototype(mDocumentURL, getter_AddRefs(proto));
|
||||
|
||||
// Same comment as nsChromeProtocolHandler::NewChannel and
|
||||
// nsXULDocument::ResumeWalk
|
||||
// - Ben Goodger
|
||||
//
|
||||
// We don't abort on failure here because there are too many valid
|
||||
// cases that can return failure, and the null-ness of |proto| is enough
|
||||
// to trigger the fail-safe parse-from-disk solution. Example failure cases
|
||||
// (for reference) include:
|
||||
//
|
||||
// NS_ERROR_NOT_AVAILABLE: the URI cannot be found in the FastLoad cache,
|
||||
// parse from disk
|
||||
// other: the FastLoad cache file, XUL.mfl, could not be found, probably
|
||||
// due to being accessed before a profile has been selected (e.g.
|
||||
// loading chrome for the profile manager itself). This must be
|
||||
// parsed from disk.
|
||||
|
||||
if (proto) {
|
||||
// If we're racing with another document to load proto, wait till the
|
||||
// load has finished loading before trying to add cloned style sheets.
|
||||
// nsXULDocument::EndLoad will call proto->NotifyLoadDone, which will
|
||||
@ -784,20 +780,16 @@ nsXULDocument::StartDocumentLoad(const char* aCommand,
|
||||
gXULCache->GetEnabled(&useXULCache);
|
||||
PRBool fillXULCache = (useXULCache && IsChromeURI(mDocumentURL));
|
||||
|
||||
// Try to open a FastLoad file for reading, or create one for writing.
|
||||
// If one exists and looks valid, the nsIFastLoadService will purvey
|
||||
// a non-null input stream via its GetInputStream method, and we will
|
||||
// deserialize saved objects from that stream. Otherwise, we'll write
|
||||
// to the output stream returned by GetOutputStream.
|
||||
if (fillXULCache && nsCRT::strcmp(aCommand, "view-source") != 0)
|
||||
StartFastLoad();
|
||||
|
||||
// It's just a vanilla document load. Create a parser to deal
|
||||
// with the stream n' stuff.
|
||||
|
||||
nsCOMPtr<nsIParser> parser;
|
||||
rv = PrepareToLoad(aContainer, aCommand, aChannel, aLoadGroup, getter_AddRefs(parser));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
mIsWritingFastLoad = PR_TRUE;
|
||||
|
||||
nsCOMPtr<nsIStreamListener> listener = do_QueryInterface(parser, &rv);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "parser doesn't support nsIStreamListener");
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
@ -1744,6 +1736,7 @@ nsXULDocument::EndLoad()
|
||||
|
||||
// Whack the prototype document into the cache so that the next
|
||||
// time somebody asks for it, they don't need to load it by hand.
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
rv = mCurrentPrototype->GetURI(getter_AddRefs(uri));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
@ -1752,8 +1745,16 @@ nsXULDocument::EndLoad()
|
||||
PRBool useXULCache;
|
||||
gXULCache->GetEnabled(&useXULCache);
|
||||
|
||||
// If the current prototype is an overlay document (non-master prototype)
|
||||
// and we're filling the FastLoad disk cache, tell the cache we're done
|
||||
// loading it, and write the prototype.
|
||||
if (useXULCache && mIsWritingFastLoad &&
|
||||
mMasterPrototype != mCurrentPrototype)
|
||||
gXULCache->WritePrototype(mCurrentPrototype);
|
||||
|
||||
nsCOMPtr<nsIXULChromeRegistry> reg(do_GetService(kChromeRegistryCID, &rv));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsCOMPtr<nsISupportsArray> sheets;
|
||||
reg->GetStyleSheets(uri, getter_AddRefs(sheets));
|
||||
|
||||
@ -1784,11 +1785,6 @@ nsXULDocument::EndLoad()
|
||||
rv = mCurrentPrototype->NotifyLoadDone();
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (mIsFastLoad) {
|
||||
rv = gFastLoadService->EndMuxedDocument(uri);
|
||||
if (NS_FAILED(rv))
|
||||
AbortFastLoads();
|
||||
}
|
||||
}
|
||||
|
||||
// Now walk the prototype to build content.
|
||||
@ -1826,23 +1822,6 @@ nsXULDocument::OnPrototypeLoadDone()
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXULDocument::OnResumeContentSink()
|
||||
{
|
||||
if (mIsFastLoad) {
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
|
||||
rv = mCurrentPrototype->GetURI(getter_AddRefs(uri));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = gFastLoadService->SelectMuxedDocument(uri);
|
||||
if (NS_FAILED(rv))
|
||||
AbortFastLoads();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PR_STATIC_CALLBACK(PRBool)
|
||||
ClearPresentationStuff(nsHashKey *aKey, void *aData, void* aClosure)
|
||||
{
|
||||
@ -2154,6 +2133,7 @@ nsXULDocument::ExecuteOnBroadcastHandlerFor(nsIContent* aBroadcaster,
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXULDocument::AttributeChanged(nsIContent* aElement,
|
||||
PRInt32 aNameSpaceID,
|
||||
@ -4917,411 +4897,6 @@ nsXULDocument::CreateElement(nsINodeInfo *aNodeInfo, nsIContent** aResult)
|
||||
}
|
||||
|
||||
|
||||
const char XUL_FASTLOAD_FILE_BASENAME[] = "XUL";
|
||||
|
||||
// XXXbe move to nsXULPrototypeDocument.cpp in the nsISerializable section.
|
||||
// We'll increment (or maybe decrement, for easier deciphering) this maigc
|
||||
// number as we flesh out the FastLoad file to include more and more data
|
||||
// induced by the master prototype document.
|
||||
|
||||
#define XUL_FASTLOAD_FILE_VERSION (0xfeedbeef - 3)
|
||||
|
||||
#define XUL_SERIALIZATION_BUFFER_SIZE (64 * 1024)
|
||||
#define XUL_DESERIALIZATION_BUFFER_SIZE (8 * 1024)
|
||||
|
||||
|
||||
class nsXULFastLoadFileIO : public nsIFastLoadFileIO
|
||||
{
|
||||
public:
|
||||
nsXULFastLoadFileIO(nsIFile* aFile)
|
||||
: mFile(aFile) {
|
||||
NS_INIT_REFCNT();
|
||||
MOZ_COUNT_CTOR(nsXULFastLoadFileIO);
|
||||
}
|
||||
|
||||
virtual ~nsXULFastLoadFileIO() {
|
||||
MOZ_COUNT_DTOR(nsXULFastLoadFileIO);
|
||||
}
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIFASTLOADFILEIO
|
||||
|
||||
nsCOMPtr<nsIFile> mFile;
|
||||
nsCOMPtr<nsIInputStream> mInputStream;
|
||||
nsCOMPtr<nsIOutputStream> mOutputStream;
|
||||
};
|
||||
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(nsXULFastLoadFileIO, nsIFastLoadFileIO)
|
||||
MOZ_DECL_CTOR_COUNTER(nsXULFastLoadFileIO)
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXULFastLoadFileIO::GetInputStream(nsIInputStream** aResult)
|
||||
{
|
||||
if (! mInputStream) {
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIInputStream> fileInput;
|
||||
rv = NS_NewLocalFileInputStream(getter_AddRefs(fileInput), mFile);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = NS_NewBufferedInputStream(getter_AddRefs(mInputStream),
|
||||
fileInput,
|
||||
XUL_DESERIALIZATION_BUFFER_SIZE);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
NS_ADDREF(*aResult = mInputStream);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXULFastLoadFileIO::GetOutputStream(nsIOutputStream** aResult)
|
||||
{
|
||||
if (! mOutputStream) {
|
||||
PRInt32 ioFlags = PR_WRONLY;
|
||||
if (! mInputStream)
|
||||
ioFlags |= PR_CREATE_FILE | PR_TRUNCATE;
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIOutputStream> fileOutput;
|
||||
rv = NS_NewLocalFileOutputStream(getter_AddRefs(fileOutput), mFile,
|
||||
ioFlags, 0644);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = NS_NewBufferedOutputStream(getter_AddRefs(mOutputStream),
|
||||
fileOutput,
|
||||
XUL_SERIALIZATION_BUFFER_SIZE);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
NS_ADDREF(*aResult = mOutputStream);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
static PRBool gDisableXULFastLoad = PR_FALSE; // enabled by default
|
||||
static PRBool gChecksumXULFastLoadFile = PR_TRUE; // XXXbe too paranoid
|
||||
|
||||
static const char kDisableXULFastLoadPref[] = "nglayout.debug.disable_xul_fastload";
|
||||
static const char kChecksumXULFastLoadFilePref[] = "nglayout.debug.checksum_xul_fastload_file";
|
||||
|
||||
PR_STATIC_CALLBACK(int)
|
||||
FastLoadPrefChangedCallback(const char* aPref, void* aClosure)
|
||||
{
|
||||
nsCOMPtr<nsIPref> prefs = do_GetService(NS_PREF_CONTRACTID);
|
||||
if (prefs) {
|
||||
PRBool wasEnabled = !gDisableXULFastLoad;
|
||||
prefs->GetBoolPref(kDisableXULFastLoadPref, &gDisableXULFastLoad);
|
||||
|
||||
if (wasEnabled && gDisableXULFastLoad)
|
||||
nsXULDocument::AbortFastLoads();
|
||||
|
||||
prefs->GetBoolPref(kChecksumXULFastLoadFilePref, &gChecksumXULFastLoadFile);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsXULDocument::StartFastLoad()
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
// Test gFastLoadList to decide whether this is the first nsXULDocument
|
||||
// participating in FastLoad. If gFastLoadList is non-null, this document
|
||||
// must not be first, but it can join the FastLoad process. Examples of
|
||||
// multiple master documents participating include hiddenWindow.xul and
|
||||
// navigator.xul on the Mac, and multiple-app-component (e.g., mailnews
|
||||
// and browser) startup due to command-line arguments.
|
||||
//
|
||||
// XXXbe we should attempt to update the FastLoad file after startup!
|
||||
//
|
||||
// XXXbe we do not yet use nsFastLoadPtrs, but once we do, we must keep
|
||||
// the FastLoad input stream open for the life of the app.
|
||||
if (gFastLoadList) {
|
||||
mIsFastLoad = PR_TRUE;
|
||||
mNextFastLoad = gFastLoadList;
|
||||
gFastLoadList = this;
|
||||
return NS_OK;
|
||||
}
|
||||
NS_ASSERTION(!gFastLoadService,
|
||||
"gFastLoadList null but gFastLoadService non-null!");
|
||||
|
||||
nsCOMPtr<nsIPref> prefs(do_GetService(NS_PREF_CONTRACTID));
|
||||
if (prefs) {
|
||||
prefs->GetBoolPref(kDisableXULFastLoadPref, &gDisableXULFastLoad);
|
||||
prefs->GetBoolPref(kChecksumXULFastLoadFilePref, &gChecksumXULFastLoadFile);
|
||||
prefs->RegisterCallback(kDisableXULFastLoadPref,
|
||||
FastLoadPrefChangedCallback,
|
||||
nsnull);
|
||||
prefs->RegisterCallback(kChecksumXULFastLoadFilePref,
|
||||
FastLoadPrefChangedCallback,
|
||||
nsnull);
|
||||
if (gDisableXULFastLoad)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
// Get the chrome directory to validate against the one stored in the
|
||||
// FastLoad file, or to store there if we're generating a new file.
|
||||
nsCOMPtr<nsIFile> chromeDir;
|
||||
rv = NS_GetSpecialDirectory(NS_APP_CHROME_DIR, getter_AddRefs(chromeDir));
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
nsCAutoString chromePath;
|
||||
rv = chromeDir->GetPath(chromePath);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
// Use a local to refer to the service till we're sure we succeeded, then
|
||||
// commit to gFastLoadService. Same for gFastLoadFile, which is used to
|
||||
// delete the FastLoad file on abort.
|
||||
nsCOMPtr<nsIFastLoadService> fastLoadService(do_GetFastLoadService());
|
||||
if (! fastLoadService)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsCOMPtr<nsIFile> file;
|
||||
rv = fastLoadService->NewFastLoadFile(XUL_FASTLOAD_FILE_BASENAME,
|
||||
getter_AddRefs(file));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// Give the FastLoad service an object by which it can get or create a
|
||||
// file output stream given an input stream on the same file.
|
||||
nsXULFastLoadFileIO* xio = new nsXULFastLoadFileIO(file);
|
||||
nsCOMPtr<nsIFastLoadFileIO> io = NS_STATIC_CAST(nsIFastLoadFileIO*, xio);
|
||||
if (! io)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
fastLoadService->SetFileIO(io);
|
||||
|
||||
// Try to read an existent FastLoad file.
|
||||
PRBool exists = PR_FALSE;
|
||||
if (NS_SUCCEEDED(file->Exists(&exists)) && exists) {
|
||||
nsCOMPtr<nsIInputStream> input;
|
||||
rv = io->GetInputStream(getter_AddRefs(input));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsCOMPtr<nsIObjectInputStream> objectInput;
|
||||
rv = fastLoadService->NewInputStream(input, getter_AddRefs(objectInput));
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
if (gChecksumXULFastLoadFile) {
|
||||
nsCOMPtr<nsIFastLoadReadControl>
|
||||
readControl(do_QueryInterface(objectInput));
|
||||
if (readControl) {
|
||||
// Verify checksum, using the fastLoadService's checksum
|
||||
// cache to avoid computing more than once per session.
|
||||
PRUint32 checksum;
|
||||
rv = readControl->GetChecksum(&checksum);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
PRUint32 verified;
|
||||
rv = fastLoadService->ComputeChecksum(file,
|
||||
readControl,
|
||||
&verified);
|
||||
if (NS_SUCCEEDED(rv) && verified != checksum) {
|
||||
#ifdef DEBUG
|
||||
printf("bad FastLoad file checksum\n");
|
||||
#endif
|
||||
rv = NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// XXXbe get version number, scripts only for now -- bump
|
||||
// version later when rest of prototype document header is
|
||||
// serialized
|
||||
PRUint32 version;
|
||||
rv = objectInput->Read32(&version);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
if (version != XUL_FASTLOAD_FILE_VERSION) {
|
||||
#ifdef DEBUG
|
||||
printf("bad FastLoad file version\n");
|
||||
#endif
|
||||
rv = NS_ERROR_UNEXPECTED;
|
||||
} else {
|
||||
nsXPIDLCString fileChromePath;
|
||||
rv = objectInput->ReadStringZ(
|
||||
getter_Copies(fileChromePath));
|
||||
if (NS_SUCCEEDED(rv) &&
|
||||
!fileChromePath.Equals(chromePath)) {
|
||||
rv = NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
fastLoadService->SetInputStream(objectInput);
|
||||
} else {
|
||||
// NB: we must close before attempting to remove, for non-Unix OSes
|
||||
// that can't do open-unlink.
|
||||
if (objectInput)
|
||||
objectInput->Close();
|
||||
else
|
||||
input->Close();
|
||||
xio->mInputStream = nsnull;
|
||||
|
||||
#ifdef DEBUG
|
||||
file->MoveTo(nsnull, NS_LITERAL_CSTRING("Invalid.mfasl"));
|
||||
#else
|
||||
file->Remove(PR_FALSE);
|
||||
#endif
|
||||
exists = PR_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
// FastLoad file not found, or invalid: write a new one.
|
||||
if (! exists) {
|
||||
nsCOMPtr<nsIOutputStream> output;
|
||||
rv = io->GetOutputStream(getter_AddRefs(output));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsCOMPtr<nsIObjectOutputStream> objectOutput;
|
||||
rv = fastLoadService->NewOutputStream(output,
|
||||
getter_AddRefs(objectOutput));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
rv = objectOutput->Write32(XUL_FASTLOAD_FILE_VERSION);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
rv = objectOutput->WriteStringZ(chromePath.get());
|
||||
}
|
||||
|
||||
// Remove here even though some errors above will lead to a FastLoad
|
||||
// file invalidation. Other errors (failure to note the dependency on
|
||||
// installed-chrome.txt, e.g.) will not cause invalidation, and we may
|
||||
// as well tidy up now.
|
||||
if (NS_FAILED(rv)) {
|
||||
if (objectOutput)
|
||||
objectOutput->Close();
|
||||
else
|
||||
output->Close();
|
||||
xio->mOutputStream = nsnull;
|
||||
|
||||
file->Remove(PR_FALSE);
|
||||
return rv;
|
||||
}
|
||||
|
||||
fastLoadService->SetOutputStream(objectOutput);
|
||||
}
|
||||
|
||||
// If this fails, some weird reentrancy or multi-threading has occurred.
|
||||
NS_ASSERTION(!gFastLoadService && !gFastLoadFile && !gFastLoadList,
|
||||
"something's very wrong!");
|
||||
|
||||
// Success! Insert this nsXULDocument into the (empty) gFastLoadList,
|
||||
// and commit locals to globals.
|
||||
mIsFastLoad = PR_TRUE;
|
||||
gFastLoadList = this;
|
||||
NS_ADDREF(gFastLoadService = fastLoadService);
|
||||
NS_ADDREF(gFastLoadFile = file);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsXULDocument::EndFastLoad()
|
||||
{
|
||||
nsresult rv = NS_OK, rv2 = NS_OK;
|
||||
|
||||
// Exclude all non-chrome loads and XUL cache hits right away.
|
||||
if (! mIsFastLoad)
|
||||
return rv;
|
||||
|
||||
// Remove this document from the global FastLoad list. We use the list's
|
||||
// emptiness instead of a counter, to decide when the FastLoad process has
|
||||
// finally completed. We use a singly-linked list because there won't be
|
||||
// more than a handful of master XUL documents racing, worst case.
|
||||
mIsFastLoad = PR_FALSE;
|
||||
RemoveFromFastLoadList();
|
||||
|
||||
// Fetch the current input (if FastLoad file existed) or output (if we're
|
||||
// creating the FastLoad file during this app startup) stream.
|
||||
nsCOMPtr<nsIObjectInputStream> objectInput;
|
||||
nsCOMPtr<nsIObjectOutputStream> objectOutput;
|
||||
gFastLoadService->GetInputStream(getter_AddRefs(objectInput));
|
||||
gFastLoadService->GetOutputStream(getter_AddRefs(objectOutput));
|
||||
|
||||
if (objectOutput) {
|
||||
#if 0
|
||||
// XXXbe for now, write scripts as we sink content...
|
||||
rv = objectOutput->WriteObject(mMasterPrototype, PR_TRUE);
|
||||
#endif
|
||||
|
||||
// If this is the last of one or more XUL master documents loaded
|
||||
// together at app startup, close the FastLoad service's singleton
|
||||
// output stream now.
|
||||
//
|
||||
// NB: we must close input after output, in case the output stream
|
||||
// implementation needs to read from the input stream, to compute a
|
||||
// FastLoad file checksum. In that case, the implementation used
|
||||
// nsIFastLoadFileIO to get the corresponding input stream for this
|
||||
// output stream.
|
||||
if (! gFastLoadList) {
|
||||
gFastLoadService->SetOutputStream(nsnull);
|
||||
rv = objectOutput->Close();
|
||||
|
||||
if (NS_SUCCEEDED(rv) && gChecksumXULFastLoadFile) {
|
||||
rv = gFastLoadService->CacheChecksum(gFastLoadFile,
|
||||
objectOutput);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (objectInput) {
|
||||
// If this is the last of one or more XUL master documents loaded
|
||||
// together at app startup, close the FastLoad service's singleton
|
||||
// input stream now.
|
||||
if (! gFastLoadList) {
|
||||
gFastLoadService->SetInputStream(nsnull);
|
||||
rv2 = objectInput->Close();
|
||||
}
|
||||
}
|
||||
|
||||
// If the list is empty now, the FastLoad process is done.
|
||||
if (! gFastLoadList) {
|
||||
NS_RELEASE(gFastLoadService);
|
||||
NS_RELEASE(gFastLoadFile);
|
||||
}
|
||||
|
||||
return NS_FAILED(rv) ? rv : rv2;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsXULDocument::AbortFastLoads()
|
||||
{
|
||||
#ifdef DEBUG_brendan
|
||||
NS_BREAK();
|
||||
#endif
|
||||
|
||||
// Save a strong ref to the FastLoad file, so we can remove it after we
|
||||
// close open streams to it.
|
||||
nsCOMPtr<nsIFile> file = gFastLoadFile;
|
||||
|
||||
// End all pseudo-concurrent XUL document FastLoads, which will close any
|
||||
// i/o streams open on the FastLoad file.
|
||||
while (gFastLoadList)
|
||||
gFastLoadList->EndFastLoad();
|
||||
|
||||
// Now rename or remove the file.
|
||||
if (file) {
|
||||
#ifdef DEBUG
|
||||
file->MoveTo(nsnull, NS_LITERAL_CSTRING("Aborted.mfasl"));
|
||||
#else
|
||||
file->Remove(PR_FALSE);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Flush the XUL cache for good measure, in case we cached a bogus/downrev
|
||||
// script, somehow.
|
||||
if (gXULCache)
|
||||
gXULCache->Flush();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsXULDocument::PrepareToLoad(nsISupports* aContainer,
|
||||
const char* aCommand,
|
||||
@ -5364,30 +4939,6 @@ nsXULDocument::PrepareToLoadPrototype(nsIURI* aURI, const char* aCommand,
|
||||
rv = mCurrentPrototype->SetURI(aURI);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// If we're reading or writing a FastLoad file, tell the FastLoad
|
||||
// service to start multiplexing data from aURI, associating it in
|
||||
// the file with the URL's string. Each time the parser resumes
|
||||
// sinking content, it "selects" the memorized document from the
|
||||
// FastLoad multiplexor, using the nsIURI* as a fast identifier.
|
||||
if (mIsFastLoad) {
|
||||
nsCAutoString urlspec;
|
||||
rv = aURI->GetAsciiSpec(urlspec);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// If StartMuxedDocument returns NS_ERROR_NOT_AVAILABLE, then
|
||||
// we must be reading the file, and urlspec was not associated
|
||||
// with any multiplexed stream in it. The FastLoad service
|
||||
// will therefore arrange to update the file, writing new data
|
||||
// at the end while old (available) data continues to be read
|
||||
// from the pre-existing part of the file.
|
||||
rv = gFastLoadService->StartMuxedDocument(aURI, urlspec.get(),
|
||||
nsIFastLoadService::NS_FASTLOAD_READ |
|
||||
nsIFastLoadService::NS_FASTLOAD_WRITE);
|
||||
NS_ASSERTION(rv != NS_ERROR_NOT_AVAILABLE, "only reading FastLoad?!");
|
||||
if (NS_FAILED(rv))
|
||||
AbortFastLoads();
|
||||
}
|
||||
|
||||
// Create a XUL content sink, a parser, and kick off a load for
|
||||
// the overlay.
|
||||
nsCOMPtr<nsIXULContentSink> sink;
|
||||
@ -6012,9 +5563,24 @@ nsXULDocument::ResumeWalk()
|
||||
#endif
|
||||
// Look in the prototype cache for the prototype document with
|
||||
// the specified overlay URI.
|
||||
rv = gXULCache->GetPrototype(uri, getter_AddRefs(mCurrentPrototype));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
gXULCache->GetPrototype(uri, getter_AddRefs(mCurrentPrototype));
|
||||
|
||||
// Same comment as nsChromeProtocolHandler::NewChannel and
|
||||
// nsXULDocument::StartDocumentLoad
|
||||
// - Ben Goodger
|
||||
//
|
||||
// We don't abort on failure here because there are too many valid
|
||||
// cases that can return failure, and the null-ness of |proto| is enough
|
||||
// to trigger the fail-safe parse-from-disk solution. Example failure cases
|
||||
// (for reference) include:
|
||||
//
|
||||
// NS_ERROR_NOT_AVAILABLE: the URI cannot be found in the FastLoad cache,
|
||||
// parse from disk
|
||||
// other: the FastLoad cache file, XUL.mfl, could not be found, probably
|
||||
// due to being accessed before a profile has been selected (e.g.
|
||||
// loading chrome for the profile manager itself). This must be
|
||||
// parsed from disk.
|
||||
|
||||
PRBool cache;
|
||||
gXULCache->GetEnabled(&cache);
|
||||
|
||||
@ -6050,6 +5616,8 @@ nsXULDocument::ResumeWalk()
|
||||
rv = PrepareToLoadPrototype(uri, "view", nsnull, getter_AddRefs(parser));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
mIsWritingFastLoad = PR_TRUE;
|
||||
|
||||
nsCOMPtr<nsIStreamListener> listener = do_QueryInterface(parser);
|
||||
if (! listener)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
@ -6100,10 +5668,11 @@ nsXULDocument::ResumeWalk()
|
||||
|
||||
StartLayout();
|
||||
|
||||
// Since we've bothered to load and parse all this fancy XUL, let's try to
|
||||
// save a condensed serialization of it for faster loading next time. We
|
||||
// do this after StartLayout() in case we want to serialize frames.
|
||||
EndFastLoad();
|
||||
PRBool useXULCache;
|
||||
gXULCache->GetEnabled(&useXULCache);
|
||||
|
||||
if (useXULCache && mIsWritingFastLoad)
|
||||
gXULCache->WritePrototype(mMasterPrototype);
|
||||
|
||||
for (PRInt32 i = mObservers.Count() - 1; i >= 0; --i) {
|
||||
nsIDocumentObserver* observer = (nsIDocumentObserver*) mObservers[i];
|
||||
@ -6122,10 +5691,10 @@ nsXULDocument::ResumeWalk()
|
||||
mPlaceHolderRequest = nsnull;
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsXULDocument::LoadScript(nsXULPrototypeScript* aScriptProto, PRBool* aBlock)
|
||||
{
|
||||
@ -6250,27 +5819,33 @@ nsXULDocument::OnStreamComplete(nsIStreamLoader* aLoader,
|
||||
// before serializing script data under scriptProto->Compile, and
|
||||
// End muxing afterward.
|
||||
nsCOMPtr<nsIURI> uri = scriptProto->mSrcURI;
|
||||
if (mIsFastLoad) {
|
||||
|
||||
nsCOMPtr<nsIFastLoadService> fastLoadService;
|
||||
gXULCache->GetFastLoadService(getter_AddRefs(fastLoadService));
|
||||
|
||||
if (fastLoadService) {
|
||||
nsCAutoString urispec;
|
||||
uri->GetAsciiSpec(urispec);
|
||||
rv = gFastLoadService->StartMuxedDocument(uri, urispec.get(),
|
||||
nsIFastLoadService::NS_FASTLOAD_WRITE);
|
||||
rv = fastLoadService->StartMuxedDocument(uri, urispec.get(),
|
||||
nsIFastLoadService::NS_FASTLOAD_WRITE);
|
||||
NS_ASSERTION(rv != NS_ERROR_NOT_AVAILABLE, "reading FastLoad?!");
|
||||
if (NS_SUCCEEDED(rv))
|
||||
gFastLoadService->SelectMuxedDocument(uri);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
nsCOMPtr<nsIURI> oldURI;
|
||||
fastLoadService->SelectMuxedDocument(uri, getter_AddRefs(oldURI));
|
||||
}
|
||||
}
|
||||
|
||||
nsString stringStr; stringStr.AssignWithConversion(string, stringLen);
|
||||
rv = scriptProto->Compile(stringStr.get(), stringLen, uri, 1, this,
|
||||
mMasterPrototype);
|
||||
mCurrentPrototype);
|
||||
|
||||
// End muxing the .js file into the FastLoad file. We don't Abort
|
||||
// the FastLoad process here, when writing, as we do when reading.
|
||||
// XXXbe maybe we should...
|
||||
// NB: we don't need to Select mDocumentURL again, because scripts
|
||||
// load after their including prototype document has fully loaded.
|
||||
if (mIsFastLoad)
|
||||
gFastLoadService->EndMuxedDocument(uri);
|
||||
if (fastLoadService)
|
||||
fastLoadService->EndMuxedDocument(uri);
|
||||
|
||||
aStatus = rv;
|
||||
if (NS_SUCCEEDED(rv) && scriptProto->mJSObject) {
|
||||
|
||||
@ -368,7 +368,6 @@ public:
|
||||
NS_IMETHOD SetTemplateBuilderFor(nsIContent* aContent, nsIXULTemplateBuilder* aBuilder);
|
||||
NS_IMETHOD GetTemplateBuilderFor(nsIContent* aContent, nsIXULTemplateBuilder** aResult);
|
||||
NS_IMETHOD OnPrototypeLoadDone();
|
||||
NS_IMETHOD OnResumeContentSink();
|
||||
NS_IMETHOD OnHide();
|
||||
|
||||
// nsIDOMEventCapturer interface
|
||||
@ -430,16 +429,6 @@ public:
|
||||
PRInt32 aNamespaceID,
|
||||
nsRDFDOMNodeList* aElements);
|
||||
|
||||
static nsresult
|
||||
GetFastLoadService(nsIFastLoadService** aResult)
|
||||
{
|
||||
NS_IF_ADDREF(*aResult = gFastLoadService);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static nsresult
|
||||
AbortFastLoads();
|
||||
|
||||
protected:
|
||||
// Implementation methods
|
||||
friend nsresult
|
||||
@ -476,27 +465,6 @@ protected:
|
||||
|
||||
nsresult CreateElement(nsINodeInfo *aNodeInfo, nsIContent** aResult);
|
||||
|
||||
nsresult StartFastLoad();
|
||||
nsresult EndFastLoad();
|
||||
|
||||
static nsIFastLoadService* gFastLoadService;
|
||||
static nsIFile* gFastLoadFile;
|
||||
static PRBool gFastLoadDone;
|
||||
static nsXULDocument* gFastLoadList;
|
||||
|
||||
void RemoveFromFastLoadList() {
|
||||
nsXULDocument** docp = &gFastLoadList;
|
||||
nsXULDocument* doc;
|
||||
while ((doc = *docp) != nsnull) {
|
||||
if (doc == this) {
|
||||
*docp = doc->mNextFastLoad;
|
||||
doc->mNextFastLoad = nsnull;
|
||||
break;
|
||||
}
|
||||
docp = &doc->mNextFastLoad;
|
||||
}
|
||||
}
|
||||
|
||||
nsresult PrepareToLoad(nsISupports* aContainer,
|
||||
const char* aCommand,
|
||||
nsIChannel* aChannel,
|
||||
@ -599,7 +567,7 @@ protected:
|
||||
PRPackedBool mIsPopup;
|
||||
PRPackedBool mIsFastLoad;
|
||||
PRPackedBool mApplyingPersistedAttrs;
|
||||
nsXULDocument* mNextFastLoad;
|
||||
PRPackedBool mIsWritingFastLoad;
|
||||
nsCOMPtr<nsIDOMXULCommandDispatcher> mCommandDispatcher; // [OWNER] of the focus tracker
|
||||
|
||||
nsCOMPtr<nsIBindingManager> mBindingManager; // [OWNER] of all bindings
|
||||
|
||||
@ -21,6 +21,8 @@
|
||||
*
|
||||
* Contributor(s):
|
||||
* Chris Waterson <waterson@netscape.com>
|
||||
* Brendan Eich <brendan@mozilla.org>
|
||||
* Ben Goodger <ben@netscape.com>
|
||||
*
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
@ -48,7 +50,9 @@
|
||||
#include "nsICSSStyleSheet.h"
|
||||
#include "nsIXULPrototypeCache.h"
|
||||
#include "nsIXULPrototypeDocument.h"
|
||||
#include "nsIXULDocument.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsIURL.h"
|
||||
#include "nsHashtable.h"
|
||||
#include "nsXPIDLString.h"
|
||||
#include "plstr.h"
|
||||
@ -58,6 +62,16 @@
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsXULDocument.h"
|
||||
|
||||
#include "nsIFastLoadService.h"
|
||||
#include "nsIFastLoadFileControl.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsIObjectInputStream.h"
|
||||
#include "nsIObjectOutputStream.h"
|
||||
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsAppDirectoryServiceDefs.h"
|
||||
|
||||
|
||||
class nsXULPrototypeCache : public nsIXULPrototypeCache
|
||||
{
|
||||
public:
|
||||
@ -86,6 +100,9 @@ public:
|
||||
NS_IMETHOD GetEnabled(PRBool* aIsEnabled);
|
||||
|
||||
NS_IMETHOD AbortFastLoads();
|
||||
NS_IMETHOD GetFastLoadService(nsIFastLoadService** aResult);
|
||||
NS_IMETHOD RemoveFromFastLoadSet(nsIURI* aDocumentURI);
|
||||
NS_IMETHOD WritePrototype(nsIXULPrototypeDocument* aPrototypeDocument);
|
||||
|
||||
protected:
|
||||
friend NS_IMETHODIMP
|
||||
@ -123,6 +140,18 @@ protected:
|
||||
return new nsIURIKey(mKey);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// FastLoad
|
||||
nsSupportsHashtable mFastLoadURITable;
|
||||
|
||||
static nsIFastLoadService* gFastLoadService;
|
||||
static nsIFile* gFastLoadFile;
|
||||
|
||||
// Bootstrap FastLoad Service
|
||||
nsresult StartFastLoad(nsIURI* aDocumentURI);
|
||||
nsresult StartFastLoadingURI(nsIURI* aURI, PRInt32 aDirectionFlags);
|
||||
};
|
||||
|
||||
static PRBool gDisableXULCache = PR_FALSE; // enabled by default
|
||||
@ -153,6 +182,9 @@ DisableXULCacheChangedCallback(const char* aPref, void* aClosure)
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
|
||||
nsIFastLoadService* nsXULPrototypeCache::gFastLoadService = nsnull;
|
||||
nsIFile* nsXULPrototypeCache::gFastLoadFile = nsnull;
|
||||
|
||||
nsXULPrototypeCache::nsXULPrototypeCache()
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
@ -162,6 +194,9 @@ nsXULPrototypeCache::nsXULPrototypeCache()
|
||||
nsXULPrototypeCache::~nsXULPrototypeCache()
|
||||
{
|
||||
FlushScripts();
|
||||
|
||||
NS_IF_RELEASE(gFastLoadService); // don't need ReleaseService nowadays!
|
||||
NS_IF_RELEASE(gFastLoadFile);
|
||||
}
|
||||
|
||||
|
||||
@ -202,11 +237,46 @@ NS_NewXULPrototypeCache(nsISupports* aOuter, REFNSIID aIID, void** aResult)
|
||||
NS_IMETHODIMP
|
||||
nsXULPrototypeCache::GetPrototype(nsIURI* aURI, nsIXULPrototypeDocument** _result)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
nsIURIKey key(aURI);
|
||||
*_result = NS_STATIC_CAST(nsIXULPrototypeDocument*, mPrototypeTable.Get(&key));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (! *_result) {
|
||||
// No prototype in XUL memory cache. Spin up FastLoad Service and
|
||||
// look in FastLoad file.
|
||||
rv = StartFastLoad(aURI);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
nsCOMPtr<nsIObjectInputStream> objectInput;
|
||||
gFastLoadService->GetInputStream(getter_AddRefs(objectInput));
|
||||
|
||||
rv = StartFastLoadingURI(aURI, nsIFastLoadService::NS_FASTLOAD_READ);
|
||||
if (NS_SUCCEEDED (rv)) {
|
||||
nsCOMPtr<nsIURI> oldURI;
|
||||
gFastLoadService->SelectMuxedDocument(aURI, getter_AddRefs(oldURI));
|
||||
|
||||
// Create a new prototype document.
|
||||
nsCOMPtr<nsIXULPrototypeDocument> protoDoc;
|
||||
rv = NS_NewXULPrototypeDocument(nsnull,
|
||||
NS_GET_IID(nsIXULPrototypeDocument),
|
||||
getter_AddRefs(protoDoc));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = protoDoc->Read(objectInput);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
NS_ADDREF(*_result = protoDoc);
|
||||
|
||||
gFastLoadService->EndMuxedDocument(aURI);
|
||||
|
||||
RemoveFromFastLoadSet(aURI);
|
||||
|
||||
PutPrototype(protoDoc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXULPrototypeCache::PutPrototype(nsIXULPrototypeDocument* aDocument)
|
||||
@ -442,8 +512,477 @@ nsXULPrototypeCache::GetEnabled(PRBool* aIsEnabled)
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXULPrototypeCache::GetFastLoadService(nsIFastLoadService** aResult)
|
||||
{
|
||||
NS_IF_ADDREF(*aResult = gFastLoadService);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
static PRBool gDisableXULFastLoad = PR_FALSE; // enabled by default
|
||||
static PRBool gChecksumXULFastLoadFile = PR_TRUE; // XXXbe too paranoid
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXULPrototypeCache::AbortFastLoads()
|
||||
{
|
||||
return nsXULDocument::AbortFastLoads();
|
||||
#ifdef DEBUG_brendan
|
||||
NS_BREAK();
|
||||
#endif
|
||||
|
||||
// Save a strong ref to the FastLoad file, so we can remove it after we
|
||||
// close open streams to it.
|
||||
nsCOMPtr<nsIFile> file = gFastLoadFile;
|
||||
|
||||
// Now rename or remove the file.
|
||||
if (file) {
|
||||
#ifdef DEBUG
|
||||
file->MoveTo(nsnull, NS_LITERAL_CSTRING("Aborted.mfasl"));
|
||||
#else
|
||||
file->Remove(PR_FALSE);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Flush the XUL cache for good measure, in case we cached a bogus/downrev
|
||||
// script, somehow.
|
||||
Flush();
|
||||
|
||||
// Clear the FastLoad set
|
||||
mFastLoadURITable.Reset();
|
||||
|
||||
if (! gFastLoadService)
|
||||
return NS_OK;
|
||||
|
||||
// Fetch the current input (if FastLoad file existed) or output (if we're
|
||||
// creating the FastLoad file during this app startup) stream.
|
||||
nsCOMPtr<nsIObjectInputStream> objectInput;
|
||||
nsCOMPtr<nsIObjectOutputStream> objectOutput;
|
||||
gFastLoadService->GetInputStream(getter_AddRefs(objectInput));
|
||||
gFastLoadService->GetOutputStream(getter_AddRefs(objectOutput));
|
||||
|
||||
if (objectOutput) {
|
||||
gFastLoadService->SetOutputStream(nsnull);
|
||||
|
||||
if (NS_SUCCEEDED(objectOutput->Close()) && gChecksumXULFastLoadFile)
|
||||
gFastLoadService->CacheChecksum(gFastLoadFile,
|
||||
objectOutput);
|
||||
}
|
||||
|
||||
if (objectInput) {
|
||||
// If this is the last of one or more XUL master documents loaded
|
||||
// together at app startup, close the FastLoad service's singleton
|
||||
// input stream now.
|
||||
gFastLoadService->SetInputStream(nsnull);
|
||||
objectInput->Close();
|
||||
}
|
||||
|
||||
// If the list is empty now, the FastLoad process is done.
|
||||
NS_RELEASE(gFastLoadService);
|
||||
NS_RELEASE(gFastLoadFile);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXULPrototypeCache::RemoveFromFastLoadSet(nsIURI* aURI)
|
||||
{
|
||||
nsIURIKey key(aURI);
|
||||
mFastLoadURITable.Remove(&key);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static const char kDisableXULFastLoadPref[] = "nglayout.debug.disable_xul_fastload";
|
||||
static const char kChecksumXULFastLoadFilePref[] = "nglayout.debug.checksum_xul_fastload_file";
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXULPrototypeCache::WritePrototype(nsIXULPrototypeDocument* aPrototypeDocument)
|
||||
{
|
||||
nsresult rv = NS_OK, rv2 = NS_OK;
|
||||
|
||||
// We're here before the FastLoad service has been initialized, probably because
|
||||
// of the profile manager. Bail quietly, don't worry, we'll be back later.
|
||||
if (! gFastLoadService)
|
||||
return NS_OK;
|
||||
|
||||
// Fetch the current input (if FastLoad file existed) or output (if we're
|
||||
// creating the FastLoad file during this app startup) stream.
|
||||
nsCOMPtr<nsIObjectInputStream> objectInput;
|
||||
nsCOMPtr<nsIObjectOutputStream> objectOutput;
|
||||
gFastLoadService->GetInputStream(getter_AddRefs(objectInput));
|
||||
gFastLoadService->GetOutputStream(getter_AddRefs(objectOutput));
|
||||
|
||||
nsCOMPtr<nsIURI> protoURI;
|
||||
aPrototypeDocument->GetURI(getter_AddRefs(protoURI));
|
||||
|
||||
// Remove this document from the FastLoad table. We use the table's
|
||||
// emptiness instead of a counter to decide when the FastLoad process
|
||||
// has completed. When complete, we can write footer details to the
|
||||
// FastLoad file.
|
||||
RemoveFromFastLoadSet(protoURI);
|
||||
|
||||
PRInt32 count = mFastLoadURITable.Count();
|
||||
|
||||
if (objectOutput) {
|
||||
rv = StartFastLoadingURI(protoURI, nsIFastLoadService::NS_FASTLOAD_WRITE);
|
||||
if (NS_SUCCEEDED (rv)) {
|
||||
// Re-select the URL of the current prototype, as out-of-line script loads
|
||||
// may have changed
|
||||
nsCOMPtr<nsIURI> oldURI;
|
||||
gFastLoadService->SelectMuxedDocument(protoURI, getter_AddRefs(oldURI));
|
||||
|
||||
aPrototypeDocument->Write(objectOutput);
|
||||
|
||||
gFastLoadService->EndMuxedDocument(protoURI);
|
||||
}
|
||||
|
||||
// If this is the last of one or more XUL master documents loaded
|
||||
// together at app startup, close the FastLoad service's singleton
|
||||
// output stream now.
|
||||
//
|
||||
// NB: we must close input after output, in case the output stream
|
||||
// implementation needs to read from the input stream, to compute a
|
||||
// FastLoad file checksum. In that case, the implementation used
|
||||
// nsIFastLoadFileIO to get the corresponding input stream for this
|
||||
// output stream.
|
||||
if (count == 0) {
|
||||
gFastLoadService->SetOutputStream(nsnull);
|
||||
rv = objectOutput->Close();
|
||||
|
||||
if (NS_SUCCEEDED(rv) && gChecksumXULFastLoadFile) {
|
||||
rv = gFastLoadService->CacheChecksum(gFastLoadFile,
|
||||
objectOutput);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (objectInput) {
|
||||
// If this is the last of one or more XUL master documents loaded
|
||||
// together at app startup, close the FastLoad service's singleton
|
||||
// input stream now.
|
||||
if (count == 0) {
|
||||
gFastLoadService->SetInputStream(nsnull);
|
||||
rv2 = objectInput->Close();
|
||||
}
|
||||
}
|
||||
|
||||
// If the list is empty now, the FastLoad process is done.
|
||||
if (count == 0) {
|
||||
NS_RELEASE(gFastLoadService);
|
||||
NS_RELEASE(gFastLoadFile);
|
||||
}
|
||||
|
||||
return NS_FAILED(rv) ? rv : rv2;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsXULPrototypeCache::StartFastLoadingURI(nsIURI* aURI, PRInt32 aDirectionFlags)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsCAutoString urlspec;
|
||||
rv = aURI->GetAsciiSpec(urlspec);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// If StartMuxedDocument returns NS_ERROR_NOT_AVAILABLE, then
|
||||
// we must be reading the file, and urlspec was not associated
|
||||
// with any multiplexed stream in it. The FastLoad service
|
||||
// will therefore arrange to update the file, writing new data
|
||||
// at the end while old (available) data continues to be read
|
||||
// from the pre-existing part of the file.
|
||||
return gFastLoadService->StartMuxedDocument(aURI, urlspec.get(), aDirectionFlags);
|
||||
}
|
||||
|
||||
PR_STATIC_CALLBACK(int)
|
||||
FastLoadPrefChangedCallback(const char* aPref, void* aClosure)
|
||||
{
|
||||
nsCOMPtr<nsIPref> prefs = do_GetService(NS_PREF_CONTRACTID);
|
||||
if (prefs) {
|
||||
PRBool wasEnabled = !gDisableXULFastLoad;
|
||||
prefs->GetBoolPref(kDisableXULFastLoadPref, &gDisableXULFastLoad);
|
||||
|
||||
if (wasEnabled && gDisableXULFastLoad) {
|
||||
static NS_DEFINE_CID(kXULPrototypeCacheCID, NS_XULPROTOTYPECACHE_CID);
|
||||
nsCOMPtr<nsIXULPrototypeCache> cache(do_GetService(kXULPrototypeCacheCID));
|
||||
if (cache)
|
||||
cache->AbortFastLoads();
|
||||
}
|
||||
|
||||
prefs->GetBoolPref(kChecksumXULFastLoadFilePref, &gChecksumXULFastLoadFile);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
class nsXULFastLoadFileIO : public nsIFastLoadFileIO
|
||||
{
|
||||
public:
|
||||
nsXULFastLoadFileIO(nsIFile* aFile)
|
||||
: mFile(aFile) {
|
||||
NS_INIT_REFCNT();
|
||||
MOZ_COUNT_CTOR(nsXULFastLoadFileIO);
|
||||
}
|
||||
|
||||
virtual ~nsXULFastLoadFileIO() {
|
||||
MOZ_COUNT_DTOR(nsXULFastLoadFileIO);
|
||||
}
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIFASTLOADFILEIO
|
||||
|
||||
nsCOMPtr<nsIFile> mFile;
|
||||
nsCOMPtr<nsIInputStream> mInputStream;
|
||||
nsCOMPtr<nsIOutputStream> mOutputStream;
|
||||
};
|
||||
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(nsXULFastLoadFileIO, nsIFastLoadFileIO)
|
||||
MOZ_DECL_CTOR_COUNTER(nsXULFastLoadFileIO)
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXULFastLoadFileIO::GetInputStream(nsIInputStream** aResult)
|
||||
{
|
||||
if (! mInputStream) {
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIInputStream> fileInput;
|
||||
rv = NS_NewLocalFileInputStream(getter_AddRefs(fileInput), mFile);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = NS_NewBufferedInputStream(getter_AddRefs(mInputStream),
|
||||
fileInput,
|
||||
XUL_DESERIALIZATION_BUFFER_SIZE);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
NS_ADDREF(*aResult = mInputStream);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXULFastLoadFileIO::GetOutputStream(nsIOutputStream** aResult)
|
||||
{
|
||||
if (! mOutputStream) {
|
||||
PRInt32 ioFlags = PR_WRONLY;
|
||||
if (! mInputStream)
|
||||
ioFlags |= PR_CREATE_FILE | PR_TRUNCATE;
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIOutputStream> fileOutput;
|
||||
rv = NS_NewLocalFileOutputStream(getter_AddRefs(fileOutput), mFile,
|
||||
ioFlags, 0644);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = NS_NewBufferedOutputStream(getter_AddRefs(mOutputStream),
|
||||
fileOutput,
|
||||
XUL_SERIALIZATION_BUFFER_SIZE);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
NS_ADDREF(*aResult = mOutputStream);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsXULPrototypeCache::StartFastLoad(nsIURI* aURI)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
PRBool isChrome = PR_FALSE;
|
||||
nsCAutoString path;
|
||||
aURI->GetPath(path);
|
||||
PRInt32 length = path.Length();
|
||||
const nsACString& extn = Substring(path, path.Length()-4, 4);
|
||||
if (! extn.Equals(NS_LITERAL_CSTRING(".xul")))
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
nsIURIKey key(aURI);
|
||||
|
||||
// Test gFastLoadList to decide whether this is the first nsXULDocument
|
||||
// participating in FastLoad. If gFastLoadList is non-null, this document
|
||||
// must not be first, but it can join the FastLoad process. Examples of
|
||||
// multiple master documents participating include hiddenWindow.xul and
|
||||
// navigator.xul on the Mac, and multiple-app-component (e.g., mailnews
|
||||
// and browser) startup due to command-line arguments.
|
||||
//
|
||||
// XXXbe we should attempt to update the FastLoad file after startup!
|
||||
//
|
||||
// XXXbe we do not yet use nsFastLoadPtrs, but once we do, we must keep
|
||||
// the FastLoad input stream open for the life of the app.
|
||||
if (gFastLoadService && gFastLoadFile) {
|
||||
mFastLoadURITable.Put(&key, aURI);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Use a local to refer to the service till we're sure we succeeded, then
|
||||
// commit to gFastLoadService. Same for gFastLoadFile, which is used to
|
||||
// delete the FastLoad file on abort.
|
||||
nsCOMPtr<nsIFastLoadService> fastLoadService(do_GetFastLoadService());
|
||||
if (! fastLoadService)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
|
||||
nsCOMPtr<nsIPref> prefs(do_GetService(NS_PREF_CONTRACTID));
|
||||
if (prefs) {
|
||||
prefs->GetBoolPref(kDisableXULFastLoadPref, &gDisableXULFastLoad);
|
||||
prefs->GetBoolPref(kChecksumXULFastLoadFilePref, &gChecksumXULFastLoadFile);
|
||||
prefs->RegisterCallback(kDisableXULFastLoadPref,
|
||||
FastLoadPrefChangedCallback,
|
||||
nsnull);
|
||||
prefs->RegisterCallback(kChecksumXULFastLoadFilePref,
|
||||
FastLoadPrefChangedCallback,
|
||||
nsnull);
|
||||
if (gDisableXULFastLoad)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
// Get the chrome directory to validate against the one stored in the
|
||||
// FastLoad file, or to store there if we're generating a new file.
|
||||
nsCOMPtr<nsIFile> chromeDir;
|
||||
rv = NS_GetSpecialDirectory(NS_APP_CHROME_DIR, getter_AddRefs(chromeDir));
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
nsCAutoString chromePath;
|
||||
rv = chromeDir->GetPath(chromePath);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
nsCOMPtr<nsIFile> file;
|
||||
rv = fastLoadService->NewFastLoadFile(XUL_FASTLOAD_FILE_BASENAME,
|
||||
getter_AddRefs(file));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// Give the FastLoad service an object by which it can get or create a
|
||||
// file output stream given an input stream on the same file.
|
||||
nsXULFastLoadFileIO* xio = new nsXULFastLoadFileIO(file);
|
||||
nsCOMPtr<nsIFastLoadFileIO> io = NS_STATIC_CAST(nsIFastLoadFileIO*, xio);
|
||||
if (! io)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
fastLoadService->SetFileIO(io);
|
||||
|
||||
// Try to read an existent FastLoad file.
|
||||
PRBool exists = PR_FALSE;
|
||||
if (NS_SUCCEEDED(file->Exists(&exists)) && exists) {
|
||||
nsCOMPtr<nsIInputStream> input;
|
||||
rv = io->GetInputStream(getter_AddRefs(input));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsCOMPtr<nsIObjectInputStream> objectInput;
|
||||
rv = fastLoadService->NewInputStream(input, getter_AddRefs(objectInput));
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
if (gChecksumXULFastLoadFile) {
|
||||
nsCOMPtr<nsIFastLoadReadControl>
|
||||
readControl(do_QueryInterface(objectInput));
|
||||
if (readControl) {
|
||||
// Verify checksum, using the fastLoadService's checksum
|
||||
// cache to avoid computing more than once per session.
|
||||
PRUint32 checksum;
|
||||
rv = readControl->GetChecksum(&checksum);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
PRUint32 verified;
|
||||
rv = fastLoadService->ComputeChecksum(file,
|
||||
readControl,
|
||||
&verified);
|
||||
if (NS_SUCCEEDED(rv) && verified != checksum) {
|
||||
#ifdef DEBUG
|
||||
printf("bad FastLoad file checksum\n");
|
||||
#endif
|
||||
rv = NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// XXXbe get version number, scripts only for now -- bump
|
||||
// version later when rest of prototype document header is
|
||||
// serialized
|
||||
PRUint32 version;
|
||||
rv = objectInput->Read32(&version);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
if (version != XUL_FASTLOAD_FILE_VERSION) {
|
||||
#ifdef DEBUG
|
||||
printf("bad FastLoad file version\n");
|
||||
#endif
|
||||
rv = NS_ERROR_UNEXPECTED;
|
||||
} else {
|
||||
nsXPIDLCString fileChromePath;
|
||||
rv = objectInput->ReadStringZ(
|
||||
getter_Copies(fileChromePath));
|
||||
if (NS_SUCCEEDED(rv) &&
|
||||
!fileChromePath.Equals(chromePath)) {
|
||||
rv = NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
fastLoadService->SetInputStream(objectInput);
|
||||
} else {
|
||||
// NB: we must close before attempting to remove, for non-Unix OSes
|
||||
// that can't do open-unlink.
|
||||
if (objectInput)
|
||||
objectInput->Close();
|
||||
else
|
||||
input->Close();
|
||||
xio->mInputStream = nsnull;
|
||||
|
||||
#ifdef DEBUG
|
||||
file->MoveTo(nsnull, NS_LITERAL_CSTRING("Invalid.mfasl"));
|
||||
#else
|
||||
file->Remove(PR_FALSE);
|
||||
#endif
|
||||
exists = PR_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
// FastLoad file not found, or invalid: write a new one.
|
||||
if (! exists) {
|
||||
nsCOMPtr<nsIOutputStream> output;
|
||||
rv = io->GetOutputStream(getter_AddRefs(output));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsCOMPtr<nsIObjectOutputStream> objectOutput;
|
||||
rv = fastLoadService->NewOutputStream(output,
|
||||
getter_AddRefs(objectOutput));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
rv = objectOutput->Write32(XUL_FASTLOAD_FILE_VERSION);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
rv = objectOutput->WriteStringZ(chromePath.get());
|
||||
}
|
||||
|
||||
// Remove here even though some errors above will lead to a FastLoad
|
||||
// file invalidation. Other errors (failure to note the dependency on
|
||||
// installed-chrome.txt, e.g.) will not cause invalidation, and we may
|
||||
// as well tidy up now.
|
||||
if (NS_FAILED(rv)) {
|
||||
if (objectOutput)
|
||||
objectOutput->Close();
|
||||
else
|
||||
output->Close();
|
||||
xio->mOutputStream = nsnull;
|
||||
|
||||
file->Remove(PR_FALSE);
|
||||
return rv;
|
||||
}
|
||||
|
||||
fastLoadService->SetOutputStream(objectOutput);
|
||||
}
|
||||
|
||||
// Success! Insert this URI into the mFastLoadURITable
|
||||
// and commit locals to globals.
|
||||
mFastLoadURITable.Put(&key, aURI);
|
||||
|
||||
NS_ADDREF(gFastLoadService = fastLoadService);
|
||||
NS_ADDREF(gFastLoadFile = file);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -22,6 +22,7 @@
|
||||
* Contributor(s):
|
||||
* Chris Waterson <waterson@netscape.com>
|
||||
* L. David Baron <dbaron@fas.harvard.edu>
|
||||
* Ben Goodger <ben@netscape.com>
|
||||
*
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
@ -286,8 +287,6 @@ NS_NewXULPrototypeDocument(nsISupports* aOuter, REFNSIID aIID, void** aResult)
|
||||
// nsISerializable methods
|
||||
//
|
||||
|
||||
#define XUL_FAST_LOAD_VERSION 0
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXULPrototypeDocument::Read(nsIObjectInputStream* aStream)
|
||||
{
|
||||
@ -295,16 +294,67 @@ nsXULPrototypeDocument::Read(nsIObjectInputStream* aStream)
|
||||
|
||||
PRUint32 version;
|
||||
rv = aStream->Read32(&version);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (version != XUL_FAST_LOAD_VERSION)
|
||||
if (version != XUL_FASTLOAD_FILE_VERSION)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
rv = aStream->ReadObject(PR_TRUE, getter_AddRefs(mURI));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
rv |= aStream->ReadObject(PR_TRUE, getter_AddRefs(mURI));
|
||||
|
||||
// XXXbe more to come
|
||||
return NS_OK;
|
||||
PRUint32 referenceCount;
|
||||
nsCOMPtr<nsIURI> referenceURI;
|
||||
|
||||
PRUint32 i;
|
||||
// nsISupportsArray mStyleSheetReferences
|
||||
rv |= aStream->Read32(&referenceCount);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
for (i = 0; i < referenceCount; ++i) {
|
||||
rv |= aStream->ReadObject(PR_TRUE, getter_AddRefs(referenceURI));
|
||||
|
||||
mStyleSheetReferences->AppendElement(referenceURI);
|
||||
}
|
||||
|
||||
// nsISupportsArray mOverlayReferences
|
||||
rv |= aStream->Read32(&referenceCount);
|
||||
for (i = 0; i < referenceCount; ++i) {
|
||||
rv |= aStream->ReadObject(PR_TRUE, getter_AddRefs(referenceURI));
|
||||
|
||||
mOverlayReferences->AppendElement(referenceURI);
|
||||
}
|
||||
|
||||
// nsIPrincipal mDocumentPrincipal
|
||||
nsCOMPtr<nsIScriptSecurityManager> securityManager =
|
||||
do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
|
||||
|
||||
if (! securityManager)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
rv |= securityManager->GetCodebasePrincipal(mURI, getter_AddRefs(mDocumentPrincipal));
|
||||
rv |= NS_ReadOptionalObject(aStream, PR_TRUE, getter_AddRefs(mDocumentPrincipal));
|
||||
|
||||
// nsIScriptGlobalObject mGlobalObject
|
||||
mGlobalObject = new nsXULPDGlobalObject();
|
||||
if (! mGlobalObject)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
rv |= mGlobalObject->SetGlobalObjectOwner(this); // does not refcount
|
||||
|
||||
mRoot = new nsXULPrototypeElement(-1);
|
||||
if (! mRoot)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
nsCOMPtr<nsIScriptContext> scriptContext;
|
||||
rv |= mGlobalObject->GetContext(getter_AddRefs(scriptContext));
|
||||
NS_ASSERTION(scriptContext != nsnull,
|
||||
"no prototype script context!");
|
||||
|
||||
PRUint32 type;
|
||||
rv |= aStream->Read32(&type);
|
||||
|
||||
if ((nsXULPrototypeNode::Type)type != nsXULPrototypeNode::eType_Element)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
rv |= mRoot->Deserialize(aStream, scriptContext, mURI);
|
||||
rv |= NotifyLoadDone();
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
@ -313,27 +363,49 @@ nsXULPrototypeDocument::Write(nsIObjectOutputStream* aStream)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
rv = aStream->Write32(XUL_FAST_LOAD_VERSION);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
rv = aStream->Write32(XUL_FASTLOAD_FILE_VERSION);
|
||||
|
||||
rv |= aStream->WriteCompoundObject(mURI, NS_GET_IID(nsIURI), PR_TRUE);
|
||||
|
||||
PRUint32 referenceCount;
|
||||
nsCOMPtr<nsIURI> referenceURI;
|
||||
|
||||
rv = aStream->WriteCompoundObject(mURI, NS_GET_IID(nsIURI), PR_TRUE);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
PRUint32 i;
|
||||
|
||||
// nsISupportsArray mStyleSheetReferences
|
||||
mStyleSheetReferences->Count(&referenceCount);
|
||||
rv |= aStream->Write32(referenceCount);
|
||||
|
||||
for (i = 0; i < referenceCount; ++i) {
|
||||
mStyleSheetReferences->QueryElementAt(i, NS_GET_IID(nsIURI), getter_AddRefs(referenceURI));
|
||||
|
||||
rv |= aStream->WriteCompoundObject(referenceURI, NS_GET_IID(nsIURI), PR_TRUE);
|
||||
}
|
||||
|
||||
// nsISupportsArray mOverlayReferences
|
||||
mOverlayReferences->Count(&referenceCount);
|
||||
rv |= aStream->Write32(referenceCount);
|
||||
|
||||
for (i = 0; i < referenceCount; ++i) {
|
||||
mOverlayReferences->QueryElementAt(i, NS_GET_IID(nsIURI), getter_AddRefs(referenceURI));
|
||||
|
||||
rv |= aStream->WriteCompoundObject(referenceURI, NS_GET_IID(nsIURI), PR_TRUE);
|
||||
}
|
||||
|
||||
// nsIPrincipal mDocumentPrincipal
|
||||
rv |= NS_WriteOptionalObject(aStream, mDocumentPrincipal, PR_TRUE);
|
||||
|
||||
// Now serialize the document contents
|
||||
nsCOMPtr<nsIScriptGlobalObject> globalObject;
|
||||
rv |= GetScriptGlobalObject(getter_AddRefs(globalObject));
|
||||
|
||||
nsCOMPtr<nsIScriptContext> scriptContext;
|
||||
rv = mGlobalObject->GetContext(getter_AddRefs(scriptContext));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
#if 0
|
||||
rv = mRoot->Serialize(aStream, scriptContext);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsCOMPtr<nsISupportsArray> mStyleSheetReferences;
|
||||
nsCOMPtr<nsISupportsArray> mOverlayReferences;
|
||||
nsCOMPtr<nsIPrincipal> mDocumentPrincipal;
|
||||
|
||||
nsCOMPtr<nsIScriptGlobalObject> mGlobalObject;
|
||||
#endif
|
||||
return NS_OK;
|
||||
rv |= globalObject->GetContext(getter_AddRefs(scriptContext));
|
||||
|
||||
if (mRoot)
|
||||
rv |= mRoot->Serialize(aStream, scriptContext);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
@ -418,7 +490,6 @@ nsXULPrototypeDocument::GetOverlayReferences(nsISupportsArray** aResult)
|
||||
}
|
||||
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXULPrototypeDocument::GetHeaderData(nsIAtom* aField, nsAString& aData) const
|
||||
{
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user