|
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 * A unique per-element set of attributes that is used as an |
|
8 * nsIStyleRule; used to implement presentational attributes. |
|
9 */ |
|
10 |
|
11 #include "nsMappedAttributes.h" |
|
12 #include "nsHTMLStyleSheet.h" |
|
13 #include "nsRuleWalker.h" |
|
14 #include "mozilla/HashFunctions.h" |
|
15 #include "mozilla/MemoryReporting.h" |
|
16 |
|
17 using namespace mozilla; |
|
18 |
|
19 nsMappedAttributes::nsMappedAttributes(nsHTMLStyleSheet* aSheet, |
|
20 nsMapRuleToAttributesFunc aMapRuleFunc) |
|
21 : mAttrCount(0), |
|
22 mSheet(aSheet), |
|
23 mRuleMapper(aMapRuleFunc) |
|
24 { |
|
25 } |
|
26 |
|
27 nsMappedAttributes::nsMappedAttributes(const nsMappedAttributes& aCopy) |
|
28 : mAttrCount(aCopy.mAttrCount), |
|
29 mSheet(aCopy.mSheet), |
|
30 mRuleMapper(aCopy.mRuleMapper) |
|
31 { |
|
32 NS_ASSERTION(mBufferSize >= aCopy.mAttrCount, "can't fit attributes"); |
|
33 |
|
34 uint32_t i; |
|
35 for (i = 0; i < mAttrCount; ++i) { |
|
36 new (&Attrs()[i]) InternalAttr(aCopy.Attrs()[i]); |
|
37 } |
|
38 } |
|
39 |
|
40 nsMappedAttributes::~nsMappedAttributes() |
|
41 { |
|
42 if (mSheet) { |
|
43 mSheet->DropMappedAttributes(this); |
|
44 } |
|
45 |
|
46 uint32_t i; |
|
47 for (i = 0; i < mAttrCount; ++i) { |
|
48 Attrs()[i].~InternalAttr(); |
|
49 } |
|
50 } |
|
51 |
|
52 |
|
53 nsMappedAttributes* |
|
54 nsMappedAttributes::Clone(bool aWillAddAttr) |
|
55 { |
|
56 uint32_t extra = aWillAddAttr ? 1 : 0; |
|
57 |
|
58 // This will call the overridden operator new |
|
59 return new (mAttrCount + extra) nsMappedAttributes(*this); |
|
60 } |
|
61 |
|
62 void* nsMappedAttributes::operator new(size_t aSize, uint32_t aAttrCount) CPP_THROW_NEW |
|
63 { |
|
64 NS_ASSERTION(aAttrCount > 0, "zero-attribute nsMappedAttributes requested"); |
|
65 |
|
66 // aSize will include the mAttrs buffer so subtract that. |
|
67 void* newAttrs = ::operator new(aSize - sizeof(void*[1]) + |
|
68 aAttrCount * sizeof(InternalAttr)); |
|
69 |
|
70 #ifdef DEBUG |
|
71 static_cast<nsMappedAttributes*>(newAttrs)->mBufferSize = aAttrCount; |
|
72 #endif |
|
73 |
|
74 return newAttrs; |
|
75 } |
|
76 |
|
77 NS_IMPL_ISUPPORTS(nsMappedAttributes, |
|
78 nsIStyleRule) |
|
79 |
|
80 void |
|
81 nsMappedAttributes::SetAndTakeAttr(nsIAtom* aAttrName, nsAttrValue& aValue) |
|
82 { |
|
83 NS_PRECONDITION(aAttrName, "null name"); |
|
84 |
|
85 uint32_t i; |
|
86 for (i = 0; i < mAttrCount && !Attrs()[i].mName.IsSmaller(aAttrName); ++i) { |
|
87 if (Attrs()[i].mName.Equals(aAttrName)) { |
|
88 Attrs()[i].mValue.Reset(); |
|
89 Attrs()[i].mValue.SwapValueWith(aValue); |
|
90 return; |
|
91 } |
|
92 } |
|
93 |
|
94 NS_ASSERTION(mBufferSize >= mAttrCount + 1, "can't fit attributes"); |
|
95 |
|
96 if (mAttrCount != i) { |
|
97 memmove(&Attrs()[i + 1], &Attrs()[i], (mAttrCount - i) * sizeof(InternalAttr)); |
|
98 } |
|
99 |
|
100 new (&Attrs()[i].mName) nsAttrName(aAttrName); |
|
101 new (&Attrs()[i].mValue) nsAttrValue(); |
|
102 Attrs()[i].mValue.SwapValueWith(aValue); |
|
103 ++mAttrCount; |
|
104 } |
|
105 |
|
106 const nsAttrValue* |
|
107 nsMappedAttributes::GetAttr(nsIAtom* aAttrName) const |
|
108 { |
|
109 NS_PRECONDITION(aAttrName, "null name"); |
|
110 |
|
111 for (uint32_t i = 0; i < mAttrCount; ++i) { |
|
112 if (Attrs()[i].mName.Equals(aAttrName)) { |
|
113 return &Attrs()[i].mValue; |
|
114 } |
|
115 } |
|
116 |
|
117 return nullptr; |
|
118 } |
|
119 |
|
120 const nsAttrValue* |
|
121 nsMappedAttributes::GetAttr(const nsAString& aAttrName) const |
|
122 { |
|
123 for (uint32_t i = 0; i < mAttrCount; ++i) { |
|
124 if (Attrs()[i].mName.Atom()->Equals(aAttrName)) { |
|
125 return &Attrs()[i].mValue; |
|
126 } |
|
127 } |
|
128 |
|
129 return nullptr; |
|
130 } |
|
131 |
|
132 bool |
|
133 nsMappedAttributes::Equals(const nsMappedAttributes* aOther) const |
|
134 { |
|
135 if (this == aOther) { |
|
136 return true; |
|
137 } |
|
138 |
|
139 if (mRuleMapper != aOther->mRuleMapper || mAttrCount != aOther->mAttrCount) { |
|
140 return false; |
|
141 } |
|
142 |
|
143 uint32_t i; |
|
144 for (i = 0; i < mAttrCount; ++i) { |
|
145 if (!Attrs()[i].mName.Equals(aOther->Attrs()[i].mName) || |
|
146 !Attrs()[i].mValue.Equals(aOther->Attrs()[i].mValue)) { |
|
147 return false; |
|
148 } |
|
149 } |
|
150 |
|
151 return true; |
|
152 } |
|
153 |
|
154 uint32_t |
|
155 nsMappedAttributes::HashValue() const |
|
156 { |
|
157 uint32_t hash = HashGeneric(mRuleMapper); |
|
158 |
|
159 uint32_t i; |
|
160 for (i = 0; i < mAttrCount; ++i) { |
|
161 hash = AddToHash(hash, |
|
162 Attrs()[i].mName.HashValue(), |
|
163 Attrs()[i].mValue.HashValue()); |
|
164 } |
|
165 |
|
166 return hash; |
|
167 } |
|
168 |
|
169 void |
|
170 nsMappedAttributes::SetStyleSheet(nsHTMLStyleSheet* aSheet) |
|
171 { |
|
172 if (mSheet) { |
|
173 mSheet->DropMappedAttributes(this); |
|
174 } |
|
175 mSheet = aSheet; // not ref counted |
|
176 } |
|
177 |
|
178 /* virtual */ void |
|
179 nsMappedAttributes::MapRuleInfoInto(nsRuleData* aRuleData) |
|
180 { |
|
181 if (mRuleMapper) { |
|
182 (*mRuleMapper)(this, aRuleData); |
|
183 } |
|
184 } |
|
185 |
|
186 #ifdef DEBUG |
|
187 /* virtual */ void |
|
188 nsMappedAttributes::List(FILE* out, int32_t aIndent) const |
|
189 { |
|
190 nsAutoString buffer; |
|
191 uint32_t i; |
|
192 |
|
193 for (i = 0; i < mAttrCount; ++i) { |
|
194 int32_t indent; |
|
195 for (indent = aIndent; indent > 0; --indent) |
|
196 fputs(" ", out); |
|
197 |
|
198 Attrs()[i].mName.GetQualifiedName(buffer); |
|
199 fputs(NS_LossyConvertUTF16toASCII(buffer).get(), out); |
|
200 |
|
201 Attrs()[i].mValue.ToString(buffer); |
|
202 fputs(NS_LossyConvertUTF16toASCII(buffer).get(), out); |
|
203 fputs("\n", out); |
|
204 } |
|
205 } |
|
206 #endif |
|
207 |
|
208 void |
|
209 nsMappedAttributes::RemoveAttrAt(uint32_t aPos, nsAttrValue& aValue) |
|
210 { |
|
211 Attrs()[aPos].mValue.SwapValueWith(aValue); |
|
212 Attrs()[aPos].~InternalAttr(); |
|
213 memmove(&Attrs()[aPos], &Attrs()[aPos + 1], |
|
214 (mAttrCount - aPos - 1) * sizeof(InternalAttr)); |
|
215 mAttrCount--; |
|
216 } |
|
217 |
|
218 const nsAttrName* |
|
219 nsMappedAttributes::GetExistingAttrNameFromQName(const nsAString& aName) const |
|
220 { |
|
221 uint32_t i; |
|
222 for (i = 0; i < mAttrCount; ++i) { |
|
223 if (Attrs()[i].mName.IsAtom()) { |
|
224 if (Attrs()[i].mName.Atom()->Equals(aName)) { |
|
225 return &Attrs()[i].mName; |
|
226 } |
|
227 } |
|
228 else { |
|
229 if (Attrs()[i].mName.NodeInfo()->QualifiedNameEquals(aName)) { |
|
230 return &Attrs()[i].mName; |
|
231 } |
|
232 } |
|
233 } |
|
234 |
|
235 return nullptr; |
|
236 } |
|
237 |
|
238 int32_t |
|
239 nsMappedAttributes::IndexOfAttr(nsIAtom* aLocalName) const |
|
240 { |
|
241 uint32_t i; |
|
242 for (i = 0; i < mAttrCount; ++i) { |
|
243 if (Attrs()[i].mName.Equals(aLocalName)) { |
|
244 return i; |
|
245 } |
|
246 } |
|
247 |
|
248 return -1; |
|
249 } |
|
250 |
|
251 size_t |
|
252 nsMappedAttributes::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const |
|
253 { |
|
254 NS_ASSERTION(mAttrCount == mBufferSize, |
|
255 "mBufferSize and mAttrCount are expected to be the same."); |
|
256 |
|
257 size_t n = aMallocSizeOf(this); |
|
258 for (uint16_t i = 0; i < mAttrCount; ++i) { |
|
259 n += Attrs()[i].mValue.SizeOfExcludingThis(aMallocSizeOf); |
|
260 } |
|
261 return n; |
|
262 } |
|
263 |