Bug 94199, part 4, serialize/deserialize xbl to startup cache, r=bz

This commit is contained in:
Neil Deakin 2011-11-03 16:39:08 -04:00
Родитель 16336f7b86
Коммит 16faece69e
28 изменённых файлов: 1816 добавлений и 88 удалений

Просмотреть файл

@ -1878,6 +1878,15 @@ NS_NewDOMDocument(nsIDOMDocument** aInstancePtrResult,
bool aLoadedAsData,
nsIScriptGlobalObject* aEventObject,
bool aSVGDocument);
// This is used only for xbl documents created from the startup cache.
// Non-cached documents are created in the same manner as xml documents.
nsresult
NS_NewXBLDocument(nsIDOMDocument** aInstancePtrResult,
nsIURI* aDocumentURI,
nsIURI* aBaseURI,
nsIPrincipal* aPrincipal);
nsresult
NS_NewPluginDocument(nsIDocument** aInstancePtrResult);

Просмотреть файл

@ -47,6 +47,8 @@ class nsString;
#define kNameSpaceID_Unknown -1
// 0 is special at C++, so use a static const PRInt32 for
// kNameSpaceID_None to keep if from being cast to pointers
// Note that the XBL cache assumes (and asserts) that it can treat a
// single-byte value higher than kNameSpaceID_LastBuiltin specially.
static const PRInt32 kNameSpaceID_None = 0;
#define kNameSpaceID_XMLNS 1 // not really a namespace, but it needs to play the game
#define kNameSpaceID_XML 2
@ -60,7 +62,7 @@ static const PRInt32 kNameSpaceID_None = 0;
#define kNameSpaceID_SVG 10
#define kNameSpaceID_XMLEvents 11
#define kNameSpaceID_LastBuiltin 11 // last 'built-in' namespace
#define NS_NAMESPACEMANAGER_CONTRACTID "@mozilla.org/content/namespacemanager;1"
#define NS_INAMESPACEMANAGER_IID \

Просмотреть файл

@ -893,6 +893,10 @@ public:
}
void SetLoadedAsData(bool aLoadedAsData) { mLoadedAsData = aLoadedAsData; }
void SetLoadedAsInteractiveData(bool aLoadedAsInteractiveData)
{
mLoadedAsInteractiveData = aLoadedAsInteractiveData;
}
nsresult CloneDocHelper(nsDocument* clone) const;

Просмотреть файл

