gecko-dev/dom/xbl/nsXBLPrototypeBinding.h

374 строки
14 KiB
C++

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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 "nsAutoPtr.h"
#include "nsClassHashtable.h"
#include "nsCOMArray.h"
#include "nsCOMPtr.h"
#include "nsICSSLoaderObserver.h"
#include "nsInterfaceHashtable.h"
#include "nsXBLDocumentInfo.h"
#include "nsXBLProtoImpl.h"
#include "nsXBLProtoImplMethod.h"
#include "nsXBLPrototypeHandler.h"
#include "nsXBLPrototypeResources.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/WeakPtr.h"
#include "mozilla/StyleSheet.h"
class nsAtom;
class nsIContent;
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 final
: public mozilla::SupportsWeakPtr<nsXBLPrototypeBinding> {
public:
MOZ_DECLARE_WEAKREFERENCE_TYPENAME(nsXBLPrototypeBinding)
mozilla::dom::Element* GetBindingElement() const { return mBinding; }
void SetBindingElement(mozilla::dom::Element* 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);
// aBoundElement is passed in here because we need to get owner document
// and PresContext in nsXBLResourceLoader::LoadResources().
bool LoadResources(nsIContent* aBoundElement);
nsresult AddResource(nsAtom* 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 nsString& ClassName() const {
return mImplementation ? mImplementation->mClassName : EmptyString();
}
nsresult InitClass(const nsString& 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(nsAtom* aAttribute, int32_t aNameSpaceID,
bool aRemoveFlag,
mozilla::dom::Element* 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(mozilla::dom::Element* aBoundElement,
nsIContent* aAnonymousContent);
void AppendStyleSheet(mozilla::StyleSheet* aSheet);
void RemoveStyleSheet(mozilla::StyleSheet* aSheet);
void InsertStyleSheetAt(size_t aIndex, mozilla::StyleSheet* aSheet);
mozilla::StyleSheet* StyleSheetAt(size_t aIndex) const;
size_t SheetCount() const;
bool HasStyleSheets() const;
void AppendStyleSheetsTo(nsTArray<mozilla::StyleSheet*>& aResult) const;
const RawServoAuthorStyles* GetServoStyles() const {
return mResources ? mResources->GetServoStyles() : nullptr;
}
void SyncServoStyles() {
MOZ_ASSERT(mResources);
mResources->SyncServoStyles();
}
RawServoAuthorStyles* GetServoStyles() {
return mResources
? const_cast<RawServoAuthorStyles*>(mResources->GetServoStyles())
: nullptr;
}
mozilla::ServoStyleRuleMap* GetServoStyleRuleMap() {
return mResources ? mResources->GetServoStyleRuleMap() : nullptr;
}
nsresult FlushSkinSheets();
nsAtom* GetBaseTag(int32_t* aNamespaceID);
void SetBaseTag(int32_t aNamespaceID, nsAtom* 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,
mozilla::dom::Document* 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.
* XBLBinding_Serialize_BindToUntrustedContent indicates that
* nsXBLPrototypeBinding::mBindToUntrustedContent should be true.
*/
public:
static nsresult ReadNewBinding(nsIObjectInputStream* aStream,
nsXBLDocumentInfo* aDocInfo,
mozilla::dom::Document* 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,
mozilla::dom::Document* 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,
mozilla::dom::Element* aElement, bool aFirstBinding = false);
void Traverse(nsCycleCollectionTraversalCallback& cb) const;
void Unlink();
void Trace(const TraceCallbacks& aCallbacks, void* aClosure) const;
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) 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.
*/
mozilla::dom::Element* GetImmediateChild(nsAtom* aTag);
mozilla::dom::Element* LocateInstance(mozilla::dom::Element* aBoundElt,
nsIContent* aTemplRoot,
nsIContent* aCopyRoot,
mozilla::dom::Element* aTemplChild);
bool ChromeOnlyContent() const { return mChromeOnlyContent; }
bool SimpleScopeChain() const { return mSimpleScopeChain; }
bool BindToUntrustedContent() const { return mBindToUntrustedContent; }
typedef nsClassHashtable<nsRefPtrHashKey<nsAtom>, nsXBLAttributeEntry>
InnerAttributeTable;
protected:
// Ensure that mAttributeTable has been created.
void EnsureAttributeTable();
// Ad an entry to the attribute table
void AddToAttributeTable(int32_t aSourceNamespaceID, nsAtom* aSourceTag,
int32_t aDestNamespaceID, nsAtom* aDestTag,
mozilla::dom::Element* aContent);
void ConstructAttributeTable(mozilla::dom::Element* aElement);
void CreateKeyHandlers();
private:
void EnsureResources();
// MEMBER VARIABLES
protected:
nsCOMPtr<nsIURI> mBindingURI;
nsCOMPtr<nsIURI> mAlternateBindingURI; // Alternate id-less URI that is only
// non-null on the first binding.
RefPtr<mozilla::dom::Element>
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).
// Weak. The docinfo will own our base binding.
mozilla::WeakPtr<nsXBLPrototypeBinding> mBaseBinding;
bool mInheritStyle;
bool mCheckedBaseProto;
bool mKeyHandlersRegistered;
bool mChromeOnlyContent;
bool mBindToUntrustedContent;
// True if constructors, handlers, etc for this binding would skip the scope
// chain for parent elements and go directly to the document.
bool mSimpleScopeChain;
nsAutoPtr<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;
explicit 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
RefPtr<nsAtom> mBaseTag; // be stored in here.
nsCOMArray<nsXBLKeyEventHandler> mKeyHandlers;
};
#endif