Line data Source code
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/. */
6 :
7 : /*
8 : * Storage of the children and attributes of a DOM node; storage for
9 : * the two is unified to minimize footprint.
10 : */
11 :
12 : #ifndef nsAttrAndChildArray_h___
13 : #define nsAttrAndChildArray_h___
14 :
15 : #include "mozilla/Attributes.h"
16 : #include "mozilla/MemoryReporting.h"
17 : #include "mozilla/dom/BorrowedAttrInfo.h"
18 :
19 : #include "nscore.h"
20 : #include "nsAttrName.h"
21 : #include "nsAttrValue.h"
22 : #include "nsCaseTreatment.h"
23 :
24 : class nsINode;
25 : class nsIContent;
26 : class nsMappedAttributes;
27 : class nsHTMLStyleSheet;
28 : class nsRuleWalker;
29 : class nsMappedAttributeElement;
30 :
31 : #define ATTRCHILD_ARRAY_GROWSIZE 8
32 : #define ATTRCHILD_ARRAY_LINEAR_THRESHOLD 32
33 :
34 : #define ATTRCHILD_ARRAY_ATTR_SLOTS_BITS 10
35 :
36 : #define ATTRCHILD_ARRAY_MAX_ATTR_COUNT \
37 : ((1 << ATTRCHILD_ARRAY_ATTR_SLOTS_BITS) - 1)
38 :
39 : #define ATTRCHILD_ARRAY_MAX_CHILD_COUNT \
40 : (~uint32_t(0) >> ATTRCHILD_ARRAY_ATTR_SLOTS_BITS)
41 :
42 : #define ATTRCHILD_ARRAY_ATTR_SLOTS_COUNT_MASK \
43 : ((1 << ATTRCHILD_ARRAY_ATTR_SLOTS_BITS) - 1)
44 :
45 :
46 : #define ATTRSIZE (sizeof(InternalAttr) / sizeof(void*))
47 :
48 : class nsAttrAndChildArray
49 : {
50 : typedef mozilla::dom::BorrowedAttrInfo BorrowedAttrInfo;
51 : public:
52 : nsAttrAndChildArray();
53 : ~nsAttrAndChildArray();
54 :
55 29809 : uint32_t ChildCount() const
56 : {
57 29809 : return mImpl ? (mImpl->mAttrAndChildCount >> ATTRCHILD_ARRAY_ATTR_SLOTS_BITS) : 0;
58 : }
59 2667 : nsIContent* ChildAt(uint32_t aPos) const
60 : {
61 2667 : NS_ASSERTION(aPos < ChildCount(), "out-of-bounds access in nsAttrAndChildArray");
62 2667 : return reinterpret_cast<nsIContent*>(mImpl->mBuffer[AttrSlotsSize() + aPos]);
63 : }
64 : nsIContent* GetSafeChildAt(uint32_t aPos) const;
65 : nsIContent * const * GetChildArray(uint32_t* aChildCount) const;
66 : nsresult AppendChild(nsIContent* aChild)
67 : {
68 : return InsertChildAt(aChild, ChildCount());
69 : }
70 : nsresult InsertChildAt(nsIContent* aChild, uint32_t aPos);
71 : void RemoveChildAt(uint32_t aPos);
72 : // Like RemoveChildAt but hands the reference to the child being
73 : // removed back to the caller instead of just releasing it.
74 : already_AddRefed<nsIContent> TakeChildAt(uint32_t aPos);
75 : int32_t IndexOfChild(const nsINode* aPossibleChild) const;
76 :
77 56070 : bool HasAttrs() const
78 : {
79 56070 : return MappedAttrCount() || (AttrSlotCount() && AttrSlotIsTaken(0));
80 : }
81 :
82 : uint32_t AttrCount() const;
83 : const nsAttrValue* GetAttr(nsIAtom* aLocalName,
84 : int32_t aNamespaceID = kNameSpaceID_None) const;
85 : // As above but using a string attr name and always using
86 : // kNameSpaceID_None. This is always case-sensitive.
87 : const nsAttrValue* GetAttr(const nsAString& aName) const;
88 : // Get an nsAttrValue by qualified name. Can optionally do
89 : // ASCII-case-insensitive name matching.
90 : const nsAttrValue* GetAttr(const nsAString& aName,
91 : nsCaseTreatment aCaseSensitive) const;
92 : const nsAttrValue* AttrAt(uint32_t aPos) const;
93 : // SetAndSwapAttr swaps the current attribute value with aValue.
94 : // If the attribute was unset, an empty value will be swapped into aValue
95 : // and aHadValue will be set to false. Otherwise, aHadValue will be set to
96 : // true.
97 : nsresult SetAndSwapAttr(nsIAtom* aLocalName, nsAttrValue& aValue,
98 : bool* aHadValue);
99 : nsresult SetAndSwapAttr(mozilla::dom::NodeInfo* aName, nsAttrValue& aValue,
100 : bool* aHadValue);
101 :
102 : // Remove the attr at position aPos. The value of the attr is placed in
103 : // aValue; any value that was already in aValue is destroyed.
104 : nsresult RemoveAttrAt(uint32_t aPos, nsAttrValue& aValue);
105 :
106 : // Returns attribute name at given position, *not* out-of-bounds safe
107 : const nsAttrName* AttrNameAt(uint32_t aPos) const;
108 :
109 : // Returns the attribute info at a given position, *not* out-of-bounds safe
110 : BorrowedAttrInfo AttrInfoAt(uint32_t aPos) const;
111 :
112 : // Returns attribute name at given position or null if aPos is out-of-bounds
113 : const nsAttrName* GetSafeAttrNameAt(uint32_t aPos) const;
114 :
115 : const nsAttrName* GetExistingAttrNameFromQName(const nsAString& aName) const;
116 : int32_t IndexOfAttr(nsIAtom* aLocalName, int32_t aNamespaceID = kNameSpaceID_None) const;
117 :
118 : // SetAndSwapMappedAttr swaps the current attribute value with aValue.
119 : // If the attribute was unset, an empty value will be swapped into aValue
120 : // and aHadValue will be set to false. Otherwise, aHadValue will be set to
121 : // true.
122 : nsresult SetAndSwapMappedAttr(nsIAtom* aLocalName, nsAttrValue& aValue,
123 : nsMappedAttributeElement* aContent,
124 : nsHTMLStyleSheet* aSheet,
125 : bool* aHadValue);
126 0 : nsresult SetMappedAttrStyleSheet(nsHTMLStyleSheet* aSheet) {
127 0 : if (!mImpl || !mImpl->mMappedAttrs) {
128 0 : return NS_OK;
129 : }
130 0 : return DoSetMappedAttrStyleSheet(aSheet);
131 : }
132 : void WalkMappedAttributeStyleRules(nsRuleWalker* aRuleWalker);
133 :
134 : void Compact();
135 :
136 1917 : bool CanFitMoreAttrs() const
137 : {
138 1917 : return AttrSlotCount() < ATTRCHILD_ARRAY_MAX_ATTR_COUNT ||
139 1917 : !AttrSlotIsTaken(ATTRCHILD_ARRAY_MAX_ATTR_COUNT - 1);
140 : }
141 :
142 : size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
143 374 : bool HasMappedAttrs() const
144 : {
145 374 : return MappedAttrCount();
146 : }
147 : const nsMappedAttributes* GetMapped() const;
148 :
149 : // Force this to have mapped attributes, even if those attributes are empty.
150 : nsresult ForceMapped(nsMappedAttributeElement* aContent, nsIDocument* aDocument);
151 :
152 : // Clear the servo declaration block on the mapped attributes, if any
153 : // Will assert off main thread
154 : void ClearMappedServoStyle();
155 :
156 : // Increases capacity (if necessary) to have enough space to accomodate the
157 : // unmapped attributes and children of |aOther|. If |aAllocateChildren| is not
158 : // true, only enough space for unmapped attributes will be reserved.
159 : // It is REQUIRED that this function be called ONLY when the array is empty.
160 : nsresult EnsureCapacityToClone(const nsAttrAndChildArray& aOther,
161 : bool aAllocateChildren);
162 :
163 : private:
164 : nsAttrAndChildArray(const nsAttrAndChildArray& aOther) = delete;
165 : nsAttrAndChildArray& operator=(const nsAttrAndChildArray& aOther) = delete;
166 :
167 : void Clear();
168 :
169 : uint32_t NonMappedAttrCount() const;
170 : uint32_t MappedAttrCount() const;
171 :
172 : // Returns a non-null zero-refcount object.
173 : nsMappedAttributes*
174 : GetModifiableMapped(nsMappedAttributeElement* aContent,
175 : nsHTMLStyleSheet* aSheet,
176 : bool aWillAddAttr,
177 : int32_t aAttrCount = 1);
178 : nsresult MakeMappedUnique(nsMappedAttributes* aAttributes);
179 :
180 7203 : uint32_t AttrSlotsSize() const
181 : {
182 7203 : return AttrSlotCount() * ATTRSIZE;
183 : }
184 :
185 833543 : uint32_t AttrSlotCount() const
186 : {
187 833543 : return mImpl ? mImpl->mAttrAndChildCount & ATTRCHILD_ARRAY_ATTR_SLOTS_COUNT_MASK : 0;
188 : }
189 :
190 547351 : bool AttrSlotIsTaken(uint32_t aSlot) const
191 : {
192 547351 : NS_PRECONDITION(aSlot < AttrSlotCount(), "out-of-bounds");
193 547351 : return mImpl->mBuffer[aSlot * ATTRSIZE];
194 : }
195 :
196 3526 : void SetChildCount(uint32_t aCount)
197 : {
198 7052 : mImpl->mAttrAndChildCount =
199 7052 : (mImpl->mAttrAndChildCount & ATTRCHILD_ARRAY_ATTR_SLOTS_COUNT_MASK) |
200 3526 : (aCount << ATTRCHILD_ARRAY_ATTR_SLOTS_BITS);
201 3526 : }
202 :
203 6489 : void SetAttrSlotCount(uint32_t aCount)
204 : {
205 12978 : mImpl->mAttrAndChildCount =
206 6489 : (mImpl->mAttrAndChildCount & ~ATTRCHILD_ARRAY_ATTR_SLOTS_COUNT_MASK) |
207 : aCount;
208 6489 : }
209 :
210 3037 : void SetAttrSlotAndChildCount(uint32_t aSlotCount, uint32_t aChildCount)
211 : {
212 6074 : mImpl->mAttrAndChildCount = aSlotCount |
213 3037 : (aChildCount << ATTRCHILD_ARRAY_ATTR_SLOTS_BITS);
214 3037 : }
215 :
216 : bool GrowBy(uint32_t aGrowSize);
217 : bool AddAttrSlot();
218 :
219 : /**
220 : * Set *aPos to aChild and update sibling pointers as needed. aIndex is the
221 : * index at which aChild is actually being inserted. aChildCount is the
222 : * number of kids we had before the insertion.
223 : */
224 : inline void SetChildAtPos(void** aPos, nsIContent* aChild, uint32_t aIndex,
225 : uint32_t aChildCount);
226 :
227 : /**
228 : * Guts of SetMappedAttrStyleSheet for the rare case when we have mapped attrs
229 : */
230 : nsresult DoSetMappedAttrStyleSheet(nsHTMLStyleSheet* aSheet);
231 :
232 248 : struct InternalAttr
233 : {
234 : nsAttrName mName;
235 : nsAttrValue mValue;
236 : };
237 :
238 : struct Impl {
239 : uint32_t mAttrAndChildCount;
240 : uint32_t mBufferSize;
241 : nsMappedAttributes* mMappedAttrs;
242 : void* mBuffer[1];
243 : };
244 :
245 : Impl* mImpl;
246 : };
247 :
248 : #endif
|