Bug 1852740: add tests for the `fetchpriority` attribute in Link headers. r=necko...
[gecko.git] / dom / base / AttrArray.h
blob9331ac232626bc22c60c22a26b146fd94c4ebb02
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 /*
8 * Storage of the attributes of a DOM node.
9 */
11 #ifndef AttrArray_h___
12 #define AttrArray_h___
14 #include "mozilla/Attributes.h"
15 #include "mozilla/MemoryReporting.h"
16 #include "mozilla/UniquePtr.h"
17 #include "mozilla/Span.h"
18 #include "mozilla/dom/BorrowedAttrInfo.h"
20 #include "nscore.h"
21 #include "nsAttrName.h"
22 #include "nsAttrValue.h"
23 #include "nsCaseTreatment.h"
25 namespace mozilla {
26 class AttributeStyles;
27 struct StyleLockedDeclarationBlock;
28 } // namespace mozilla
30 class AttrArray {
31 using BorrowedAttrInfo = mozilla::dom::BorrowedAttrInfo;
33 public:
34 AttrArray() = default;
35 ~AttrArray() = default;
37 bool HasAttrs() const { return !!AttrCount(); }
39 uint32_t AttrCount() const { return mImpl ? mImpl->mAttrCount : 0; }
41 const nsAttrValue* GetAttr(const nsAtom* aLocalName) const;
43 const nsAttrValue* GetAttr(const nsAtom* aLocalName,
44 int32_t aNamespaceID) const;
45 // As above but using a string attr name and always using
46 // kNameSpaceID_None. This is always case-sensitive.
47 const nsAttrValue* GetAttr(const nsAString& aName) const;
48 // Get an nsAttrValue by qualified name. Can optionally do
49 // ASCII-case-insensitive name matching.
50 const nsAttrValue* GetAttr(const nsAString& aName,
51 nsCaseTreatment aCaseSensitive) const;
52 const nsAttrValue* AttrAt(uint32_t aPos) const;
53 // SetAndSwapAttr swaps the current attribute value with aValue.
54 // If the attribute was unset, an empty value will be swapped into aValue
55 // and aHadValue will be set to false. Otherwise, aHadValue will be set to
56 // true.
57 nsresult SetAndSwapAttr(nsAtom* aLocalName, nsAttrValue& aValue,
58 bool* aHadValue);
59 nsresult SetAndSwapAttr(mozilla::dom::NodeInfo* aName, nsAttrValue& aValue,
60 bool* aHadValue);
62 // This stores the argument and clears the pending mapped attribute evaluation
63 // bit, so after calling this IsPendingMappedAttributeEvaluation() is
64 // guaranteed to return false.
65 void SetMappedDeclarationBlock(
66 already_AddRefed<mozilla::StyleLockedDeclarationBlock>);
68 bool IsPendingMappedAttributeEvaluation() const {
69 return mImpl && mImpl->mMappedAttributeBits & 1;
72 mozilla::StyleLockedDeclarationBlock* GetMappedDeclarationBlock() const {
73 return mImpl ? mImpl->GetMappedDeclarationBlock() : nullptr;
76 // Remove the attr at position aPos. The value of the attr is placed in
77 // aValue; any value that was already in aValue is destroyed.
78 nsresult RemoveAttrAt(uint32_t aPos, nsAttrValue& aValue);
80 // Returns attribute name at given position, *not* out-of-bounds safe
81 const nsAttrName* AttrNameAt(uint32_t aPos) const;
83 // Returns the attribute info at a given position, *not* out-of-bounds safe
84 BorrowedAttrInfo AttrInfoAt(uint32_t aPos) const;
86 // Returns attribute name at given position or null if aPos is out-of-bounds
87 const nsAttrName* GetSafeAttrNameAt(uint32_t aPos) const;
89 const nsAttrName* GetExistingAttrNameFromQName(const nsAString& aName) const;
90 int32_t IndexOfAttr(const nsAtom* aLocalName) const;
91 int32_t IndexOfAttr(const nsAtom* aLocalName, int32_t aNamespaceID) const;
93 void Compact();
95 size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
97 // Mark the element as pending mapped attribute evaluation. This should be
98 // called when a mapped attribute is changed (regardless of connectedness).
99 bool MarkAsPendingPresAttributeEvaluation() {
100 // It'd be great to be able to assert that mImpl is non-null or we're the
101 // <body> element.
102 if (MOZ_UNLIKELY(!mImpl) && !GrowBy(1)) {
103 return false;
105 InfallibleMarkAsPendingPresAttributeEvaluation();
106 return true;
109 // See above.
110 void InfallibleMarkAsPendingPresAttributeEvaluation() {
111 MOZ_ASSERT(mImpl);
112 mImpl->mMappedAttributeBits |= 1;
115 // Clear the servo declaration block on the mapped attributes, if any
116 // Will assert off main thread
117 void ClearMappedServoStyle();
119 // Increases capacity (if necessary) to have enough space to accomodate the
120 // unmapped attributes of |aOther|.
121 nsresult EnsureCapacityToClone(const AttrArray& aOther);
123 enum AttrValuesState { ATTR_MISSING = -1, ATTR_VALUE_NO_MATCH = -2 };
124 using AttrValuesArray = nsStaticAtom* const;
125 int32_t FindAttrValueIn(int32_t aNameSpaceID, const nsAtom* aName,
126 AttrValuesArray* aValues,
127 nsCaseTreatment aCaseSensitive) const;
129 inline bool GetAttr(int32_t aNameSpaceID, const nsAtom* aName,
130 nsAString& aResult) const {
131 MOZ_ASSERT(aResult.IsEmpty(), "Should have empty string coming in");
132 const nsAttrValue* val = GetAttr(aName, aNameSpaceID);
133 if (!val) {
134 return false;
136 val->ToString(aResult);
137 return true;
140 inline bool GetAttr(const nsAtom* aName, nsAString& aResult) const {
141 MOZ_ASSERT(aResult.IsEmpty(), "Should have empty string coming in");
142 const nsAttrValue* val = GetAttr(aName);
143 if (!val) {
144 return false;
146 val->ToString(aResult);
147 return true;
150 inline bool HasAttr(const nsAtom* aName) const { return !!GetAttr(aName); }
152 inline bool HasAttr(int32_t aNameSpaceID, const nsAtom* aName) const {
153 return !!GetAttr(aName, aNameSpaceID);
156 inline bool AttrValueIs(int32_t aNameSpaceID, const nsAtom* aName,
157 const nsAString& aValue,
158 nsCaseTreatment aCaseSensitive) const {
159 NS_ASSERTION(aName, "Must have attr name");
160 NS_ASSERTION(aNameSpaceID != kNameSpaceID_Unknown, "Must have namespace");
161 const nsAttrValue* val = GetAttr(aName, aNameSpaceID);
162 return val && val->Equals(aValue, aCaseSensitive);
165 inline bool AttrValueIs(int32_t aNameSpaceID, const nsAtom* aName,
166 const nsAtom* aValue,
167 nsCaseTreatment aCaseSensitive) const {
168 NS_ASSERTION(aName, "Must have attr name");
169 NS_ASSERTION(aNameSpaceID != kNameSpaceID_Unknown, "Must have namespace");
170 NS_ASSERTION(aValue, "Null value atom");
172 const nsAttrValue* val = GetAttr(aName, aNameSpaceID);
173 return val && val->Equals(aValue, aCaseSensitive);
176 struct InternalAttr {
177 nsAttrName mName;
178 nsAttrValue mValue;
181 AttrArray(const AttrArray& aOther) = delete;
182 AttrArray& operator=(const AttrArray& aOther) = delete;
184 bool GrowBy(uint32_t aGrowSize);
185 bool GrowTo(uint32_t aCapacity);
187 private:
188 // Tries to create an attribute, growing the buffer if needed, with the given
189 // name and value.
191 // The value is moved from the argument.
193 // `Name` can be anything you construct a `nsAttrName` with (either an atom or
194 // a NodeInfo pointer).
195 template <typename Name>
196 nsresult AddNewAttribute(Name*, nsAttrValue&);
198 class Impl {
199 public:
200 constexpr static size_t AllocationSizeForAttributes(uint32_t aAttrCount) {
201 return sizeof(Impl) + aAttrCount * sizeof(InternalAttr);
204 mozilla::StyleLockedDeclarationBlock* GetMappedDeclarationBlock() const {
205 return reinterpret_cast<mozilla::StyleLockedDeclarationBlock*>(
206 mMappedAttributeBits & ~uintptr_t(1));
209 auto Attrs() const {
210 return mozilla::Span<const InternalAttr>{mBuffer, mAttrCount};
213 auto Attrs() { return mozilla::Span<InternalAttr>{mBuffer, mAttrCount}; }
215 Impl(const Impl&) = delete;
216 Impl(Impl&&) = delete;
217 ~Impl();
219 uint32_t mAttrCount;
220 uint32_t mCapacity; // In number of InternalAttrs
222 // mMappedAttributeBits is a tagged pointer of a
223 // StyleLockedDeclarationBlock, which holds the style information that our
224 // attributes map to.
226 // If the lower bit is set, then our mapped attributes are dirty. This just
227 // means that we might have mapped attributes (or used to and no longer
228 // have), and are pending an update to recompute our declaration.
229 uintptr_t mMappedAttributeBits = 0;
231 // Allocated in the same buffer as `Impl`.
232 InternalAttr mBuffer[0];
235 mozilla::Span<InternalAttr> Attrs() {
236 return mImpl ? mImpl->Attrs() : mozilla::Span<InternalAttr>();
239 mozilla::Span<const InternalAttr> Attrs() const {
240 return mImpl ? mImpl->Attrs() : mozilla::Span<const InternalAttr>();
243 mozilla::UniquePtr<Impl> mImpl;
246 #endif