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: /* michael@0: * Implementation of the |attributes| property of DOM Core's Element object. michael@0: */ michael@0: michael@0: #ifndef nsDOMAttributeMap_h michael@0: #define nsDOMAttributeMap_h michael@0: michael@0: #include "mozilla/MemoryReporting.h" michael@0: #include "mozilla/dom/Attr.h" michael@0: #include "mozilla/ErrorResult.h" michael@0: #include "nsCycleCollectionParticipant.h" michael@0: #include "nsIDOMMozNamedAttrMap.h" michael@0: #include "nsRefPtrHashtable.h" michael@0: #include "nsString.h" michael@0: #include "nsWrapperCache.h" michael@0: michael@0: class nsIAtom; michael@0: class nsINodeInfo; michael@0: class nsIDocument; michael@0: michael@0: /** michael@0: * Structure used as a key for caching Attrs in nsDOMAttributeMap's mAttributeCache. michael@0: */ michael@0: class nsAttrKey michael@0: { michael@0: public: michael@0: /** michael@0: * The namespace of the attribute michael@0: */ michael@0: int32_t mNamespaceID; michael@0: michael@0: /** michael@0: * The atom for attribute, weak ref. is fine as we only use it for the michael@0: * hashcode, we never dereference it. michael@0: */ michael@0: nsIAtom* mLocalName; michael@0: michael@0: nsAttrKey(int32_t aNs, nsIAtom* aName) michael@0: : mNamespaceID(aNs), mLocalName(aName) {} michael@0: michael@0: nsAttrKey(const nsAttrKey& aAttr) michael@0: : mNamespaceID(aAttr.mNamespaceID), mLocalName(aAttr.mLocalName) {} michael@0: }; michael@0: michael@0: /** michael@0: * PLDHashEntryHdr implementation for nsAttrKey. michael@0: */ michael@0: class nsAttrHashKey : public PLDHashEntryHdr michael@0: { michael@0: public: michael@0: typedef const nsAttrKey& KeyType; michael@0: typedef const nsAttrKey* KeyTypePointer; michael@0: michael@0: nsAttrHashKey(KeyTypePointer aKey) : mKey(*aKey) {} michael@0: nsAttrHashKey(const nsAttrHashKey& aCopy) : mKey(aCopy.mKey) {} michael@0: ~nsAttrHashKey() {} michael@0: michael@0: KeyType GetKey() const { return mKey; } michael@0: bool KeyEquals(KeyTypePointer aKey) const michael@0: { michael@0: return mKey.mLocalName == aKey->mLocalName && michael@0: mKey.mNamespaceID == aKey->mNamespaceID; michael@0: } michael@0: michael@0: static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; } michael@0: static PLDHashNumber HashKey(KeyTypePointer aKey) michael@0: { michael@0: if (!aKey) michael@0: return 0; michael@0: michael@0: return mozilla::HashGeneric(aKey->mNamespaceID, aKey->mLocalName); michael@0: } michael@0: enum { ALLOW_MEMMOVE = true }; michael@0: michael@0: private: michael@0: nsAttrKey mKey; michael@0: }; michael@0: michael@0: // Helper class that implements the nsIDOMMozNamedAttrMap interface. michael@0: class nsDOMAttributeMap : public nsIDOMMozNamedAttrMap michael@0: , public nsWrapperCache michael@0: { michael@0: public: michael@0: typedef mozilla::dom::Attr Attr; michael@0: typedef mozilla::dom::Element Element; michael@0: typedef mozilla::ErrorResult ErrorResult; michael@0: michael@0: nsDOMAttributeMap(Element *aContent); michael@0: virtual ~nsDOMAttributeMap(); michael@0: michael@0: NS_DECL_CYCLE_COLLECTING_ISUPPORTS michael@0: NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS(nsDOMAttributeMap) michael@0: michael@0: // nsIDOMMozNamedAttrMap interface michael@0: NS_DECL_NSIDOMMOZNAMEDATTRMAP michael@0: michael@0: void DropReference(); michael@0: michael@0: Element* GetContent() michael@0: { michael@0: return mContent; michael@0: } michael@0: michael@0: /** michael@0: * Called when mContent is moved into a new document. michael@0: * Updates the nodeinfos of all owned nodes. michael@0: */ michael@0: nsresult SetOwnerDocument(nsIDocument* aDocument); michael@0: michael@0: /** michael@0: * Drop an attribute from the map's cache (does not remove the attribute michael@0: * from the node!) michael@0: */ michael@0: void DropAttribute(int32_t aNamespaceID, nsIAtom* aLocalName); michael@0: michael@0: /** michael@0: * Returns the number of attribute nodes currently in the map. michael@0: * Note: this is just the number of cached attribute nodes, not the number of michael@0: * attributes in mContent. michael@0: * michael@0: * @return The number of attribute nodes in the map. michael@0: */ michael@0: uint32_t Count() const; michael@0: michael@0: typedef nsRefPtrHashtable AttrCache; michael@0: michael@0: /** michael@0: * Enumerates over the attribute nodess in the map and calls aFunc for each michael@0: * one. If aFunc returns PL_DHASH_STOP we'll stop enumerating at that point. michael@0: * michael@0: * @return The number of attribute nodes that aFunc was called for. michael@0: */ michael@0: uint32_t Enumerate(AttrCache::EnumReadFunction aFunc, void *aUserArg) const; michael@0: michael@0: Element* GetParentObject() const michael@0: { michael@0: return mContent; michael@0: } michael@0: virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE; michael@0: michael@0: // WebIDL michael@0: Attr* GetNamedItem(const nsAString& aAttrName); michael@0: Attr* NamedGetter(const nsAString& aAttrName, bool& aFound); michael@0: bool NameIsEnumerable(const nsAString& aName); michael@0: already_AddRefed michael@0: SetNamedItem(Attr& aAttr, ErrorResult& aError) michael@0: { michael@0: return SetNamedItemInternal(aAttr, false, aError); michael@0: } michael@0: already_AddRefed michael@0: RemoveNamedItem(const nsAString& aName, ErrorResult& aError); michael@0: michael@0: Attr* Item(uint32_t aIndex); michael@0: Attr* IndexedGetter(uint32_t aIndex, bool& aFound); michael@0: uint32_t Length() const; michael@0: michael@0: Attr* michael@0: GetNamedItemNS(const nsAString& aNamespaceURI, michael@0: const nsAString& aLocalName); michael@0: already_AddRefed michael@0: SetNamedItemNS(Attr& aNode, ErrorResult& aError) michael@0: { michael@0: return SetNamedItemInternal(aNode, true, aError); michael@0: } michael@0: already_AddRefed michael@0: RemoveNamedItemNS(const nsAString& aNamespaceURI, const nsAString& aLocalName, michael@0: ErrorResult& aError); michael@0: michael@0: void GetSupportedNames(unsigned, nsTArray& aNames) michael@0: { michael@0: // No supported names we want to show up in iteration. michael@0: } michael@0: michael@0: size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; michael@0: michael@0: private: michael@0: nsCOMPtr mContent; michael@0: michael@0: /** michael@0: * Cache of Attrs. michael@0: */ michael@0: AttrCache mAttributeCache; michael@0: michael@0: /** michael@0: * SetNamedItem() (aWithNS = false) and SetNamedItemNS() (aWithNS = michael@0: * true) implementation. michael@0: */ michael@0: already_AddRefed michael@0: SetNamedItemInternal(Attr& aNode, bool aWithNS, ErrorResult& aError); michael@0: michael@0: already_AddRefed michael@0: GetAttrNodeInfo(const nsAString& aNamespaceURI, michael@0: const nsAString& aLocalName); michael@0: michael@0: Attr* GetAttribute(nsINodeInfo* aNodeInfo, bool aNsAware); michael@0: michael@0: /** michael@0: * Remove an attribute, returns the removed node. michael@0: */ michael@0: already_AddRefed RemoveAttribute(nsINodeInfo* aNodeInfo); michael@0: }; michael@0: michael@0: // XXX khuey yes this is crazy. The bindings code needs to see this include, michael@0: // but if we pull it in at the top of the file we get a circular include michael@0: // problem. michael@0: #include "mozilla/dom/Element.h" michael@0: michael@0: #endif /* nsDOMAttributeMap_h */