Backed out changeset 2450366cf7ca (bug 1891629) for causing win msix mochitest failures
[gecko.git] / dom / base / nsAttrValue.h
blob4ef63c287f6a8fea756b3520522d575ae91fbe8d
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/. */
7 /*
8 * A struct that represents the value (type and actual data) of an
9 * attribute.
12 #ifndef nsAttrValue_h___
13 #define nsAttrValue_h___
15 #include <type_traits>
17 #include "nscore.h"
18 #include "nsString.h"
19 #include "nsStringBuffer.h"
20 #include "nsColor.h"
21 #include "nsCaseTreatment.h"
22 #include "nsMargin.h"
23 #include "nsStringFwd.h"
24 #include "nsTArrayForwardDeclare.h"
25 #include "nsAtom.h"
26 #include "mozilla/AtomArray.h"
27 #include "mozilla/EnumTypeTraits.h"
28 #include "mozilla/MemoryReporting.h"
30 class nsIPrincipal;
31 class nsIURI;
32 class nsStyledElement;
33 struct MiscContainer;
35 namespace mozilla {
36 class DeclarationBlock;
37 class ShadowParts;
38 class SVGAnimatedIntegerPair;
39 class SVGAnimatedLength;
40 class SVGAnimatedNumberPair;
41 class SVGAnimatedOrient;
42 class SVGAnimatedPreserveAspectRatio;
43 class SVGAnimatedViewBox;
44 class SVGLengthList;
45 class SVGNumberList;
46 class SVGPathData;
47 class SVGPointList;
48 class SVGStringList;
49 class SVGTransformList;
51 struct AttrAtomArray {
52 AtomArray mArray;
53 mutable bool mMayContainDuplicates = false;
54 UniquePtr<AttrAtomArray> CreateDeduplicatedCopyIfDifferent() const {
55 if (!mMayContainDuplicates) {
56 return nullptr;
58 return CreateDeduplicatedCopyIfDifferentImpl();
60 bool operator==(const AttrAtomArray& aOther) const {
61 return mArray == aOther.mArray;
64 private:
65 UniquePtr<AttrAtomArray> CreateDeduplicatedCopyIfDifferentImpl() const;
68 namespace dom {
69 class DOMString;
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)))
97 /**
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 {
109 public:
110 explicit nsCheapString(nsStringBuffer* aBuf) {
111 if (aBuf) aBuf->ToString(aBuf->StorageSize() / sizeof(char16_t) - 1, *this);
115 class nsAttrValue {
116 friend struct MiscContainer;
118 public:
119 // This has to be the same as in ValueBaseType
120 enum ValueType {
121 eString = 0x00, // 00
122 // 01 this value indicates a 'misc' struct
123 eAtom = 0x02, // 10
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'
129 // struct.
130 eCSSDeclaration = 0x10,
131 eURL,
132 eImage,
133 eAtomArray,
134 eDoubleValue,
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.
138 eShadowParts,
139 eSVGIntegerPair,
140 eSVGTypesBegin = eSVGIntegerPair,
141 eSVGOrient,
142 eSVGLength,
143 eSVGLengthList,
144 eSVGNumberList,
145 eSVGNumberPair,
146 eSVGPathData,
147 eSVGPointList,
148 eSVGPreserveAspectRatio,
149 eSVGStringList,
150 eSVGTransformList,
151 eSVGViewBox,
152 eSVGTypesEnd = eSVGViewBox,
155 nsAttrValue();
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);
161 ~nsAttrValue();
163 inline const nsAttrValue& operator=(const nsAttrValue& aOther);
165 static void Init();
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;
176 void Reset();
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
215 * eAtom.
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[] = {
311 * { "string1", 1 },
312 * { "string2", 2 },
313 * { nullptr, 0 }
316 struct EnumTable {
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 */
334 const char* tag;
335 /** The enum value that maps to this string */
336 int16_t value;
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,
351 bool aCaseSensitive,
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;
489 private:
490 // These have to be the same as in ValueType
491 enum ValueBaseType {
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
531 // exist already.
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);
558 uintptr_t mBits;
561 inline const nsAttrValue& nsAttrValue::operator=(const nsAttrValue& aOther) {
562 SetTo(aOther);
563 return *this;
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; }
577 #endif