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