зеркало из https://github.com/mozilla/gecko-dev.git
343 строки
12 KiB
C++
343 строки
12 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#ifndef nsXBLPrototypeBinding_h__
|
|
#define nsXBLPrototypeBinding_h__
|
|
|
|
#include "nsClassHashtable.h"
|
|
#include "nsCOMArray.h"
|
|
#include "nsCOMPtr.h"
|
|
#include "nsICSSLoaderObserver.h"
|
|
#include "nsInterfaceHashtable.h"
|
|
#include "nsWeakReference.h"
|
|
#include "nsXBLDocumentInfo.h"
|
|
#include "nsXBLProtoImpl.h"
|
|
#include "nsXBLProtoImplMethod.h"
|
|
#include "nsXBLPrototypeHandler.h"
|
|
#include "nsXBLPrototypeResources.h"
|
|
|
|
class nsIAtom;
|
|
class nsIContent;
|
|
class nsIDocument;
|
|
class nsXBLAttributeEntry;
|
|
class nsXBLBinding;
|
|
class nsXBLProtoImplField;
|
|
|
|
// *********************************************************************/
|
|
// The XBLPrototypeBinding class
|
|
|
|
// Instances of this class are owned by the nsXBLDocumentInfo object returned
|
|
// by XBLDocumentInfo(). Consumers who want to refcount things should refcount
|
|
// that.
|
|
class nsXBLPrototypeBinding MOZ_FINAL
|
|
{
|
|
public:
|
|
nsIContent* GetBindingElement() const { return mBinding; }
|
|
void SetBindingElement(nsIContent* aElement);
|
|
|
|
nsIURI* BindingURI() const { return mBindingURI; }
|
|
nsIURI* AlternateBindingURI() const { return mAlternateBindingURI; }
|
|
nsIURI* DocURI() const { return mXBLDocInfoWeak->DocumentURI(); }
|
|
nsIURI* GetBaseBindingURI() const { return mBaseBindingURI; }
|
|
|
|
// Checks if aURI refers to this binding by comparing to both possible
|
|
// binding URIs.
|
|
bool CompareBindingURI(nsIURI* aURI) const;
|
|
|
|
bool GetAllowScripts() const;
|
|
|
|
nsresult BindingAttached(nsIContent* aBoundElement);
|
|
nsresult BindingDetached(nsIContent* aBoundElement);
|
|
|
|
bool LoadResources();
|
|
nsresult AddResource(nsIAtom* aResourceType, const nsAString& aSrc);
|
|
|
|
bool InheritsStyle() const { return mInheritStyle; }
|
|
void SetInheritsStyle(bool aInheritStyle) { mInheritStyle = aInheritStyle; }
|
|
|
|
nsXBLPrototypeHandler* GetPrototypeHandlers() { return mPrototypeHandler; }
|
|
void SetPrototypeHandlers(nsXBLPrototypeHandler* aHandler) { mPrototypeHandler = aHandler; }
|
|
|
|
nsXBLProtoImplAnonymousMethod* GetConstructor();
|
|
nsresult SetConstructor(nsXBLProtoImplAnonymousMethod* aConstructor);
|
|
nsXBLProtoImplAnonymousMethod* GetDestructor();
|
|
nsresult SetDestructor(nsXBLProtoImplAnonymousMethod* aDestructor);
|
|
|
|
nsXBLProtoImplField* FindField(const nsString& aFieldName) const
|
|
{
|
|
return mImplementation ? mImplementation->FindField(aFieldName) : nullptr;
|
|
}
|
|
|
|
// Resolve all the fields for this binding on the object |obj|.
|
|
// False return means a JS exception was set.
|
|
bool ResolveAllFields(JSContext* cx, JS::Handle<JSObject*> obj) const
|
|
{
|
|
return !mImplementation || mImplementation->ResolveAllFields(cx, obj);
|
|
}
|
|
|
|
// Undefine all our fields from object |obj| (which should be a
|
|
// JSObject for a bound element).
|
|
void UndefineFields(JSContext* cx, JS::Handle<JSObject*> obj) const {
|
|
if (mImplementation) {
|
|
mImplementation->UndefineFields(cx, obj);
|
|
}
|
|
}
|
|
|
|
const nsCString& ClassName() const {
|
|
return mImplementation ? mImplementation->mClassName : EmptyCString();
|
|
}
|
|
|
|
nsresult InitClass(const nsCString& aClassName, JSContext * aContext,
|
|
JS::Handle<JSObject*> aScriptObject,
|
|
JS::MutableHandle<JSObject*> aClassObject,
|
|
bool* aNew);
|
|
|
|
nsresult ConstructInterfaceTable(const nsAString& aImpls);
|
|
|
|
void SetImplementation(nsXBLProtoImpl* aImpl) { mImplementation = aImpl; }
|
|
nsXBLProtoImpl* GetImplementation() { return mImplementation; }
|
|
nsresult InstallImplementation(nsXBLBinding* aBinding);
|
|
bool HasImplementation() const { return mImplementation != nullptr; }
|
|
|
|
void AttributeChanged(nsIAtom* aAttribute, int32_t aNameSpaceID,
|
|
bool aRemoveFlag, nsIContent* aChangedElement,
|
|
nsIContent* aAnonymousContent, bool aNotify);
|
|
|
|
void SetBasePrototype(nsXBLPrototypeBinding* aBinding);
|
|
nsXBLPrototypeBinding* GetBasePrototype() { return mBaseBinding; }
|
|
|
|
nsXBLDocumentInfo* XBLDocumentInfo() const { return mXBLDocInfoWeak; }
|
|
bool IsChrome() { return mXBLDocInfoWeak->IsChrome(); }
|
|
|
|
void SetInitialAttributes(nsIContent* aBoundElement, nsIContent* aAnonymousContent);
|
|
|
|
nsIStyleRuleProcessor* GetRuleProcessor();
|
|
nsXBLPrototypeResources::sheet_array_type* GetOrCreateStyleSheets();
|
|
nsXBLPrototypeResources::sheet_array_type* GetStyleSheets();
|
|
|
|
bool HasStyleSheets() {
|
|
return mResources && mResources->mStyleSheetList.Length() > 0;
|
|
}
|
|
|
|
nsresult FlushSkinSheets();
|
|
|
|
nsIAtom* GetBaseTag(int32_t* aNamespaceID);
|
|
void SetBaseTag(int32_t aNamespaceID, nsIAtom* aTag);
|
|
|
|
bool ImplementsInterface(REFNSIID aIID) const;
|
|
|
|
nsresult AddResourceListener(nsIContent* aBoundElement);
|
|
|
|
void Initialize();
|
|
|
|
nsresult ResolveBaseBinding();
|
|
|
|
const nsCOMArray<nsXBLKeyEventHandler>* GetKeyEventHandlers()
|
|
{
|
|
if (!mKeyHandlersRegistered) {
|
|
CreateKeyHandlers();
|
|
mKeyHandlersRegistered = true;
|
|
}
|
|
|
|
return &mKeyHandlers;
|
|
}
|
|
|
|
private:
|
|
nsresult Read(nsIObjectInputStream* aStream,
|
|
nsXBLDocumentInfo* aDocInfo,
|
|
nsIDocument* aDocument,
|
|
uint8_t aFlags);
|
|
|
|
/**
|
|
* Read a new 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.
|
|
* XBLBinding_Serialize_ChromeOnlyContent indicates that
|
|
* nsXBLPrototypeBinding::mChromeOnlyContent should be true.
|
|
*/
|
|
public:
|
|
static nsresult ReadNewBinding(nsIObjectInputStream* aStream,
|
|
nsXBLDocumentInfo* aDocInfo,
|
|
nsIDocument* aDocument,
|
|
uint8_t 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.
|
|
*
|
|
* 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
|
|
* 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);
|
|
|
|
/**
|
|
* Read or write a namespace id from or to aStream. If the namespace matches
|
|
* one of the built-in ones defined in nsNameSpaceManager.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, int32_t& aNameSpaceID);
|
|
nsresult WriteNamespace(nsIObjectOutputStream* aStream, int32_t aNameSpaceID);
|
|
|
|
public:
|
|
nsXBLPrototypeBinding();
|
|
~nsXBLPrototypeBinding();
|
|
|
|
// Init must be called after construction to initialize the prototype
|
|
// binding. It may well throw errors (eg on out-of-memory). Do not confuse
|
|
// this with the Initialize() method, which must be called after the
|
|
// binding's handlers, properties, etc are all set.
|
|
nsresult Init(const nsACString& aRef,
|
|
nsXBLDocumentInfo* aInfo,
|
|
nsIContent* aElement,
|
|
bool aFirstBinding = false);
|
|
|
|
void Traverse(nsCycleCollectionTraversalCallback &cb) const;
|
|
void UnlinkJSObjects();
|
|
void Trace(const TraceCallbacks& aCallbacks, void *aClosure) const;
|
|
|
|
// Internal member functions.
|
|
public:
|
|
/**
|
|
* GetImmediateChild locates the immediate child of our binding element which
|
|
* has the localname given by aTag and is in the XBL namespace.
|
|
*/
|
|
nsIContent* GetImmediateChild(nsIAtom* aTag);
|
|
nsIContent* LocateInstance(nsIContent* aBoundElt,
|
|
nsIContent* aTemplRoot,
|
|
nsIContent* aCopyRoot,
|
|
nsIContent* aTemplChild);
|
|
|
|
bool ChromeOnlyContent() { return mChromeOnlyContent; }
|
|
|
|
typedef nsClassHashtable<nsISupportsHashKey, nsXBLAttributeEntry> InnerAttributeTable;
|
|
|
|
protected:
|
|
// Ensure that mAttributeTable has been created.
|
|
void EnsureAttributeTable();
|
|
// Ad an entry to the attribute table
|
|
void AddToAttributeTable(int32_t aSourceNamespaceID, nsIAtom* aSourceTag,
|
|
int32_t aDestNamespaceID, nsIAtom* aDestTag,
|
|
nsIContent* aContent);
|
|
void ConstructAttributeTable(nsIContent* aElement);
|
|
void CreateKeyHandlers();
|
|
|
|
// MEMBER VARIABLES
|
|
protected:
|
|
nsCOMPtr<nsIURI> mBindingURI;
|
|
nsCOMPtr<nsIURI> mAlternateBindingURI; // Alternate id-less URI that is only non-null on the first binding.
|
|
nsCOMPtr<nsIContent> mBinding; // Strong. We own a ref to our content element in the binding doc.
|
|
nsAutoPtr<nsXBLPrototypeHandler> mPrototypeHandler; // Strong. DocInfo owns us, and we own the handlers.
|
|
|
|
// the url of the base binding
|
|
nsCOMPtr<nsIURI> mBaseBindingURI;
|
|
|
|
nsXBLProtoImpl* mImplementation; // Our prototype implementation (includes methods, properties, fields,
|
|
// the constructor, and the destructor).
|
|
|
|
nsXBLPrototypeBinding* mBaseBinding; // Weak. The docinfo will own our base binding.
|
|
bool mInheritStyle;
|
|
bool mCheckedBaseProto;
|
|
bool mKeyHandlersRegistered;
|
|
bool mChromeOnlyContent;
|
|
|
|
nsXBLPrototypeResources* mResources; // If we have any resources, this will be non-null.
|
|
|
|
nsXBLDocumentInfo* mXBLDocInfoWeak; // A pointer back to our doc info. Weak, since it owns us.
|
|
|
|
// A table for attribute containers. Namespace IDs are used as
|
|
// keys in the table. Containers are InnerAttributeTables.
|
|
// This table is used to efficiently handle attribute changes.
|
|
nsAutoPtr<nsClassHashtable<nsUint32HashKey, InnerAttributeTable>> mAttributeTable;
|
|
|
|
class IIDHashKey : public PLDHashEntryHdr
|
|
{
|
|
public:
|
|
typedef const nsIID& KeyType;
|
|
typedef const nsIID* KeyTypePointer;
|
|
|
|
IIDHashKey(const nsIID* aKey)
|
|
: mKey(*aKey)
|
|
{}
|
|
IIDHashKey(const IIDHashKey& aOther)
|
|
: mKey(aOther.GetKey())
|
|
{}
|
|
~IIDHashKey()
|
|
{}
|
|
|
|
KeyType GetKey() const
|
|
{
|
|
return mKey;
|
|
}
|
|
bool KeyEquals(const KeyTypePointer aKey) const
|
|
{
|
|
return mKey.Equals(*aKey);
|
|
}
|
|
|
|
static KeyTypePointer KeyToPointer(KeyType aKey)
|
|
{
|
|
return &aKey;
|
|
}
|
|
static PLDHashNumber HashKey(const KeyTypePointer aKey)
|
|
{
|
|
// Just use the 32-bit m0 field.
|
|
return aKey->m0;
|
|
}
|
|
|
|
enum { ALLOW_MEMMOVE = true };
|
|
|
|
private:
|
|
nsIID mKey;
|
|
};
|
|
nsInterfaceHashtable<IIDHashKey, nsIContent> mInterfaceTable; // A table of cached interfaces that we support.
|
|
|
|
int32_t mBaseNameSpaceID; // If we extend a tagname/namespace, then that information will
|
|
nsCOMPtr<nsIAtom> mBaseTag; // be stored in here.
|
|
|
|
nsCOMArray<nsXBLKeyEventHandler> mKeyHandlers;
|
|
};
|
|
|
|
#endif
|