|
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 struct that represents the value (type and actual data) of an |
|
8 * attribute. |
|
9 */ |
|
10 |
|
11 #ifndef nsAttrValue_h___ |
|
12 #define nsAttrValue_h___ |
|
13 |
|
14 #include "nscore.h" |
|
15 #include "nsStringGlue.h" |
|
16 #include "nsStringBuffer.h" |
|
17 #include "nsColor.h" |
|
18 #include "nsCaseTreatment.h" |
|
19 #include "nsMargin.h" |
|
20 #include "nsCOMPtr.h" |
|
21 #include "SVGAttrValueWrapper.h" |
|
22 #include "nsTArrayForwardDeclare.h" |
|
23 #include "nsIAtom.h" |
|
24 #include "mozilla/MemoryReporting.h" |
|
25 #include "mozilla/dom/BindingDeclarations.h" |
|
26 |
|
27 class nsAString; |
|
28 class nsIDocument; |
|
29 class nsStyledElementNotElementCSSInlineStyle; |
|
30 struct MiscContainer; |
|
31 |
|
32 namespace mozilla { |
|
33 namespace css { |
|
34 class StyleRule; |
|
35 struct URLValue; |
|
36 struct ImageValue; |
|
37 } |
|
38 } |
|
39 |
|
40 #define NS_ATTRVALUE_MAX_STRINGLENGTH_ATOM 12 |
|
41 |
|
42 #define NS_ATTRVALUE_BASETYPE_MASK (uintptr_t(3)) |
|
43 #define NS_ATTRVALUE_POINTERVALUE_MASK (~NS_ATTRVALUE_BASETYPE_MASK) |
|
44 |
|
45 #define NS_ATTRVALUE_INTEGERTYPE_BITS 4 |
|
46 #define NS_ATTRVALUE_INTEGERTYPE_MASK (uintptr_t((1 << NS_ATTRVALUE_INTEGERTYPE_BITS) - 1)) |
|
47 #define NS_ATTRVALUE_INTEGERTYPE_MULTIPLIER (1 << NS_ATTRVALUE_INTEGERTYPE_BITS) |
|
48 #define NS_ATTRVALUE_INTEGERTYPE_MAXVALUE ((1 << (31 - NS_ATTRVALUE_INTEGERTYPE_BITS)) - 1) |
|
49 #define NS_ATTRVALUE_INTEGERTYPE_MINVALUE (-NS_ATTRVALUE_INTEGERTYPE_MAXVALUE - 1) |
|
50 |
|
51 #define NS_ATTRVALUE_ENUMTABLEINDEX_BITS (32 - 16 - NS_ATTRVALUE_INTEGERTYPE_BITS) |
|
52 #define NS_ATTRVALUE_ENUMTABLE_VALUE_NEEDS_TO_UPPER (1 << (NS_ATTRVALUE_ENUMTABLEINDEX_BITS - 1)) |
|
53 #define NS_ATTRVALUE_ENUMTABLEINDEX_MAXVALUE (NS_ATTRVALUE_ENUMTABLE_VALUE_NEEDS_TO_UPPER - 1) |
|
54 #define NS_ATTRVALUE_ENUMTABLEINDEX_MASK \ |
|
55 (uintptr_t((((1 << NS_ATTRVALUE_ENUMTABLEINDEX_BITS) - 1) &~ NS_ATTRVALUE_ENUMTABLE_VALUE_NEEDS_TO_UPPER))) |
|
56 |
|
57 /** |
|
58 * A class used to construct a nsString from a nsStringBuffer (we might |
|
59 * want to move this to nsString at some point). |
|
60 * |
|
61 * WARNING: Note that nsCheapString doesn't take an explicit length -- it |
|
62 * assumes the string is maximally large, given the nsStringBuffer's storage |
|
63 * size. This means the given string buffer *must* be sized exactly correctly |
|
64 * for the string it contains (including one byte for a null terminator). If |
|
65 * it has any unused storage space, then that will result in bogus characters |
|
66 * at the end of our nsCheapString. |
|
67 */ |
|
68 class nsCheapString : public nsString { |
|
69 public: |
|
70 nsCheapString(nsStringBuffer* aBuf) |
|
71 { |
|
72 if (aBuf) |
|
73 aBuf->ToString(aBuf->StorageSize()/sizeof(char16_t) - 1, *this); |
|
74 } |
|
75 }; |
|
76 |
|
77 class nsAttrValue { |
|
78 friend struct MiscContainer; |
|
79 public: |
|
80 typedef nsTArray< nsCOMPtr<nsIAtom> > AtomArray; |
|
81 |
|
82 // This has to be the same as in ValueBaseType |
|
83 enum ValueType { |
|
84 eString = 0x00, // 00 |
|
85 // 01 this value indicates an 'misc' struct |
|
86 eAtom = 0x02, // 10 |
|
87 eInteger = 0x03, // 0011 |
|
88 eColor = 0x07, // 0111 |
|
89 eEnum = 0x0B, // 1011 This should eventually die |
|
90 ePercent = 0x0F, // 1111 |
|
91 // Values below here won't matter, they'll be always stored in the 'misc' |
|
92 // struct. |
|
93 eCSSStyleRule = 0x10 |
|
94 ,eURL = 0x11 |
|
95 ,eImage = 0x12 |
|
96 ,eAtomArray = 0x13 |
|
97 ,eDoubleValue = 0x14 |
|
98 ,eIntMarginValue = 0x15 |
|
99 ,eSVGAngle = 0x16 |
|
100 ,eSVGTypesBegin = eSVGAngle |
|
101 ,eSVGIntegerPair = 0x17 |
|
102 ,eSVGLength = 0x18 |
|
103 ,eSVGLengthList = 0x19 |
|
104 ,eSVGNumberList = 0x1A |
|
105 ,eSVGNumberPair = 0x1B |
|
106 ,eSVGPathData = 0x1C |
|
107 ,eSVGPointList = 0x1D |
|
108 ,eSVGPreserveAspectRatio = 0x1E |
|
109 ,eSVGStringList = 0x1F |
|
110 ,eSVGTransformList = 0x20 |
|
111 ,eSVGViewBox = 0x21 |
|
112 ,eSVGTypesEnd = eSVGViewBox |
|
113 }; |
|
114 |
|
115 nsAttrValue(); |
|
116 nsAttrValue(const nsAttrValue& aOther); |
|
117 explicit nsAttrValue(const nsAString& aValue); |
|
118 explicit nsAttrValue(nsIAtom* aValue); |
|
119 nsAttrValue(mozilla::css::StyleRule* aValue, const nsAString* aSerialized); |
|
120 explicit nsAttrValue(const nsIntMargin& aValue); |
|
121 ~nsAttrValue(); |
|
122 |
|
123 inline const nsAttrValue& operator=(const nsAttrValue& aOther); |
|
124 |
|
125 static nsresult Init(); |
|
126 static void Shutdown(); |
|
127 |
|
128 ValueType Type() const; |
|
129 |
|
130 void Reset(); |
|
131 |
|
132 void SetTo(const nsAttrValue& aOther); |
|
133 void SetTo(const nsAString& aValue); |
|
134 void SetTo(nsIAtom* aValue); |
|
135 void SetTo(int16_t aInt); |
|
136 void SetTo(int32_t aInt, const nsAString* aSerialized); |
|
137 void SetTo(double aValue, const nsAString* aSerialized); |
|
138 void SetTo(mozilla::css::StyleRule* aValue, const nsAString* aSerialized); |
|
139 void SetTo(mozilla::css::URLValue* aValue, const nsAString* aSerialized); |
|
140 void SetTo(const nsIntMargin& aValue); |
|
141 void SetTo(const nsSVGAngle& aValue, const nsAString* aSerialized); |
|
142 void SetTo(const nsSVGIntegerPair& aValue, const nsAString* aSerialized); |
|
143 void SetTo(const nsSVGLength2& aValue, const nsAString* aSerialized); |
|
144 void SetTo(const mozilla::SVGLengthList& aValue, |
|
145 const nsAString* aSerialized); |
|
146 void SetTo(const mozilla::SVGNumberList& aValue, |
|
147 const nsAString* aSerialized); |
|
148 void SetTo(const nsSVGNumberPair& aValue, const nsAString* aSerialized); |
|
149 void SetTo(const mozilla::SVGPathData& aValue, const nsAString* aSerialized); |
|
150 void SetTo(const mozilla::SVGPointList& aValue, const nsAString* aSerialized); |
|
151 void SetTo(const mozilla::SVGAnimatedPreserveAspectRatio& aValue, |
|
152 const nsAString* aSerialized); |
|
153 void SetTo(const mozilla::SVGStringList& aValue, |
|
154 const nsAString* aSerialized); |
|
155 void SetTo(const mozilla::SVGTransformList& aValue, |
|
156 const nsAString* aSerialized); |
|
157 void SetTo(const nsSVGViewBox& aValue, const nsAString* aSerialized); |
|
158 |
|
159 /** |
|
160 * Sets this object with the string or atom representation of aValue. |
|
161 * |
|
162 * After calling this method, this object will have type eString unless the |
|
163 * type of aValue is eAtom, in which case this object will also have type |
|
164 * eAtom. |
|
165 */ |
|
166 void SetToSerialized(const nsAttrValue& aValue); |
|
167 |
|
168 void SwapValueWith(nsAttrValue& aOther); |
|
169 |
|
170 void ToString(nsAString& aResult) const; |
|
171 inline void ToString(mozilla::dom::DOMString& aResult) const; |
|
172 |
|
173 /** |
|
174 * Returns the value of this object as an atom. If necessary, the value will |
|
175 * first be serialised using ToString before converting to an atom. |
|
176 */ |
|
177 already_AddRefed<nsIAtom> GetAsAtom() const; |
|
178 |
|
179 // Methods to get value. These methods do not convert so only use them |
|
180 // to retrieve the datatype that this nsAttrValue has. |
|
181 inline bool IsEmptyString() const; |
|
182 const nsCheapString GetStringValue() const; |
|
183 inline nsIAtom* GetAtomValue() const; |
|
184 inline int32_t GetIntegerValue() const; |
|
185 bool GetColorValue(nscolor& aColor) const; |
|
186 inline int16_t GetEnumValue() const; |
|
187 inline float GetPercentValue() const; |
|
188 inline AtomArray* GetAtomArrayValue() const; |
|
189 inline mozilla::css::StyleRule* GetCSSStyleRuleValue() const; |
|
190 inline mozilla::css::URLValue* GetURLValue() const; |
|
191 inline mozilla::css::ImageValue* GetImageValue() const; |
|
192 inline double GetDoubleValue() const; |
|
193 bool GetIntMarginValue(nsIntMargin& aMargin) const; |
|
194 |
|
195 /** |
|
196 * Returns the string corresponding to the stored enum value. |
|
197 * |
|
198 * @param aResult the string representing the enum tag |
|
199 * @param aRealTag wheter we want to have the real tag or the saved one |
|
200 */ |
|
201 void GetEnumString(nsAString& aResult, bool aRealTag) const; |
|
202 |
|
203 // Methods to get access to atoms we may have |
|
204 // Returns the number of atoms we have; 0 if we have none. It's OK |
|
205 // to call this without checking the type first; it handles that. |
|
206 uint32_t GetAtomCount() const; |
|
207 // Returns the atom at aIndex (0-based). Do not call this with |
|
208 // aIndex >= GetAtomCount(). |
|
209 nsIAtom* AtomAt(int32_t aIndex) const; |
|
210 |
|
211 uint32_t HashValue() const; |
|
212 bool Equals(const nsAttrValue& aOther) const; |
|
213 // aCaseSensitive == eIgnoreCase means ASCII case-insenstive matching |
|
214 bool Equals(const nsAString& aValue, nsCaseTreatment aCaseSensitive) const; |
|
215 bool Equals(nsIAtom* aValue, nsCaseTreatment aCaseSensitive) const; |
|
216 |
|
217 /** |
|
218 * Compares this object with aOther according to their string representation. |
|
219 * |
|
220 * For example, when called on an object with type eInteger and value 4, and |
|
221 * given aOther of type eString and value "4", EqualsAsStrings will return |
|
222 * true (while Equals will return false). |
|
223 */ |
|
224 bool EqualsAsStrings(const nsAttrValue& aOther) const; |
|
225 |
|
226 /** |
|
227 * Returns true if this AttrValue is equal to the given atom, or is an |
|
228 * array which contains the given atom. |
|
229 */ |
|
230 bool Contains(nsIAtom* aValue, nsCaseTreatment aCaseSensitive) const; |
|
231 /** |
|
232 * Returns true if this AttrValue is an atom equal to the given |
|
233 * string, or is an array of atoms which contains the given string. |
|
234 * This always does a case-sensitive comparison. |
|
235 */ |
|
236 bool Contains(const nsAString& aValue) const; |
|
237 |
|
238 void ParseAtom(const nsAString& aValue); |
|
239 void ParseAtomArray(const nsAString& aValue); |
|
240 void ParseStringOrAtom(const nsAString& aValue); |
|
241 |
|
242 /** |
|
243 * Structure for a mapping from int (enum) values to strings. When you use |
|
244 * it you generally create an array of them. |
|
245 * Instantiate like this: |
|
246 * EnumTable myTable[] = { |
|
247 * { "string1", 1 }, |
|
248 * { "string2", 2 }, |
|
249 * { 0 } |
|
250 * } |
|
251 */ |
|
252 struct EnumTable { |
|
253 /** The string the value maps to */ |
|
254 const char* tag; |
|
255 /** The enum value that maps to this string */ |
|
256 int16_t value; |
|
257 }; |
|
258 |
|
259 /** |
|
260 * Parse into an enum value. |
|
261 * |
|
262 * @param aValue the string to find the value for |
|
263 * @param aTable the enumeration to map with |
|
264 * @param aCaseSensitive specify if the parsing has to be case sensitive |
|
265 * @param aDefaultValue if non-null, this function will always return true. |
|
266 * Failure to parse aValue as one of the values in aTable will just |
|
267 * cause aDefaultValue->value to be stored as the enumeration value. |
|
268 * @return whether the enum value was found or not |
|
269 */ |
|
270 bool ParseEnumValue(const nsAString& aValue, |
|
271 const EnumTable* aTable, |
|
272 bool aCaseSensitive, |
|
273 const EnumTable* aDefaultValue = nullptr); |
|
274 |
|
275 /** |
|
276 * Parse a string into an integer. Can optionally parse percent (n%). |
|
277 * This method explicitly sets a lower bound of zero on the element, |
|
278 * whether it be percent or raw integer. |
|
279 * |
|
280 * @param aString the string to parse |
|
281 * @return whether the value could be parsed |
|
282 * |
|
283 * @see http://www.whatwg.org/html/#rules-for-parsing-dimension-values |
|
284 */ |
|
285 bool ParseSpecialIntValue(const nsAString& aString); |
|
286 |
|
287 |
|
288 /** |
|
289 * Parse a string value into an integer. |
|
290 * |
|
291 * @param aString the string to parse |
|
292 * @return whether the value could be parsed |
|
293 */ |
|
294 bool ParseIntValue(const nsAString& aString) { |
|
295 return ParseIntWithBounds(aString, INT32_MIN, INT32_MAX); |
|
296 } |
|
297 |
|
298 /** |
|
299 * Parse a string value into an integer with minimum value and maximum value. |
|
300 * |
|
301 * @param aString the string to parse |
|
302 * @param aMin the minimum value (if value is less it will be bumped up) |
|
303 * @param aMax the maximum value (if value is greater it will be chopped down) |
|
304 * @return whether the value could be parsed |
|
305 */ |
|
306 bool ParseIntWithBounds(const nsAString& aString, int32_t aMin, |
|
307 int32_t aMax = INT32_MAX); |
|
308 |
|
309 /** |
|
310 * Parse a string value into a non-negative integer. |
|
311 * This method follows the rules for parsing non-negative integer from: |
|
312 * http://dev.w3.org/html5/spec/infrastructure.html#rules-for-parsing-non-negative-integers |
|
313 * |
|
314 * @param aString the string to parse |
|
315 * @return whether the value is valid |
|
316 */ |
|
317 bool ParseNonNegativeIntValue(const nsAString& aString); |
|
318 |
|
319 /** |
|
320 * Parse a string value into a positive integer. |
|
321 * This method follows the rules for parsing non-negative integer from: |
|
322 * http://dev.w3.org/html5/spec/infrastructure.html#rules-for-parsing-non-negative-integers |
|
323 * In addition of these rules, the value has to be greater than zero. |
|
324 * |
|
325 * This is generally used for parsing content attributes which reflecting IDL |
|
326 * attributes are limited to only non-negative numbers greater than zero, see: |
|
327 * http://dev.w3.org/html5/spec/common-dom-interfaces.html#limited-to-only-non-negative-numbers-greater-than-zero |
|
328 * |
|
329 * @param aString the string to parse |
|
330 * @return whether the value was valid |
|
331 */ |
|
332 bool ParsePositiveIntValue(const nsAString& aString); |
|
333 |
|
334 /** |
|
335 * Parse a string into a color. This implements what HTML5 calls the |
|
336 * "rules for parsing a legacy color value". |
|
337 * |
|
338 * @param aString the string to parse |
|
339 * @return whether the value could be parsed |
|
340 */ |
|
341 bool ParseColor(const nsAString& aString); |
|
342 |
|
343 /** |
|
344 * Parse a string value into a double-precision floating point value. |
|
345 * |
|
346 * @param aString the string to parse |
|
347 * @return whether the value could be parsed |
|
348 */ |
|
349 bool ParseDoubleValue(const nsAString& aString); |
|
350 |
|
351 /** |
|
352 * Parse a lazy URI. This just sets up the storage for the URI; it |
|
353 * doesn't actually allocate it. |
|
354 */ |
|
355 bool ParseLazyURIValue(const nsAString& aString); |
|
356 |
|
357 /** |
|
358 * Parse a margin string of format 'top, right, bottom, left' into |
|
359 * an nsIntMargin. |
|
360 * |
|
361 * @param aString the string to parse |
|
362 * @return whether the value could be parsed |
|
363 */ |
|
364 bool ParseIntMarginValue(const nsAString& aString); |
|
365 |
|
366 /** |
|
367 * Convert a URL nsAttrValue to an Image nsAttrValue. |
|
368 * |
|
369 * @param aDocument the document this nsAttrValue belongs to. |
|
370 */ |
|
371 void LoadImage(nsIDocument* aDocument); |
|
372 |
|
373 /** |
|
374 * Parse a string into a CSS style rule. |
|
375 * |
|
376 * @param aString the style attribute value to be parsed. |
|
377 * @param aElement the element the attribute is set on. |
|
378 */ |
|
379 bool ParseStyleAttribute(const nsAString& aString, |
|
380 nsStyledElementNotElementCSSInlineStyle* aElement); |
|
381 |
|
382 size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; |
|
383 |
|
384 private: |
|
385 // These have to be the same as in ValueType |
|
386 enum ValueBaseType { |
|
387 eStringBase = eString, // 00 |
|
388 eOtherBase = 0x01, // 01 |
|
389 eAtomBase = eAtom, // 10 |
|
390 eIntegerBase = 0x03 // 11 |
|
391 }; |
|
392 |
|
393 inline ValueBaseType BaseType() const; |
|
394 inline bool IsSVGType(ValueType aType) const; |
|
395 |
|
396 /** |
|
397 * Get the index of an EnumTable in the sEnumTableArray. |
|
398 * If the EnumTable is not in the sEnumTableArray, it is added. |
|
399 * |
|
400 * @param aTable the EnumTable to get the index of. |
|
401 * @return the index of the EnumTable. |
|
402 */ |
|
403 int16_t GetEnumTableIndex(const EnumTable* aTable); |
|
404 |
|
405 inline void SetPtrValueAndType(void* aValue, ValueBaseType aType); |
|
406 void SetIntValueAndType(int32_t aValue, ValueType aType, |
|
407 const nsAString* aStringValue); |
|
408 void SetColorValue(nscolor aColor, const nsAString& aString); |
|
409 void SetMiscAtomOrString(const nsAString* aValue); |
|
410 void ResetMiscAtomOrString(); |
|
411 void SetSVGType(ValueType aType, const void* aValue, |
|
412 const nsAString* aSerialized); |
|
413 inline void ResetIfSet(); |
|
414 |
|
415 inline void* GetPtr() const; |
|
416 inline MiscContainer* GetMiscContainer() const; |
|
417 inline int32_t GetIntInternal() const; |
|
418 |
|
419 // Clears the current MiscContainer. This will return null if there is no |
|
420 // existing container. |
|
421 MiscContainer* ClearMiscContainer(); |
|
422 // Like ClearMiscContainer, except allocates a new container if one does not |
|
423 // exist already. |
|
424 MiscContainer* EnsureEmptyMiscContainer(); |
|
425 bool EnsureEmptyAtomArray(); |
|
426 already_AddRefed<nsStringBuffer> |
|
427 GetStringBuffer(const nsAString& aValue) const; |
|
428 // aStrict is set true if stringifying the return value equals with |
|
429 // aValue. |
|
430 int32_t StringToInteger(const nsAString& aValue, |
|
431 bool* aStrict, |
|
432 nsresult* aErrorCode, |
|
433 bool aCanBePercent = false, |
|
434 bool* aIsPercent = nullptr) const; |
|
435 // Given an enum table and a particular entry in that table, return |
|
436 // the actual integer value we should store. |
|
437 int32_t EnumTableEntryToValue(const EnumTable* aEnumTable, |
|
438 const EnumTable* aTableEntry); |
|
439 |
|
440 static nsTArray<const EnumTable*>* sEnumTableArray; |
|
441 |
|
442 uintptr_t mBits; |
|
443 }; |
|
444 |
|
445 inline const nsAttrValue& |
|
446 nsAttrValue::operator=(const nsAttrValue& aOther) |
|
447 { |
|
448 SetTo(aOther); |
|
449 return *this; |
|
450 } |
|
451 |
|
452 inline nsIAtom* |
|
453 nsAttrValue::GetAtomValue() const |
|
454 { |
|
455 NS_PRECONDITION(Type() == eAtom, "wrong type"); |
|
456 return reinterpret_cast<nsIAtom*>(GetPtr()); |
|
457 } |
|
458 |
|
459 inline nsAttrValue::ValueBaseType |
|
460 nsAttrValue::BaseType() const |
|
461 { |
|
462 return static_cast<ValueBaseType>(mBits & NS_ATTRVALUE_BASETYPE_MASK); |
|
463 } |
|
464 |
|
465 inline void* |
|
466 nsAttrValue::GetPtr() const |
|
467 { |
|
468 NS_ASSERTION(BaseType() != eIntegerBase, |
|
469 "getting pointer from non-pointer"); |
|
470 return reinterpret_cast<void*>(mBits & NS_ATTRVALUE_POINTERVALUE_MASK); |
|
471 } |
|
472 |
|
473 inline bool |
|
474 nsAttrValue::IsEmptyString() const |
|
475 { |
|
476 return !mBits; |
|
477 } |
|
478 |
|
479 inline void |
|
480 nsAttrValue::ToString(mozilla::dom::DOMString& aResult) const |
|
481 { |
|
482 switch (Type()) { |
|
483 case eString: |
|
484 { |
|
485 nsStringBuffer* str = static_cast<nsStringBuffer*>(GetPtr()); |
|
486 if (str) { |
|
487 aResult.SetStringBuffer(str, str->StorageSize()/sizeof(char16_t) - 1); |
|
488 } |
|
489 // else aResult is already empty |
|
490 return; |
|
491 } |
|
492 case eAtom: |
|
493 { |
|
494 nsIAtom *atom = static_cast<nsIAtom*>(GetPtr()); |
|
495 aResult.SetStringBuffer(atom->GetStringBuffer(), atom->GetLength()); |
|
496 break; |
|
497 } |
|
498 default: |
|
499 { |
|
500 ToString(aResult.AsAString()); |
|
501 } |
|
502 } |
|
503 } |
|
504 |
|
505 #endif |