1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * IBM Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 2004
20 : * IBM Corporation. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * IBM Corporation
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either the GNU General Public License Version 2 or later (the "GPL"), or
27 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : /*
40 : * A unique per-element set of attributes that is used as an
41 : * nsIStyleRule; used to implement presentational attributes.
42 : */
43 :
44 : #include "nsMappedAttributes.h"
45 : #include "nsHTMLStyleSheet.h"
46 : #include "nsRuleWalker.h"
47 : #include "prmem.h"
48 : #include "mozilla/HashFunctions.h"
49 :
50 : using namespace mozilla;
51 :
52 0 : nsMappedAttributes::nsMappedAttributes(nsHTMLStyleSheet* aSheet,
53 : nsMapRuleToAttributesFunc aMapRuleFunc)
54 : : mAttrCount(0),
55 : mSheet(aSheet),
56 0 : mRuleMapper(aMapRuleFunc)
57 : {
58 0 : }
59 :
60 0 : nsMappedAttributes::nsMappedAttributes(const nsMappedAttributes& aCopy)
61 : : mAttrCount(aCopy.mAttrCount),
62 : mSheet(aCopy.mSheet),
63 0 : mRuleMapper(aCopy.mRuleMapper)
64 : {
65 0 : NS_ASSERTION(mBufferSize >= aCopy.mAttrCount, "can't fit attributes");
66 :
67 : PRUint32 i;
68 0 : for (i = 0; i < mAttrCount; ++i) {
69 0 : new (&Attrs()[i]) InternalAttr(aCopy.Attrs()[i]);
70 : }
71 0 : }
72 :
73 0 : nsMappedAttributes::~nsMappedAttributes()
74 : {
75 0 : if (mSheet) {
76 0 : mSheet->DropMappedAttributes(this);
77 : }
78 :
79 : PRUint32 i;
80 0 : for (i = 0; i < mAttrCount; ++i) {
81 0 : Attrs()[i].~InternalAttr();
82 : }
83 0 : }
84 :
85 :
86 : nsMappedAttributes*
87 0 : nsMappedAttributes::Clone(bool aWillAddAttr)
88 : {
89 0 : PRUint32 extra = aWillAddAttr ? 1 : 0;
90 :
91 : // This will call the overridden operator new
92 0 : return new (mAttrCount + extra) nsMappedAttributes(*this);
93 : }
94 :
95 0 : void* nsMappedAttributes::operator new(size_t aSize, PRUint32 aAttrCount) CPP_THROW_NEW
96 : {
97 0 : NS_ASSERTION(aAttrCount > 0, "zero-attribute nsMappedAttributes requested");
98 :
99 : // aSize will include the mAttrs buffer so subtract that.
100 : void* newAttrs = ::operator new(aSize - sizeof(void*[1]) +
101 0 : aAttrCount * sizeof(InternalAttr));
102 :
103 : #ifdef DEBUG
104 0 : if (newAttrs) {
105 0 : static_cast<nsMappedAttributes*>(newAttrs)->mBufferSize = aAttrCount;
106 : }
107 : #endif
108 :
109 0 : return newAttrs;
110 : }
111 :
112 0 : NS_IMPL_ISUPPORTS1(nsMappedAttributes,
113 : nsIStyleRule)
114 :
115 : nsresult
116 0 : nsMappedAttributes::SetAndTakeAttr(nsIAtom* aAttrName, nsAttrValue& aValue)
117 : {
118 0 : NS_PRECONDITION(aAttrName, "null name");
119 :
120 : PRUint32 i;
121 0 : for (i = 0; i < mAttrCount && !Attrs()[i].mName.IsSmaller(aAttrName); ++i) {
122 0 : if (Attrs()[i].mName.Equals(aAttrName)) {
123 0 : Attrs()[i].mValue.Reset();
124 0 : Attrs()[i].mValue.SwapValueWith(aValue);
125 :
126 0 : return NS_OK;
127 : }
128 : }
129 :
130 0 : NS_ASSERTION(mBufferSize >= mAttrCount + 1, "can't fit attributes");
131 :
132 0 : if (mAttrCount != i) {
133 0 : memmove(&Attrs()[i + 1], &Attrs()[i], (mAttrCount - i) * sizeof(InternalAttr));
134 : }
135 :
136 0 : new (&Attrs()[i].mName) nsAttrName(aAttrName);
137 0 : new (&Attrs()[i].mValue) nsAttrValue();
138 0 : Attrs()[i].mValue.SwapValueWith(aValue);
139 0 : ++mAttrCount;
140 :
141 0 : return NS_OK;
142 : }
143 :
144 : const nsAttrValue*
145 0 : nsMappedAttributes::GetAttr(nsIAtom* aAttrName) const
146 : {
147 0 : NS_PRECONDITION(aAttrName, "null name");
148 :
149 0 : PRInt32 i = IndexOfAttr(aAttrName, kNameSpaceID_None);
150 0 : if (i >= 0) {
151 0 : return &Attrs()[i].mValue;
152 : }
153 :
154 0 : return nsnull;
155 : }
156 :
157 : bool
158 0 : nsMappedAttributes::Equals(const nsMappedAttributes* aOther) const
159 : {
160 0 : if (this == aOther) {
161 0 : return true;
162 : }
163 :
164 0 : if (mRuleMapper != aOther->mRuleMapper || mAttrCount != aOther->mAttrCount) {
165 0 : return false;
166 : }
167 :
168 : PRUint32 i;
169 0 : for (i = 0; i < mAttrCount; ++i) {
170 0 : if (!Attrs()[i].mName.Equals(aOther->Attrs()[i].mName) ||
171 0 : !Attrs()[i].mValue.Equals(aOther->Attrs()[i].mValue)) {
172 0 : return false;
173 : }
174 : }
175 :
176 0 : return true;
177 : }
178 :
179 : PRUint32
180 0 : nsMappedAttributes::HashValue() const
181 : {
182 0 : PRUint32 hash = HashGeneric(mRuleMapper);
183 :
184 : PRUint32 i;
185 0 : for (i = 0; i < mAttrCount; ++i) {
186 : hash = AddToHash(hash,
187 0 : Attrs()[i].mName.HashValue(),
188 0 : Attrs()[i].mValue.HashValue());
189 : }
190 :
191 0 : return hash;
192 : }
193 :
194 : void
195 0 : nsMappedAttributes::SetStyleSheet(nsHTMLStyleSheet* aSheet)
196 : {
197 0 : if (mSheet) {
198 0 : mSheet->DropMappedAttributes(this);
199 : }
200 0 : mSheet = aSheet; // not ref counted
201 0 : }
202 :
203 : /* virtual */ void
204 0 : nsMappedAttributes::MapRuleInfoInto(nsRuleData* aRuleData)
205 : {
206 0 : if (mRuleMapper) {
207 0 : (*mRuleMapper)(this, aRuleData);
208 : }
209 0 : }
210 :
211 : #ifdef DEBUG
212 : /* virtual */ void
213 0 : nsMappedAttributes::List(FILE* out, PRInt32 aIndent) const
214 : {
215 0 : nsAutoString buffer;
216 : PRUint32 i;
217 :
218 0 : for (i = 0; i < mAttrCount; ++i) {
219 : PRInt32 indent;
220 0 : for (indent = aIndent; indent > 0; --indent)
221 0 : fputs(" ", out);
222 :
223 0 : Attrs()[i].mName.GetQualifiedName(buffer);
224 0 : fputs(NS_LossyConvertUTF16toASCII(buffer).get(), out);
225 :
226 0 : Attrs()[i].mValue.ToString(buffer);
227 0 : fputs(NS_LossyConvertUTF16toASCII(buffer).get(), out);
228 0 : fputs("\n", out);
229 : }
230 0 : }
231 : #endif
232 :
233 : void
234 0 : nsMappedAttributes::RemoveAttrAt(PRUint32 aPos, nsAttrValue& aValue)
235 : {
236 0 : Attrs()[aPos].mValue.SwapValueWith(aValue);
237 0 : Attrs()[aPos].~InternalAttr();
238 0 : memmove(&Attrs()[aPos], &Attrs()[aPos + 1],
239 0 : (mAttrCount - aPos - 1) * sizeof(InternalAttr));
240 0 : mAttrCount--;
241 0 : }
242 :
243 : const nsAttrName*
244 0 : nsMappedAttributes::GetExistingAttrNameFromQName(const nsAString& aName) const
245 : {
246 : PRUint32 i;
247 0 : for (i = 0; i < mAttrCount; ++i) {
248 0 : if (Attrs()[i].mName.IsAtom()) {
249 0 : if (Attrs()[i].mName.Atom()->Equals(aName)) {
250 0 : return &Attrs()[i].mName;
251 : }
252 : }
253 : else {
254 0 : if (Attrs()[i].mName.NodeInfo()->QualifiedNameEquals(aName)) {
255 0 : return &Attrs()[i].mName;
256 : }
257 : }
258 : }
259 :
260 0 : return nsnull;
261 : }
262 :
263 : PRInt32
264 0 : nsMappedAttributes::IndexOfAttr(nsIAtom* aLocalName, PRInt32 aNamespaceID) const
265 : {
266 : PRUint32 i;
267 0 : if (aNamespaceID == kNameSpaceID_None) {
268 : // This should be the common case so lets make an optimized loop
269 0 : for (i = 0; i < mAttrCount; ++i) {
270 0 : if (Attrs()[i].mName.Equals(aLocalName)) {
271 0 : return i;
272 : }
273 : }
274 : }
275 : else {
276 0 : for (i = 0; i < mAttrCount; ++i) {
277 0 : if (Attrs()[i].mName.Equals(aLocalName, aNamespaceID)) {
278 0 : return i;
279 : }
280 : }
281 : }
282 :
283 0 : return -1;
284 : }
285 :
286 : size_t
287 0 : nsMappedAttributes::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
288 : {
289 0 : NS_ASSERTION(mAttrCount == mBufferSize,
290 : "mBufferSize and mAttrCount are expected to be the same.");
291 :
292 0 : size_t n = aMallocSizeOf(this);
293 0 : for (PRUint16 i = 0; i < mAttrCount; ++i) {
294 0 : n += Attrs()[i].mValue.SizeOfExcludingThis(aMallocSizeOf);
295 : }
296 0 : return n;
297 : }
298 :
|