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"
26 #include "mozilla/AtomArray.h"
27 #include "mozilla/EnumTypeTraits.h"
28 #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
;
51 struct AttrAtomArray
{
53 mutable bool mMayContainDuplicates
= false;
54 UniquePtr
<AttrAtomArray
> CreateDeduplicatedCopyIfDifferent() const {
55 if (!mMayContainDuplicates
) {
58 return CreateDeduplicatedCopyIfDifferentImpl();
60 bool operator==(const AttrAtomArray
& aOther
) const {
61 return mArray
== aOther
.mArray
;
65 UniquePtr
<AttrAtomArray
> CreateDeduplicatedCopyIfDifferentImpl() const;
71 } // namespace mozilla
73 #define NS_ATTRVALUE_MAX_STRINGLENGTH_ATOM 12
75 const uintptr_t NS_ATTRVALUE_BASETYPE_MASK
= 3;
76 #define NS_ATTRVALUE_POINTERVALUE_MASK (~NS_ATTRVALUE_BASETYPE_MASK)
78 #define NS_ATTRVALUE_INTEGERTYPE_BITS 4
79 #define NS_ATTRVALUE_INTEGERTYPE_MASK \
80 (uintptr_t((1 << NS_ATTRVALUE_INTEGERTYPE_BITS) - 1))
81 #define NS_ATTRVALUE_INTEGERTYPE_MULTIPLIER (1 << NS_ATTRVALUE_INTEGERTYPE_BITS)
82 #define NS_ATTRVALUE_INTEGERTYPE_MAXVALUE \
83 ((1 << (31 - NS_ATTRVALUE_INTEGERTYPE_BITS)) - 1)
84 #define NS_ATTRVALUE_INTEGERTYPE_MINVALUE \
85 (-NS_ATTRVALUE_INTEGERTYPE_MAXVALUE - 1)
87 #define NS_ATTRVALUE_ENUMTABLEINDEX_BITS \
88 (32 - 16 - NS_ATTRVALUE_INTEGERTYPE_BITS)
89 #define NS_ATTRVALUE_ENUMTABLE_VALUE_NEEDS_TO_UPPER \
90 (1 << (NS_ATTRVALUE_ENUMTABLEINDEX_BITS - 1))
91 #define NS_ATTRVALUE_ENUMTABLEINDEX_MAXVALUE \
92 (NS_ATTRVALUE_ENUMTABLE_VALUE_NEEDS_TO_UPPER - 1)
93 #define NS_ATTRVALUE_ENUMTABLEINDEX_MASK \
94 (uintptr_t((((1 << NS_ATTRVALUE_ENUMTABLEINDEX_BITS) - 1) & \
95 ~NS_ATTRVALUE_ENUMTABLE_VALUE_NEEDS_TO_UPPER)))
98 * A class used to construct a nsString from a nsStringBuffer (we might
99 * want to move this to nsString at some point).
101 * WARNING: Note that nsCheapString doesn't take an explicit length -- it
102 * assumes the string is maximally large, given the nsStringBuffer's storage
103 * size. This means the given string buffer *must* be sized exactly correctly
104 * for the string it contains (including one byte for a null terminator). If
105 * it has any unused storage space, then that will result in bogus characters
106 * at the end of our nsCheapString.
108 class nsCheapString
: public nsString
{
110 explicit nsCheapString(nsStringBuffer
* aBuf
) {
111 if (aBuf
) aBuf
->ToString(aBuf
->StorageSize() / sizeof(char16_t
) - 1, *this);
116 friend struct MiscContainer
;
119 // This has to be the same as in ValueBaseType
121 eString
= 0x00, // 00
122 // 01 this value indicates a 'misc' struct
124 eInteger
= 0x03, // 0011
125 eColor
= 0x07, // 0111
126 eEnum
= 0x0B, // 1011 This should eventually die
127 ePercent
= 0x0F, // 1111
128 // Values below here won't matter, they'll be always stored in the 'misc'
130 eCSSDeclaration
= 0x10,
135 // eShadowParts is refcounted in the misc container, as we do copy attribute
136 // values quite a bit (for example to process style invalidation), and the
137 // underlying value could get expensive to copy.
140 eSVGTypesBegin
= eSVGIntegerPair
,
148 eSVGPreserveAspectRatio
,
152 eSVGTypesEnd
= eSVGViewBox
,
156 nsAttrValue(const nsAttrValue
& aOther
);
157 explicit nsAttrValue(const nsAString
& aValue
);
158 explicit nsAttrValue(nsAtom
* aValue
);
159 nsAttrValue(already_AddRefed
<mozilla::DeclarationBlock
> aValue
,
160 const nsAString
* aSerialized
);
163 inline const nsAttrValue
& operator=(const nsAttrValue
& aOther
);
166 static void Shutdown();
168 inline ValueType
Type() const;
169 // Returns true when this value is self-contained and does not depend on
170 // the state of its associated element.
171 // Returns false when this value depends on the state of its associated
172 // element and may be invalid if that state has been changed by changes to
173 // that element state outside of attribute setting.
174 inline bool StoresOwnData() const;
178 void SetTo(const nsAttrValue
& aOther
);
179 void SetTo(const nsAString
& aValue
);
180 void SetTo(nsAtom
* aValue
);
181 void SetTo(int16_t aInt
);
182 void SetTo(int32_t aInt
, const nsAString
* aSerialized
);
183 void SetTo(double aValue
, const nsAString
* aSerialized
);
184 void SetTo(already_AddRefed
<mozilla::DeclarationBlock
> aValue
,
185 const nsAString
* aSerialized
);
186 void SetTo(nsIURI
* aValue
, const nsAString
* aSerialized
);
187 void SetTo(const mozilla::SVGAnimatedIntegerPair
& aValue
,
188 const nsAString
* aSerialized
);
189 void SetTo(const mozilla::SVGAnimatedLength
& aValue
,
190 const nsAString
* aSerialized
);
191 void SetTo(const mozilla::SVGAnimatedNumberPair
& aValue
,
192 const nsAString
* aSerialized
);
193 void SetTo(const mozilla::SVGAnimatedOrient
& aValue
,
194 const nsAString
* aSerialized
);
195 void SetTo(const mozilla::SVGAnimatedPreserveAspectRatio
& aValue
,
196 const nsAString
* aSerialized
);
197 void SetTo(const mozilla::SVGAnimatedViewBox
& aValue
,
198 const nsAString
* aSerialized
);
199 void SetTo(const mozilla::SVGLengthList
& aValue
,
200 const nsAString
* aSerialized
);
201 void SetTo(const mozilla::SVGNumberList
& aValue
,
202 const nsAString
* aSerialized
);
203 void SetTo(const mozilla::SVGPathData
& aValue
, const nsAString
* aSerialized
);
204 void SetTo(const mozilla::SVGPointList
& aValue
, const nsAString
* aSerialized
);
205 void SetTo(const mozilla::SVGStringList
& aValue
,
206 const nsAString
* aSerialized
);
207 void SetTo(const mozilla::SVGTransformList
& aValue
,
208 const nsAString
* aSerialized
);
211 * Sets this object with the string or atom representation of aValue.
213 * After calling this method, this object will have type eString unless the
214 * type of aValue is eAtom, in which case this object will also have type
217 void SetToSerialized(const nsAttrValue
& aValue
);
219 void SwapValueWith(nsAttrValue
& aOther
);
221 void RemoveDuplicatesFromAtomArray();
223 void ToString(nsAString
& aResult
) const;
224 inline void ToString(mozilla::dom::DOMString
& aResult
) const;
227 * Returns the value of this object as an atom. If necessary, the value will
228 * first be serialised using ToString before converting to an atom.
230 already_AddRefed
<nsAtom
> GetAsAtom() const;
232 // Methods to get value. These methods do not convert so only use them
233 // to retrieve the datatype that this nsAttrValue has.
234 inline bool IsEmptyString() const;
235 const nsCheapString
GetStringValue() const;
236 inline nsAtom
* GetAtomValue() const;
237 inline int32_t GetIntegerValue() const;
238 bool GetColorValue(nscolor
& aColor
) const;
239 inline int16_t GetEnumValue() const;
240 inline double GetPercentValue() const;
241 inline const mozilla::AttrAtomArray
* GetAtomArrayValue() const;
242 inline mozilla::DeclarationBlock
* GetCSSDeclarationValue() const;
243 inline nsIURI
* GetURLValue() const;
244 inline double GetDoubleValue() const;
245 inline const mozilla::ShadowParts
& GetShadowPartsValue() const;
248 * Returns the string corresponding to the stored enum value.
250 * @param aResult the string representing the enum tag
251 * @param aRealTag wheter we want to have the real tag or the saved one
253 void GetEnumString(nsAString
& aResult
, bool aRealTag
) const;
255 // Methods to get access to atoms we may have
256 // Returns the number of atoms we have; 0 if we have none. It's OK
257 // to call this without checking the type first; it handles that.
258 uint32_t GetAtomCount() const;
259 // Returns the atom at aIndex (0-based). Do not call this with
260 // aIndex >= GetAtomCount().
261 nsAtom
* AtomAt(int32_t aIndex
) const;
263 uint32_t HashValue() const;
264 bool Equals(const nsAttrValue
& aOther
) const;
265 // aCaseSensitive == eIgnoreCase means ASCII case-insenstive matching
266 bool Equals(const nsAString
& aValue
, nsCaseTreatment aCaseSensitive
) const;
267 bool Equals(const nsAtom
* aValue
, nsCaseTreatment aCaseSensitive
) const;
268 bool HasPrefix(const nsAString
& aValue
, nsCaseTreatment aCaseSensitive
) const;
269 bool HasSuffix(const nsAString
& aValue
, nsCaseTreatment aCaseSensitive
) const;
270 bool HasSubstring(const nsAString
& aValue
,
271 nsCaseTreatment aCaseSensitive
) const;
274 * Compares this object with aOther according to their string representation.
276 * For example, when called on an object with type eInteger and value 4, and
277 * given aOther of type eString and value "4", EqualsAsStrings will return
278 * true (while Equals will return false).
280 bool EqualsAsStrings(const nsAttrValue
& aOther
) const;
283 * Returns true if this AttrValue is equal to the given atom, or is an
284 * array which contains the given atom.
286 bool Contains(nsAtom
* aValue
, nsCaseTreatment aCaseSensitive
) const;
288 * Returns true if this AttrValue is an atom equal to the given
289 * string, or is an array of atoms which contains the given string.
290 * This always does a case-sensitive comparison.
292 bool Contains(const nsAString
& aValue
) const;
294 void ParseAtom(const nsAString
& aValue
);
295 void ParseAtomArray(const nsAString
& aValue
);
296 void ParseAtomArray(nsAtom
* aValue
);
297 void ParseStringOrAtom(const nsAString
& aValue
);
300 * Parses an exportparts attribute.
302 * https://drafts.csswg.org/css-shadow-parts/#parsing-mapping-list
304 void ParsePartMapping(const nsAString
&);
307 * Structure for a mapping from int (enum) values to strings. When you use
308 * it you generally create an array of them.
309 * Instantiate like this:
310 * EnumTable myTable[] = {
317 // EnumTable can be initialized either with an int16_t value
318 // or a value of an enumeration type that can fit within an int16_t.
320 constexpr EnumTable(const char* aTag
, int16_t aValue
)
321 : tag(aTag
), value(aValue
) {}
323 template <typename T
,
324 typename
= typename
std::enable_if
<std::is_enum
<T
>::value
>::type
>
325 constexpr EnumTable(const char* aTag
, T aValue
)
326 : tag(aTag
), value(static_cast<int16_t>(aValue
)) {
327 static_assert(mozilla::EnumTypeFitsWithin
<T
, int16_t>::value
,
328 "aValue must be an enum that fits within int16_t");
329 // TODO: statically assert there are no duplicate values, otherwise
330 // `GetEnumString()` above will return wrong values.
333 /** The string the value maps to */
335 /** The enum value that maps to this string */
340 * Parse into an enum value.
342 * @param aValue the string to find the value for
343 * @param aTable the enumeration to map with
344 * @param aCaseSensitive specify if the parsing has to be case sensitive
345 * @param aDefaultValue if non-null, this function will always return true.
346 * Failure to parse aValue as one of the values in aTable will just
347 * cause aDefaultValue->value to be stored as the enumeration value.
348 * @return whether the enum value was found or not
350 bool ParseEnumValue(const nsAString
& aValue
, const EnumTable
* aTable
,
352 const EnumTable
* aDefaultValue
= nullptr);
355 * Parse a string into a dimension value. This is similar to
356 * https://html.spec.whatwg.org/multipage/#rules-for-parsing-dimension-values
357 * but drops the fractional part of the value for now, until we figure out how
358 * to store that in our nsAttrValue.
360 * The resulting value (if the parse succeeds) is one of eInteger,
361 * eDoubleValue, or ePercent, depending on whether we found a fractional part
362 * and whether we found '%' at the end of the value.
364 * @param aInput the string to parse
365 * @return whether the value could be parsed
367 bool ParseHTMLDimension(const nsAString
& aInput
) {
368 return DoParseHTMLDimension(aInput
, false);
372 * Parse a string into a nonzero dimension value. This implements
373 * https://html.spec.whatwg.org/multipage/#rules-for-parsing-non-zero-dimension-values
374 * subject to the same constraints as ParseHTMLDimension above.
376 * @param aInput the string to parse
377 * @return whether the value could be parsed
379 bool ParseNonzeroHTMLDimension(const nsAString
& aInput
) {
380 return DoParseHTMLDimension(aInput
, true);
384 * Parse a string value into an integer.
386 * @param aString the string to parse
387 * @return whether the value could be parsed
389 bool ParseIntValue(const nsAString
& aString
) {
390 return ParseIntWithBounds(aString
, INT32_MIN
, INT32_MAX
);
394 * Parse a string value into an integer with minimum value and maximum value.
396 * @param aString the string to parse
397 * @param aMin the minimum value (if value is less it will be bumped up)
398 * @param aMax the maximum value (if value is greater it will be chopped down)
399 * @return whether the value could be parsed
401 bool ParseIntWithBounds(const nsAString
& aString
, int32_t aMin
,
402 int32_t aMax
= INT32_MAX
);
405 * Parse a string value into an integer with a fallback for invalid values.
406 * Also allows clamping to a maximum value to support col/colgroup.span (this
407 * is not per spec right now).
409 * @param aString the string to parse
410 * @param aDefault the default value
411 * @param aMax the maximum value (if value is greater it will be clamped)
413 void ParseIntWithFallback(const nsAString
& aString
, int32_t aDefault
,
414 int32_t aMax
= INT32_MAX
);
417 * Parse a string value into a non-negative integer.
418 * This method follows the rules for parsing non-negative integer from:
419 * http://dev.w3.org/html5/spec/infrastructure.html#rules-for-parsing-non-negative-integers
421 * @param aString the string to parse
422 * @return whether the value is valid
424 bool ParseNonNegativeIntValue(const nsAString
& aString
);
427 * Parse a string value into a clamped non-negative integer.
428 * This method follows the rules for parsing non-negative integer from:
429 * https://html.spec.whatwg.org/multipage/infrastructure.html#clamped-to-the-range
431 * @param aString the string to parse
432 * @param aDefault value to return for negative or invalid values
433 * @param aMin minimum value
434 * @param aMax maximum value
436 void ParseClampedNonNegativeInt(const nsAString
& aString
, int32_t aDefault
,
437 int32_t aMin
, int32_t aMax
);
440 * Parse a string value into a positive integer.
441 * This method follows the rules for parsing non-negative integer from:
442 * http://dev.w3.org/html5/spec/infrastructure.html#rules-for-parsing-non-negative-integers
443 * In addition of these rules, the value has to be greater than zero.
445 * This is generally used for parsing content attributes which reflecting IDL
446 * attributes are limited to only non-negative numbers greater than zero, see:
447 * http://dev.w3.org/html5/spec/common-dom-interfaces.html#limited-to-only-non-negative-numbers-greater-than-zero
449 * @param aString the string to parse
450 * @return whether the value was valid
452 bool ParsePositiveIntValue(const nsAString
& aString
);
455 * Parse a string into a color. This implements what HTML5 calls the
456 * "rules for parsing a legacy color value".
458 * @param aString the string to parse
459 * @return whether the value could be parsed
461 bool ParseColor(const nsAString
& aString
);
464 * Parse a string value into a double-precision floating point value.
466 * @param aString the string to parse
467 * @return whether the value could be parsed
469 bool ParseDoubleValue(const nsAString
& aString
);
472 * Parse a string into a CSS style rule.
474 * @param aString the style attribute value to be parsed.
475 * @param aElement the element the attribute is set on.
476 * @param aMaybeScriptedPrincipal if available, the scripted principal
477 * responsible for this attribute value, as passed to
478 * Element::ParseAttribute.
480 bool ParseStyleAttribute(const nsAString
& aString
,
481 nsIPrincipal
* aMaybeScriptedPrincipal
,
482 nsStyledElement
* aElement
);
484 size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf
) const;
486 nsAtom
* GetStoredAtom() const;
487 nsStringBuffer
* GetStoredStringBuffer() const;
490 // These have to be the same as in ValueType
492 eStringBase
= eString
, // 00
493 eOtherBase
= 0x01, // 01
494 eAtomBase
= eAtom
, // 10
495 eIntegerBase
= 0x03 // 11
498 inline ValueBaseType
BaseType() const;
499 inline bool IsSVGType(ValueType aType
) const;
502 * Get the index of an EnumTable in the sEnumTableArray.
503 * If the EnumTable is not in the sEnumTableArray, it is added.
505 * @param aTable the EnumTable to get the index of.
506 * @return the index of the EnumTable.
508 int16_t GetEnumTableIndex(const EnumTable
* aTable
);
510 inline void SetPtrValueAndType(void* aValue
, ValueBaseType aType
);
511 void SetIntValueAndType(int32_t aValue
, ValueType aType
,
512 const nsAString
* aStringValue
);
513 // aType can be ePercent or eDoubleValue.
514 void SetDoubleValueAndType(double aValue
, ValueType aType
,
515 const nsAString
* aStringValue
);
516 void SetColorValue(nscolor aColor
, const nsAString
& aString
);
517 void SetMiscAtomOrString(const nsAString
* aValue
);
518 void ResetMiscAtomOrString();
519 void SetSVGType(ValueType aType
, const void* aValue
,
520 const nsAString
* aSerialized
);
521 inline void ResetIfSet();
523 inline void* GetPtr() const;
524 inline MiscContainer
* GetMiscContainer() const;
525 inline int32_t GetIntInternal() const;
527 // Clears the current MiscContainer. This will return null if there is no
528 // existing container.
529 MiscContainer
* ClearMiscContainer();
530 // Like ClearMiscContainer, except allocates a new container if one does not
532 MiscContainer
* EnsureEmptyMiscContainer();
533 already_AddRefed
<nsStringBuffer
> GetStringBuffer(
534 const nsAString
& aValue
) const;
535 // Given an enum table and a particular entry in that table, return
536 // the actual integer value we should store.
537 int32_t EnumTableEntryToValue(const EnumTable
* aEnumTable
,
538 const EnumTable
* aTableEntry
);
540 template <typename F
>
541 bool SubstringCheck(const nsAString
& aValue
,
542 nsCaseTreatment aCaseSensitive
) const;
544 static MiscContainer
* AllocMiscContainer();
545 static void DeallocMiscContainer(MiscContainer
* aCont
);
547 static nsTArray
<const EnumTable
*>* sEnumTableArray
;
550 * Helper for ParseHTMLDimension and ParseNonzeroHTMLDimension.
552 * @param aInput the string to parse
553 * @param aEnsureNonzero whether to fail the parse if the value is 0
554 * @return whether the value could be parsed
556 bool DoParseHTMLDimension(const nsAString
& aInput
, bool aEnsureNonzero
);
561 inline const nsAttrValue
& nsAttrValue::operator=(const nsAttrValue
& aOther
) {
566 inline nsAttrValue::ValueBaseType
nsAttrValue::BaseType() const {
567 return static_cast<ValueBaseType
>(mBits
& NS_ATTRVALUE_BASETYPE_MASK
);
570 inline void* nsAttrValue::GetPtr() const {
571 NS_ASSERTION(BaseType() != eIntegerBase
, "getting pointer from non-pointer");
572 return reinterpret_cast<void*>(mBits
& NS_ATTRVALUE_POINTERVALUE_MASK
);
575 inline bool nsAttrValue::IsEmptyString() const { return !mBits
; }