зеркало из https://github.com/mozilla/gecko-dev.git
374 строки
14 KiB
C++
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
|