diff options
Diffstat (limited to '')
-rw-r--r-- | dom/base/AttrArray.h | 261 |
1 files changed, 261 insertions, 0 deletions
diff --git a/dom/base/AttrArray.h b/dom/base/AttrArray.h new file mode 100644 index 0000000000..47e91793ce --- /dev/null +++ b/dom/base/AttrArray.h @@ -0,0 +1,261 @@ +/* -*- 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/. */ + +/* + * Storage of the attributes of a DOM node. + */ + +#ifndef AttrArray_h___ +#define AttrArray_h___ + +#include "mozilla/Attributes.h" +#include "mozilla/MemoryReporting.h" +#include "mozilla/UniquePtr.h" +#include "mozilla/Span.h" +#include "mozilla/dom/BorrowedAttrInfo.h" + +#include "nscore.h" +#include "nsAttrName.h" +#include "nsAttrValue.h" +#include "nsCaseTreatment.h" + +class nsINode; +class nsIContent; +class nsMappedAttributes; +class nsHTMLStyleSheet; +class nsRuleWalker; +class nsMappedAttributeElement; + +class AttrArray { + using BorrowedAttrInfo = mozilla::dom::BorrowedAttrInfo; + + public: + AttrArray() = default; + ~AttrArray() = default; + + bool HasAttrs() const { return NonMappedAttrCount() || MappedAttrCount(); } + + uint32_t AttrCount() const { + return NonMappedAttrCount() + MappedAttrCount(); + } + + const nsAttrValue* GetAttr(const nsAtom* aLocalName, + int32_t aNamespaceID = kNameSpaceID_None) const; + // As above but using a string attr name and always using + // kNameSpaceID_None. This is always case-sensitive. + const nsAttrValue* GetAttr(const nsAString& aName) const; + // Get an nsAttrValue by qualified name. Can optionally do + // ASCII-case-insensitive name matching. + const nsAttrValue* GetAttr(const nsAString& aName, + nsCaseTreatment aCaseSensitive) const; + const nsAttrValue* AttrAt(uint32_t aPos) const; + // SetAndSwapAttr swaps the current attribute value with aValue. + // If the attribute was unset, an empty value will be swapped into aValue + // and aHadValue will be set to false. Otherwise, aHadValue will be set to + // true. + nsresult SetAndSwapAttr(nsAtom* aLocalName, nsAttrValue& aValue, + bool* aHadValue); + nsresult SetAndSwapAttr(mozilla::dom::NodeInfo* aName, nsAttrValue& aValue, + bool* aHadValue); + + // Remove the attr at position aPos. The value of the attr is placed in + // aValue; any value that was already in aValue is destroyed. + nsresult RemoveAttrAt(uint32_t aPos, nsAttrValue& aValue); + + // Returns attribute name at given position, *not* out-of-bounds safe + const nsAttrName* AttrNameAt(uint32_t aPos) const; + + // Returns the attribute info at a given position, *not* out-of-bounds safe + BorrowedAttrInfo AttrInfoAt(uint32_t aPos) const; + + // Returns attribute name at given position or null if aPos is out-of-bounds + const nsAttrName* GetSafeAttrNameAt(uint32_t aPos) const; + + const nsAttrName* GetExistingAttrNameFromQName(const nsAString& aName) const; + int32_t IndexOfAttr(const nsAtom* aLocalName, + int32_t aNamespaceID = kNameSpaceID_None) const; + + // SetAndSwapMappedAttr swaps the current attribute value with aValue. + // If the attribute was unset, an empty value will be swapped into aValue + // and aHadValue will be set to false. Otherwise, aHadValue will be set to + // true. + nsresult SetAndSwapMappedAttr(nsAtom* aLocalName, nsAttrValue& aValue, + nsMappedAttributeElement* aContent, + nsHTMLStyleSheet* aSheet, bool* aHadValue); + nsresult SetMappedAttrStyleSheet(nsHTMLStyleSheet* aSheet) { + if (!mImpl || !mImpl->mMappedAttrs) { + return NS_OK; + } + return DoSetMappedAttrStyleSheet(aSheet); + } + + // Update the rule mapping function on our mapped attributes, if we have any. + // We take a nsMappedAttributeElement, not a nsMapRuleToAttributesFunc, + // because the latter is defined in a header we can't include here. + nsresult UpdateMappedAttrRuleMapper(nsMappedAttributeElement& aElement) { + if (!mImpl || !mImpl->mMappedAttrs) { + return NS_OK; + } + return DoUpdateMappedAttrRuleMapper(aElement); + } + + void Compact(); + + size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; + bool HasMappedAttrs() const { return MappedAttrCount(); } + const nsMappedAttributes* GetMapped() const; + + // Force this to have mapped attributes, even if those attributes are empty. + nsresult ForceMapped(nsMappedAttributeElement* aContent, + mozilla::dom::Document* aDocument); + + // Clear the servo declaration block on the mapped attributes, if any + // Will assert off main thread + void ClearMappedServoStyle(); + + // Increases capacity (if necessary) to have enough space to accomodate the + // unmapped attributes of |aOther|. + nsresult EnsureCapacityToClone(const AttrArray& aOther); + + enum AttrValuesState { ATTR_MISSING = -1, ATTR_VALUE_NO_MATCH = -2 }; + using AttrValuesArray = nsStaticAtom* const; + int32_t FindAttrValueIn(int32_t aNameSpaceID, const nsAtom* aName, + AttrValuesArray* aValues, + nsCaseTreatment aCaseSensitive) const; + + inline bool GetAttr(int32_t aNameSpaceID, const nsAtom* aName, + nsAString& aResult) const { + MOZ_ASSERT(aResult.IsEmpty(), "Should have empty string coming in"); + + const nsAttrValue* val = GetAttr(aName, aNameSpaceID); + if (val) { + val->ToString(aResult); + return true; + } + return false; + } + + inline bool HasAttr(int32_t aNameSpaceID, const nsAtom* aName) const { + return GetAttr(aName, aNameSpaceID) != nullptr; + } + + inline bool AttrValueIs(int32_t aNameSpaceID, const nsAtom* aName, + const nsAString& aValue, + nsCaseTreatment aCaseSensitive) const { + NS_ASSERTION(aName, "Must have attr name"); + NS_ASSERTION(aNameSpaceID != kNameSpaceID_Unknown, "Must have namespace"); + + const nsAttrValue* val = GetAttr(aName, aNameSpaceID); + return val && val->Equals(aValue, aCaseSensitive); + } + + inline bool AttrValueIs(int32_t aNameSpaceID, const nsAtom* aName, + const nsAtom* aValue, + nsCaseTreatment aCaseSensitive) const { + NS_ASSERTION(aName, "Must have attr name"); + NS_ASSERTION(aNameSpaceID != kNameSpaceID_Unknown, "Must have namespace"); + NS_ASSERTION(aValue, "Null value atom"); + + const nsAttrValue* val = GetAttr(aName, aNameSpaceID); + return val && val->Equals(aValue, aCaseSensitive); + } + + struct InternalAttr { + nsAttrName mName; + nsAttrValue mValue; + }; + + private: + AttrArray(const AttrArray& aOther) = delete; + AttrArray& operator=(const AttrArray& aOther) = delete; + + uint32_t NonMappedAttrCount() const { return mImpl ? mImpl->mAttrCount : 0; } + + uint32_t MappedAttrCount() const { + return mImpl && mImpl->mMappedAttrs ? DoGetMappedAttrCount() : 0; + } + + uint32_t DoGetMappedAttrCount() const; + + // Returns a non-null zero-refcount object. + nsMappedAttributes* GetModifiableMapped(nsMappedAttributeElement* aContent, + nsHTMLStyleSheet* aSheet, + bool aWillAddAttr, + int32_t aAttrCount = 1); + nsresult MakeMappedUnique(nsMappedAttributes* aAttributes); + + bool GrowBy(uint32_t aGrowSize); + + // Tries to create an attribute, growing the buffer if needed, with the given + // name and value. + // + // The value is moved from the argument. + // + // `Name` can be anything you construct a `nsAttrName` with (either an atom or + // a NodeInfo pointer). + template <typename Name> + nsresult AddNewAttribute(Name*, nsAttrValue&); + + /** + * Guts of SetMappedAttrStyleSheet for the rare case when we have mapped attrs + */ + nsresult DoSetMappedAttrStyleSheet(nsHTMLStyleSheet* aSheet); + + /** + * Guts of UpdateMappedAttrRuleMapper for the case when we have mapped attrs. + */ + nsresult DoUpdateMappedAttrRuleMapper(nsMappedAttributeElement& aElement); + +#ifdef _MSC_VER +// Disable MSVC warning 'nonstandard extension used: zero-sized array in +// struct/union' +# pragma warning(push) +# pragma warning(disable : 4200) +#endif + class Impl { + public: + constexpr static size_t AllocationSizeForAttributes(uint32_t aAttrCount) { + return sizeof(Impl) + aAttrCount * sizeof(InternalAttr); + } + + auto NonMappedAttrs() const { + return mozilla::Span<const InternalAttr>{mBuffer, mAttrCount}; + } + + auto NonMappedAttrs() { + return mozilla::Span<InternalAttr>{mBuffer, mAttrCount}; + } + + Impl(const Impl&) = delete; + Impl(Impl&&) = delete; + ~Impl(); + + uint32_t mAttrCount; + uint32_t mCapacity; // In number of InternalAttrs + + // Manually refcounted. + nsMappedAttributes* mMappedAttrs; + + // Allocated in the same buffer as `Impl`. + InternalAttr mBuffer[0]; + }; +#ifdef _MSC_VER +# pragma warning(pop) +#endif + + mozilla::Span<InternalAttr> NonMappedAttrs() { + return mImpl ? mImpl->NonMappedAttrs() : mozilla::Span<InternalAttr>(); + } + + mozilla::Span<const InternalAttr> NonMappedAttrs() const { + return mImpl ? mImpl->NonMappedAttrs() + : mozilla::Span<const InternalAttr>(); + } + + mozilla::UniquePtr<Impl> mImpl; +}; + +#endif |