Bug 1750871 - run mochitest-remote on fission everywhere. r=releng-reviewers,aki
[gecko.git] / dom / base / nsAttrValue.h
blob7f2e6c230eea686dc24c7824b757675844a2b58d
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 "mozilla/AtomArray.h"
26 #include "mozilla/EnumTypeTraits.h"
27 #include "mozilla/MemoryReporting.h"
29 class nsAtom;
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 namespace dom {
52 class DOMString;
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)))
80 /**
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 {
92 public:
93 explicit nsCheapString(nsStringBuffer* aBuf) {
94 if (aBuf) aBuf->ToString(aBuf->StorageSize() / sizeof(char16_t) - 1, *this);
98 class nsAttrValue {
99 friend struct MiscContainer;
101 public:
102 // This has to be the same as in ValueBaseType
103 enum ValueType {
104 eString = 0x00, // 00
105 // 01 this value indicates a 'misc' struct
106 eAtom = 0x02, // 10
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'
112 // struct.
113 eCSSDeclaration = 0x10,
114 eURL,
115 eImage,
116 eAtomArray,
117 eDoubleValue,
118 eIntMarginValue,
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.
122 eShadowParts,
123 eSVGIntegerPair,
124 eSVGTypesBegin = eSVGIntegerPair,
125 eSVGOrient,
126 eSVGLength,
127 eSVGLengthList,
128 eSVGNumberList,
129 eSVGNumberPair,
130 eSVGPathData,
131 eSVGPointList,
132 eSVGPreserveAspectRatio,
133 eSVGStringList,
134 eSVGTransformList,
135 eSVGViewBox,
136 eSVGTypesEnd = eSVGViewBox,
139 nsAttrValue();
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);
146 ~nsAttrValue();
148 inline const nsAttrValue& operator=(const nsAttrValue& aOther);
150 static void Init();
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;
161 void Reset();
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
201 * eAtom.
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[] = {
295 * { "string1", 1 },
296 * { "string2", 2 },
297 * { nullptr, 0 }
300 struct EnumTable {
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 */
316 const char* tag;
317 /** The enum value that maps to this string */
318 int16_t value;
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,
333 bool aCaseSensitive,
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
455 * an nsIntMargin.
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;
477 private:
478 // These have to be the same as in ValueType
479 enum ValueBaseType {
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
519 // exist already.
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);
548 uintptr_t mBits;
551 inline const nsAttrValue& nsAttrValue::operator=(const nsAttrValue& aOther) {
552 SetTo(aOther);
553 return *this;
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; }
567 #endif