@ -566,7 +566,9 @@ nsXBLContentSink::ConstructBinding(PRUint32 aLineNumber)
NS_ConvertUTF16toUTF8 cid(id);
nsresult rv = NS_OK;
// Don't create a binding with no id. nsXBLPrototypeBinding::Read also
// performs this check.
if (!cid.IsEmpty()) {
mBinding = new nsXBLPrototypeBinding();
if (!mBinding)
@ -894,6 +896,8 @@ nsXBLContentSink::CreateElement(const PRUnichar** aAtts, PRUint32 aAttsCount,
#ifdef MOZ_XUL
}
// Note that this needs to match the code in nsXBLPrototypeBinding::ReadContentNode.
*aAppendContent = true;
nsRefPtr<nsXULPrototypeElement> prototype = new nsXULPrototypeElement();
if (!prototype)

Просмотреть файл

@ -56,7 +56,13 @@
#include "nsDOMJSUtils.h"
#include "mozilla/Services.h"
#include "xpcpublic.h"
#include "mozilla/scache/StartupCache.h"
#include "mozilla/scache/StartupCacheUtils.h"
using namespace mozilla::scache;
static const char kXBLCachePrefix[] = "xblcache";
static NS_DEFINE_CID(kDOMScriptObjectFactoryCID, NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
// An XBLDocumentInfo object has a special context associated with it which we can use to pre-compile
@ -561,6 +567,138 @@ nsXBLDocumentInfo::SetPrototypeBinding(const nsACString& aRef, nsXBLPrototypeBin
return NS_OK;
}
void
nsXBLDocumentInfo::RemovePrototypeBinding(const nsACString& aRef)
{
if (mBindingTable) {
// Use a flat string to avoid making a copy.
const nsPromiseFlatCString& flat = PromiseFlatCString(aRef);
nsCStringKey key(flat);
mBindingTable->Remove(&key);
}
}
// Callback to enumerate over the bindings from this document and write them
// out to the cache.
bool
WriteBinding(nsHashKey *aKey, void *aData, void* aClosure)
{
nsXBLPrototypeBinding* binding = static_cast<nsXBLPrototypeBinding *>(aData);
binding->Write((nsIObjectOutputStream*)aClosure);
return kHashEnumerateNext;
}
// static
nsresult
nsXBLDocumentInfo::ReadPrototypeBindings(nsIURI* aURI, nsXBLDocumentInfo** aDocInfo)
{
*aDocInfo = nsnull;
nsCAutoString spec(kXBLCachePrefix);
nsresult rv = PathifyURI(aURI, spec);
NS_ENSURE_SUCCESS(rv, rv);
StartupCache* startupCache = StartupCache::GetSingleton();
NS_ENSURE_TRUE(startupCache, NS_ERROR_FAILURE);
nsAutoArrayPtr<char> buf;
PRUint32 len;
rv = startupCache->GetBuffer(spec.get(), getter_Transfers(buf), &len);
// GetBuffer will fail if the binding is not in the cache.
if (NS_FAILED(rv))
return rv;
nsCOMPtr<nsIObjectInputStream> stream;
rv = NewObjectInputStreamFromBuffer(buf, len, getter_AddRefs(stream));
NS_ENSURE_SUCCESS(rv, rv);
buf.forget();
// The file compatibility.ini stores the build id. This is checked in
// nsAppRunner.cpp and will delete the cache if a different build is
// present. However, we check that the version matches here to be safe.
PRUint32 version;
rv = stream->Read32(&version);
NS_ENSURE_SUCCESS(rv, rv);
if (version != XBLBinding_Serialize_Version) {
// The version that exists is different than expected, likely created with a
// different build, so invalidate the cache.
startupCache->InvalidateCache();
return NS_ERROR_NOT_AVAILABLE;
}
nsCOMPtr<nsIPrincipal> principal;
nsContentUtils::GetSecurityManager()->
GetSystemPrincipal(getter_AddRefs(principal));
nsCOMPtr<nsIDOMDocument> domdoc;
rv = NS_NewXBLDocument(getter_AddRefs(domdoc), aURI, nsnull, principal);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDocument> doc = do_QueryInterface(domdoc);
nsRefPtr<nsXBLDocumentInfo> docInfo = NS_NewXBLDocumentInfo(doc);
while (1) {
PRUint8 flags;
nsresult rv = stream->Read8(&flags);
NS_ENSURE_SUCCESS(rv, rv);
if (flags == XBLBinding_Serialize_NoMoreBindings)
break;
nsXBLPrototypeBinding* binding = new nsXBLPrototypeBinding();
rv = binding->Read(stream, docInfo, doc, flags);
if (NS_FAILED(rv)) {
delete binding;
return rv;
}
}
docInfo.swap(*aDocInfo);
return NS_OK;
}
nsresult
nsXBLDocumentInfo::WritePrototypeBindings()
{
// Only write out bindings with the system principal
if (!nsContentUtils::IsSystemPrincipal(mDocument->NodePrincipal()))
return NS_OK;
nsCAutoString spec(kXBLCachePrefix);
nsresult rv = PathifyURI(DocumentURI(), spec);
NS_ENSURE_SUCCESS(rv, rv);
StartupCache* startupCache = StartupCache::GetSingleton();
NS_ENSURE_TRUE(startupCache, rv);
nsCOMPtr<nsIObjectOutputStream> stream;
nsCOMPtr<nsIStorageStream> storageStream;
rv = NewObjectOutputWrappedStorageStream(getter_AddRefs(stream),
getter_AddRefs(storageStream),
true);
NS_ENSURE_SUCCESS(rv, rv);
rv = stream->Write32(XBLBinding_Serialize_Version);
NS_ENSURE_SUCCESS(rv, rv);
if (mBindingTable)
mBindingTable->Enumerate(WriteBinding, stream);
// write a end marker at the end
rv = stream->Write8(XBLBinding_Serialize_NoMoreBindings);
NS_ENSURE_SUCCESS(rv, rv);
stream->Close();
NS_ENSURE_SUCCESS(rv, rv);
PRUint32 len;
nsAutoArrayPtr<char> buf;
rv = NewBufferFromStorageStream(storageStream, getter_Transfers(buf), &len);
NS_ENSURE_SUCCESS(rv, rv);
return startupCache->PutBuffer(spec.get(), buf, len);
}
void
nsXBLDocumentInfo::SetFirstPrototypeBinding(nsXBLPrototypeBinding* aBinding)
{

Просмотреть файл

@ -68,6 +68,11 @@ public:
nsresult SetPrototypeBinding(const nsACString& aRef,
nsXBLPrototypeBinding* aBinding);
// This removes the binding without deleting it
void RemovePrototypeBinding(const nsACString& aRef);
nsresult WritePrototypeBindings();
void SetFirstPrototypeBinding(nsXBLPrototypeBinding* aBinding);
void FlushSkinStylesheets();
@ -77,6 +82,8 @@ public:
// nsIScriptGlobalObjectOwner methods
virtual nsIScriptGlobalObject* GetScriptGlobalObject();
static nsresult ReadPrototypeBindings(nsIURI* aURI, nsXBLDocumentInfo** aDocInfo);
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsXBLDocumentInfo,
nsIScriptGlobalObjectOwner)

Просмотреть файл

@ -47,6 +47,7 @@
#include "nsIServiceManager.h"
#include "nsIDOMNode.h"
#include "nsXBLPrototypeBinding.h"
#include "nsXBLProtoImplProperty.h"
// Checks that the version is not modified in a given scope.
class AutoVersionChecker
@ -299,6 +300,159 @@ nsXBLProtoImpl::DestroyMembers()
mDestructor = nsnull;
}
nsresult
nsXBLProtoImpl::Read(nsIScriptContext* aContext,
nsIObjectInputStream* aStream,
nsXBLPrototypeBinding* aBinding,
nsIScriptGlobalObject* aGlobal)
{
// Set up a class object first so that deserialization is possible
JSContext *cx = static_cast<JSContext *>(aContext->GetNativeContext());
JSObject *global = aGlobal->GetGlobalJSObject();
void* classObject;
nsresult rv = aBinding->InitClass(mClassName, cx, global, global, &classObject);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(classObject, NS_ERROR_FAILURE);
mClassObject = (JSObject*) classObject;
nsXBLProtoImplField* previousField = nsnull;
nsXBLProtoImplMember* previousMember = nsnull;
do {
XBLBindingSerializeDetails type;
rv = aStream->Read8(&type);
NS_ENSURE_SUCCESS(rv, rv);
if (type == XBLBinding_Serialize_NoMoreItems)
break;
switch (type & XBLBinding_Serialize_Mask) {
case XBLBinding_Serialize_Field:
{
nsXBLProtoImplField* field =
new nsXBLProtoImplField(type & XBLBinding_Serialize_ReadOnly);
rv = field->Read(aContext, aStream);
if (NS_FAILED(rv)) {
delete field;
return rv;
}
if (previousField) {
previousField->SetNext(field);
}
else {
mFields = field;
}
previousField = field;
break;
}
case XBLBinding_Serialize_GetterProperty:
case XBLBinding_Serialize_SetterProperty:
case XBLBinding_Serialize_GetterSetterProperty:
{
nsAutoString name;
nsresult rv = aStream->ReadString(name);
NS_ENSURE_SUCCESS(rv, rv);
nsXBLProtoImplProperty* prop =
new nsXBLProtoImplProperty(name.get(), type & XBLBinding_Serialize_ReadOnly);
rv = prop->Read(aContext, aStream, type & XBLBinding_Serialize_Mask);
if (NS_FAILED(rv)) {
delete prop;
return rv;
}
previousMember = AddMember(prop, previousMember);
break;
}
case XBLBinding_Serialize_Method:
{
nsAutoString name;
rv = aStream->ReadString(name);
NS_ENSURE_SUCCESS(rv, rv);
nsXBLProtoImplMethod* method = new nsXBLProtoImplMethod(name.get());
rv = method->Read(aContext, aStream);
if (NS_FAILED(rv)) {
delete method;
return rv;
}
previousMember = AddMember(method, previousMember);
break;
}
case XBLBinding_Serialize_Constructor:
{
mConstructor = new nsXBLProtoImplAnonymousMethod();
rv = mConstructor->Read(aContext, aStream);
if (NS_FAILED(rv)) {
delete mConstructor;
mConstructor = nsnull;
return rv;
}
previousMember = AddMember(mConstructor, previousMember);
break;
}
case XBLBinding_Serialize_Destructor:
{
mDestructor = new nsXBLProtoImplAnonymousMethod();
rv = mDestructor->Read(aContext, aStream);
if (NS_FAILED(rv)) {
delete mDestructor;
mDestructor = nsnull;
return rv;
}
previousMember = AddMember(mDestructor, previousMember);
break;
}
default:
NS_ERROR("Unexpected binding member type");
break;
}
} while (1);
return NS_OK;
}
nsresult
nsXBLProtoImpl::Write(nsIScriptContext* aContext,
nsIObjectOutputStream* aStream,
nsXBLPrototypeBinding* aBinding)
{
nsresult rv;
if (!mClassObject) {
rv = CompilePrototypeMembers(aBinding);
NS_ENSURE_SUCCESS(rv, rv);
}
rv = aStream->WriteStringZ(mClassName.get());
NS_ENSURE_SUCCESS(rv, rv);
for (nsXBLProtoImplField* curr = mFields; curr; curr = curr->GetNext()) {
rv = curr->Write(aContext, aStream);
NS_ENSURE_SUCCESS(rv, rv);
}
for (nsXBLProtoImplMember* curr = mMembers; curr; curr = curr->GetNext()) {
if (curr == mConstructor) {
rv = mConstructor->Write(aContext, aStream, XBLBinding_Serialize_Constructor);
}
else if (curr == mDestructor) {
rv = mDestructor->Write(aContext, aStream, XBLBinding_Serialize_Destructor);
}
else {
rv = curr->Write(aContext, aStream);
}
NS_ENSURE_SUCCESS(rv, rv);
}
return aStream->Write8(XBLBinding_Serialize_NoMoreItems);
}
nsresult
NS_NewXBLProtoImpl(nsXBLPrototypeBinding* aBinding,
const PRUnichar* aClassName,

Просмотреть файл

@ -105,7 +105,26 @@ public:
return mClassObject != nsnull;
}
nsresult Read(nsIScriptContext* aContext,
nsIObjectInputStream* aStream,
nsXBLPrototypeBinding* aBinding,
nsIScriptGlobalObject* aGlobal);
nsresult Write(nsIScriptContext* aContext,
nsIObjectOutputStream* aStream,
nsXBLPrototypeBinding* aBinding);
protected:
// used by Read to add each member
nsXBLProtoImplMember* AddMember(nsXBLProtoImplMember* aMember,
nsXBLProtoImplMember* aPreviousMember)
{
if (aPreviousMember)
aPreviousMember->SetNext(aMember);
else
mMembers = aMember;
return aMember;
}
void DestroyMembers();
public:

Просмотреть файл

@ -48,6 +48,8 @@
#include "nsIScriptContext.h"
#include "nsContentUtils.h"
#include "nsIURI.h"
#include "nsXBLSerialize.h"
#include "nsXBLPrototypeBinding.h"
nsXBLProtoImplField::nsXBLProtoImplField(const PRUnichar* aName, const PRUnichar* aReadOnly)
: mNext(nsnull),
@ -66,6 +68,20 @@ nsXBLProtoImplField::nsXBLProtoImplField(const PRUnichar* aName, const PRUnichar
}
}
nsXBLProtoImplField::nsXBLProtoImplField(bool aIsReadOnly)
: mNext(nsnull),
mFieldText(nsnull),
mFieldTextLength(0),
mLineNumber(0)
{
MOZ_COUNT_CTOR(nsXBLProtoImplField);
mJSAttributes = JSPROP_ENUMERATE;
if (aIsReadOnly)
mJSAttributes |= JSPROP_READONLY;
}
nsXBLProtoImplField::~nsXBLProtoImplField()
{
MOZ_COUNT_DTOR(nsXBLProtoImplField);
@ -152,3 +168,45 @@ nsXBLProtoImplField::InstallField(nsIScriptContext* aContext,
*aDidInstall = true;
return NS_OK;
}
nsresult
nsXBLProtoImplField::Read(nsIScriptContext* aContext,
nsIObjectInputStream* aStream)
{
nsAutoString name;
nsresult rv = aStream->ReadString(name);
NS_ENSURE_SUCCESS(rv, rv);
mName = ToNewUnicode(name);
rv = aStream->Read32(&mLineNumber);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString fieldText;
rv = aStream->ReadString(fieldText);
NS_ENSURE_SUCCESS(rv, rv);
mFieldTextLength = fieldText.Length();
if (mFieldTextLength)
mFieldText = ToNewUnicode(fieldText);
return NS_OK;
}
nsresult
nsXBLProtoImplField::Write(nsIScriptContext* aContext,
nsIObjectOutputStream* aStream)
{
XBLBindingSerializeDetails type = XBLBinding_Serialize_Field;
if (mJSAttributes & JSPROP_READONLY) {
type |= XBLBinding_Serialize_ReadOnly;
}
nsresult rv = aStream->Write8(type);
NS_ENSURE_SUCCESS(rv, rv);
rv = aStream->WriteWStringZ(mName);
NS_ENSURE_SUCCESS(rv, rv);
rv = aStream->Write32(mLineNumber);
NS_ENSURE_SUCCESS(rv, rv);
return aStream->WriteWStringZ(mFieldText ? mFieldText : EmptyString().get());
}

Просмотреть файл

@ -52,6 +52,7 @@ class nsXBLProtoImplField
{
public:
nsXBLProtoImplField(const PRUnichar* aName, const PRUnichar* aReadOnly);
nsXBLProtoImplField(const bool aIsReadOnly);
~nsXBLProtoImplField();
void AppendFieldText(const nsAString& aText);
@ -68,6 +69,9 @@ public:
nsIURI* aBindingDocURI,
bool* aDidInstall) const;
nsresult Read(nsIScriptContext* aContext, nsIObjectInputStream* aStream);
nsresult Write(nsIScriptContext* aContext, nsIObjectOutputStream* aStream);
const PRUnichar* GetName() const { return mName; }
protected:

Просмотреть файл

@ -119,6 +119,12 @@ public:
virtual void Trace(TraceCallback aCallback, void *aClosure) const = 0;
virtual nsresult Write(nsIScriptContext* aContext,
nsIObjectOutputStream* aStream)
{
return NS_OK;
}
protected:
nsXBLProtoImplMember* mNext; // The members of an implementation are chained.
PRUnichar* mName; // The name of the field, method, or property.

Просмотреть файл

@ -51,6 +51,7 @@
#include "nsContentUtils.h"
#include "nsIScriptSecurityManager.h"
#include "nsIXPConnect.h"
#include "nsXBLPrototypeBinding.h"
nsXBLProtoImplMethod::nsXBLProtoImplMethod(const PRUnichar* aName) :
nsXBLProtoImplMember(aName),
@ -267,6 +268,41 @@ nsXBLProtoImplMethod::Trace(TraceCallback aCallback, void *aClosure) const
}
}
nsresult
nsXBLProtoImplMethod::Read(nsIScriptContext* aContext,
nsIObjectInputStream* aStream)
{
void* methodCode;
PRUint32 lineNumber;
nsresult rv = XBL_DeserializeFunction(aContext, aStream, this,
&lineNumber, &methodCode);
mJSMethodObject = (JSObject *)methodCode;
if (NS_FAILED(rv)) {
SetUncompiledMethod(nsnull);
return rv;
}
#ifdef DEBUG
mIsCompiled = true;
#endif
return NS_OK;
}
nsresult
nsXBLProtoImplMethod::Write(nsIScriptContext* aContext,
nsIObjectOutputStream* aStream)
{
nsresult rv = aStream->Write8(XBLBinding_Serialize_Method);
NS_ENSURE_SUCCESS(rv, rv);
rv = aStream->WriteWStringZ(mName);
NS_ENSURE_SUCCESS(rv, rv);
// XXXndeakin fix line number
return XBL_SerializeFunction(aContext, aStream, mJSMethodObject, 0);
}
nsresult
nsXBLProtoImplAnonymousMethod::Execute(nsIContent* aBoundElement)
{
@ -348,3 +384,20 @@ nsXBLProtoImplAnonymousMethod::Execute(nsIContent* aBoundElement)
return NS_OK;
}
nsresult
nsXBLProtoImplAnonymousMethod::Write(nsIScriptContext* aContext,
nsIObjectOutputStream* aStream,
XBLBindingSerializeDetails aType)
{
if (mJSMethodObject) {
nsresult rv = aStream->Write8(aType);
NS_ENSURE_SUCCESS(rv, rv);
// XXXndeakin write out line number
rv = XBL_SerializeFunction(aContext, aStream, mJSMethodObject, 0);
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
}

Просмотреть файл

@ -45,6 +45,7 @@
#include "nsIContent.h"
#include "nsString.h"
#include "nsXBLProtoImplMember.h"
#include "nsXBLSerialize.h"
struct nsXBLParameter {
nsXBLParameter* mNext;
@ -130,6 +131,9 @@ public:
virtual void Trace(TraceCallback aCallback, void *aClosure) const;
nsresult Read(nsIScriptContext* aContext, nsIObjectInputStream* aStream);
virtual nsresult Write(nsIScriptContext* aContext, nsIObjectOutputStream* aStream);
bool IsCompiled() const
{
return !(mUncompiledMethod & BIT_UNCOMPILED);
@ -175,6 +179,10 @@ public:
const nsCString& aClassStr) {
return NS_OK;
}
nsresult Write(nsIScriptContext* aContext,
nsIObjectOutputStream* aStream,
XBLBindingSerializeDetails aType);
};
#endif // nsXBLProtoImplMethod_h__

Просмотреть файл

@ -48,6 +48,8 @@
#include "nsIScriptContext.h"
#include "nsIScriptGlobalObject.h"
#include "nsContentUtils.h"
#include "nsXBLPrototypeBinding.h"
#include "nsXBLSerialize.h"
nsXBLProtoImplProperty::nsXBLProtoImplProperty(const PRUnichar* aName,
const PRUnichar* aGetter,
@ -75,6 +77,22 @@ nsXBLProtoImplProperty::nsXBLProtoImplProperty(const PRUnichar* aName,
AppendSetterText(nsDependentString(aSetter));
}
nsXBLProtoImplProperty::nsXBLProtoImplProperty(const PRUnichar* aName,
const bool aIsReadOnly)
: nsXBLProtoImplMember(aName),
mGetterText(nsnull),
mSetterText(nsnull),
mJSAttributes(JSPROP_ENUMERATE)
#ifdef DEBUG
, mIsCompiled(false)
#endif
{
MOZ_COUNT_CTOR(nsXBLProtoImplProperty);
if (aIsReadOnly)
mJSAttributes |= JSPROP_READONLY;
}
nsXBLProtoImplProperty::~nsXBLProtoImplProperty()
{
MOZ_COUNT_DTOR(nsXBLProtoImplProperty);
@ -336,3 +354,76 @@ nsXBLProtoImplProperty::Trace(TraceCallback aCallback, void *aClosure) const
"mJSSetterObject", aClosure);
}
}
nsresult
nsXBLProtoImplProperty::Read(nsIScriptContext* aContext,
nsIObjectInputStream* aStream,
XBLBindingSerializeDetails aType)
{
nsresult rv;
PRUint32 lineNumber;
void* scriptObject;
if (aType == XBLBinding_Serialize_GetterProperty ||
aType == XBLBinding_Serialize_GetterSetterProperty) {
rv = XBL_DeserializeFunction(aContext, aStream, this, &lineNumber, &scriptObject);
NS_ENSURE_SUCCESS(rv, rv);
mJSGetterObject = (JSObject *)scriptObject;
mJSAttributes |= JSPROP_GETTER | JSPROP_SHARED;
}
if (aType == XBLBinding_Serialize_SetterProperty ||
aType == XBLBinding_Serialize_GetterSetterProperty) {
rv = XBL_DeserializeFunction(aContext, aStream, this, &lineNumber, &scriptObject);
NS_ENSURE_SUCCESS(rv, rv);
mJSSetterObject = (JSObject *)scriptObject;
mJSAttributes |= JSPROP_SETTER | JSPROP_SHARED;
}
#ifdef DEBUG
mIsCompiled = true;
#endif
return NS_OK;
}
nsresult
nsXBLProtoImplProperty::Write(nsIScriptContext* aContext,
nsIObjectOutputStream* aStream)
{
XBLBindingSerializeDetails type;
if (mJSAttributes & JSPROP_GETTER) {
type = mJSAttributes & JSPROP_SETTER ?
XBLBinding_Serialize_GetterSetterProperty :
XBLBinding_Serialize_GetterProperty;
}
else {
type = XBLBinding_Serialize_SetterProperty;
}
if (mJSAttributes & JSPROP_READONLY) {
type |= XBLBinding_Serialize_ReadOnly;
}
nsresult rv = aStream->Write8(type);
NS_ENSURE_SUCCESS(rv, rv);
rv = aStream->WriteWStringZ(mName);
NS_ENSURE_SUCCESS(rv, rv);
if (mJSAttributes & JSPROP_GETTER) {
// XXXndeakin write out line number
rv = XBL_SerializeFunction(aContext, aStream, mJSGetterObject, 0);
NS_ENSURE_SUCCESS(rv, rv);
}
if (mJSAttributes & JSPROP_SETTER) {
// XXXndeakin write out line number
rv = XBL_SerializeFunction(aContext, aStream, mJSSetterObject, 0);
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
}

Просмотреть файл

@ -44,6 +44,7 @@
#include "jsapi.h"
#include "nsIContent.h"
#include "nsString.h"
#include "nsXBLSerialize.h"
#include "nsXBLProtoImplMember.h"
class nsXBLProtoImplProperty: public nsXBLProtoImplMember
@ -53,6 +54,8 @@ public:
const PRUnichar* aGetter,
const PRUnichar* aSetter,
const PRUnichar* aReadOnly);
nsXBLProtoImplProperty(const PRUnichar* aName, bool aIsReadOnly);
virtual ~nsXBLProtoImplProperty();
@ -73,6 +76,12 @@ public:
virtual void Trace(TraceCallback aCallback, void *aClosure) const;
nsresult Read(nsIScriptContext* aContext,
nsIObjectInputStream* aStream,
XBLBindingSerializeDetails aType);
virtual nsresult Write(nsIScriptContext* aContext,
nsIObjectOutputStream* aStream);
protected:
union {
// The raw text for the getter (prior to compilation).

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -47,6 +47,7 @@
#include "nsWeakReference.h"
#include "nsIContent.h"
#include "nsHashtable.h"
#include "nsClassHashtable.h"
#include "nsXBLDocumentInfo.h"
#include "nsCOMArray.h"
#include "nsXBLProtoImpl.h"
@ -61,6 +62,34 @@ class nsXBLProtoImplField;
class nsXBLBinding;
class nsCSSStyleSheet;
// This structure represents an insertion point, and is used when writing out
// insertion points. It contains comparison operators so that it can be stored
// in an array sorted by index.
struct InsertionItem {
PRUint32 insertionIndex;
nsIAtom* tag;
nsIContent* defaultContent;
InsertionItem(PRUint32 aInsertionIndex, nsIAtom* aTag, nsIContent* aDefaultContent)
: insertionIndex(aInsertionIndex), tag(aTag), defaultContent(aDefaultContent) { }
bool operator<(const InsertionItem& item) const
{
NS_ASSERTION(insertionIndex != item.insertionIndex || defaultContent == item.defaultContent,
"default content is different for same index");
return insertionIndex < item.insertionIndex;
}
bool operator==(const InsertionItem& item) const
{
NS_ASSERTION(insertionIndex != item.insertionIndex || defaultContent == item.defaultContent,
"default content is different for same index");
return insertionIndex == item.insertionIndex;
}
};
typedef nsClassHashtable<nsISupportsHashKey, nsAutoTArray<InsertionItem, 1> > ArrayOfInsertionPointsByContent;
// *********************************************************************/
// The XBLPrototypeBinding class
@ -191,6 +220,84 @@ public:
return &mKeyHandlers;
}
/**
* Read this binding from the stream aStream into the xbl document aDocument.
* aDocInfo should be the xbl document info for the binding document.
* aFlags can contain XBLBinding_Serialize_InheritStyle to indicate that
* mInheritStyle flag should be set, and XBLBinding_Serialize_IsFirstBinding
* to indicate the first binding in a document.
*/
nsresult Read(nsIObjectInputStream* aStream,
nsXBLDocumentInfo* aDocInfo,
nsIDocument* aDocument,
PRUint8 aFlags);
/**
* Write this binding to the stream.
*/
nsresult Write(nsIObjectOutputStream* aStream);
/**
* Read a content node from aStream and return it in aChild.
* aDocument and aNim are the document and node info manager for the document
* the child will be inserted into.
*/
nsresult ReadContentNode(nsIObjectInputStream* aStream,
nsIDocument* aDocument,
nsNodeInfoManager* aNim,
nsIContent** aChild);
/**
* Write the content node aNode to aStream.
* aInsertionPointsByContent is a hash of the insertion points in the binding,
* keyed by where there are in the content hierarchy.
*
* This method is called recursively for each child descendant. For the topmost
* call, aNode must be an element.
*
* Text, CDATA and comment nodes are serialized as:
* the constant XBLBinding_Serialize_TextNode, XBLBinding_Serialize_CDATANode
* or XBLBinding_Serialize_CommentNode
* the text for the node
* Elements are serialized in the following format:
* node's namespace, written with WriteNamespace
* node's namespace prefix
* node's tag
* 32-bit attribute count
* table of attributes:
* attribute's namespace, written with WriteNamespace
* attribute's namespace prefix
* attribute's tag
* attribute's value
* attribute forwarding table:
* source namespace
* source attribute
* destination namespace
* destination attribute
* the constant XBLBinding_Serialize_NoMoreAttributes
* insertion points within this node:
* child index to insert within node
* default content serialized in the same manner or XBLBinding_Serialize_NoContent
* count of insertion points at that index
* that number of string tags (those in the <children>'s includes attribute)
* the constant XBLBinding_Serialize_NoMoreInsertionPoints
* 32-bit count of the number of child nodes
* each child node is serialized in the same manner in sequence
* the constant XBLBinding_Serialize_NoContent
*/
nsresult WriteContentNode(nsIObjectOutputStream* aStream,
nsIContent* aNode,
ArrayOfInsertionPointsByContent& aInsertionPointsByContent);
/**
* Read or write a namespace id from or to aStream. If the namespace matches
* one of the built-in ones defined in nsINameSpaceManager.h, it will be written as
* a single byte with that value. Otherwise, XBLBinding_Serialize_CustomNamespace is
* written out, followed by a string written with writeWStringZ.
*/
nsresult ReadNamespace(nsIObjectInputStream* aStream, PRInt32& aNameSpaceID);
nsresult WriteNamespace(nsIObjectOutputStream* aStream, PRInt32 aNameSpaceID);
public:
nsXBLPrototypeBinding();
~nsXBLPrototypeBinding();
@ -228,7 +335,13 @@ public:
nsIContent* aCopyRoot,
nsIContent* aTemplChild);
protected:
protected:
// Ensure that mAttributeTable has been created.
void EnsureAttributeTable();
// Ad an entry to the attribute table
void AddToAttributeTable(PRInt32 aSourceNamespaceID, nsIAtom* aSourceTag,
PRInt32 aDestNamespaceID, nsIAtom* aDestTag,
nsIContent* aContent);
void ConstructAttributeTable(nsIContent* aElement);
void ConstructInsertionTable(nsIContent* aElement);
void GetNestedChildren(nsIAtom* aTag, PRInt32 aNamespace,
@ -236,30 +349,6 @@ protected:
nsCOMArray<nsIContent> & aList);
void CreateKeyHandlers();
protected:
// Internal helper class for managing our IID table.
class nsIIDKey : public nsHashKey {
protected:
nsIID mKey;
public:
nsIIDKey(REFNSIID key) : mKey(key) {}
~nsIIDKey(void) {}
PRUint32 HashCode(void) const {
// Just use the 32-bit m0 field.
return mKey.m0;
}
bool Equals(const nsHashKey *aKey) const {
return mKey.Equals( ((nsIIDKey*) aKey)->mKey);
}
nsHashKey *Clone(void) const {
return new nsIIDKey(mKey);
}
};
// MEMBER VARIABLES
protected:
nsCOMPtr<nsIURI> mBindingURI;
@ -298,4 +387,3 @@ protected:
};
#endif

