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: * Class that represents the name (nodeinfo or atom) of an attribute; michael@0: * using nodeinfos all the time is too slow, so we use atoms when we michael@0: * can. michael@0: */ michael@0: michael@0: #ifndef nsAttrName_h___ michael@0: #define nsAttrName_h___ michael@0: michael@0: #include "nsINodeInfo.h" michael@0: #include "nsIAtom.h" michael@0: #include "nsDOMString.h" michael@0: michael@0: #define NS_ATTRNAME_NODEINFO_BIT 1 michael@0: class nsAttrName michael@0: { michael@0: public: michael@0: nsAttrName(const nsAttrName& aOther) michael@0: : mBits(aOther.mBits) michael@0: { michael@0: AddRefInternalName(); michael@0: } michael@0: michael@0: explicit nsAttrName(nsIAtom* aAtom) michael@0: : mBits(reinterpret_cast(aAtom)) michael@0: { michael@0: NS_ASSERTION(aAtom, "null atom-name in nsAttrName"); michael@0: NS_ADDREF(aAtom); michael@0: } michael@0: michael@0: explicit nsAttrName(nsINodeInfo* aNodeInfo) michael@0: { michael@0: NS_ASSERTION(aNodeInfo, "null nodeinfo-name in nsAttrName"); michael@0: if (aNodeInfo->NamespaceEquals(kNameSpaceID_None)) { michael@0: mBits = reinterpret_cast(aNodeInfo->NameAtom()); michael@0: NS_ADDREF(aNodeInfo->NameAtom()); michael@0: } michael@0: else { michael@0: mBits = reinterpret_cast(aNodeInfo) | michael@0: NS_ATTRNAME_NODEINFO_BIT; michael@0: NS_ADDREF(aNodeInfo); michael@0: } michael@0: } michael@0: michael@0: ~nsAttrName() michael@0: { michael@0: ReleaseInternalName(); michael@0: } michael@0: michael@0: void SetTo(nsINodeInfo* aNodeInfo) michael@0: { michael@0: NS_ASSERTION(aNodeInfo, "null nodeinfo-name in nsAttrName"); michael@0: michael@0: ReleaseInternalName(); michael@0: if (aNodeInfo->NamespaceEquals(kNameSpaceID_None)) { michael@0: mBits = reinterpret_cast(aNodeInfo->NameAtom()); michael@0: NS_ADDREF(aNodeInfo->NameAtom()); michael@0: } michael@0: else { michael@0: mBits = reinterpret_cast(aNodeInfo) | michael@0: NS_ATTRNAME_NODEINFO_BIT; michael@0: NS_ADDREF(aNodeInfo); michael@0: } michael@0: } michael@0: michael@0: void SetTo(nsIAtom* aAtom) michael@0: { michael@0: NS_ASSERTION(aAtom, "null atom-name in nsAttrName"); michael@0: michael@0: ReleaseInternalName(); michael@0: mBits = reinterpret_cast(aAtom); michael@0: NS_ADDREF(aAtom); michael@0: } michael@0: michael@0: bool IsAtom() const michael@0: { michael@0: return !(mBits & NS_ATTRNAME_NODEINFO_BIT); michael@0: } michael@0: michael@0: nsINodeInfo* NodeInfo() const michael@0: { michael@0: NS_ASSERTION(!IsAtom(), "getting nodeinfo-value of atom-name"); michael@0: return reinterpret_cast(mBits & ~NS_ATTRNAME_NODEINFO_BIT); michael@0: } michael@0: michael@0: nsIAtom* Atom() const michael@0: { michael@0: NS_ASSERTION(IsAtom(), "getting atom-value of nodeinfo-name"); michael@0: return reinterpret_cast(mBits); michael@0: } michael@0: michael@0: bool Equals(const nsAttrName& aOther) const michael@0: { michael@0: return mBits == aOther.mBits; michael@0: } michael@0: michael@0: // Faster comparison in the case we know the namespace is null michael@0: bool Equals(nsIAtom* aAtom) const michael@0: { michael@0: return reinterpret_cast(aAtom) == mBits; michael@0: } michael@0: michael@0: // And the same but without forcing callers to atomize michael@0: bool Equals(const nsAString& aLocalName) const michael@0: { michael@0: return IsAtom() && Atom()->Equals(aLocalName); michael@0: } michael@0: michael@0: bool Equals(nsIAtom* aLocalName, int32_t aNamespaceID) const michael@0: { michael@0: if (aNamespaceID == kNameSpaceID_None) { michael@0: return Equals(aLocalName); michael@0: } michael@0: return !IsAtom() && NodeInfo()->Equals(aLocalName, aNamespaceID); michael@0: } michael@0: michael@0: bool Equals(nsINodeInfo* aNodeInfo) const michael@0: { michael@0: return Equals(aNodeInfo->NameAtom(), aNodeInfo->NamespaceID()); michael@0: } michael@0: michael@0: int32_t NamespaceID() const michael@0: { michael@0: return IsAtom() ? kNameSpaceID_None : NodeInfo()->NamespaceID(); michael@0: } michael@0: michael@0: int32_t NamespaceEquals(int32_t aNamespaceID) const michael@0: { michael@0: return aNamespaceID == kNameSpaceID_None ? michael@0: IsAtom() : michael@0: (!IsAtom() && NodeInfo()->NamespaceEquals(aNamespaceID)); michael@0: } michael@0: michael@0: nsIAtom* LocalName() const michael@0: { michael@0: return IsAtom() ? Atom() : NodeInfo()->NameAtom(); michael@0: } michael@0: michael@0: nsIAtom* GetPrefix() const michael@0: { michael@0: return IsAtom() ? nullptr : NodeInfo()->GetPrefixAtom(); michael@0: } michael@0: michael@0: bool QualifiedNameEquals(const nsAString& aName) const michael@0: { michael@0: return IsAtom() ? Atom()->Equals(aName) : michael@0: NodeInfo()->QualifiedNameEquals(aName); michael@0: } michael@0: michael@0: void GetQualifiedName(nsAString& aStr) const michael@0: { michael@0: if (IsAtom()) { michael@0: Atom()->ToString(aStr); michael@0: } michael@0: else { michael@0: aStr = NodeInfo()->QualifiedName(); michael@0: } michael@0: } michael@0: michael@0: #ifdef MOZILLA_INTERNAL_API michael@0: void GetPrefix(nsAString& aStr) const michael@0: { michael@0: if (IsAtom()) { michael@0: SetDOMStringToNull(aStr); michael@0: } michael@0: else { michael@0: NodeInfo()->GetPrefix(aStr); michael@0: } michael@0: } michael@0: #endif michael@0: michael@0: uint32_t HashValue() const michael@0: { michael@0: // mBits and uint32_t might have different size. This should silence michael@0: // any warnings or compile-errors. This is what the implementation of michael@0: // NS_PTR_TO_INT32 does to take care of the same problem. michael@0: return mBits - 0; michael@0: } michael@0: michael@0: bool IsSmaller(nsIAtom* aOther) const michael@0: { michael@0: return mBits < reinterpret_cast(aOther); michael@0: } michael@0: michael@0: private: michael@0: michael@0: void AddRefInternalName() michael@0: { michael@0: // Since both nsINodeInfo and nsIAtom inherit nsISupports as its first michael@0: // interface we can safely assume that it's first in the vtable michael@0: nsISupports* name = reinterpret_cast michael@0: (mBits & ~NS_ATTRNAME_NODEINFO_BIT); michael@0: michael@0: NS_ADDREF(name); michael@0: } michael@0: michael@0: void ReleaseInternalName() michael@0: { michael@0: // Since both nsINodeInfo and nsIAtom inherit nsISupports as its first michael@0: // interface we can safely assume that it's first in the vtable michael@0: nsISupports* name = reinterpret_cast michael@0: (mBits & ~NS_ATTRNAME_NODEINFO_BIT); michael@0: michael@0: NS_RELEASE(name); michael@0: } michael@0: michael@0: uintptr_t mBits; michael@0: }; michael@0: michael@0: #endif