|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 /* |
|
7 * Storage of the children and attributes of a DOM node; storage for |
|
8 * the two is unified to minimize footprint. |
|
9 */ |
|
10 |
|
11 #ifndef nsAttrAndChildArray_h___ |
|
12 #define nsAttrAndChildArray_h___ |
|
13 |
|
14 #include "mozilla/Attributes.h" |
|
15 #include "mozilla/MemoryReporting.h" |
|
16 |
|
17 #include "nscore.h" |
|
18 #include "nsAttrName.h" |
|
19 #include "nsAttrValue.h" |
|
20 #include "nsCaseTreatment.h" |
|
21 |
|
22 class nsINode; |
|
23 class nsIContent; |
|
24 class nsMappedAttributes; |
|
25 class nsHTMLStyleSheet; |
|
26 class nsRuleWalker; |
|
27 class nsMappedAttributeElement; |
|
28 |
|
29 #define ATTRCHILD_ARRAY_GROWSIZE 8 |
|
30 #define ATTRCHILD_ARRAY_LINEAR_THRESHOLD 32 |
|
31 |
|
32 #define ATTRCHILD_ARRAY_ATTR_SLOTS_BITS 10 |
|
33 |
|
34 #define ATTRCHILD_ARRAY_MAX_ATTR_COUNT \ |
|
35 ((1 << ATTRCHILD_ARRAY_ATTR_SLOTS_BITS) - 1) |
|
36 |
|
37 #define ATTRCHILD_ARRAY_MAX_CHILD_COUNT \ |
|
38 (~uint32_t(0) >> ATTRCHILD_ARRAY_ATTR_SLOTS_BITS) |
|
39 |
|
40 #define ATTRCHILD_ARRAY_ATTR_SLOTS_COUNT_MASK \ |
|
41 ((1 << ATTRCHILD_ARRAY_ATTR_SLOTS_BITS) - 1) |
|
42 |
|
43 |
|
44 #define ATTRSIZE (sizeof(InternalAttr) / sizeof(void*)) |
|
45 |
|
46 class nsAttrAndChildArray |
|
47 { |
|
48 public: |
|
49 nsAttrAndChildArray(); |
|
50 ~nsAttrAndChildArray(); |
|
51 |
|
52 uint32_t ChildCount() const |
|
53 { |
|
54 return mImpl ? (mImpl->mAttrAndChildCount >> ATTRCHILD_ARRAY_ATTR_SLOTS_BITS) : 0; |
|
55 } |
|
56 nsIContent* ChildAt(uint32_t aPos) const |
|
57 { |
|
58 NS_ASSERTION(aPos < ChildCount(), "out-of-bounds access in nsAttrAndChildArray"); |
|
59 return reinterpret_cast<nsIContent*>(mImpl->mBuffer[AttrSlotsSize() + aPos]); |
|
60 } |
|
61 nsIContent* GetSafeChildAt(uint32_t aPos) const; |
|
62 nsIContent * const * GetChildArray(uint32_t* aChildCount) const; |
|
63 nsresult AppendChild(nsIContent* aChild) |
|
64 { |
|
65 return InsertChildAt(aChild, ChildCount()); |
|
66 } |
|
67 nsresult InsertChildAt(nsIContent* aChild, uint32_t aPos); |
|
68 void RemoveChildAt(uint32_t aPos); |
|
69 // Like RemoveChildAt but hands the reference to the child being |
|
70 // removed back to the caller instead of just releasing it. |
|
71 already_AddRefed<nsIContent> TakeChildAt(uint32_t aPos); |
|
72 int32_t IndexOfChild(const nsINode* aPossibleChild) const; |
|
73 |
|
74 bool HasAttrs() const |
|
75 { |
|
76 return MappedAttrCount() || (AttrSlotCount() && AttrSlotIsTaken(0)); |
|
77 } |
|
78 |
|
79 uint32_t AttrCount() const; |
|
80 const nsAttrValue* GetAttr(nsIAtom* aLocalName, |
|
81 int32_t aNamespaceID = kNameSpaceID_None) const; |
|
82 // As above but using a string attr name and always using |
|
83 // kNameSpaceID_None. This is always case-sensitive. |
|
84 const nsAttrValue* GetAttr(const nsAString& aName) const; |
|
85 // Get an nsAttrValue by qualified name. Can optionally do |
|
86 // ASCII-case-insensitive name matching. |
|
87 const nsAttrValue* GetAttr(const nsAString& aName, |
|
88 nsCaseTreatment aCaseSensitive) const; |
|
89 const nsAttrValue* AttrAt(uint32_t aPos) const; |
|
90 nsresult SetAndTakeAttr(nsIAtom* aLocalName, nsAttrValue& aValue); |
|
91 nsresult SetAndTakeAttr(nsINodeInfo* aName, nsAttrValue& aValue); |
|
92 |
|
93 // Remove the attr at position aPos. The value of the attr is placed in |
|
94 // aValue; any value that was already in aValue is destroyed. |
|
95 nsresult RemoveAttrAt(uint32_t aPos, nsAttrValue& aValue); |
|
96 |
|
97 // Returns attribute name at given position, *not* out-of-bounds safe |
|
98 const nsAttrName* AttrNameAt(uint32_t aPos) const; |
|
99 |
|
100 // Returns attribute name at given position or null if aPos is out-of-bounds |
|
101 const nsAttrName* GetSafeAttrNameAt(uint32_t aPos) const; |
|
102 |
|
103 const nsAttrName* GetExistingAttrNameFromQName(const nsAString& aName) const; |
|
104 int32_t IndexOfAttr(nsIAtom* aLocalName, int32_t aNamespaceID = kNameSpaceID_None) const; |
|
105 |
|
106 nsresult SetAndTakeMappedAttr(nsIAtom* aLocalName, nsAttrValue& aValue, |
|
107 nsMappedAttributeElement* aContent, |
|
108 nsHTMLStyleSheet* aSheet); |
|
109 nsresult SetMappedAttrStyleSheet(nsHTMLStyleSheet* aSheet) { |
|
110 if (!mImpl || !mImpl->mMappedAttrs) { |
|
111 return NS_OK; |
|
112 } |
|
113 return DoSetMappedAttrStyleSheet(aSheet); |
|
114 } |
|
115 void WalkMappedAttributeStyleRules(nsRuleWalker* aRuleWalker); |
|
116 |
|
117 void Compact(); |
|
118 |
|
119 bool CanFitMoreAttrs() const |
|
120 { |
|
121 return AttrSlotCount() < ATTRCHILD_ARRAY_MAX_ATTR_COUNT || |
|
122 !AttrSlotIsTaken(ATTRCHILD_ARRAY_MAX_ATTR_COUNT - 1); |
|
123 } |
|
124 |
|
125 size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; |
|
126 bool HasMappedAttrs() const |
|
127 { |
|
128 return MappedAttrCount(); |
|
129 } |
|
130 |
|
131 private: |
|
132 nsAttrAndChildArray(const nsAttrAndChildArray& aOther) MOZ_DELETE; |
|
133 nsAttrAndChildArray& operator=(const nsAttrAndChildArray& aOther) MOZ_DELETE; |
|
134 |
|
135 void Clear(); |
|
136 |
|
137 uint32_t NonMappedAttrCount() const; |
|
138 uint32_t MappedAttrCount() const; |
|
139 |
|
140 // Returns a non-null zero-refcount object. |
|
141 nsMappedAttributes* |
|
142 GetModifiableMapped(nsMappedAttributeElement* aContent, |
|
143 nsHTMLStyleSheet* aSheet, |
|
144 bool aWillAddAttr); |
|
145 nsresult MakeMappedUnique(nsMappedAttributes* aAttributes); |
|
146 |
|
147 uint32_t AttrSlotsSize() const |
|
148 { |
|
149 return AttrSlotCount() * ATTRSIZE; |
|
150 } |
|
151 |
|
152 uint32_t AttrSlotCount() const |
|
153 { |
|
154 return mImpl ? mImpl->mAttrAndChildCount & ATTRCHILD_ARRAY_ATTR_SLOTS_COUNT_MASK : 0; |
|
155 } |
|
156 |
|
157 bool AttrSlotIsTaken(uint32_t aSlot) const |
|
158 { |
|
159 NS_PRECONDITION(aSlot < AttrSlotCount(), "out-of-bounds"); |
|
160 return mImpl->mBuffer[aSlot * ATTRSIZE]; |
|
161 } |
|
162 |
|
163 void SetChildCount(uint32_t aCount) |
|
164 { |
|
165 mImpl->mAttrAndChildCount = |
|
166 (mImpl->mAttrAndChildCount & ATTRCHILD_ARRAY_ATTR_SLOTS_COUNT_MASK) | |
|
167 (aCount << ATTRCHILD_ARRAY_ATTR_SLOTS_BITS); |
|
168 } |
|
169 |
|
170 void SetAttrSlotCount(uint32_t aCount) |
|
171 { |
|
172 mImpl->mAttrAndChildCount = |
|
173 (mImpl->mAttrAndChildCount & ~ATTRCHILD_ARRAY_ATTR_SLOTS_COUNT_MASK) | |
|
174 aCount; |
|
175 } |
|
176 |
|
177 void SetAttrSlotAndChildCount(uint32_t aSlotCount, uint32_t aChildCount) |
|
178 { |
|
179 mImpl->mAttrAndChildCount = aSlotCount | |
|
180 (aChildCount << ATTRCHILD_ARRAY_ATTR_SLOTS_BITS); |
|
181 } |
|
182 |
|
183 bool GrowBy(uint32_t aGrowSize); |
|
184 bool AddAttrSlot(); |
|
185 |
|
186 /** |
|
187 * Set *aPos to aChild and update sibling pointers as needed. aIndex is the |
|
188 * index at which aChild is actually being inserted. aChildCount is the |
|
189 * number of kids we had before the insertion. |
|
190 */ |
|
191 inline void SetChildAtPos(void** aPos, nsIContent* aChild, uint32_t aIndex, |
|
192 uint32_t aChildCount); |
|
193 |
|
194 /** |
|
195 * Guts of SetMappedAttrStyleSheet for the rare case when we have mapped attrs |
|
196 */ |
|
197 nsresult DoSetMappedAttrStyleSheet(nsHTMLStyleSheet* aSheet); |
|
198 |
|
199 struct InternalAttr |
|
200 { |
|
201 nsAttrName mName; |
|
202 nsAttrValue mValue; |
|
203 }; |
|
204 |
|
205 struct Impl { |
|
206 uint32_t mAttrAndChildCount; |
|
207 uint32_t mBufferSize; |
|
208 nsMappedAttributes* mMappedAttrs; |
|
209 void* mBuffer[1]; |
|
210 }; |
|
211 |
|
212 Impl* mImpl; |
|
213 }; |
|
214 |
|
215 #endif |