Просмотреть файл

@ -79,6 +79,7 @@
#include "nsReadableUtils.h"
#include "nsCRT.h"
#include "nsXBLEventHandler.h"
#include "nsXBLSerialize.h"
#include "nsEventDispatcher.h"
#include "mozilla/Preferences.h"
@ -123,10 +124,7 @@ nsXBLPrototypeHandler::nsXBLPrototypeHandler(const PRUnichar* aEvent,
mNextHandler(nsnull),
mPrototypeBinding(aBinding)
{
++gRefCnt;
if (gRefCnt == 1)
// Get the primary accelerator key.
InitAccessKeys();
Init();
ConstructPrototype(nsnull, aEvent, aPhase, aAction, aCommand, aKeyCode,
aCharCode, aModifiers, aButton, aClickCount,
@ -139,15 +137,21 @@ nsXBLPrototypeHandler::nsXBLPrototypeHandler(nsIContent* aHandlerElement)
mNextHandler(nsnull),
mPrototypeBinding(nsnull)
{
++gRefCnt;
if (gRefCnt == 1)
// Get the primary accelerator key.
InitAccessKeys();
Init();
// Make sure our prototype is initialized.
ConstructPrototype(aHandlerElement);
}
nsXBLPrototypeHandler::nsXBLPrototypeHandler(nsXBLPrototypeBinding* aBinding)
: mHandlerText(nsnull),
mLineNumber(nsnull),
mNextHandler(nsnull),
mPrototypeBinding(aBinding)
{
Init();
}
nsXBLPrototypeHandler::~nsXBLPrototypeHandler()
{
--gRefCnt;
@ -1030,3 +1034,67 @@ nsXBLPrototypeHandler::ModifiersMatchMask(nsIDOMUIEvent* aEvent,
return true;
}
nsresult
nsXBLPrototypeHandler::Read(nsIScriptContext* aContext, nsIObjectInputStream* aStream)
{
nsresult rv = aStream->Read8(&mPhase);
NS_ENSURE_SUCCESS(rv, rv);
rv = aStream->Read8(&mKeyMask);
NS_ENSURE_SUCCESS(rv, rv);
rv = aStream->Read8(&mType);
NS_ENSURE_SUCCESS(rv, rv);
rv = aStream->Read8(&mMisc);
NS_ENSURE_SUCCESS(rv, rv);
PRUint32 detail;
rv = aStream->Read32(&detail);
NS_ENSURE_SUCCESS(rv, rv);
mDetail = detail;
nsAutoString name;
rv = aStream->ReadString(name);
NS_ENSURE_SUCCESS(rv, rv);
mEventName = do_GetAtom(name);
rv = aStream->Read32(&mLineNumber);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString handlerText;
rv = aStream->ReadString(handlerText);
NS_ENSURE_SUCCESS(rv, rv);
if (!handlerText.IsEmpty())
mHandlerText = ToNewUnicode(handlerText);
return NS_OK;
}
nsresult
nsXBLPrototypeHandler::Write(nsIScriptContext* aContext, nsIObjectOutputStream* aStream)
{
// Make sure we don't write out NS_HANDLER_TYPE_XUL types, as they are used
// for <keyset> elements.
if (mType & NS_HANDLER_TYPE_XUL)
return NS_OK;
XBLBindingSerializeDetails type = XBLBinding_Serialize_Handler;
nsresult rv = aStream->Write8(type);
rv = aStream->Write8(mPhase);
NS_ENSURE_SUCCESS(rv, rv);
rv = aStream->Write8(mKeyMask);
NS_ENSURE_SUCCESS(rv, rv);
rv = aStream->Write8(mType);
NS_ENSURE_SUCCESS(rv, rv);
rv = aStream->Write8(mMisc);
NS_ENSURE_SUCCESS(rv, rv);
rv = aStream->Write32(mDetail);
NS_ENSURE_SUCCESS(rv, rv);
rv = aStream->WriteWStringZ(nsDependentAtomString(mEventName).get());
NS_ENSURE_SUCCESS(rv, rv);
rv = aStream->Write32(mLineNumber);
NS_ENSURE_SUCCESS(rv, rv);
return aStream->WriteWStringZ(mHandlerText ? mHandlerText : EmptyString().get());
}

Просмотреть файл

@ -88,6 +88,9 @@ public:
// This constructor is used only by XUL key handlers (e.g., <key>)
nsXBLPrototypeHandler(nsIContent* aKeyElement);
// This constructor is used for handlers loaded from the cache
nsXBLPrototypeHandler(nsXBLPrototypeBinding* aBinding);
~nsXBLPrototypeHandler();
// if aCharCode is not zero, it is used instead of the charCode of aKeyEvent.
@ -157,10 +160,20 @@ public:
return (mType & NS_HANDLER_ALLOW_UNTRUSTED) != 0;
}
nsresult Read(nsIScriptContext* aContext, nsIObjectInputStream* aStream);
nsresult Write(nsIScriptContext* aContext, nsIObjectOutputStream* aStream);
public:
static PRUint32 gRefCnt;
protected:
void Init() {
++gRefCnt;
if (gRefCnt == 1)
// Get the primary accelerator key.
InitAccessKeys();
}
already_AddRefed<nsIController> GetController(nsIDOMEventTarget* aTarget);
inline PRInt32 GetMatchingKeyCode(const nsAString& aKeyName);

Просмотреть файл

@ -139,3 +139,11 @@ nsXBLPrototypeResources::FlushSkinSheets()
return NS_OK;
}
nsresult
nsXBLPrototypeResources::Write(nsIObjectOutputStream* aStream)
{
if (mLoader)
return mLoader->Write(aStream);
return NS_OK;
}

Просмотреть файл

@ -63,6 +63,8 @@ public:
void AddResourceListener(nsIContent* aElement);
nsresult FlushSkinSheets();
nsresult Write(nsIObjectOutputStream* aStream);
nsXBLPrototypeResources(nsXBLPrototypeBinding* aBinding);
~nsXBLPrototypeResources();

Просмотреть файл

@ -290,3 +290,25 @@ nsXBLResourceLoader::NotifyBoundElements()
// Delete ourselves.
NS_RELEASE(mResources->mLoader);
}
nsresult
nsXBLResourceLoader::Write(nsIObjectOutputStream* aStream)
{
nsresult rv;
for (nsXBLResource* curr = mResourceList; curr; curr = curr->mNext) {
if (curr->mType == nsGkAtoms::image)
rv = aStream->Write8(XBLBinding_Serialize_Image);
else if (curr->mType == nsGkAtoms::stylesheet)
rv = aStream->Write8(XBLBinding_Serialize_Stylesheet);
else
continue;
NS_ENSURE_SUCCESS(rv, rv);
rv = aStream->WriteWStringZ(curr->mSrc.get());
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
}

Просмотреть файл

@ -91,6 +91,8 @@ public:
void NotifyBoundElements();
nsresult Write(nsIObjectOutputStream* aStream);
// MEMBER VARIABLES
nsXBLPrototypeBinding* mBinding; // A pointer back to our binding.
nsXBLPrototypeResources* mResources; // A pointer back to our resources

Просмотреть файл

@ -43,9 +43,11 @@
nsresult
XBL_SerializeFunction(nsIScriptContext* aContext,
nsIObjectOutputStream* aStream,
JSObject* aFunctionObject)
JSObject* aFunctionObject,
PRUint32 aLineNumber)
{
nsresult rv = NS_OK;
nsresult rv = aStream->Write32(aLineNumber);
NS_ENSURE_SUCCESS(rv, rv);
JSContext* cx = (JSContext*) aContext->GetNativeContext();
JSXDRState *xdr = ::JS_XDRNewMem(cx, JSXDR_ENCODE);

Просмотреть файл

@ -43,11 +43,73 @@
#include "nsIScriptContext.h"
#include "nsIObjectInputStream.h"
#include "nsIObjectOutputStream.h"
#include "nsINameSpaceManager.h"
typedef PRUint8 XBLBindingSerializeDetails;
// A version number to ensure we don't load cached data in a different
// file format.
#define XBLBinding_Serialize_Version 0x00000001
// Set for the first binding in a document
#define XBLBinding_Serialize_IsFirstBinding 1
// Set to indicate that nsXBLPrototypeBinding::mInheritStyle should be true
#define XBLBinding_Serialize_InheritStyle 2
// Appears at the end of the serialized data to indicate that no more bindings
// are present for this document.
#define XBLBinding_Serialize_NoMoreBindings 0x80
// Implementation member types. The serialized value for each member contains one
// of these values, combined with the read-only flag XBLBinding_Serialize_ReadOnly.
// Use XBLBinding_Serialize_Mask to filter out the read-only flag and check for
// just the member type.
#define XBLBinding_Serialize_NoMoreItems 0 // appears at the end of the members list
#define XBLBinding_Serialize_Field 1
#define XBLBinding_Serialize_GetterProperty 2
#define XBLBinding_Serialize_SetterProperty 3
#define XBLBinding_Serialize_GetterSetterProperty 4
#define XBLBinding_Serialize_Method 5
#define XBLBinding_Serialize_Constructor 6
#define XBLBinding_Serialize_Destructor 7
#define XBLBinding_Serialize_Handler 8
#define XBLBinding_Serialize_Image 9
#define XBLBinding_Serialize_Stylesheet 10
#define XBLBinding_Serialize_Mask 0x0F
#define XBLBinding_Serialize_ReadOnly 0x80
// Appears at the end of the list of insertion points to indicate that there
// are no more.
#define XBLBinding_Serialize_NoMoreInsertionPoints 0xFFFFFFFF
// When serializing content nodes, a single-byte namespace id is written out
// first. The special values below can appear in place of a namespace id.
// Indicates that this is not one of the built-in namespaces defined in
// nsINameSpaceManager.h. The string form will be serialized immediately
// following.
#define XBLBinding_Serialize_CustomNamespace 0xFE
// Flags to indicate a non-element node. Otherwise, it is an element.
#define XBLBinding_Serialize_TextNode 0xFB
#define XBLBinding_Serialize_CDATANode 0xFC
#define XBLBinding_Serialize_CommentNode 0xFD
// Indicates that there is no content to serialize/deserialize
#define XBLBinding_Serialize_NoContent 0xFF
// Appears at the end of the forwarded attributes list to indicate that there
// are no more attributes.
#define XBLBinding_Serialize_NoMoreAttributes 0xFF
PR_STATIC_ASSERT(XBLBinding_Serialize_CustomNamespace >= kNameSpaceID_LastBuiltin);
nsresult
XBL_SerializeFunction(nsIScriptContext* aContext,
nsIObjectOutputStream* aStream,
JSObject* aFunctionObject);
JSObject* aFunctionObject,
PRUint32 aLineNumber);
nsresult
XBL_DeserializeFunction(nsIScriptContext* aContext,

Просмотреть файл

@ -85,6 +85,7 @@
#include "nsStyleContext.h"
#include "nsIScriptSecurityManager.h"
#include "nsIScriptError.h"
#include "nsXBLSerialize.h"
#ifdef MOZ_XUL
#include "nsXULPrototypeCache.h"
@ -840,9 +841,6 @@ nsXBLService::GetBinding(nsIContent* aBoundElement, nsIURI* aURI,
if (!docInfo)
return NS_ERROR_FAILURE;
// Get our doc info and determine our script access.
nsCOMPtr<nsIDocument> doc = docInfo->GetDocument();
nsXBLPrototypeBinding* protoBinding = docInfo->GetPrototypeBinding(ref);
NS_WARN_IF_FALSE(protoBinding, "Unable to locate an XBL binding");
@ -1059,7 +1057,23 @@ nsXBLService::LoadBindingDocumentInfo(nsIContent* aBoundElement,
return NS_OK;
}
}
#ifdef MOZ_XUL
// Next, look in the startup cache
bool useStartupCache = useXULCache && IsChromeOrResourceURI(documentURI);
if (!info && useStartupCache) {
rv = nsXBLDocumentInfo::ReadPrototypeBindings(documentURI, getter_AddRefs(info));
if (NS_SUCCEEDED(rv)) {
cache->PutXBLDocumentInfo(info);
if (bindingManager) {
// Cache it in our binding manager's document table.
bindingManager->PutXBLDocumentInfo(info);
}
}
}
#endif
if (!info) {
// Finally, if all lines of defense fail, we go and fetch the binding
// document.
@ -1072,7 +1086,7 @@ nsXBLService::LoadBindingDocumentInfo(nsIContent* aBoundElement,
nsCOMPtr<nsIDocument> document;
FetchBindingDocument(aBoundElement, aBoundDocument, documentURI,
aBindingURI, aForceSyncLoad, getter_AddRefs(document));
if (document) {
nsBindingManager *xblDocBindingManager = document->BindingManager();
info = xblDocBindingManager->GetXBLDocumentInfo(documentURI);
@ -1084,8 +1098,11 @@ nsXBLService::LoadBindingDocumentInfo(nsIContent* aBoundElement,
// If the doc is a chrome URI, then we put it into the XUL cache.
#ifdef MOZ_XUL
if (useXULCache && IsChromeOrResourceURI(documentURI)) {
if (useStartupCache) {
cache->PutXBLDocumentInfo(info);
// now write the bindings into the startup cache
info->WritePrototypeBindings();
}
#endif

Просмотреть файл

@ -219,6 +219,27 @@ NS_NewXMLDocument(nsIDocument** aInstancePtrResult)
return rv;
}
nsresult
NS_NewXBLDocument(nsIDOMDocument** aInstancePtrResult,
nsIURI* aDocumentURI,
nsIURI* aBaseURI,
nsIPrincipal* aPrincipal)
{
nsresult rv = NS_NewDOMDocument(aInstancePtrResult,
NS_LITERAL_STRING("http://www.mozilla.org/xbl"),
NS_LITERAL_STRING("bindings"), nsnull,
aDocumentURI, aBaseURI, aPrincipal, false,
nsnull, false);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDocument> idoc = do_QueryInterface(*aInstancePtrResult);
nsDocument* doc = static_cast<nsDocument*>(idoc.get());
doc->SetLoadedAsInteractiveData(true);
doc->SetReadyStateInternal(nsIDocument::READYSTATE_COMPLETE);
return NS_OK;
}
// NOTE! nsDocument::operator new() zeroes out all members, so don't
// bother initializing members to 0.

Просмотреть файл

@ -60,6 +60,9 @@ NewObjectOutputWrappedStorageStream(nsIObjectOutputStream **wrapperStream,
nsIStorageStream** stream,
bool wantDebugStream);
// Creates a buffer for storing the stream into the cache. The buffer is
// allocated with 'new []'. Typically, the caller would store the buffer in
// an nsAutoArrayPtr<char> and then call nsIStartupCache::PutBuffer with it.
NS_EXPORT nsresult
NewBufferFromStorageStream(nsIStorageStream *storageStream,
char** buffer, PRUint32* len);