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/. */
8 * A struct that represents the value (type and actual data) of an
12 #ifndef nsAttrValue_h___
13 #define nsAttrValue_h___
15 #include <type_traits>
19 #include "nsStringBuffer.h"
21 #include "nsCaseTreatment.h"
23 #include "nsStringFwd.h"
24 #include "nsTArrayForwardDeclare.h"
25 #include "mozilla/AtomArray.h"
26 #include "mozilla/EnumTypeTraits.h"
27 #include "mozilla/MemoryReporting.h"
32 class nsStyledElement
;
36 class DeclarationBlock
;
38 class SVGAnimatedIntegerPair
;
39 class SVGAnimatedLength
;
40 class SVGAnimatedNumberPair
;
41 class SVGAnimatedOrient
;
42 class SVGAnimatedPreserveAspectRatio
;
43 class SVGAnimatedViewBox
;
49 class SVGTransformList
;
54 } // namespace mozilla
56 #define NS_ATTRVALUE_MAX_STRINGLENGTH_ATOM 12
58 const uintptr_t NS_ATTRVALUE_BASETYPE_MASK
= 3;
59 #define NS_ATTRVALUE_POINTERVALUE_MASK (~NS_ATTRVALUE_BASETYPE_MASK)
61 #define NS_ATTRVALUE_INTEGERTYPE_BITS 4
62 #define NS_ATTRVALUE_INTEGERTYPE_MASK \
63 (uintptr_t((1 << NS_ATTRVALUE_INTEGERTYPE_BITS) - 1))
64 #define NS_ATTRVALUE_INTEGERTYPE_MULTIPLIER (1 << NS_ATTRVALUE_INTEGERTYPE_BITS)
65 #define NS_ATTRVALUE_INTEGERTYPE_MAXVALUE \
66 ((1 << (31 - NS_ATTRVALUE_INTEGERTYPE_BITS)) - 1)
67 #define NS_ATTRVALUE_INTEGERTYPE_MINVALUE \
68 (-NS_ATTRVALUE_INTEGERTYPE_MAXVALUE - 1)
70 #define NS_ATTRVALUE_ENUMTABLEINDEX_BITS \
71 (32 - 16 - NS_ATTRVALUE_INTEGERTYPE_BITS)
72 #define NS_ATTRVALUE_ENUMTABLE_VALUE_NEEDS_TO_UPPER \
73 (1 << (NS_ATTRVALUE_ENUMTABLEINDEX_BITS - 1))
74 #define NS_ATTRVALUE_ENUMTABLEINDEX_MAXVALUE \
75 (NS_ATTRVALUE_ENUMTABLE_VALUE_NEEDS_TO_UPPER - 1)
76 #define NS_ATTRVALUE_ENUMTABLEINDEX_MASK \
77 (uintptr_t((((1 << NS_ATTRVALUE_ENUMTABLEINDEX_BITS) - 1) & \
78 ~NS_ATTRVALUE_ENUMTABLE_VALUE_NEEDS_TO_UPPER)))
81 * A class used to construct a nsString from a nsStringBuffer (we might
82 * want to move this to nsString at some point).
84 * WARNING: Note that nsCheapString doesn't take an explicit length -- it
85 * assumes the string is maximally large, given the nsStringBuffer's storage
86 * size. This means the given string buffer *must* be sized exactly correctly
87 * for the string it contains (including one byte for a null terminator). If
88 * it has any unused storage space, then that will result in bogus characters
89 * at the end of our nsCheapString.
91 class nsCheapString
: public nsString
{
93 explicit nsCheapString(nsStringBuffer
* aBuf
) {
94 if (aBuf
) aBuf
->ToString(aBuf
->StorageSize() / sizeof(char16_t
) - 1, *this);
99 friend struct MiscContainer
;
102 // This has to be the same as in ValueBaseType
104 eString
= 0x00, // 00
105 // 01 this value indicates a 'misc' struct
107 eInteger
= 0x03, // 0011
108 eColor
= 0x07, // 0111
109 eEnum
= 0x0B, // 1011 This should eventually die
110 ePercent
= 0x0F, // 1111
111 // Values below here won't matter, they'll be always stored in the 'misc'
113 eCSSDeclaration
= 0x10,
119 // eShadowParts is refcounted in the misc container, as we do copy attribute
120 // values quite a bit (for example to process style invalidation), and the
121 // underlying value could get expensive to copy.
124 eSVGTypesBegin
= eSVGIntegerPair
,
132 eSVGPreserveAspectRatio
,
136 eSVGTypesEnd
= eSVGViewBox
,
140 nsAttrValue(const nsAttrValue
& aOther
);
141 explicit nsAttrValue(const nsAString
& aValue
);
142 explicit nsAttrValue(nsAtom
* aValue
);
143 nsAttrValue(already_AddRefed
<mozilla::DeclarationBlock
> aValue
,
144 const nsAString
* aSerialized
);
145 explicit nsAttrValue(const nsIntMargin
& aValue
);
148 inline const nsAttrValue
& operator=(const nsAttrValue
& aOther
);
151 static void Shutdown();
153 inline ValueType
Type() const;
154 // Returns true when this value is self-contained and does not depend on
155 // the state of its associated element.
156 // Returns false when this value depends on the state of its associated
157 // element and may be invalid if that state has been changed by changes to
158 // that element state outside of attribute setting.
159 inline bool StoresOwnData() const;
163 void SetTo(const nsAttrValue
& aOther
);
164 void SetTo(const nsAString
& aValue
);
165 void SetTo(nsAtom
* aValue
);
166 void SetTo(int16_t aInt
);
167 void SetTo(int32_t aInt
, const nsAString
* aSerialized
);
168 void SetTo(double aValue
, const nsAString
* aSerialized
);
169 void SetTo(already_AddRefed
<mozilla::DeclarationBlock
> aValue
,
170 const nsAString
* aSerialized
);
171 void SetTo(nsIURI
* aValue
, const nsAString
* aSerialized
);
172 void SetTo(const nsIntMargin
& aValue
);
173 void SetTo(const mozilla::SVGAnimatedIntegerPair
& aValue
,
174 const nsAString
* aSerialized
);
175 void SetTo(const mozilla::SVGAnimatedLength
& aValue
,
176 const nsAString
* aSerialized
);
177 void SetTo(const mozilla::SVGAnimatedNumberPair
& aValue
,
178 const nsAString
* aSerialized
);
179 void SetTo(const mozilla::SVGAnimatedOrient
& aValue
,
180 const nsAString
* aSerialized
);
181 void SetTo(const mozilla::SVGAnimatedPreserveAspectRatio
& aValue
,
182 const nsAString
* aSerialized
);
183 void SetTo(const mozilla::SVGAnimatedViewBox
& aValue
,
184 const nsAString
* aSerialized
);
185 void SetTo(const mozilla::SVGLengthList
& aValue
,
186 const nsAString
* aSerialized
);
187 void SetTo(const mozilla::SVGNumberList
& aValue
,
188 const nsAString
* aSerialized
);
189 void SetTo(const mozilla::SVGPathData
& aValue
, const nsAString
* aSerialized
);
190 void SetTo(const mozilla::SVGPointList
& aValue
, const nsAString
* aSerialized
);
191 void SetTo(const mozilla::SVGStringList
& aValue
,
192 const nsAString
* aSerialized
);
193 void SetTo(const mozilla::SVGTransformList
& aValue
,
194 const nsAString
* aSerialized
);
197 * Sets this object with the string or atom representation of aValue.
199 * After calling this method, this object will have type eString unless the
200 * type of aValue is eAtom, in which case this object will also have type
203 void SetToSerialized(const nsAttrValue
& aValue
);
205 void SwapValueWith(nsAttrValue
& aOther
);
207 void ToString(nsAString
& aResult
) const;
208 inline void ToString(mozilla::dom::DOMString
& aResult
) const;
211 * Returns the value of this object as an atom. If necessary, the value will
212 * first be serialised using ToString before converting to an atom.
214 already_AddRefed
<nsAtom
> GetAsAtom() const;
216 // Methods to get value. These methods do not convert so only use them
217 // to retrieve the datatype that this nsAttrValue has.
218 inline bool IsEmptyString() const;
219 const nsCheapString
GetStringValue() const;
220 inline nsAtom
* GetAtomValue() const;
221 inline int32_t GetIntegerValue() const;
222 bool GetColorValue(nscolor
& aColor
) const;
223 inline int16_t GetEnumValue() const;
224 inline double GetPercentValue() const;
225 inline mozilla::AtomArray
* GetAtomArrayValue() const;
226 inline mozilla::DeclarationBlock
* GetCSSDeclarationValue() const;
227 inline nsIURI
* GetURLValue() const;
228 inline double GetDoubleValue() const;
229 bool GetIntMarginValue(nsIntMargin
& aMargin
) const;
230 inline const mozilla::ShadowParts
& GetShadowPartsValue() const;
233 * Returns the string corresponding to the stored enum value.
235 * @param aResult the string representing the enum tag
236 * @param aRealTag wheter we want to have the real tag or the saved one
238 void GetEnumString(nsAString
& aResult
, bool aRealTag
) const;
240 // Methods to get access to atoms we may have
241 // Returns the number of atoms we have; 0 if we have none. It's OK
242 // to call this without checking the type first; it handles that.
243 uint32_t GetAtomCount() const;
244 // Returns the atom at aIndex (0-based). Do not call this with
245 // aIndex >= GetAtomCount().
246 nsAtom
* AtomAt(int32_t aIndex
) const;
248 uint32_t HashValue() const;
249 bool Equals(const nsAttrValue
& aOther
) const;
250 // aCaseSensitive == eIgnoreCase means ASCII case-insenstive matching
251 bool Equals(const nsAString
& aValue
, nsCaseTreatment aCaseSensitive
) const;
252 bool Equals(const nsAtom
* aValue
, nsCaseTreatment aCaseSensitive
) const;
253 bool HasPrefix(const nsAString
& aValue
, nsCaseTreatment aCaseSensitive
) const;
254 bool HasSuffix(const nsAString
& aValue
, nsCaseTreatment aCaseSensitive
) const;
255 bool HasSubstring(const nsAString
& aValue
,
256 nsCaseTreatment aCaseSensitive
) const;
259 * Compares this object with aOther according to their string representation.
261 * For example, when called on an object with type eInteger and value 4, and
262 * given aOther of type eString and value "4", EqualsAsStrings will return
263 * true (while Equals will return false).
265 bool EqualsAsStrings(const nsAttrValue
& aOther
) const;
268 * Returns true if this AttrValue is equal to the given atom, or is an
269 * array which contains the given atom.
271 bool Contains(nsAtom
* aValue
, nsCaseTreatment aCaseSensitive
) const;
273 * Returns true if this AttrValue is an atom equal to the given
274 * string, or is an array of atoms which contains the given string.
275 * This always does a case-sensitive comparison.
277 bool Contains(const nsAString
& aValue
) const;
279 void ParseAtom(const nsAString
& aValue
);
280 void ParseAtomArray(const nsAString
& aValue
);
281 void ParseStringOrAtom(const nsAString
& aValue
);
284 * Parses an exportparts attribute.
286 * https://drafts.csswg.org/css-shadow-parts/#parsing-mapping-list
288 void ParsePartMapping(const nsAString
&);
291 * Structure for a mapping from int (enum) values to strings. When you use
292 * it you generally create an array of them.
293 * Instantiate like this:
294 * EnumTable myTable[] = {
301 // EnumTable can be initialized either with an int16_t value
302 // or a value of an enumeration type that can fit within an int16_t.
304 constexpr EnumTable(const char* aTag
, int16_t aValue
)
305 : tag(aTag
), value(aValue
) {}
307 template <typename T
,
308 typename
= typename
std::enable_if
<std::is_enum
<T
>::value
>::type
>
309 constexpr EnumTable(const char* aTag
, T aValue
)
310 : tag(aTag
), value(static_cast<int16_t>(aValue
)) {
311 static_assert(mozilla::EnumTypeFitsWithin
<T
, int16_t>::value
,
312 "aValue must be an enum that fits within int16_t");
315 /** The string the value maps to */
317 /** The enum value that maps to this string */
322 * Parse into an enum value.
324 * @param aValue the string to find the value for
325 * @param aTable the enumeration to map with
326 * @param aCaseSensitive specify if the parsing has to be case sensitive
327 * @param aDefaultValue if non-null, this function will always return true.
328 * Failure to parse aValue as one of the values in aTable will just
329 * cause aDefaultValue->value to be stored as the enumeration value.
330 * @return whether the enum value was found or not
332 bool ParseEnumValue(const nsAString
& aValue
, const EnumTable
* aTable
,
334 const EnumTable
* aDefaultValue
= nullptr);
337 * Parse a string into a dimension value. This is similar to
338 * https://html.spec.whatwg.org/multipage/#rules-for-parsing-dimension-values
339 * but drops the fractional part of the value for now, until we figure out how
340 * to store that in our nsAttrValue.
342 * The resulting value (if the parse succeeds) is one of eInteger,
343 * eDoubleValue, or ePercent, depending on whether we found a fractional part
344 * and whether we found '%' at the end of the value.
346 * @param aInput the string to parse
347 * @return whether the value could be parsed
349 bool ParseHTMLDimension(const nsAString
& aInput
) {
350 return DoParseHTMLDimension(aInput
, false);
354 * Parse a string into a nonzero dimension value. This implements
355 * https://html.spec.whatwg.org/multipage/#rules-for-parsing-non-zero-dimension-values
356 * subject to the same constraints as ParseHTMLDimension above.
358 * @param aInput the string to parse
359 * @return whether the value could be parsed
361 bool ParseNonzeroHTMLDimension(const nsAString
& aInput
) {
362 return DoParseHTMLDimension(aInput
, true);
366 * Parse a string value into an integer.
368 * @param aString the string to parse
369 * @return whether the value could be parsed
371 bool ParseIntValue(const nsAString
& aString
) {
372 return ParseIntWithBounds(aString
, INT32_MIN
, INT32_MAX
);
376 * Parse a string value into an integer with minimum value and maximum value.
378 * @param aString the string to parse
379 * @param aMin the minimum value (if value is less it will be bumped up)
380 * @param aMax the maximum value (if value is greater it will be chopped down)
381 * @return whether the value could be parsed
383 bool ParseIntWithBounds(const nsAString
& aString
, int32_t aMin
,
384 int32_t aMax
= INT32_MAX
);
387 * Parse a string value into an integer with a fallback for invalid values.
388 * Also allows clamping to a maximum value to support col/colgroup.span (this
389 * is not per spec right now).
391 * @param aString the string to parse
392 * @param aDefault the default value
393 * @param aMax the maximum value (if value is greater it will be clamped)
395 void ParseIntWithFallback(const nsAString
& aString
, int32_t aDefault
,
396 int32_t aMax
= INT32_MAX
);
399 * Parse a string value into a non-negative integer.
400 * This method follows the rules for parsing non-negative integer from:
401 * http://dev.w3.org/html5/spec/infrastructure.html#rules-for-parsing-non-negative-integers
403 * @param aString the string to parse
404 * @return whether the value is valid
406 bool ParseNonNegativeIntValue(const nsAString
& aString
);
409 * Parse a string value into a clamped non-negative integer.
410 * This method follows the rules for parsing non-negative integer from:
411 * https://html.spec.whatwg.org/multipage/infrastructure.html#clamped-to-the-range
413 * @param aString the string to parse
414 * @param aDefault value to return for negative or invalid values
415 * @param aMin minimum value
416 * @param aMax maximum value
418 void ParseClampedNonNegativeInt(const nsAString
& aString
, int32_t aDefault
,
419 int32_t aMin
, int32_t aMax
);
422 * Parse a string value into a positive integer.
423 * This method follows the rules for parsing non-negative integer from:
424 * http://dev.w3.org/html5/spec/infrastructure.html#rules-for-parsing-non-negative-integers
425 * In addition of these rules, the value has to be greater than zero.
427 * This is generally used for parsing content attributes which reflecting IDL
428 * attributes are limited to only non-negative numbers greater than zero, see:
429 * http://dev.w3.org/html5/spec/common-dom-interfaces.html#limited-to-only-non-negative-numbers-greater-than-zero
431 * @param aString the string to parse
432 * @return whether the value was valid
434 bool ParsePositiveIntValue(const nsAString
& aString
);
437 * Parse a string into a color. This implements what HTML5 calls the
438 * "rules for parsing a legacy color value".
440 * @param aString the string to parse
441 * @return whether the value could be parsed
443 bool ParseColor(const nsAString
& aString
);
446 * Parse a string value into a double-precision floating point value.
448 * @param aString the string to parse
449 * @return whether the value could be parsed
451 bool ParseDoubleValue(const nsAString
& aString
);
454 * Parse a margin string of format 'top, right, bottom, left' into
457 * @param aString the string to parse
458 * @return whether the value could be parsed
460 bool ParseIntMarginValue(const nsAString
& aString
);
463 * Parse a string into a CSS style rule.
465 * @param aString the style attribute value to be parsed.
466 * @param aElement the element the attribute is set on.
467 * @param aMaybeScriptedPrincipal if available, the scripted principal
468 * responsible for this attribute value, as passed to
469 * Element::ParseAttribute.
471 bool ParseStyleAttribute(const nsAString
& aString
,
472 nsIPrincipal
* aMaybeScriptedPrincipal
,
473 nsStyledElement
* aElement
);
475 size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf
) const;
478 // These have to be the same as in ValueType
480 eStringBase
= eString
, // 00
481 eOtherBase
= 0x01, // 01
482 eAtomBase
= eAtom
, // 10
483 eIntegerBase
= 0x03 // 11
486 inline ValueBaseType
BaseType() const;
487 inline bool IsSVGType(ValueType aType
) const;
490 * Get the index of an EnumTable in the sEnumTableArray.
491 * If the EnumTable is not in the sEnumTableArray, it is added.
493 * @param aTable the EnumTable to get the index of.
494 * @return the index of the EnumTable.
496 int16_t GetEnumTableIndex(const EnumTable
* aTable
);
498 inline void SetPtrValueAndType(void* aValue
, ValueBaseType aType
);
499 void SetIntValueAndType(int32_t aValue
, ValueType aType
,
500 const nsAString
* aStringValue
);
501 // aType can be ePercent or eDoubleValue.
502 void SetDoubleValueAndType(double aValue
, ValueType aType
,
503 const nsAString
* aStringValue
);
504 void SetColorValue(nscolor aColor
, const nsAString
& aString
);
505 void SetMiscAtomOrString(const nsAString
* aValue
);
506 void ResetMiscAtomOrString();
507 void SetSVGType(ValueType aType
, const void* aValue
,
508 const nsAString
* aSerialized
);
509 inline void ResetIfSet();
511 inline void* GetPtr() const;
512 inline MiscContainer
* GetMiscContainer() const;
513 inline int32_t GetIntInternal() const;
515 // Clears the current MiscContainer. This will return null if there is no
516 // existing container.
517 MiscContainer
* ClearMiscContainer();
518 // Like ClearMiscContainer, except allocates a new container if one does not
520 MiscContainer
* EnsureEmptyMiscContainer();
521 bool EnsureEmptyAtomArray();
522 already_AddRefed
<nsStringBuffer
> GetStringBuffer(
523 const nsAString
& aValue
) const;
524 // Given an enum table and a particular entry in that table, return
525 // the actual integer value we should store.
526 int32_t EnumTableEntryToValue(const EnumTable
* aEnumTable
,
527 const EnumTable
* aTableEntry
);
529 template <typename F
>
530 bool SubstringCheck(const nsAString
& aValue
,
531 nsCaseTreatment aCaseSensitive
) const;
533 static MiscContainer
* AllocMiscContainer();
534 static void DeallocMiscContainer(MiscContainer
* aCont
);
536 static nsTArray
<const EnumTable
*>* sEnumTableArray
;
537 static MiscContainer
* sMiscContainerCache
;
540 * Helper for ParseHTMLDimension and ParseNonzeroHTMLDimension.
542 * @param aInput the string to parse
543 * @param aEnsureNonzero whether to fail the parse if the value is 0
544 * @return whether the value could be parsed
546 bool DoParseHTMLDimension(const nsAString
& aInput
, bool aEnsureNonzero
);
551 inline const nsAttrValue
& nsAttrValue::operator=(const nsAttrValue
& aOther
) {
556 inline nsAttrValue::ValueBaseType
nsAttrValue::BaseType() const {
557 return static_cast<ValueBaseType
>(mBits
& NS_ATTRVALUE_BASETYPE_MASK
);
560 inline void* nsAttrValue::GetPtr() const {
561 NS_ASSERTION(BaseType() != eIntegerBase
, "getting pointer from non-pointer");
562 return reinterpret_cast<void*>(mBits
& NS_ATTRVALUE_POINTERVALUE_MASK
);
565 inline bool nsAttrValue::IsEmptyString() const { return !mBits
; }