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/. */
6 
7 /* representation of simple property values within CSS declarations */
8 
9 #include "nsCSSValue.h"
10 
11 #include "mozilla/CORSMode.h"
12 #include "mozilla/ServoBindings.h"
13 #include "mozilla/ServoStyleSet.h"
14 #include "mozilla/ServoTypes.h"
15 #include "mozilla/StyleSheetInlines.h"
16 #include "mozilla/Likely.h"
17 #include "mozilla/MemoryReporting.h"
18 #include "mozilla/css/ImageLoader.h"
19 #include "CSSCalc.h"
20 #include "gfxFontConstants.h"
21 #include "imgIRequest.h"
22 #include "imgRequestProxy.h"
23 #include "nsIDocument.h"
24 #include "nsIURIMutator.h"
25 #include "nsCSSProps.h"
26 #include "nsNetUtil.h"
27 #include "nsPresContext.h"
28 #include "nsStyleUtil.h"
29 #include "nsDeviceContext.h"
30 #ifdef MOZ_OLD_STYLE
31 #include "nsStyleSet.h"
32 #endif
33 #include "nsContentUtils.h"
34 
35 using namespace mozilla;
36 using namespace mozilla::css;
37 
38 template <class T>
MightHaveRef(const T & aString)39 static bool MightHaveRef(const T& aString) {
40   const typename T::char_type* current = aString.BeginReading();
41   for (; current != aString.EndReading(); current++) {
42     if (*current == '#') {
43       return true;
44     }
45   }
46 
47   return false;
48 }
49 
nsCSSValue(int32_t aValue,nsCSSUnit aUnit)50 nsCSSValue::nsCSSValue(int32_t aValue, nsCSSUnit aUnit) : mUnit(aUnit) {
51   MOZ_ASSERT(aUnit == eCSSUnit_Integer || aUnit == eCSSUnit_Enumerated ||
52                  aUnit == eCSSUnit_EnumColor,
53              "not an int value");
54   if (aUnit == eCSSUnit_Integer || aUnit == eCSSUnit_Enumerated ||
55       aUnit == eCSSUnit_EnumColor) {
56     mValue.mInt = aValue;
57   } else {
58     mUnit = eCSSUnit_Null;
59     mValue.mInt = 0;
60   }
61 }
62 
nsCSSValue(float aValue,nsCSSUnit aUnit)63 nsCSSValue::nsCSSValue(float aValue, nsCSSUnit aUnit) : mUnit(aUnit) {
64   MOZ_ASSERT(eCSSUnit_Percent <= aUnit, "not a float value");
65   if (eCSSUnit_Percent <= aUnit) {
66     mValue.mFloat = aValue;
67     MOZ_ASSERT(!mozilla::IsNaN(mValue.mFloat));
68   } else {
69     mUnit = eCSSUnit_Null;
70     mValue.mInt = 0;
71   }
72 }
73 
nsCSSValue(const nsString & aValue,nsCSSUnit aUnit)74 nsCSSValue::nsCSSValue(const nsString& aValue, nsCSSUnit aUnit) : mUnit(aUnit) {
75   MOZ_ASSERT(UnitHasStringValue(), "not a string value");
76   if (UnitHasStringValue()) {
77     mValue.mString = BufferFromString(aValue).take();
78   } else {
79     mUnit = eCSSUnit_Null;
80     mValue.mInt = 0;
81   }
82 }
83 
nsCSSValue(nsCSSValue::Array * aValue,nsCSSUnit aUnit)84 nsCSSValue::nsCSSValue(nsCSSValue::Array* aValue, nsCSSUnit aUnit)
85     : mUnit(aUnit) {
86   MOZ_ASSERT(UnitHasArrayValue(), "bad unit");
87   mValue.mArray = aValue;
88   mValue.mArray->AddRef();
89 }
90 
nsCSSValue(mozilla::css::URLValue * aValue)91 nsCSSValue::nsCSSValue(mozilla::css::URLValue* aValue) : mUnit(eCSSUnit_URL) {
92   mValue.mURL = aValue;
93   mValue.mURL->AddRef();
94 }
95 
nsCSSValue(mozilla::css::ImageValue * aValue)96 nsCSSValue::nsCSSValue(mozilla::css::ImageValue* aValue)
97     : mUnit(eCSSUnit_Image) {
98   mValue.mImage = aValue;
99   mValue.mImage->AddRef();
100 }
101 
nsCSSValue(nsCSSValueGradient * aValue)102 nsCSSValue::nsCSSValue(nsCSSValueGradient* aValue) : mUnit(eCSSUnit_Gradient) {
103   mValue.mGradient = aValue;
104   mValue.mGradient->AddRef();
105 }
106 
nsCSSValue(nsCSSValueTokenStream * aValue)107 nsCSSValue::nsCSSValue(nsCSSValueTokenStream* aValue)
108     : mUnit(eCSSUnit_TokenStream) {
109   mValue.mTokenStream = aValue;
110   mValue.mTokenStream->AddRef();
111 }
112 
nsCSSValue(mozilla::css::GridTemplateAreasValue * aValue)113 nsCSSValue::nsCSSValue(mozilla::css::GridTemplateAreasValue* aValue)
114     : mUnit(eCSSUnit_GridTemplateAreas) {
115   mValue.mGridTemplateAreas = aValue;
116   mValue.mGridTemplateAreas->AddRef();
117 }
118 
nsCSSValue(SharedFontList * aValue)119 nsCSSValue::nsCSSValue(SharedFontList* aValue)
120     : mUnit(eCSSUnit_FontFamilyList) {
121   mValue.mFontFamilyList = aValue;
122   mValue.mFontFamilyList->AddRef();
123 }
124 
nsCSSValue(const nsCSSValue & aCopy)125 nsCSSValue::nsCSSValue(const nsCSSValue& aCopy) : mUnit(aCopy.mUnit) {
126   if (mUnit <= eCSSUnit_DummyInherit) {
127     // nothing to do, but put this important case first
128   } else if (eCSSUnit_Percent <= mUnit) {
129     mValue.mFloat = aCopy.mValue.mFloat;
130     MOZ_ASSERT(!mozilla::IsNaN(mValue.mFloat));
131   } else if (UnitHasStringValue()) {
132     mValue.mString = aCopy.mValue.mString;
133     mValue.mString->AddRef();
134   } else if (eCSSUnit_Integer <= mUnit && mUnit <= eCSSUnit_EnumColor) {
135     mValue.mInt = aCopy.mValue.mInt;
136   } else if (IsIntegerColorUnit()) {
137     mValue.mColor = aCopy.mValue.mColor;
138   } else if (IsFloatColorUnit()) {
139     mValue.mFloatColor = aCopy.mValue.mFloatColor;
140     mValue.mFloatColor->AddRef();
141   } else if (eCSSUnit_ComplexColor == mUnit) {
142     mValue.mComplexColor = aCopy.mValue.mComplexColor;
143     mValue.mComplexColor->AddRef();
144   } else if (UnitHasArrayValue()) {
145     mValue.mArray = aCopy.mValue.mArray;
146     mValue.mArray->AddRef();
147   } else if (eCSSUnit_URL == mUnit) {
148     mValue.mURL = aCopy.mValue.mURL;
149     mValue.mURL->AddRef();
150   } else if (eCSSUnit_Image == mUnit) {
151     mValue.mImage = aCopy.mValue.mImage;
152     mValue.mImage->AddRef();
153   } else if (eCSSUnit_Gradient == mUnit) {
154     mValue.mGradient = aCopy.mValue.mGradient;
155     mValue.mGradient->AddRef();
156   } else if (eCSSUnit_TokenStream == mUnit) {
157     mValue.mTokenStream = aCopy.mValue.mTokenStream;
158     mValue.mTokenStream->AddRef();
159   } else if (eCSSUnit_Pair == mUnit) {
160     mValue.mPair = aCopy.mValue.mPair;
161     mValue.mPair->AddRef();
162   } else if (eCSSUnit_Triplet == mUnit) {
163     mValue.mTriplet = aCopy.mValue.mTriplet;
164     mValue.mTriplet->AddRef();
165   } else if (eCSSUnit_Rect == mUnit) {
166     mValue.mRect = aCopy.mValue.mRect;
167     mValue.mRect->AddRef();
168   } else if (eCSSUnit_List == mUnit) {
169     mValue.mList = aCopy.mValue.mList;
170     mValue.mList->AddRef();
171   } else if (eCSSUnit_ListDep == mUnit) {
172     mValue.mListDependent = aCopy.mValue.mListDependent;
173   } else if (eCSSUnit_SharedList == mUnit) {
174     mValue.mSharedList = aCopy.mValue.mSharedList;
175     mValue.mSharedList->AddRef();
176   } else if (eCSSUnit_PairList == mUnit) {
177     mValue.mPairList = aCopy.mValue.mPairList;
178     mValue.mPairList->AddRef();
179   } else if (eCSSUnit_PairListDep == mUnit) {
180     mValue.mPairListDependent = aCopy.mValue.mPairListDependent;
181   } else if (eCSSUnit_GridTemplateAreas == mUnit) {
182     mValue.mGridTemplateAreas = aCopy.mValue.mGridTemplateAreas;
183     mValue.mGridTemplateAreas->AddRef();
184   } else if (eCSSUnit_FontFamilyList == mUnit) {
185     mValue.mFontFamilyList = aCopy.mValue.mFontFamilyList;
186     mValue.mFontFamilyList->AddRef();
187   } else if (eCSSUnit_AtomIdent == mUnit) {
188     mValue.mAtom = aCopy.mValue.mAtom;
189     mValue.mAtom->AddRef();
190   } else {
191     MOZ_ASSERT(false, "unknown unit");
192   }
193 }
194 
operator =(const nsCSSValue & aCopy)195 nsCSSValue& nsCSSValue::operator=(const nsCSSValue& aCopy) {
196   if (this != &aCopy) {
197     Reset();
198     new (this) nsCSSValue(aCopy);
199   }
200   return *this;
201 }
202 
operator =(nsCSSValue && aOther)203 nsCSSValue& nsCSSValue::operator=(nsCSSValue&& aOther) {
204   MOZ_ASSERT(this != &aOther, "Self assigment with rvalue reference");
205 
206   Reset();
207   mUnit = aOther.mUnit;
208   mValue = aOther.mValue;
209   aOther.mUnit = eCSSUnit_Null;
210 
211   return *this;
212 }
213 
operator ==(const nsCSSValue & aOther) const214 bool nsCSSValue::operator==(const nsCSSValue& aOther) const {
215   MOZ_ASSERT(mUnit != eCSSUnit_ListDep && aOther.mUnit != eCSSUnit_ListDep &&
216                  mUnit != eCSSUnit_PairListDep &&
217                  aOther.mUnit != eCSSUnit_PairListDep,
218              "don't use operator== with dependent lists");
219 
220   if (mUnit == aOther.mUnit) {
221     if (mUnit <= eCSSUnit_DummyInherit) {
222       return true;
223     } else if (UnitHasStringValue()) {
224       return (NS_strcmp(GetBufferValue(mValue.mString),
225                         GetBufferValue(aOther.mValue.mString)) == 0);
226     } else if ((eCSSUnit_Integer <= mUnit) && (mUnit <= eCSSUnit_EnumColor)) {
227       return mValue.mInt == aOther.mValue.mInt;
228     } else if (IsIntegerColorUnit()) {
229       return mValue.mColor == aOther.mValue.mColor;
230     } else if (IsFloatColorUnit()) {
231       return *mValue.mFloatColor == *aOther.mValue.mFloatColor;
232     } else if (eCSSUnit_ComplexColor == mUnit) {
233       return *mValue.mComplexColor == *aOther.mValue.mComplexColor;
234     } else if (UnitHasArrayValue()) {
235       return *mValue.mArray == *aOther.mValue.mArray;
236     } else if (eCSSUnit_URL == mUnit) {
237       return mValue.mURL->Equals(*aOther.mValue.mURL);
238     } else if (eCSSUnit_Image == mUnit) {
239       return mValue.mImage->Equals(*aOther.mValue.mImage);
240     } else if (eCSSUnit_Gradient == mUnit) {
241       return *mValue.mGradient == *aOther.mValue.mGradient;
242     } else if (eCSSUnit_TokenStream == mUnit) {
243       return *mValue.mTokenStream == *aOther.mValue.mTokenStream;
244     } else if (eCSSUnit_Pair == mUnit) {
245       return *mValue.mPair == *aOther.mValue.mPair;
246     } else if (eCSSUnit_Triplet == mUnit) {
247       return *mValue.mTriplet == *aOther.mValue.mTriplet;
248     } else if (eCSSUnit_Rect == mUnit) {
249       return *mValue.mRect == *aOther.mValue.mRect;
250     } else if (eCSSUnit_List == mUnit) {
251       return nsCSSValueList::Equal(mValue.mList, aOther.mValue.mList);
252     } else if (eCSSUnit_SharedList == mUnit) {
253       return *mValue.mSharedList == *aOther.mValue.mSharedList;
254     } else if (eCSSUnit_PairList == mUnit) {
255       return nsCSSValuePairList::Equal(mValue.mPairList,
256                                        aOther.mValue.mPairList);
257     } else if (eCSSUnit_GridTemplateAreas == mUnit) {
258       return *mValue.mGridTemplateAreas == *aOther.mValue.mGridTemplateAreas;
259     } else if (eCSSUnit_FontFamilyList == mUnit) {
260       return mValue.mFontFamilyList->mNames ==
261              aOther.mValue.mFontFamilyList->mNames;
262     } else if (eCSSUnit_AtomIdent == mUnit) {
263       return mValue.mAtom == aOther.mValue.mAtom;
264     } else {
265       return mValue.mFloat == aOther.mValue.mFloat;
266     }
267   }
268   return false;
269 }
270 
GetAngleValueInRadians() const271 double nsCSSValue::GetAngleValueInRadians() const {
272   double angle = GetFloatValue();
273 
274   switch (GetUnit()) {
275     case eCSSUnit_Radian:
276       return angle;
277     case eCSSUnit_Turn:
278       return angle * 2 * M_PI;
279     case eCSSUnit_Degree:
280       return angle * M_PI / 180.0;
281     case eCSSUnit_Grad:
282       return angle * M_PI / 200.0;
283 
284     default:
285       MOZ_ASSERT(false, "unrecognized angular unit");
286       return 0.0;
287   }
288 }
289 
GetAngleValueInDegrees() const290 double nsCSSValue::GetAngleValueInDegrees() const {
291   double angle = GetFloatValue();
292 
293   switch (GetUnit()) {
294     case eCSSUnit_Degree:
295       return angle;
296     case eCSSUnit_Grad:
297       return angle * 0.9;  // grad / 400 * 360
298     case eCSSUnit_Radian:
299       return angle * 180.0 / M_PI;  // rad / 2pi * 360
300     case eCSSUnit_Turn:
301       return angle * 360.0;
302 
303     default:
304       MOZ_ASSERT(false, "unrecognized angular unit");
305       return 0.0;
306   }
307 }
308 
GetImageValue(nsIDocument * aDocument) const309 imgRequestProxy* nsCSSValue::GetImageValue(nsIDocument* aDocument) const {
310   MOZ_ASSERT(mUnit == eCSSUnit_Image, "not an Image value");
311   return mValue.mImage->mRequests.GetWeak(aDocument);
312 }
313 
GetPossiblyStaticImageValue(nsIDocument * aDocument,nsPresContext * aPresContext) const314 already_AddRefed<imgRequestProxy> nsCSSValue::GetPossiblyStaticImageValue(
315     nsIDocument* aDocument, nsPresContext* aPresContext) const {
316   imgRequestProxy* req = GetImageValue(aDocument);
317   if (aPresContext->IsDynamic()) {
318     return do_AddRef(req);
319   }
320   return nsContentUtils::GetStaticRequest(aDocument, req);
321 }
322 
GetPixelLength() const323 nscoord nsCSSValue::GetPixelLength() const {
324   MOZ_ASSERT(IsPixelLengthUnit(), "not a fixed length unit");
325 
326   double scaleFactor;
327   switch (mUnit) {
328     case eCSSUnit_Pixel:
329       return nsPresContext::CSSPixelsToAppUnits(mValue.mFloat);
330     case eCSSUnit_Pica:
331       scaleFactor = 16.0;
332       break;
333     case eCSSUnit_Point:
334       scaleFactor = 4 / 3.0;
335       break;
336     case eCSSUnit_Inch:
337       scaleFactor = 96.0;
338       break;
339     case eCSSUnit_Millimeter:
340       scaleFactor = 96 / 25.4;
341       break;
342     case eCSSUnit_Centimeter:
343       scaleFactor = 96 / 2.54;
344       break;
345     case eCSSUnit_Quarter:
346       scaleFactor = 96 / 101.6;
347       break;
348     default:
349       NS_ERROR("should never get here");
350       return 0;
351   }
352   return nsPresContext::CSSPixelsToAppUnits(float(mValue.mFloat * scaleFactor));
353 }
354 
355 // Assert against resetting non-trivial CSS values from the parallel Servo
356 // traversal, since the refcounts aren't thread-safe.
357 // Note that the caller might be an OMTA thread, which is allowed to operate off
358 // main thread because it owns all of the corresponding nsCSSValues and any that
359 // they might be sharing members with. Since this can happen concurrently with
360 // the servo traversal, we have to use a more-precise (but slower) test.
361 #define DO_RELEASE(member)                                         \
362   {                                                                \
363     MOZ_ASSERT(!ServoStyleSet::IsCurrentThreadInServoTraversal()); \
364     mValue.member->Release();                                      \
365   }
366 
DoReset()367 void nsCSSValue::DoReset() {
368   if (UnitHasStringValue()) {
369     mValue.mString->Release();
370   } else if (IsFloatColorUnit()) {
371     DO_RELEASE(mFloatColor);
372   } else if (eCSSUnit_ComplexColor == mUnit) {
373     DO_RELEASE(mComplexColor);
374   } else if (UnitHasArrayValue()) {
375     DO_RELEASE(mArray);
376   } else if (eCSSUnit_URL == mUnit) {
377     DO_RELEASE(mURL);
378   } else if (eCSSUnit_Image == mUnit) {
379     DO_RELEASE(mImage);
380   } else if (eCSSUnit_Gradient == mUnit) {
381     DO_RELEASE(mGradient);
382   } else if (eCSSUnit_TokenStream == mUnit) {
383     DO_RELEASE(mTokenStream);
384   } else if (eCSSUnit_Pair == mUnit) {
385     DO_RELEASE(mPair);
386   } else if (eCSSUnit_Triplet == mUnit) {
387     DO_RELEASE(mTriplet);
388   } else if (eCSSUnit_Rect == mUnit) {
389     DO_RELEASE(mRect);
390   } else if (eCSSUnit_List == mUnit) {
391     DO_RELEASE(mList);
392   } else if (eCSSUnit_SharedList == mUnit) {
393     DO_RELEASE(mSharedList);
394   } else if (eCSSUnit_PairList == mUnit) {
395     DO_RELEASE(mPairList);
396   } else if (eCSSUnit_GridTemplateAreas == mUnit) {
397     DO_RELEASE(mGridTemplateAreas);
398   } else if (eCSSUnit_FontFamilyList == mUnit) {
399     DO_RELEASE(mFontFamilyList);
400   } else if (eCSSUnit_AtomIdent == mUnit) {
401     DO_RELEASE(mAtom);
402   }
403   mUnit = eCSSUnit_Null;
404 }
405 
406 #undef DO_RELEASE
407 
SetIntValue(int32_t aValue,nsCSSUnit aUnit)408 void nsCSSValue::SetIntValue(int32_t aValue, nsCSSUnit aUnit) {
409   MOZ_ASSERT(aUnit == eCSSUnit_Integer || aUnit == eCSSUnit_Enumerated ||
410                  aUnit == eCSSUnit_EnumColor,
411              "not an int value");
412   Reset();
413   if (aUnit == eCSSUnit_Integer || aUnit == eCSSUnit_Enumerated ||
414       aUnit == eCSSUnit_EnumColor) {
415     mUnit = aUnit;
416     mValue.mInt = aValue;
417   }
418 }
419 
SetPercentValue(float aValue)420 void nsCSSValue::SetPercentValue(float aValue) {
421   Reset();
422   mUnit = eCSSUnit_Percent;
423   mValue.mFloat = aValue;
424   MOZ_ASSERT(!mozilla::IsNaN(mValue.mFloat));
425 }
426 
SetFloatValue(float aValue,nsCSSUnit aUnit)427 void nsCSSValue::SetFloatValue(float aValue, nsCSSUnit aUnit) {
428   MOZ_ASSERT(IsFloatUnit(aUnit), "not a float value");
429   Reset();
430   if (IsFloatUnit(aUnit)) {
431     mUnit = aUnit;
432     mValue.mFloat = aValue;
433     MOZ_ASSERT(!mozilla::IsNaN(mValue.mFloat));
434   }
435 }
436 
SetStringValue(const nsString & aValue,nsCSSUnit aUnit)437 void nsCSSValue::SetStringValue(const nsString& aValue, nsCSSUnit aUnit) {
438   Reset();
439   mUnit = aUnit;
440   MOZ_ASSERT(UnitHasStringValue(), "not a string unit");
441   if (UnitHasStringValue()) {
442     mValue.mString = BufferFromString(aValue).take();
443   } else
444     mUnit = eCSSUnit_Null;
445 }
446 
SetAtomIdentValue(already_AddRefed<nsAtom> aValue)447 void nsCSSValue::SetAtomIdentValue(already_AddRefed<nsAtom> aValue) {
448   Reset();
449   mUnit = eCSSUnit_AtomIdent;
450   mValue.mAtom = aValue.take();
451 }
452 
SetColorValue(nscolor aValue)453 void nsCSSValue::SetColorValue(nscolor aValue) {
454   SetIntegerColorValue(aValue, eCSSUnit_RGBAColor);
455 }
456 
SetIntegerColorValue(nscolor aValue,nsCSSUnit aUnit)457 void nsCSSValue::SetIntegerColorValue(nscolor aValue, nsCSSUnit aUnit) {
458   Reset();
459   mUnit = aUnit;
460   MOZ_ASSERT(IsIntegerColorUnit(), "bad unit");
461   mValue.mColor = aValue;
462 }
463 
SetIntegerCoordValue(nscoord aValue)464 void nsCSSValue::SetIntegerCoordValue(nscoord aValue) {
465   SetFloatValue(nsPresContext::AppUnitsToFloatCSSPixels(aValue),
466                 eCSSUnit_Pixel);
467 }
468 
SetFloatColorValue(float aComponent1,float aComponent2,float aComponent3,float aAlpha,nsCSSUnit aUnit)469 void nsCSSValue::SetFloatColorValue(float aComponent1, float aComponent2,
470                                     float aComponent3, float aAlpha,
471                                     nsCSSUnit aUnit) {
472   Reset();
473   mUnit = aUnit;
474   MOZ_ASSERT(IsFloatColorUnit(), "bad unit");
475   mValue.mFloatColor =
476       new nsCSSValueFloatColor(aComponent1, aComponent2, aComponent3, aAlpha);
477   mValue.mFloatColor->AddRef();
478 }
479 
SetRGBAColorValue(const RGBAColorData & aValue)480 void nsCSSValue::SetRGBAColorValue(const RGBAColorData& aValue) {
481   SetFloatColorValue(aValue.mR, aValue.mG, aValue.mB, aValue.mA,
482                      eCSSUnit_PercentageRGBAColor);
483 }
484 
SetComplexColorValue(already_AddRefed<ComplexColorValue> aValue)485 void nsCSSValue::SetComplexColorValue(
486     already_AddRefed<ComplexColorValue> aValue) {
487   Reset();
488   mUnit = eCSSUnit_ComplexColor;
489   mValue.mComplexColor = aValue.take();
490 }
491 
SetArrayValue(nsCSSValue::Array * aValue,nsCSSUnit aUnit)492 void nsCSSValue::SetArrayValue(nsCSSValue::Array* aValue, nsCSSUnit aUnit) {
493   Reset();
494   mUnit = aUnit;
495   MOZ_ASSERT(UnitHasArrayValue(), "bad unit");
496   mValue.mArray = aValue;
497   mValue.mArray->AddRef();
498 }
499 
SetURLValue(mozilla::css::URLValue * aValue)500 void nsCSSValue::SetURLValue(mozilla::css::URLValue* aValue) {
501   Reset();
502   mUnit = eCSSUnit_URL;
503   mValue.mURL = aValue;
504   mValue.mURL->AddRef();
505 }
506 
SetImageValue(mozilla::css::ImageValue * aValue)507 void nsCSSValue::SetImageValue(mozilla::css::ImageValue* aValue) {
508   Reset();
509   mUnit = eCSSUnit_Image;
510   mValue.mImage = aValue;
511   mValue.mImage->AddRef();
512 }
513 
SetGradientValue(nsCSSValueGradient * aValue)514 void nsCSSValue::SetGradientValue(nsCSSValueGradient* aValue) {
515   Reset();
516   mUnit = eCSSUnit_Gradient;
517   mValue.mGradient = aValue;
518   mValue.mGradient->AddRef();
519 }
520 
SetTokenStreamValue(nsCSSValueTokenStream * aValue)521 void nsCSSValue::SetTokenStreamValue(nsCSSValueTokenStream* aValue) {
522   Reset();
523   mUnit = eCSSUnit_TokenStream;
524   mValue.mTokenStream = aValue;
525   mValue.mTokenStream->AddRef();
526 }
527 
SetGridTemplateAreas(mozilla::css::GridTemplateAreasValue * aValue)528 void nsCSSValue::SetGridTemplateAreas(
529     mozilla::css::GridTemplateAreasValue* aValue) {
530   Reset();
531   mUnit = eCSSUnit_GridTemplateAreas;
532   mValue.mGridTemplateAreas = aValue;
533   mValue.mGridTemplateAreas->AddRef();
534 }
535 
SetFontFamilyListValue(already_AddRefed<SharedFontList> aValue)536 void nsCSSValue::SetFontFamilyListValue(
537     already_AddRefed<SharedFontList> aValue) {
538   Reset();
539   mUnit = eCSSUnit_FontFamilyList;
540   mValue.mFontFamilyList = aValue.take();
541 }
542 
SetPairValue(const nsCSSValuePair * aValue)543 void nsCSSValue::SetPairValue(const nsCSSValuePair* aValue) {
544   // pairs should not be used for null/inherit/initial values
545   MOZ_ASSERT(aValue && aValue->mXValue.GetUnit() != eCSSUnit_Null &&
546                  aValue->mYValue.GetUnit() != eCSSUnit_Null &&
547                  aValue->mXValue.GetUnit() != eCSSUnit_Inherit &&
548                  aValue->mYValue.GetUnit() != eCSSUnit_Inherit &&
549                  aValue->mXValue.GetUnit() != eCSSUnit_Initial &&
550                  aValue->mYValue.GetUnit() != eCSSUnit_Initial &&
551                  aValue->mXValue.GetUnit() != eCSSUnit_Unset &&
552                  aValue->mYValue.GetUnit() != eCSSUnit_Unset,
553              "missing or inappropriate pair value");
554   Reset();
555   mUnit = eCSSUnit_Pair;
556   mValue.mPair = new nsCSSValuePair_heap(aValue->mXValue, aValue->mYValue);
557   mValue.mPair->AddRef();
558 }
559 
SetPairValue(const nsCSSValue & xValue,const nsCSSValue & yValue)560 void nsCSSValue::SetPairValue(const nsCSSValue& xValue,
561                               const nsCSSValue& yValue) {
562   MOZ_ASSERT(xValue.GetUnit() != eCSSUnit_Null &&
563                  yValue.GetUnit() != eCSSUnit_Null &&
564                  xValue.GetUnit() != eCSSUnit_Inherit &&
565                  yValue.GetUnit() != eCSSUnit_Inherit &&
566                  xValue.GetUnit() != eCSSUnit_Initial &&
567                  yValue.GetUnit() != eCSSUnit_Initial &&
568                  xValue.GetUnit() != eCSSUnit_Unset &&
569                  yValue.GetUnit() != eCSSUnit_Unset,
570              "inappropriate pair value");
571   Reset();
572   mUnit = eCSSUnit_Pair;
573   mValue.mPair = new nsCSSValuePair_heap(xValue, yValue);
574   mValue.mPair->AddRef();
575 }
576 
SetTripletValue(const nsCSSValueTriplet * aValue)577 void nsCSSValue::SetTripletValue(const nsCSSValueTriplet* aValue) {
578   // triplet should not be used for null/inherit/initial values
579   MOZ_ASSERT(aValue && aValue->mXValue.GetUnit() != eCSSUnit_Null &&
580                  aValue->mYValue.GetUnit() != eCSSUnit_Null &&
581                  aValue->mZValue.GetUnit() != eCSSUnit_Null &&
582                  aValue->mXValue.GetUnit() != eCSSUnit_Inherit &&
583                  aValue->mYValue.GetUnit() != eCSSUnit_Inherit &&
584                  aValue->mZValue.GetUnit() != eCSSUnit_Inherit &&
585                  aValue->mXValue.GetUnit() != eCSSUnit_Initial &&
586                  aValue->mYValue.GetUnit() != eCSSUnit_Initial &&
587                  aValue->mZValue.GetUnit() != eCSSUnit_Initial &&
588                  aValue->mXValue.GetUnit() != eCSSUnit_Unset &&
589                  aValue->mYValue.GetUnit() != eCSSUnit_Unset &&
590                  aValue->mZValue.GetUnit() != eCSSUnit_Unset,
591              "missing or inappropriate triplet value");
592   Reset();
593   mUnit = eCSSUnit_Triplet;
594   mValue.mTriplet = new nsCSSValueTriplet_heap(aValue->mXValue, aValue->mYValue,
595                                                aValue->mZValue);
596   mValue.mTriplet->AddRef();
597 }
598 
SetTripletValue(const nsCSSValue & xValue,const nsCSSValue & yValue,const nsCSSValue & zValue)599 void nsCSSValue::SetTripletValue(const nsCSSValue& xValue,
600                                  const nsCSSValue& yValue,
601                                  const nsCSSValue& zValue) {
602   // Only allow Null for the z component
603   MOZ_ASSERT(xValue.GetUnit() != eCSSUnit_Null &&
604                  yValue.GetUnit() != eCSSUnit_Null &&
605                  xValue.GetUnit() != eCSSUnit_Inherit &&
606                  yValue.GetUnit() != eCSSUnit_Inherit &&
607                  zValue.GetUnit() != eCSSUnit_Inherit &&
608                  xValue.GetUnit() != eCSSUnit_Initial &&
609                  yValue.GetUnit() != eCSSUnit_Initial &&
610                  zValue.GetUnit() != eCSSUnit_Initial &&
611                  xValue.GetUnit() != eCSSUnit_Unset &&
612                  yValue.GetUnit() != eCSSUnit_Unset &&
613                  zValue.GetUnit() != eCSSUnit_Unset,
614              "inappropriate triplet value");
615   Reset();
616   mUnit = eCSSUnit_Triplet;
617   mValue.mTriplet = new nsCSSValueTriplet_heap(xValue, yValue, zValue);
618   mValue.mTriplet->AddRef();
619 }
620 
SetRectValue()621 nsCSSRect& nsCSSValue::SetRectValue() {
622   Reset();
623   mUnit = eCSSUnit_Rect;
624   mValue.mRect = new nsCSSRect_heap;
625   mValue.mRect->AddRef();
626   return *mValue.mRect;
627 }
628 
SetListValue()629 nsCSSValueList* nsCSSValue::SetListValue() {
630   Reset();
631   mUnit = eCSSUnit_List;
632   mValue.mList = new nsCSSValueList_heap;
633   mValue.mList->AddRef();
634   return mValue.mList;
635 }
636 
SetSharedListValue(nsCSSValueSharedList * aList)637 void nsCSSValue::SetSharedListValue(nsCSSValueSharedList* aList) {
638   Reset();
639   mUnit = eCSSUnit_SharedList;
640   mValue.mSharedList = aList;
641   mValue.mSharedList->AddRef();
642 }
643 
SetDependentListValue(nsCSSValueList * aList)644 void nsCSSValue::SetDependentListValue(nsCSSValueList* aList) {
645   Reset();
646   if (aList) {
647     mUnit = eCSSUnit_ListDep;
648     mValue.mListDependent = aList;
649   }
650 }
651 
AdoptListValue(UniquePtr<nsCSSValueList> aValue)652 void nsCSSValue::AdoptListValue(UniquePtr<nsCSSValueList> aValue) {
653   // We have to copy the first element since for owned lists the first
654   // element should be an nsCSSValueList_heap object.
655   SetListValue();
656   mValue.mList->mValue = Move(aValue->mValue);
657   mValue.mList->mNext = aValue->mNext;
658   aValue->mNext = nullptr;
659   aValue.reset();
660 }
661 
SetPairListValue()662 nsCSSValuePairList* nsCSSValue::SetPairListValue() {
663   Reset();
664   mUnit = eCSSUnit_PairList;
665   mValue.mPairList = new nsCSSValuePairList_heap;
666   mValue.mPairList->AddRef();
667   return mValue.mPairList;
668 }
669 
SetDependentPairListValue(nsCSSValuePairList * aList)670 void nsCSSValue::SetDependentPairListValue(nsCSSValuePairList* aList) {
671   Reset();
672   if (aList) {
673     mUnit = eCSSUnit_PairListDep;
674     mValue.mPairListDependent = aList;
675   }
676 }
677 
AdoptPairListValue(UniquePtr<nsCSSValuePairList> aValue)678 void nsCSSValue::AdoptPairListValue(UniquePtr<nsCSSValuePairList> aValue) {
679   // We have to copy the first element, since for owned pair lists, the first
680   // element should be an nsCSSValuePairList_heap object.
681   SetPairListValue();
682   mValue.mPairList->mXValue = Move(aValue->mXValue);
683   mValue.mPairList->mYValue = Move(aValue->mYValue);
684   mValue.mPairList->mNext = aValue->mNext;
685   aValue->mNext = nullptr;
686   aValue.reset();
687 }
688 
SetAutoValue()689 void nsCSSValue::SetAutoValue() {
690   Reset();
691   mUnit = eCSSUnit_Auto;
692 }
693 
SetInheritValue()694 void nsCSSValue::SetInheritValue() {
695   Reset();
696   mUnit = eCSSUnit_Inherit;
697 }
698 
SetInitialValue()699 void nsCSSValue::SetInitialValue() {
700   Reset();
701   mUnit = eCSSUnit_Initial;
702 }
703 
SetUnsetValue()704 void nsCSSValue::SetUnsetValue() {
705   Reset();
706   mUnit = eCSSUnit_Unset;
707 }
708 
SetNoneValue()709 void nsCSSValue::SetNoneValue() {
710   Reset();
711   mUnit = eCSSUnit_None;
712 }
713 
SetAllValue()714 void nsCSSValue::SetAllValue() {
715   Reset();
716   mUnit = eCSSUnit_All;
717 }
718 
SetNormalValue()719 void nsCSSValue::SetNormalValue() {
720   Reset();
721   mUnit = eCSSUnit_Normal;
722 }
723 
SetSystemFontValue()724 void nsCSSValue::SetSystemFontValue() {
725   Reset();
726   mUnit = eCSSUnit_System_Font;
727 }
728 
SetDummyValue()729 void nsCSSValue::SetDummyValue() {
730   Reset();
731   mUnit = eCSSUnit_Dummy;
732 }
733 
SetDummyInheritValue()734 void nsCSSValue::SetDummyInheritValue() {
735   Reset();
736   mUnit = eCSSUnit_DummyInherit;
737 }
738 
SetCalcValue(const nsStyleCoord::CalcValue * aCalc)739 void nsCSSValue::SetCalcValue(const nsStyleCoord::CalcValue* aCalc) {
740   RefPtr<nsCSSValue::Array> arr = nsCSSValue::Array::Create(1);
741   if (!aCalc->mHasPercent) {
742     arr->Item(0).SetIntegerCoordValue(aCalc->mLength);
743   } else {
744     nsCSSValue::Array* arr2 = nsCSSValue::Array::Create(2);
745     arr->Item(0).SetArrayValue(arr2, eCSSUnit_Calc_Plus);
746     arr2->Item(0).SetIntegerCoordValue(aCalc->mLength);
747     arr2->Item(1).SetPercentValue(aCalc->mPercent);
748   }
749 
750   SetArrayValue(arr, eCSSUnit_Calc);
751 }
752 
GetCalcValue() const753 nsStyleCoord::CalcValue nsCSSValue::GetCalcValue() const {
754   MOZ_ASSERT(mUnit == eCSSUnit_Calc, "The unit should be eCSSUnit_Calc");
755 
756   const nsCSSValue::Array* array = GetArrayValue();
757   MOZ_ASSERT(array->Count() == 1, "There should be a 1-length array");
758 
759   const nsCSSValue& rootValue = array->Item(0);
760 
761   nsStyleCoord::CalcValue result;
762 
763   if (rootValue.GetUnit() == eCSSUnit_Pixel) {
764     result.mLength = rootValue.GetPixelLength();
765     result.mPercent = 0.0f;
766     result.mHasPercent = false;
767   } else {
768     MOZ_ASSERT(rootValue.GetUnit() == eCSSUnit_Calc_Plus,
769                "Calc unit should be eCSSUnit_Calc_Plus");
770 
771     const nsCSSValue::Array* calcPlusArray = rootValue.GetArrayValue();
772     MOZ_ASSERT(calcPlusArray->Count() == 2,
773                "eCSSUnit_Calc_Plus should have a 2-length array");
774 
775     const nsCSSValue& length = calcPlusArray->Item(0);
776     const nsCSSValue& percent = calcPlusArray->Item(1);
777     MOZ_ASSERT(length.GetUnit() == eCSSUnit_Pixel,
778                "The first value should be eCSSUnit_Pixel");
779     MOZ_ASSERT(percent.GetUnit() == eCSSUnit_Percent,
780                "The first value should be eCSSUnit_Percent");
781     result.mLength = length.GetPixelLength();
782     result.mPercent = percent.GetPercentValue();
783     result.mHasPercent = true;
784   }
785 
786   return result;
787 }
788 
StartImageLoad(nsIDocument * aDocument,mozilla::CORSMode aCORSMode) const789 void nsCSSValue::StartImageLoad(nsIDocument* aDocument,
790                                 mozilla::CORSMode aCORSMode) const {
791   MOZ_ASSERT(eCSSUnit_URL == mUnit, "Not a URL value!");
792   mozilla::css::ImageValue* image =
793       mozilla::css::ImageValue::CreateFromURLValue(mValue.mURL, aDocument,
794                                                    aCORSMode);
795 
796   nsCSSValue* writable = const_cast<nsCSSValue*>(this);
797   writable->SetImageValue(image);
798 }
799 
GetColorValue() const800 nscolor nsCSSValue::GetColorValue() const {
801   MOZ_ASSERT(IsNumericColorUnit(), "not a color value");
802   if (IsFloatColorUnit()) {
803     return mValue.mFloatColor->GetColorValue(mUnit);
804   }
805   return mValue.mColor;
806 }
807 
IsNonTransparentColor() const808 bool nsCSSValue::IsNonTransparentColor() const {
809   // We have the value in the form it was specified in at this point, so we
810   // have to look for both the keyword 'transparent' and its equivalent in
811   // rgba notation.
812   nsDependentString buf;
813   return (IsIntegerColorUnit() && NS_GET_A(GetColorValue()) > 0) ||
814          (IsFloatColorUnit() && mValue.mFloatColor->IsNonTransparentColor()) ||
815          (mUnit == eCSSUnit_Ident &&
816           !nsGkAtoms::transparent->Equals(GetStringValue(buf))) ||
817          (mUnit == eCSSUnit_EnumColor);
818 }
819 
InitFunction(nsCSSKeyword aFunctionId,uint32_t aNumArgs)820 nsCSSValue::Array* nsCSSValue::InitFunction(nsCSSKeyword aFunctionId,
821                                             uint32_t aNumArgs) {
822   RefPtr<nsCSSValue::Array> func = Array::Create(aNumArgs + 1);
823   func->Item(0).SetIntValue(aFunctionId, eCSSUnit_Enumerated);
824   SetArrayValue(func, eCSSUnit_Function);
825   return func;
826 }
827 
EqualsFunction(nsCSSKeyword aFunctionId) const828 bool nsCSSValue::EqualsFunction(nsCSSKeyword aFunctionId) const {
829   if (mUnit != eCSSUnit_Function) {
830     return false;
831   }
832 
833   nsCSSValue::Array* func = mValue.mArray;
834   MOZ_ASSERT(func && func->Count() >= 1 &&
835                  func->Item(0).GetUnit() == eCSSUnit_Enumerated,
836              "illegally structured function value");
837 
838   nsCSSKeyword thisFunctionId = func->Item(0).GetKeywordValue();
839   return thisFunctionId == aFunctionId;
840 }
841 
842 // static
BufferFromString(const nsString & aValue)843 already_AddRefed<nsStringBuffer> nsCSSValue::BufferFromString(
844     const nsString& aValue) {
845   RefPtr<nsStringBuffer> buffer = nsStringBuffer::FromString(aValue);
846   if (buffer) {
847     return buffer.forget();
848   }
849 
850   nsString::size_type length = aValue.Length();
851 
852   // NOTE: Alloc prouduces a new, already-addref'd (refcnt = 1) buffer.
853   // NOTE: String buffer allocation is currently fallible.
854   size_t sz = (length + 1) * sizeof(char16_t);
855   buffer = nsStringBuffer::Alloc(sz);
856   if (MOZ_UNLIKELY(!buffer)) {
857     NS_ABORT_OOM(sz);
858   }
859 
860   char16_t* data = static_cast<char16_t*>(buffer->Data());
861   nsCharTraits<char16_t>::copy(data, aValue.get(), length);
862   // Null-terminate.
863   data[length] = 0;
864   return buffer.forget();
865 }
866 
AtomizeIdentValue()867 void nsCSSValue::AtomizeIdentValue() {
868   MOZ_ASSERT(mUnit == eCSSUnit_Ident);
869   RefPtr<nsAtom> atom = NS_Atomize(GetStringBufferValue());
870   Reset();
871   mUnit = eCSSUnit_AtomIdent;
872   mValue.mAtom = atom.forget().take();
873 }
874 
875 namespace {
876 
877 struct CSSValueSerializeCalcOps {
CSSValueSerializeCalcOps__anoneb803ea90111::CSSValueSerializeCalcOps878   CSSValueSerializeCalcOps(nsCSSPropertyID aProperty, nsAString& aResult)
879       : mProperty(aProperty), mResult(aResult) {}
880 
881   typedef nsCSSValue input_type;
882   typedef nsCSSValue::Array input_array_type;
883 
GetUnit__anoneb803ea90111::CSSValueSerializeCalcOps884   static nsCSSUnit GetUnit(const input_type& aValue) {
885     return aValue.GetUnit();
886   }
887 
Append__anoneb803ea90111::CSSValueSerializeCalcOps888   void Append(const char* aString) { mResult.AppendASCII(aString); }
889 
AppendLeafValue__anoneb803ea90111::CSSValueSerializeCalcOps890   void AppendLeafValue(const input_type& aValue) {
891     MOZ_ASSERT(aValue.GetUnit() == eCSSUnit_Percent || aValue.IsLengthUnit() ||
892                    aValue.GetUnit() == eCSSUnit_Number,
893                "unexpected unit");
894     aValue.AppendToString(mProperty, mResult);
895   }
896 
AppendCoefficient__anoneb803ea90111::CSSValueSerializeCalcOps897   void AppendCoefficient(const input_type& aValue) {
898     MOZ_ASSERT(aValue.GetUnit() == eCSSUnit_Number, "unexpected unit");
899     aValue.AppendToString(mProperty, mResult);
900   }
901 
902  private:
903   nsCSSPropertyID mProperty;
904   nsAString& mResult;
905 };
906 
907 }  // namespace
908 
AppendPolygonToString(nsCSSPropertyID aProperty,nsAString & aResult) const909 void nsCSSValue::AppendPolygonToString(nsCSSPropertyID aProperty,
910                                        nsAString& aResult) const {
911   const nsCSSValue::Array* array = GetArrayValue();
912   MOZ_ASSERT(array->Count() > 1 && array->Count() <= 3,
913              "Polygons must have name and at least one more value.");
914   // When the array has 2 elements, the item on index 1 is the coordinate
915   // pair list.
916   // When the array has 3 elements, the item on index 1 is a fill-rule
917   // and item on index 2 is the coordinate pair list.
918   size_t index = 1;
919   if (array->Count() == 3) {
920     const nsCSSValue& fillRuleValue = array->Item(index);
921     MOZ_ASSERT(fillRuleValue.GetUnit() == eCSSUnit_Enumerated,
922                "Expected polygon fill rule.");
923     int32_t fillRule = fillRuleValue.GetIntValue();
924     AppendASCIItoUTF16(
925         nsCSSProps::ValueToKeyword(fillRule, nsCSSProps::kFillRuleKTable),
926         aResult);
927     aResult.AppendLiteral(", ");
928     ++index;
929   }
930   array->Item(index).AppendToString(aProperty, aResult);
931 }
932 
AppendPositionCoordinateToString(const nsCSSValue & aValue,nsCSSPropertyID aProperty,nsAString & aResult) const933 inline void nsCSSValue::AppendPositionCoordinateToString(
934     const nsCSSValue& aValue, nsCSSPropertyID aProperty,
935     nsAString& aResult) const {
936   if (aValue.GetUnit() == eCSSUnit_Enumerated) {
937     int32_t intValue = aValue.GetIntValue();
938     AppendASCIItoUTF16(
939         nsCSSProps::ValueToKeyword(intValue, nsCSSProps::kShapeRadiusKTable),
940         aResult);
941   } else {
942     aValue.AppendToString(aProperty, aResult);
943   }
944 }
945 
AppendCircleOrEllipseToString(nsCSSKeyword aFunctionId,nsCSSPropertyID aProperty,nsAString & aResult) const946 void nsCSSValue::AppendCircleOrEllipseToString(nsCSSKeyword aFunctionId,
947                                                nsCSSPropertyID aProperty,
948                                                nsAString& aResult) const {
949   const nsCSSValue::Array* array = GetArrayValue();
950   size_t count = aFunctionId == eCSSKeyword_circle ? 2 : 3;
951   MOZ_ASSERT(array->Count() == count + 1, "wrong number of arguments");
952 
953   bool hasRadii = array->Item(1).GetUnit() != eCSSUnit_Null;
954 
955   // closest-side is the default, so we don't need to
956   // output it if all values are closest-side.
957   if (array->Item(1).GetUnit() == eCSSUnit_Enumerated &&
958       StyleShapeRadius(array->Item(1).GetIntValue()) ==
959           StyleShapeRadius::ClosestSide &&
960       (aFunctionId == eCSSKeyword_circle ||
961        (array->Item(2).GetUnit() == eCSSUnit_Enumerated &&
962         StyleShapeRadius(array->Item(2).GetIntValue()) ==
963             StyleShapeRadius::ClosestSide))) {
964     hasRadii = false;
965   } else {
966     AppendPositionCoordinateToString(array->Item(1), aProperty, aResult);
967 
968     if (hasRadii && aFunctionId == eCSSKeyword_ellipse) {
969       aResult.Append(' ');
970       AppendPositionCoordinateToString(array->Item(2), aProperty, aResult);
971     }
972   }
973 
974   if (hasRadii) {
975     aResult.Append(' ');
976   }
977 
978   // Any position specified?
979   if (array->Item(count).GetUnit() != eCSSUnit_Array) {
980     MOZ_ASSERT(array->Item(count).GetUnit() == eCSSUnit_Null,
981                "unexpected value");
982     // We only serialize to the 2 or 4 value form
983     // |circle()| is valid, but should be expanded
984     // to |circle(at 50% 50%)|
985     aResult.AppendLiteral("at 50% 50%");
986     return;
987   }
988 
989   aResult.AppendLiteral("at ");
990   array->Item(count).AppendBasicShapePositionToString(aResult);
991 }
992 
993 // https://drafts.csswg.org/css-shapes/#basic-shape-serialization
994 // basic-shape asks us to omit a lot of redundant things whilst serializing
995 // position values. Other specs are not clear about this
996 // (https://github.com/w3c/csswg-drafts/issues/368), so for now we special-case
997 // basic shapes only
AppendBasicShapePositionToString(nsAString & aResult) const998 void nsCSSValue::AppendBasicShapePositionToString(nsAString& aResult) const {
999   const nsCSSValue::Array* array = GetArrayValue();
1000   // We always parse these into an array of four elements
1001   MOZ_ASSERT(array->Count() == 4,
1002              "basic-shape position value doesn't have enough elements");
1003 
1004   const nsCSSValue& xEdge = array->Item(0);
1005   const nsCSSValue& xOffset = array->Item(1);
1006   const nsCSSValue& yEdge = array->Item(2);
1007   const nsCSSValue& yOffset = array->Item(3);
1008 
1009   MOZ_ASSERT(xEdge.GetUnit() == eCSSUnit_Enumerated &&
1010                  yEdge.GetUnit() == eCSSUnit_Enumerated &&
1011                  xOffset.IsLengthPercentCalcUnit() &&
1012                  yOffset.IsLengthPercentCalcUnit() &&
1013                  xEdge.GetIntValue() != NS_STYLE_IMAGELAYER_POSITION_CENTER &&
1014                  yEdge.GetIntValue() != NS_STYLE_IMAGELAYER_POSITION_CENTER,
1015              "Ensure invariants from ParsePositionValueBasicShape "
1016              "haven't been modified");
1017   if (xEdge.GetIntValue() == NS_STYLE_IMAGELAYER_POSITION_LEFT &&
1018       yEdge.GetIntValue() == NS_STYLE_IMAGELAYER_POSITION_TOP) {
1019     // We can omit these defaults
1020     xOffset.AppendToString(eCSSProperty_UNKNOWN, aResult);
1021     aResult.Append(' ');
1022     yOffset.AppendToString(eCSSProperty_UNKNOWN, aResult);
1023   } else {
1024     // We only serialize to the two or four valued form
1025     xEdge.AppendToString(eCSSProperty_object_position, aResult);
1026     aResult.Append(' ');
1027     xOffset.AppendToString(eCSSProperty_UNKNOWN, aResult);
1028     aResult.Append(' ');
1029     yEdge.AppendToString(eCSSProperty_object_position, aResult);
1030     aResult.Append(' ');
1031     yOffset.AppendToString(eCSSProperty_UNKNOWN, aResult);
1032   }
1033 }
1034 
1035 // Helper to append |aString| with the shorthand sides notation used in e.g.
1036 // 'padding'. |aProperties| and |aValues| are expected to have 4 elements.
AppendSidesShorthandToString(const nsCSSPropertyID aProperties[],const nsCSSValue * aValues[],nsAString & aString)1037 /*static*/ void nsCSSValue::AppendSidesShorthandToString(
1038     const nsCSSPropertyID aProperties[], const nsCSSValue* aValues[],
1039     nsAString& aString) {
1040   const nsCSSValue& value1 = *aValues[0];
1041   const nsCSSValue& value2 = *aValues[1];
1042   const nsCSSValue& value3 = *aValues[2];
1043   const nsCSSValue& value4 = *aValues[3];
1044 
1045   MOZ_ASSERT(value1.GetUnit() != eCSSUnit_Null, "null value 1");
1046   value1.AppendToString(aProperties[0], aString);
1047   if (value1 != value2 || value1 != value3 || value1 != value4) {
1048     aString.Append(char16_t(' '));
1049     MOZ_ASSERT(value2.GetUnit() != eCSSUnit_Null, "null value 2");
1050     value2.AppendToString(aProperties[1], aString);
1051     if (value1 != value3 || value2 != value4) {
1052       aString.Append(char16_t(' '));
1053       MOZ_ASSERT(value3.GetUnit() != eCSSUnit_Null, "null value 3");
1054       value3.AppendToString(aProperties[2], aString);
1055       if (value2 != value4) {
1056         aString.Append(char16_t(' '));
1057         MOZ_ASSERT(value4.GetUnit() != eCSSUnit_Null, "null value 4");
1058         value4.AppendToString(aProperties[3], aString);
1059       }
1060     }
1061   }
1062 }
1063 
AppendBasicShapeRadiusToString(const nsCSSPropertyID aProperties[],const nsCSSValue * aValues[],nsAString & aResult)1064 /*static*/ void nsCSSValue::AppendBasicShapeRadiusToString(
1065     const nsCSSPropertyID aProperties[], const nsCSSValue* aValues[],
1066     nsAString& aResult) {
1067   bool needY = false;
1068   const nsCSSValue* xVals[4];
1069   const nsCSSValue* yVals[4];
1070   for (int i = 0; i < 4; i++) {
1071     if (aValues[i]->GetUnit() == eCSSUnit_Pair) {
1072       needY = true;
1073       xVals[i] = &aValues[i]->GetPairValue().mXValue;
1074       yVals[i] = &aValues[i]->GetPairValue().mYValue;
1075     } else {
1076       xVals[i] = yVals[i] = aValues[i];
1077     }
1078   }
1079 
1080   AppendSidesShorthandToString(aProperties, xVals, aResult);
1081   if (needY) {
1082     aResult.AppendLiteral(" / ");
1083     AppendSidesShorthandToString(aProperties, yVals, aResult);
1084   }
1085 }
1086 
AppendInsetToString(nsCSSPropertyID aProperty,nsAString & aResult) const1087 void nsCSSValue::AppendInsetToString(nsCSSPropertyID aProperty,
1088                                      nsAString& aResult) const {
1089   const nsCSSValue::Array* array = GetArrayValue();
1090   MOZ_ASSERT(array->Count() == 6,
1091              "inset function has wrong number of arguments");
1092   if (array->Item(1).GetUnit() != eCSSUnit_Null) {
1093     array->Item(1).AppendToString(aProperty, aResult);
1094     if (array->Item(2).GetUnit() != eCSSUnit_Null) {
1095       aResult.Append(' ');
1096       array->Item(2).AppendToString(aProperty, aResult);
1097       if (array->Item(3).GetUnit() != eCSSUnit_Null) {
1098         aResult.Append(' ');
1099         array->Item(3).AppendToString(aProperty, aResult);
1100         if (array->Item(4).GetUnit() != eCSSUnit_Null) {
1101           aResult.Append(' ');
1102           array->Item(4).AppendToString(aProperty, aResult);
1103         }
1104       }
1105     }
1106   }
1107 
1108   if (array->Item(5).GetUnit() == eCSSUnit_Array) {
1109     const nsCSSPropertyID* subprops =
1110         nsCSSProps::SubpropertyEntryFor(eCSSProperty_border_radius);
1111     const nsCSSValue::Array* radius = array->Item(5).GetArrayValue();
1112     MOZ_ASSERT(radius->Count() == 4, "expected 4 radii values");
1113     const nsCSSValue* vals[4] = {&(radius->Item(0)), &(radius->Item(1)),
1114                                  &(radius->Item(2)), &(radius->Item(3))};
1115     aResult.AppendLiteral(" round ");
1116     AppendBasicShapeRadiusToString(subprops, vals, aResult);
1117   } else {
1118     MOZ_ASSERT(array->Item(5).GetUnit() == eCSSUnit_Null, "unexpected value");
1119   }
1120 }
1121 
AppendAlignJustifyValueToString(int32_t aValue,nsAString & aResult)1122 /* static */ void nsCSSValue::AppendAlignJustifyValueToString(
1123     int32_t aValue, nsAString& aResult) {
1124   auto legacy = aValue & NS_STYLE_ALIGN_LEGACY;
1125   if (legacy) {
1126     aValue &= ~legacy;
1127     aResult.AppendLiteral("legacy ");
1128   }
1129   // Don't serialize the 'unsafe' keyword; it's the default.
1130   auto overflowPos = aValue & (NS_STYLE_ALIGN_SAFE | NS_STYLE_ALIGN_UNSAFE);
1131   if (MOZ_UNLIKELY(overflowPos == NS_STYLE_ALIGN_SAFE)) {
1132     aResult.AppendLiteral("safe ");
1133   }
1134   aValue &= ~overflowPos;
1135   MOZ_ASSERT(!(aValue & NS_STYLE_ALIGN_FLAG_BITS),
1136              "unknown bits in align/justify value");
1137   MOZ_ASSERT(
1138       (aValue != NS_STYLE_ALIGN_AUTO && aValue != NS_STYLE_ALIGN_NORMAL &&
1139        aValue != NS_STYLE_ALIGN_BASELINE &&
1140        aValue != NS_STYLE_ALIGN_LAST_BASELINE) ||
1141           (!legacy && !overflowPos),
1142       "auto/normal/baseline/'last baseline' never have any flags");
1143   MOZ_ASSERT(legacy == 0 || overflowPos == 0,
1144              "'legacy' together with <overflow-position>");
1145   if (aValue == NS_STYLE_ALIGN_LAST_BASELINE) {
1146     aResult.AppendLiteral("last ");
1147     aValue = NS_STYLE_ALIGN_BASELINE;
1148   }
1149   const auto& kwtable(nsCSSProps::kAlignAllKeywords);
1150   AppendASCIItoUTF16(nsCSSProps::ValueToKeyword(aValue, kwtable), aResult);
1151 }
1152 
1153 /**
1154  * Returns a re-ordered version of an csCSSValue::Array representing a shadow
1155  * item (including a drop-shadow() filter function) suitable for serialization.
1156  */
1157 static already_AddRefed<nsCSSValue::Array>
GetReorderedShadowArrayForSerialization(const nsCSSValue::Array * aOriginalArray)1158 GetReorderedShadowArrayForSerialization(
1159     const nsCSSValue::Array* aOriginalArray) {
1160   MOZ_ASSERT(aOriginalArray);
1161 
1162   RefPtr<nsCSSValue::Array> reorderArray = nsCSSValue::Array::Create(6);
1163 
1164   reorderArray->Item(0) = aOriginalArray->Item(4);  // Color
1165   for (uint8_t i = 0; i < 4; i++) {
1166     reorderArray->Item(i + 1) = aOriginalArray->Item(i);  // Length
1167   }
1168   reorderArray->Item(5) = aOriginalArray->Item(5);  // Inset
1169 
1170   return reorderArray.forget();
1171 }
1172 
AppendToString(nsCSSPropertyID aProperty,nsAString & aResult) const1173 void nsCSSValue::AppendToString(nsCSSPropertyID aProperty,
1174                                 nsAString& aResult) const {
1175   // eCSSProperty_UNKNOWN gets used for some recursive calls below.
1176   MOZ_ASSERT(
1177       (0 <= aProperty && aProperty <= eCSSProperty_COUNT_no_shorthands) ||
1178           aProperty == eCSSProperty_UNKNOWN || aProperty == eCSSProperty_DOM,
1179       "property ID out of range");
1180 
1181   nsCSSUnit unit = GetUnit();
1182   if (unit == eCSSUnit_Null) {
1183     return;
1184   }
1185 
1186   if (eCSSUnit_String <= unit && unit <= eCSSUnit_Attr) {
1187     if (unit == eCSSUnit_Attr) {
1188       aResult.AppendLiteral("attr(");
1189     }
1190     nsAutoString buffer;
1191     GetStringValue(buffer);
1192     if (unit == eCSSUnit_String) {
1193       nsStyleUtil::AppendEscapedCSSString(buffer, aResult);
1194     } else {
1195       nsStyleUtil::AppendEscapedCSSIdent(buffer, aResult);
1196     }
1197   } else if (eCSSUnit_Array <= unit && unit <= eCSSUnit_Symbols) {
1198     switch (unit) {
1199       case eCSSUnit_Counter:
1200         aResult.AppendLiteral("counter(");
1201         break;
1202       case eCSSUnit_Counters:
1203         aResult.AppendLiteral("counters(");
1204         break;
1205       case eCSSUnit_Cubic_Bezier:
1206         aResult.AppendLiteral("cubic-bezier(");
1207         break;
1208       case eCSSUnit_Steps:
1209         aResult.AppendLiteral("steps(");
1210         break;
1211       case eCSSUnit_Symbols:
1212         aResult.AppendLiteral("symbols(");
1213         break;
1214       default:
1215         break;
1216     }
1217 
1218     nsCSSValue::Array* array = GetArrayValue();
1219 
1220     // CSSParserImpl::ParseShadowItem stores shadow items in a specific order
1221     // that does not match the order we use when serializing computed shadow
1222     // items. In order to match the computed value order, we shuffle the items
1223     // in the shadow array before serializing it.
1224     RefPtr<nsCSSValue::Array> reordered;
1225     if (aProperty == eCSSProperty_text_shadow ||
1226         aProperty == eCSSProperty_box_shadow ||
1227         aProperty == eCSSProperty_filter) {
1228       reordered = GetReorderedShadowArrayForSerialization(array);
1229       array = reordered.get();
1230     }
1231 
1232     bool mark = false;
1233     for (size_t i = 0, i_end = array->Count(); i < i_end; ++i) {
1234       if (mark && array->Item(i).GetUnit() != eCSSUnit_Null) {
1235         if ((unit == eCSSUnit_Array &&
1236              eCSSProperty_transition_timing_function != aProperty) ||
1237             unit == eCSSUnit_Symbols)
1238           aResult.Append(' ');
1239         else if (unit != eCSSUnit_Steps)
1240           aResult.AppendLiteral(", ");
1241       }
1242       if (unit == eCSSUnit_Steps && i == 1) {
1243         MOZ_ASSERT(array->Item(i).GetUnit() == eCSSUnit_Enumerated,
1244                    "unexpected value");
1245         int32_t side = array->Item(i).GetIntValue();
1246         MOZ_ASSERT(side == NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_START ||
1247                        side == NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_END ||
1248                        side == -1,
1249                    "unexpected value");
1250         if (side == NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_START) {
1251           aResult.AppendLiteral(", start");
1252         } else if (side == NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_END) {
1253           aResult.AppendLiteral(", end");
1254         }
1255         continue;
1256       }
1257       if (unit == eCSSUnit_Symbols && i == 0) {
1258         MOZ_ASSERT(array->Item(i).GetUnit() == eCSSUnit_Enumerated,
1259                    "unexpected value");
1260         int32_t system = array->Item(i).GetIntValue();
1261         if (system != NS_STYLE_COUNTER_SYSTEM_SYMBOLIC) {
1262           AppendASCIItoUTF16(nsCSSProps::ValueToKeyword(
1263                                  system, nsCSSProps::kCounterSystemKTable),
1264                              aResult);
1265           mark = true;
1266         }
1267         continue;
1268       }
1269       nsCSSPropertyID prop =
1270           ((eCSSUnit_Counter <= unit && unit <= eCSSUnit_Counters) &&
1271            i == array->Count() - 1)
1272               ? eCSSProperty_list_style_type
1273               : aProperty;
1274       if (array->Item(i).GetUnit() != eCSSUnit_Null) {
1275         array->Item(i).AppendToString(prop, aResult);
1276         mark = true;
1277       }
1278     }
1279     if (eCSSUnit_Array == unit &&
1280         aProperty == eCSSProperty_transition_timing_function) {
1281       aResult.Append(')');
1282     }
1283   }
1284   /* Although Function is backed by an Array, we'll handle it separately
1285    * because it's a bit quirky.
1286    */
1287   else if (eCSSUnit_Function == unit) {
1288     const nsCSSValue::Array* array = GetArrayValue();
1289     MOZ_ASSERT(array->Count() >= 1,
1290                "Functions must have at least one element for the name.");
1291 
1292     const nsCSSValue& functionName = array->Item(0);
1293     MOZ_ASSERT(functionName.GetUnit() == eCSSUnit_Enumerated,
1294                "Functions must have an enumerated name.");
1295     // The first argument is always of nsCSSKeyword type.
1296     const nsCSSKeyword functionId = functionName.GetKeywordValue();
1297 
1298     // minmax(auto, <flex>) is equivalent to (and is our internal representation
1299     // of) <flex>, and both are serialized as <flex>
1300     if (functionId == eCSSKeyword_minmax && array->Count() == 3 &&
1301         array->Item(1).GetUnit() == eCSSUnit_Auto &&
1302         array->Item(2).GetUnit() == eCSSUnit_FlexFraction) {
1303       array->Item(2).AppendToString(aProperty, aResult);
1304       MOZ_ASSERT(aProperty == eCSSProperty_grid_template_columns ||
1305                  aProperty == eCSSProperty_grid_template_rows ||
1306                  aProperty == eCSSProperty_grid_auto_columns ||
1307                  aProperty == eCSSProperty_grid_auto_rows);
1308       return;
1309     }
1310 
1311     /* Append the function name. */
1312     NS_ConvertASCIItoUTF16 ident(nsCSSKeywords::GetStringValue(functionId));
1313     // Bug 721136: Normalize the identifier to lowercase, except that things
1314     // like scaleX should have the last character capitalized.  This matches
1315     // what other browsers do.
1316     switch (functionId) {
1317       case eCSSKeyword_rotatex:
1318       case eCSSKeyword_scalex:
1319       case eCSSKeyword_skewx:
1320       case eCSSKeyword_translatex:
1321         ident.Replace(ident.Length() - 1, 1, char16_t('X'));
1322         break;
1323 
1324       case eCSSKeyword_rotatey:
1325       case eCSSKeyword_scaley:
1326       case eCSSKeyword_skewy:
1327       case eCSSKeyword_translatey:
1328         ident.Replace(ident.Length() - 1, 1, char16_t('Y'));
1329         break;
1330 
1331       case eCSSKeyword_rotatez:
1332       case eCSSKeyword_scalez:
1333       case eCSSKeyword_translatez:
1334         ident.Replace(ident.Length() - 1, 1, char16_t('Z'));
1335         break;
1336 
1337       default:
1338         break;
1339     }
1340     nsStyleUtil::AppendEscapedCSSIdent(ident, aResult);
1341     aResult.Append('(');
1342 
1343     switch (functionId) {
1344       case eCSSKeyword_polygon:
1345         AppendPolygonToString(aProperty, aResult);
1346         break;
1347 
1348       case eCSSKeyword_circle:
1349       case eCSSKeyword_ellipse:
1350         AppendCircleOrEllipseToString(functionId, aProperty, aResult);
1351         break;
1352 
1353       case eCSSKeyword_inset:
1354         AppendInsetToString(aProperty, aResult);
1355         break;
1356 
1357       default: {
1358         // Now, step through the function contents, writing each of
1359         // them as we go.
1360         for (size_t index = 1; index < array->Count(); ++index) {
1361           array->Item(index).AppendToString(aProperty, aResult);
1362 
1363           /* If we're not at the final element, append a comma. */
1364           if (index + 1 != array->Count()) aResult.AppendLiteral(", ");
1365         }
1366       }
1367     }
1368 
1369     /* Finally, append the closing parenthesis. */
1370     aResult.Append(')');
1371   } else if (IsCalcUnit()) {
1372     MOZ_ASSERT(GetUnit() == eCSSUnit_Calc, "unexpected unit");
1373     CSSValueSerializeCalcOps ops(aProperty, aResult);
1374     css::SerializeCalc(*this, ops);
1375   } else if (eCSSUnit_Integer == unit) {
1376     aResult.AppendInt(GetIntValue(), 10);
1377   } else if (eCSSUnit_Enumerated == unit) {
1378     int32_t intValue = GetIntValue();
1379     switch (aProperty) {
1380       case eCSSProperty_text_combine_upright:
1381         if (intValue <= NS_STYLE_TEXT_COMBINE_UPRIGHT_ALL) {
1382           AppendASCIItoUTF16(
1383               nsCSSProps::LookupPropertyValue(aProperty, intValue), aResult);
1384         } else if (intValue == NS_STYLE_TEXT_COMBINE_UPRIGHT_DIGITS_2) {
1385           aResult.AppendLiteral("digits 2");
1386         } else if (intValue == NS_STYLE_TEXT_COMBINE_UPRIGHT_DIGITS_3) {
1387           aResult.AppendLiteral("digits 3");
1388         } else {
1389           aResult.AppendLiteral("digits 4");
1390         }
1391         break;
1392 
1393       case eCSSProperty_text_decoration_line:
1394         if (NS_STYLE_TEXT_DECORATION_LINE_NONE == intValue) {
1395           AppendASCIItoUTF16(
1396               nsCSSProps::LookupPropertyValue(aProperty, intValue), aResult);
1397         } else {
1398           // Ignore the "override all" internal value.
1399           // (It doesn't have a string representation.)
1400           intValue &= ~NS_STYLE_TEXT_DECORATION_LINE_OVERRIDE_ALL;
1401           nsStyleUtil::AppendBitmaskCSSValue(
1402               aProperty, intValue, NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE,
1403               NS_STYLE_TEXT_DECORATION_LINE_BLINK, aResult);
1404         }
1405         break;
1406 
1407       case eCSSProperty_paint_order:
1408         static_assert(
1409             NS_STYLE_PAINT_ORDER_BITWIDTH * NS_STYLE_PAINT_ORDER_LAST_VALUE <=
1410                 8,
1411             "SVGStyleStruct::mPaintOrder and the following cast not big "
1412             "enough");
1413         nsStyleUtil::AppendPaintOrderValue(static_cast<uint8_t>(GetIntValue()),
1414                                            aResult);
1415         break;
1416 
1417       case eCSSProperty_font_synthesis:
1418         nsStyleUtil::AppendBitmaskCSSValue(aProperty, intValue,
1419                                            NS_FONT_SYNTHESIS_WEIGHT,
1420                                            NS_FONT_SYNTHESIS_STYLE, aResult);
1421         break;
1422 
1423       case eCSSProperty_font_variant_east_asian:
1424         nsStyleUtil::AppendBitmaskCSSValue(
1425             aProperty, intValue, NS_FONT_VARIANT_EAST_ASIAN_JIS78,
1426             NS_FONT_VARIANT_EAST_ASIAN_RUBY, aResult);
1427         break;
1428 
1429       case eCSSProperty_font_variant_ligatures:
1430         nsStyleUtil::AppendBitmaskCSSValue(
1431             aProperty, intValue, NS_FONT_VARIANT_LIGATURES_NONE,
1432             NS_FONT_VARIANT_LIGATURES_NO_CONTEXTUAL, aResult);
1433         break;
1434 
1435       case eCSSProperty_font_variant_numeric:
1436         nsStyleUtil::AppendBitmaskCSSValue(
1437             aProperty, intValue, NS_FONT_VARIANT_NUMERIC_LINING,
1438             NS_FONT_VARIANT_NUMERIC_ORDINAL, aResult);
1439         break;
1440 
1441       case eCSSProperty_grid_auto_flow:
1442         nsStyleUtil::AppendBitmaskCSSValue(
1443             aProperty, intValue, NS_STYLE_GRID_AUTO_FLOW_ROW,
1444             NS_STYLE_GRID_AUTO_FLOW_DENSE, aResult);
1445         break;
1446 
1447       case eCSSProperty_grid_column_start:
1448       case eCSSProperty_grid_column_end:
1449       case eCSSProperty_grid_row_start:
1450       case eCSSProperty_grid_row_end:
1451         // "span" is the only enumerated-unit value for these properties
1452         aResult.AppendLiteral("span");
1453         break;
1454 
1455       case eCSSProperty_touch_action:
1456         nsStyleUtil::AppendBitmaskCSSValue(
1457             aProperty, intValue, NS_STYLE_TOUCH_ACTION_NONE,
1458             NS_STYLE_TOUCH_ACTION_MANIPULATION, aResult);
1459         break;
1460 
1461       case eCSSProperty_clip_path:
1462         AppendASCIItoUTF16(
1463             nsCSSProps::ValueToKeyword(intValue,
1464                                        nsCSSProps::kClipPathGeometryBoxKTable),
1465             aResult);
1466         break;
1467 
1468       case eCSSProperty_shape_outside:
1469         AppendASCIItoUTF16(
1470             nsCSSProps::ValueToKeyword(intValue,
1471                                        nsCSSProps::kShapeOutsideShapeBoxKTable),
1472             aResult);
1473         break;
1474 
1475       case eCSSProperty_contain:
1476         if (intValue & NS_STYLE_CONTAIN_STRICT) {
1477           NS_ASSERTION(
1478               intValue == (NS_STYLE_CONTAIN_STRICT | NS_STYLE_CONTAIN_ALL_BITS),
1479               "contain: strict should imply contain: layout style paint");
1480           // Only output strict.
1481           intValue = NS_STYLE_CONTAIN_STRICT;
1482         }
1483         nsStyleUtil::AppendBitmaskCSSValue(aProperty, intValue,
1484                                            NS_STYLE_CONTAIN_STRICT,
1485                                            NS_STYLE_CONTAIN_PAINT, aResult);
1486         break;
1487 
1488       case eCSSProperty_align_content:
1489       case eCSSProperty_justify_content: {
1490         AppendAlignJustifyValueToString(intValue & NS_STYLE_ALIGN_ALL_BITS,
1491                                         aResult);
1492         auto fallback = intValue >> NS_STYLE_ALIGN_ALL_SHIFT;
1493         if (fallback) {
1494           MOZ_ASSERT(nsCSSProps::ValueToKeywordEnum(
1495                          fallback & ~NS_STYLE_ALIGN_FLAG_BITS,
1496                          nsCSSProps::kAlignSelfPosition) != eCSSKeyword_UNKNOWN,
1497                      "unknown fallback value");
1498           aResult.Append(' ');
1499           AppendAlignJustifyValueToString(fallback, aResult);
1500         }
1501         break;
1502       }
1503 
1504       case eCSSProperty_align_items:
1505       case eCSSProperty_align_self:
1506       case eCSSProperty_justify_items:
1507       case eCSSProperty_justify_self:
1508         AppendAlignJustifyValueToString(intValue, aResult);
1509         break;
1510 
1511       case eCSSProperty_text_emphasis_position: {
1512         nsStyleUtil::AppendBitmaskCSSValue(
1513             aProperty, intValue, NS_STYLE_TEXT_EMPHASIS_POSITION_OVER,
1514             NS_STYLE_TEXT_EMPHASIS_POSITION_RIGHT, aResult);
1515         break;
1516       }
1517 
1518       case eCSSProperty_text_emphasis_style: {
1519         auto fill = intValue & NS_STYLE_TEXT_EMPHASIS_STYLE_FILL_MASK;
1520         AppendASCIItoUTF16(nsCSSProps::ValueToKeyword(
1521                                fill, nsCSSProps::kTextEmphasisStyleFillKTable),
1522                            aResult);
1523         aResult.Append(' ');
1524         auto shape = intValue & NS_STYLE_TEXT_EMPHASIS_STYLE_SHAPE_MASK;
1525         AppendASCIItoUTF16(
1526             nsCSSProps::ValueToKeyword(
1527                 shape, nsCSSProps::kTextEmphasisStyleShapeKTable),
1528             aResult);
1529         break;
1530       }
1531 
1532       default:
1533         const nsCString& name =
1534             nsCSSProps::LookupPropertyValue(aProperty, intValue);
1535         AppendASCIItoUTF16(name, aResult);
1536         break;
1537     }
1538   } else if (eCSSUnit_EnumColor == unit) {
1539     // we can lookup the property in the ColorTable and then
1540     // get a string mapping the name
1541     nsAutoCString str;
1542     if (nsCSSProps::GetColorName(GetIntValue(), str)) {
1543       AppendASCIItoUTF16(str, aResult);
1544     } else {
1545       MOZ_ASSERT(false, "bad color value");
1546     }
1547   } else if (IsNumericColorUnit(unit)) {
1548     nscolor color = GetColorValue();
1549     // For brevity, we omit the alpha component if it's equal to 255 (full
1550     // opaque). Also, we use "rgba" rather than "rgb" when the color includes
1551     // the non-opaque alpha value, for backwards-compat (even though they're
1552     // aliases as of css-color-4).
1553     // e.g.:
1554     //   rgba(1, 2, 3, 1.0) => rgb(1, 2, 3)
1555     //   rgba(1, 2, 3, 0.5) => rgba(1, 2, 3, 0.5)
1556 
1557     uint8_t a = NS_GET_A(color);
1558     bool showAlpha = (a != 255);
1559 
1560     if (showAlpha) {
1561       aResult.AppendLiteral("rgba(");
1562     } else {
1563       aResult.AppendLiteral("rgb(");
1564     }
1565 
1566     NS_NAMED_LITERAL_STRING(comma, ", ");
1567 
1568     aResult.AppendInt(NS_GET_R(color), 10);
1569     aResult.Append(comma);
1570     aResult.AppendInt(NS_GET_G(color), 10);
1571     aResult.Append(comma);
1572     aResult.AppendInt(NS_GET_B(color), 10);
1573     if (showAlpha) {
1574       aResult.Append(comma);
1575       aResult.AppendFloat(nsStyleUtil::ColorComponentToFloat(a));
1576     }
1577     aResult.Append(char16_t(')'));
1578   } else if (eCSSUnit_ComplexColor == unit) {
1579     StyleComplexColor color = GetStyleComplexColorValue();
1580     nsCSSValue serializable;
1581     if (color.IsCurrentColor()) {
1582       serializable.SetIntValue(NS_COLOR_CURRENTCOLOR, eCSSUnit_EnumColor);
1583     } else if (color.IsNumericColor()) {
1584       serializable.SetColorValue(color.mColor);
1585     } else {
1586       MOZ_ASSERT_UNREACHABLE("Cannot serialize a complex color");
1587     }
1588     serializable.AppendToString(aProperty, aResult);
1589   } else if (eCSSUnit_URL == unit || eCSSUnit_Image == unit) {
1590     aResult.AppendLiteral("url(");
1591     nsStyleUtil::AppendEscapedCSSString(
1592         nsDependentString(GetOriginalURLValue()), aResult);
1593     aResult.Append(')');
1594   } else if (eCSSUnit_Element == unit) {
1595     aResult.AppendLiteral("-moz-element(#");
1596     nsAutoString tmpStr;
1597     GetStringValue(tmpStr);
1598     nsStyleUtil::AppendEscapedCSSIdent(tmpStr, aResult);
1599     aResult.Append(')');
1600   } else if (eCSSUnit_Percent == unit) {
1601     aResult.AppendFloat(GetPercentValue() * 100.0f);
1602   } else if (eCSSUnit_Percent < unit) {  // length unit
1603     aResult.AppendFloat(GetFloatValue());
1604   } else if (eCSSUnit_Gradient == unit) {
1605     nsCSSValueGradient* gradient = GetGradientValue();
1606 
1607     if (gradient->mIsLegacySyntax) {
1608       if (gradient->mIsMozLegacySyntax) {
1609         aResult.AppendLiteral("-moz-");
1610       } else {
1611         aResult.AppendLiteral("-webkit-");
1612       }
1613     }
1614     if (gradient->mIsRepeating) {
1615       aResult.AppendLiteral("repeating-");
1616     }
1617     if (gradient->mIsRadial) {
1618       aResult.AppendLiteral("radial-gradient(");
1619     } else {
1620       aResult.AppendLiteral("linear-gradient(");
1621     }
1622 
1623     bool needSep = false;
1624     if (gradient->mIsRadial && !gradient->mIsLegacySyntax) {
1625       if (!gradient->mIsExplicitSize) {
1626         if (gradient->GetRadialShape().GetUnit() != eCSSUnit_None) {
1627           MOZ_ASSERT(
1628               gradient->GetRadialShape().GetUnit() == eCSSUnit_Enumerated,
1629               "bad unit for radial gradient shape");
1630           int32_t intValue = gradient->GetRadialShape().GetIntValue();
1631           MOZ_ASSERT(intValue != NS_STYLE_GRADIENT_SHAPE_LINEAR,
1632                      "radial gradient with linear shape?!");
1633           AppendASCIItoUTF16(
1634               nsCSSProps::ValueToKeyword(
1635                   intValue, nsCSSProps::kRadialGradientShapeKTable),
1636               aResult);
1637           needSep = true;
1638         }
1639 
1640         if (gradient->GetRadialSize().GetUnit() != eCSSUnit_None) {
1641           if (needSep) {
1642             aResult.Append(' ');
1643           }
1644           MOZ_ASSERT(gradient->GetRadialSize().GetUnit() == eCSSUnit_Enumerated,
1645                      "bad unit for radial gradient size");
1646           int32_t intValue = gradient->GetRadialSize().GetIntValue();
1647           AppendASCIItoUTF16(
1648               nsCSSProps::ValueToKeyword(intValue,
1649                                          nsCSSProps::kRadialGradientSizeKTable),
1650               aResult);
1651           needSep = true;
1652         }
1653       } else {
1654         MOZ_ASSERT(gradient->GetRadiusX().GetUnit() != eCSSUnit_None,
1655                    "bad unit for radial gradient explicit size");
1656         gradient->GetRadiusX().AppendToString(aProperty, aResult);
1657         if (gradient->GetRadiusY().GetUnit() != eCSSUnit_None) {
1658           aResult.Append(' ');
1659           gradient->GetRadiusY().AppendToString(aProperty, aResult);
1660         }
1661         needSep = true;
1662       }
1663     }
1664     if (!gradient->mIsRadial &&
1665         !(gradient->mIsLegacySyntax && gradient->mIsMozLegacySyntax)) {
1666       if (gradient->mBgPos.mXValue.GetUnit() != eCSSUnit_None ||
1667           gradient->mBgPos.mYValue.GetUnit() != eCSSUnit_None) {
1668         MOZ_ASSERT(gradient->mAngle.GetUnit() == eCSSUnit_None);
1669         MOZ_ASSERT(
1670             gradient->mBgPos.mXValue.GetUnit() == eCSSUnit_Enumerated &&
1671                 gradient->mBgPos.mYValue.GetUnit() == eCSSUnit_Enumerated,
1672             "unexpected unit");
1673         if (!gradient->mIsLegacySyntax) {
1674           aResult.AppendLiteral("to ");
1675         }
1676         bool didAppendX = false;
1677         if (!(gradient->mBgPos.mXValue.GetIntValue() &
1678               NS_STYLE_IMAGELAYER_POSITION_CENTER)) {
1679           gradient->mBgPos.mXValue.AppendToString(
1680               eCSSProperty_background_position_x, aResult);
1681           didAppendX = true;
1682         }
1683         if (!(gradient->mBgPos.mYValue.GetIntValue() &
1684               NS_STYLE_IMAGELAYER_POSITION_CENTER)) {
1685           if (didAppendX) {
1686             // We're appending both an x-keyword and a y-keyword.
1687             // Add a space between them here.
1688             aResult.Append(' ');
1689           }
1690           gradient->mBgPos.mYValue.AppendToString(
1691               eCSSProperty_background_position_y, aResult);
1692         }
1693         needSep = true;
1694       } else if (gradient->mAngle.GetUnit() != eCSSUnit_None) {
1695         gradient->mAngle.AppendToString(aProperty, aResult);
1696         needSep = true;
1697       }
1698     } else if (gradient->mBgPos.mXValue.GetUnit() != eCSSUnit_None ||
1699                gradient->mBgPos.mYValue.GetUnit() != eCSSUnit_None ||
1700                gradient->mAngle.GetUnit() != eCSSUnit_None) {
1701       if (needSep) {
1702         aResult.Append(' ');
1703       }
1704       if (gradient->mIsRadial && !gradient->mIsLegacySyntax) {
1705         aResult.AppendLiteral("at ");
1706       }
1707       if (gradient->mBgPos.mXValue.GetUnit() != eCSSUnit_None) {
1708         gradient->mBgPos.mXValue.AppendToString(
1709             eCSSProperty_background_position_x, aResult);
1710         aResult.Append(' ');
1711       }
1712       if (gradient->mBgPos.mYValue.GetUnit() != eCSSUnit_None) {
1713         gradient->mBgPos.mYValue.AppendToString(
1714             eCSSProperty_background_position_y, aResult);
1715         aResult.Append(' ');
1716       }
1717       if (gradient->mAngle.GetUnit() != eCSSUnit_None) {
1718         MOZ_ASSERT(gradient->mIsLegacySyntax,
1719                    "angle is allowed only for legacy syntax");
1720         gradient->mAngle.AppendToString(aProperty, aResult);
1721       }
1722       needSep = true;
1723     }
1724 
1725     if (gradient->mIsRadial && gradient->mIsLegacySyntax &&
1726         (gradient->GetRadialShape().GetUnit() != eCSSUnit_None ||
1727          gradient->GetRadialSize().GetUnit() != eCSSUnit_None)) {
1728       MOZ_ASSERT(!gradient->mIsExplicitSize);
1729       if (needSep) {
1730         aResult.AppendLiteral(", ");
1731       }
1732       if (gradient->GetRadialShape().GetUnit() != eCSSUnit_None) {
1733         MOZ_ASSERT(gradient->GetRadialShape().GetUnit() == eCSSUnit_Enumerated,
1734                    "bad unit for radial gradient shape");
1735         int32_t intValue = gradient->GetRadialShape().GetIntValue();
1736         MOZ_ASSERT(intValue != NS_STYLE_GRADIENT_SHAPE_LINEAR,
1737                    "radial gradient with linear shape?!");
1738         AppendASCIItoUTF16(
1739             nsCSSProps::ValueToKeyword(intValue,
1740                                        nsCSSProps::kRadialGradientShapeKTable),
1741             aResult);
1742         aResult.Append(' ');
1743       }
1744 
1745       if (gradient->GetRadialSize().GetUnit() != eCSSUnit_None) {
1746         MOZ_ASSERT(gradient->GetRadialSize().GetUnit() == eCSSUnit_Enumerated,
1747                    "bad unit for radial gradient size");
1748         int32_t intValue = gradient->GetRadialSize().GetIntValue();
1749         AppendASCIItoUTF16(nsCSSProps::ValueToKeyword(
1750                                intValue, nsCSSProps::kRadialGradientSizeKTable),
1751                            aResult);
1752       }
1753       needSep = true;
1754     }
1755     if (needSep) {
1756       aResult.AppendLiteral(", ");
1757     }
1758 
1759     for (uint32_t i = 0;;) {
1760       bool isInterpolationHint = gradient->mStops[i].mIsInterpolationHint;
1761       if (!isInterpolationHint) {
1762         gradient->mStops[i].mColor.AppendToString(aProperty, aResult);
1763       }
1764       if (gradient->mStops[i].mLocation.GetUnit() != eCSSUnit_None) {
1765         if (!isInterpolationHint) {
1766           aResult.Append(' ');
1767         }
1768         gradient->mStops[i].mLocation.AppendToString(aProperty, aResult);
1769       }
1770       if (++i == gradient->mStops.Length()) {
1771         break;
1772       }
1773       aResult.AppendLiteral(", ");
1774     }
1775 
1776     aResult.Append(')');
1777   } else if (eCSSUnit_TokenStream == unit) {
1778     nsCSSPropertyID shorthand = mValue.mTokenStream->mShorthandPropertyID;
1779     if (shorthand == eCSSProperty_UNKNOWN ||
1780         nsCSSProps::PropHasFlags(shorthand, CSS_PROPERTY_IS_ALIAS) ||
1781         aProperty == eCSSProperty__x_system_font) {
1782       // We treat serialization of aliases like '-moz-transform' as a special
1783       // case, since it really wants to be serialized as if it were a longhand
1784       // even though it is implemented as a shorthand. We also need to
1785       // serialize -x-system-font's token stream value, even though the
1786       // value is set through the font shorthand.  This serialization
1787       // of -x-system-font is needed when we need to output the
1788       // 'font' shorthand followed by a number of overriding font
1789       // longhand components.
1790       aResult.Append(mValue.mTokenStream->mTokenStream);
1791     }
1792   } else if (eCSSUnit_Pair == unit) {
1793     if (eCSSProperty_font_variant_alternates == aProperty) {
1794       int32_t intValue = GetPairValue().mXValue.GetIntValue();
1795       nsAutoString out;
1796 
1797       // simple, enumerated values
1798       nsStyleUtil::AppendBitmaskCSSValue(
1799           aProperty, intValue & NS_FONT_VARIANT_ALTERNATES_ENUMERATED_MASK,
1800           NS_FONT_VARIANT_ALTERNATES_HISTORICAL,
1801           NS_FONT_VARIANT_ALTERNATES_HISTORICAL, out);
1802 
1803       // functional values
1804       const nsCSSValueList* list = GetPairValue().mYValue.GetListValue();
1805       AutoTArray<gfxAlternateValue, 8> altValues;
1806 
1807       nsStyleUtil::ComputeFunctionalAlternates(list, altValues);
1808       nsStyleUtil::SerializeFunctionalAlternates(altValues, out);
1809       aResult.Append(out);
1810     } else {
1811       GetPairValue().AppendToString(aProperty, aResult);
1812     }
1813   } else if (eCSSUnit_Triplet == unit) {
1814     GetTripletValue().AppendToString(aProperty, aResult);
1815   } else if (eCSSUnit_Rect == unit) {
1816     GetRectValue().AppendToString(aProperty, aResult);
1817   } else if (eCSSUnit_List == unit || eCSSUnit_ListDep == unit) {
1818     GetListValue()->AppendToString(aProperty, aResult);
1819   } else if (eCSSUnit_SharedList == unit) {
1820     GetSharedListValue()->AppendToString(aProperty, aResult);
1821   } else if (eCSSUnit_PairList == unit || eCSSUnit_PairListDep == unit) {
1822     switch (aProperty) {
1823       case eCSSProperty_font_feature_settings:
1824         nsStyleUtil::AppendFontFeatureSettings(*this, aResult);
1825         break;
1826       default:
1827         GetPairListValue()->AppendToString(aProperty, aResult);
1828         break;
1829     }
1830   } else if (eCSSUnit_GridTemplateAreas == unit) {
1831     const mozilla::css::GridTemplateAreasValue* areas = GetGridTemplateAreas();
1832     MOZ_ASSERT(!areas->mTemplates.IsEmpty(),
1833                "Unexpected empty array in GridTemplateAreasValue");
1834     nsStyleUtil::AppendEscapedCSSString(areas->mTemplates[0], aResult);
1835     for (uint32_t i = 1; i < areas->mTemplates.Length(); i++) {
1836       aResult.Append(char16_t(' '));
1837       nsStyleUtil::AppendEscapedCSSString(areas->mTemplates[i], aResult);
1838     }
1839   } else if (eCSSUnit_FontFamilyList == unit) {
1840     nsStyleUtil::AppendEscapedCSSFontFamilyList(mValue.mFontFamilyList,
1841                                                 aResult);
1842   } else if (eCSSUnit_AtomIdent == unit) {
1843     nsDependentAtomString buffer(GetAtomValue());
1844     nsStyleUtil::AppendEscapedCSSIdent(buffer, aResult);
1845   }
1846 
1847   switch (unit) {
1848     case eCSSUnit_Null:
1849       break;
1850     case eCSSUnit_Auto:
1851       aResult.AppendLiteral("auto");
1852       break;
1853     case eCSSUnit_Inherit:
1854       aResult.AppendLiteral("inherit");
1855       break;
1856     case eCSSUnit_Initial:
1857       aResult.AppendLiteral("initial");
1858       break;
1859     case eCSSUnit_Unset:
1860       aResult.AppendLiteral("unset");
1861       break;
1862     case eCSSUnit_None:
1863       aResult.AppendLiteral("none");
1864       break;
1865     case eCSSUnit_Normal:
1866       aResult.AppendLiteral("normal");
1867       break;
1868     case eCSSUnit_System_Font:
1869       aResult.AppendLiteral("-moz-use-system-font");
1870       break;
1871     case eCSSUnit_All:
1872       aResult.AppendLiteral("all");
1873       break;
1874     case eCSSUnit_Dummy:
1875     case eCSSUnit_DummyInherit:
1876       MOZ_ASSERT(false, "should never serialize");
1877       break;
1878 
1879     case eCSSUnit_FontFamilyList:
1880       break;
1881     case eCSSUnit_String:
1882       break;
1883     case eCSSUnit_Ident:
1884       break;
1885     case eCSSUnit_AtomIdent:
1886       break;
1887     case eCSSUnit_URL:
1888       break;
1889     case eCSSUnit_Image:
1890       break;
1891     case eCSSUnit_Element:
1892       break;
1893     case eCSSUnit_Array:
1894       break;
1895     case eCSSUnit_Attr:
1896     case eCSSUnit_Cubic_Bezier:
1897     case eCSSUnit_Steps:
1898     case eCSSUnit_Symbols:
1899     case eCSSUnit_Counter:
1900     case eCSSUnit_Counters:
1901       aResult.Append(char16_t(')'));
1902       break;
1903     case eCSSUnit_Local_Font:
1904       break;
1905     case eCSSUnit_Font_Format:
1906       break;
1907     case eCSSUnit_Function:
1908       break;
1909     case eCSSUnit_Calc:
1910       break;
1911     case eCSSUnit_Calc_Plus:
1912       break;
1913     case eCSSUnit_Calc_Minus:
1914       break;
1915     case eCSSUnit_Calc_Times_L:
1916       break;
1917     case eCSSUnit_Calc_Times_R:
1918       break;
1919     case eCSSUnit_Calc_Divided:
1920       break;
1921     case eCSSUnit_Integer:
1922       break;
1923     case eCSSUnit_Enumerated:
1924       break;
1925     case eCSSUnit_EnumColor:
1926       break;
1927     case eCSSUnit_RGBColor:
1928       break;
1929     case eCSSUnit_RGBAColor:
1930       break;
1931     case eCSSUnit_HexColor:
1932       break;
1933     case eCSSUnit_ShortHexColor:
1934       break;
1935     case eCSSUnit_HexColorAlpha:
1936       break;
1937     case eCSSUnit_ShortHexColorAlpha:
1938       break;
1939     case eCSSUnit_PercentageRGBColor:
1940       break;
1941     case eCSSUnit_PercentageRGBAColor:
1942       break;
1943     case eCSSUnit_HSLColor:
1944       break;
1945     case eCSSUnit_HSLAColor:
1946       break;
1947     case eCSSUnit_ComplexColor:
1948       break;
1949     case eCSSUnit_Percent:
1950       aResult.Append(char16_t('%'));
1951       break;
1952     case eCSSUnit_Number:
1953       break;
1954     case eCSSUnit_Gradient:
1955       break;
1956     case eCSSUnit_TokenStream:
1957       break;
1958     case eCSSUnit_Pair:
1959       break;
1960     case eCSSUnit_Triplet:
1961       break;
1962     case eCSSUnit_Rect:
1963       break;
1964     case eCSSUnit_List:
1965       break;
1966     case eCSSUnit_ListDep:
1967       break;
1968     case eCSSUnit_SharedList:
1969       break;
1970     case eCSSUnit_PairList:
1971       break;
1972     case eCSSUnit_PairListDep:
1973       break;
1974     case eCSSUnit_GridTemplateAreas:
1975       break;
1976 
1977     case eCSSUnit_Inch:
1978       aResult.AppendLiteral("in");
1979       break;
1980     case eCSSUnit_Millimeter:
1981       aResult.AppendLiteral("mm");
1982       break;
1983     case eCSSUnit_Centimeter:
1984       aResult.AppendLiteral("cm");
1985       break;
1986     case eCSSUnit_Point:
1987       aResult.AppendLiteral("pt");
1988       break;
1989     case eCSSUnit_Pica:
1990       aResult.AppendLiteral("pc");
1991       break;
1992     case eCSSUnit_Quarter:
1993       aResult.AppendLiteral("q");
1994       break;
1995 
1996     case eCSSUnit_ViewportWidth:
1997       aResult.AppendLiteral("vw");
1998       break;
1999     case eCSSUnit_ViewportHeight:
2000       aResult.AppendLiteral("vh");
2001       break;
2002     case eCSSUnit_ViewportMin:
2003       aResult.AppendLiteral("vmin");
2004       break;
2005     case eCSSUnit_ViewportMax:
2006       aResult.AppendLiteral("vmax");
2007       break;
2008 
2009     case eCSSUnit_EM:
2010       aResult.AppendLiteral("em");
2011       break;
2012     case eCSSUnit_XHeight:
2013       aResult.AppendLiteral("ex");
2014       break;
2015     case eCSSUnit_Char:
2016       aResult.AppendLiteral("ch");
2017       break;
2018     case eCSSUnit_RootEM:
2019       aResult.AppendLiteral("rem");
2020       break;
2021 
2022     case eCSSUnit_Pixel:
2023       aResult.AppendLiteral("px");
2024       break;
2025 
2026     case eCSSUnit_Degree:
2027       aResult.AppendLiteral("deg");
2028       break;
2029     case eCSSUnit_Grad:
2030       aResult.AppendLiteral("grad");
2031       break;
2032     case eCSSUnit_Radian:
2033       aResult.AppendLiteral("rad");
2034       break;
2035     case eCSSUnit_Turn:
2036       aResult.AppendLiteral("turn");
2037       break;
2038 
2039     case eCSSUnit_Hertz:
2040       aResult.AppendLiteral("Hz");
2041       break;
2042     case eCSSUnit_Kilohertz:
2043       aResult.AppendLiteral("kHz");
2044       break;
2045 
2046     case eCSSUnit_Seconds:
2047       aResult.Append(char16_t('s'));
2048       break;
2049     case eCSSUnit_Milliseconds:
2050       aResult.AppendLiteral("ms");
2051       break;
2052 
2053     case eCSSUnit_FlexFraction:
2054       aResult.AppendLiteral("fr");
2055       break;
2056   }
2057 }
2058 
SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const2059 size_t nsCSSValue::SizeOfExcludingThis(
2060     mozilla::MallocSizeOf aMallocSizeOf) const {
2061   size_t n = 0;
2062 
2063   switch (GetUnit()) {
2064     // No value: nothing extra to measure.
2065     case eCSSUnit_Null:
2066     case eCSSUnit_Auto:
2067     case eCSSUnit_Inherit:
2068     case eCSSUnit_Initial:
2069     case eCSSUnit_Unset:
2070     case eCSSUnit_None:
2071     case eCSSUnit_Normal:
2072     case eCSSUnit_System_Font:
2073     case eCSSUnit_All:
2074     case eCSSUnit_Dummy:
2075     case eCSSUnit_DummyInherit:
2076       break;
2077 
2078     // String
2079     case eCSSUnit_String:
2080     case eCSSUnit_Ident:
2081     case eCSSUnit_Attr:
2082     case eCSSUnit_Local_Font:
2083     case eCSSUnit_Font_Format:
2084     case eCSSUnit_Element:
2085       n += mValue.mString->SizeOfIncludingThisIfUnshared(aMallocSizeOf);
2086       break;
2087 
2088     // Array
2089     case eCSSUnit_Array:
2090     case eCSSUnit_Counter:
2091     case eCSSUnit_Counters:
2092     case eCSSUnit_Cubic_Bezier:
2093     case eCSSUnit_Steps:
2094     case eCSSUnit_Symbols:
2095     case eCSSUnit_Function:
2096     case eCSSUnit_Calc:
2097     case eCSSUnit_Calc_Plus:
2098     case eCSSUnit_Calc_Minus:
2099     case eCSSUnit_Calc_Times_L:
2100     case eCSSUnit_Calc_Times_R:
2101     case eCSSUnit_Calc_Divided:
2102       break;
2103 
2104     // URL
2105     case eCSSUnit_URL:
2106       n += mValue.mURL->SizeOfIncludingThis(aMallocSizeOf);
2107       break;
2108 
2109     // Image
2110     case eCSSUnit_Image:
2111       n += mValue.mImage->SizeOfIncludingThis(aMallocSizeOf);
2112       break;
2113 
2114     // Gradient
2115     case eCSSUnit_Gradient:
2116       n += mValue.mGradient->SizeOfIncludingThis(aMallocSizeOf);
2117       break;
2118 
2119     // TokenStream
2120     case eCSSUnit_TokenStream:
2121       n += mValue.mTokenStream->SizeOfIncludingThis(aMallocSizeOf);
2122       break;
2123 
2124     // Pair
2125     case eCSSUnit_Pair:
2126       n += mValue.mPair->SizeOfIncludingThis(aMallocSizeOf);
2127       break;
2128 
2129     // Triplet
2130     case eCSSUnit_Triplet:
2131       n += mValue.mTriplet->SizeOfIncludingThis(aMallocSizeOf);
2132       break;
2133 
2134     // Rect
2135     case eCSSUnit_Rect:
2136       n += mValue.mRect->SizeOfIncludingThis(aMallocSizeOf);
2137       break;
2138 
2139     // List
2140     case eCSSUnit_List:
2141       n += mValue.mList->SizeOfIncludingThis(aMallocSizeOf);
2142       break;
2143 
2144     // ListDep: not measured because it's non-owning.
2145     case eCSSUnit_ListDep:
2146       break;
2147 
2148     // SharedList
2149     case eCSSUnit_SharedList:
2150       // Makes more sense not to measure, since it most cases the list
2151       // will be shared.
2152       break;
2153 
2154     // PairList
2155     case eCSSUnit_PairList:
2156       n += mValue.mPairList->SizeOfIncludingThis(aMallocSizeOf);
2157       break;
2158 
2159     // PairListDep: not measured because it's non-owning.
2160     case eCSSUnit_PairListDep:
2161       break;
2162 
2163     // GridTemplateAreas
2164     case eCSSUnit_GridTemplateAreas:
2165       n += mValue.mGridTemplateAreas->SizeOfIncludingThis(aMallocSizeOf);
2166       break;
2167 
2168     case eCSSUnit_FontFamilyList:
2169       // The SharedFontList is a refcounted object, but is unique per
2170       // declaration. We don't measure the references from computed
2171       // values.
2172       n += mValue.mFontFamilyList->SizeOfIncludingThis(aMallocSizeOf);
2173       break;
2174 
2175     // Atom is always shared, and thus should not be counted.
2176     case eCSSUnit_AtomIdent:
2177       break;
2178 
2179     // Int: nothing extra to measure.
2180     case eCSSUnit_Integer:
2181     case eCSSUnit_Enumerated:
2182     case eCSSUnit_EnumColor:
2183       break;
2184 
2185     // Integer Color: nothing extra to measure.
2186     case eCSSUnit_RGBColor:
2187     case eCSSUnit_RGBAColor:
2188     case eCSSUnit_HexColor:
2189     case eCSSUnit_ShortHexColor:
2190     case eCSSUnit_HexColorAlpha:
2191     case eCSSUnit_ShortHexColorAlpha:
2192       break;
2193 
2194     // Float Color
2195     case eCSSUnit_PercentageRGBColor:
2196     case eCSSUnit_PercentageRGBAColor:
2197     case eCSSUnit_HSLColor:
2198     case eCSSUnit_HSLAColor:
2199       n += mValue.mFloatColor->SizeOfIncludingThis(aMallocSizeOf);
2200       break;
2201 
2202     // Complex Color
2203     case eCSSUnit_ComplexColor:
2204       n += mValue.mComplexColor->SizeOfIncludingThis(aMallocSizeOf);
2205       break;
2206 
2207     // Float: nothing extra to measure.
2208     case eCSSUnit_Percent:
2209     case eCSSUnit_Number:
2210     case eCSSUnit_ViewportWidth:
2211     case eCSSUnit_ViewportHeight:
2212     case eCSSUnit_ViewportMin:
2213     case eCSSUnit_ViewportMax:
2214     case eCSSUnit_EM:
2215     case eCSSUnit_XHeight:
2216     case eCSSUnit_Char:
2217     case eCSSUnit_RootEM:
2218     case eCSSUnit_Point:
2219     case eCSSUnit_Inch:
2220     case eCSSUnit_Millimeter:
2221     case eCSSUnit_Centimeter:
2222     case eCSSUnit_Pica:
2223     case eCSSUnit_Pixel:
2224     case eCSSUnit_Quarter:
2225     case eCSSUnit_Degree:
2226     case eCSSUnit_Grad:
2227     case eCSSUnit_Turn:
2228     case eCSSUnit_Radian:
2229     case eCSSUnit_Hertz:
2230     case eCSSUnit_Kilohertz:
2231     case eCSSUnit_Seconds:
2232     case eCSSUnit_Milliseconds:
2233     case eCSSUnit_FlexFraction:
2234       break;
2235 
2236     default:
2237       MOZ_ASSERT(false, "bad nsCSSUnit");
2238       break;
2239   }
2240 
2241   return n;
2242 }
2243 
2244 // --- nsCSSValueList -----------------
2245 
~nsCSSValueList()2246 nsCSSValueList::~nsCSSValueList() {
2247   MOZ_COUNT_DTOR(nsCSSValueList);
2248   NS_CSS_DELETE_LIST_MEMBER(nsCSSValueList, this, mNext);
2249 }
2250 
Clone() const2251 nsCSSValueList* nsCSSValueList::Clone() const {
2252   nsCSSValueList* result = new nsCSSValueList(*this);
2253   nsCSSValueList* dest = result;
2254   const nsCSSValueList* src = this->mNext;
2255   while (src) {
2256     dest->mNext = new nsCSSValueList(*src);
2257     dest = dest->mNext;
2258     src = src->mNext;
2259   }
2260 
2261   MOZ_ASSERT(result, "shouldn't return null; supposed to be infallible");
2262   return result;
2263 }
2264 
CloneInto(nsCSSValueList * aList) const2265 void nsCSSValueList::CloneInto(nsCSSValueList* aList) const {
2266   NS_ASSERTION(!aList->mNext, "Must be an empty list!");
2267   aList->mValue = mValue;
2268   aList->mNext = mNext ? mNext->Clone() : nullptr;
2269 }
2270 
AppendValueListToString(const nsCSSValueList * val,nsCSSPropertyID aProperty,nsAString & aResult)2271 static void AppendValueListToString(const nsCSSValueList* val,
2272                                     nsCSSPropertyID aProperty,
2273                                     nsAString& aResult) {
2274   for (;;) {
2275     val->mValue.AppendToString(aProperty, aResult);
2276     val = val->mNext;
2277     if (!val) break;
2278 
2279     if (nsCSSProps::PropHasFlags(aProperty,
2280                                  CSS_PROPERTY_VALUE_LIST_USES_COMMAS))
2281       aResult.Append(char16_t(','));
2282     aResult.Append(char16_t(' '));
2283   }
2284 }
2285 
AppendGridTemplateToString(const nsCSSValueList * val,nsCSSPropertyID aProperty,nsAString & aResult)2286 static void AppendGridTemplateToString(const nsCSSValueList* val,
2287                                        nsCSSPropertyID aProperty,
2288                                        nsAString& aResult) {
2289   // This is called for the "list" that's the top-level value of the property.
2290   bool isSubgrid = false;
2291   for (;;) {
2292     bool addSpaceSeparator = true;
2293     nsCSSUnit unit = val->mValue.GetUnit();
2294 
2295     if (unit == eCSSUnit_Enumerated &&
2296         val->mValue.GetIntValue() == NS_STYLE_GRID_TEMPLATE_SUBGRID) {
2297       MOZ_ASSERT(!isSubgrid, "saw subgrid once already");
2298       isSubgrid = true;
2299       aResult.AppendLiteral("subgrid");
2300 
2301     } else if (unit == eCSSUnit_Pair) {
2302       // This is a repeat 'auto-fill' / 'auto-fit'.
2303       const nsCSSValuePair& pair = val->mValue.GetPairValue();
2304       switch (pair.mXValue.GetIntValue()) {
2305         case NS_STYLE_GRID_REPEAT_AUTO_FILL:
2306           aResult.AppendLiteral("repeat(auto-fill, ");
2307           break;
2308         case NS_STYLE_GRID_REPEAT_AUTO_FIT:
2309           aResult.AppendLiteral("repeat(auto-fit, ");
2310           break;
2311         default:
2312           MOZ_ASSERT_UNREACHABLE("unexpected enum value");
2313       }
2314       const nsCSSValueList* repeatList = pair.mYValue.GetListValue();
2315       if (repeatList->mValue.GetUnit() != eCSSUnit_Null) {
2316         aResult.Append('[');
2317         AppendValueListToString(repeatList->mValue.GetListValue(), aProperty,
2318                                 aResult);
2319         aResult.Append(']');
2320         if (!isSubgrid) {
2321           aResult.Append(' ');
2322         }
2323       } else if (isSubgrid) {
2324         aResult.AppendLiteral("[]");
2325       }
2326       if (!isSubgrid) {
2327         repeatList = repeatList->mNext;
2328         repeatList->mValue.AppendToString(aProperty, aResult);
2329         repeatList = repeatList->mNext;
2330         if (repeatList->mValue.GetUnit() != eCSSUnit_Null) {
2331           aResult.AppendLiteral(" [");
2332           AppendValueListToString(repeatList->mValue.GetListValue(), aProperty,
2333                                   aResult);
2334           aResult.Append(']');
2335         }
2336       }
2337       aResult.Append(')');
2338 
2339     } else if (unit == eCSSUnit_Null) {
2340       // Empty or omitted <line-names>.
2341       if (isSubgrid) {
2342         aResult.AppendLiteral("[]");
2343       } else {
2344         // Serializes to nothing.
2345         addSpaceSeparator = false;  // Avoid a double space.
2346       }
2347 
2348     } else if (unit == eCSSUnit_List || unit == eCSSUnit_ListDep) {
2349       // Non-empty <line-names>
2350       aResult.Append('[');
2351       AppendValueListToString(val->mValue.GetListValue(), aProperty, aResult);
2352       aResult.Append(']');
2353 
2354     } else {
2355       // <track-size>
2356       val->mValue.AppendToString(aProperty, aResult);
2357       if (!isSubgrid && val->mNext &&
2358           val->mNext->mValue.GetUnit() == eCSSUnit_Null && !val->mNext->mNext) {
2359         // Break out of the loop early to avoid a trailing space.
2360         break;
2361       }
2362     }
2363 
2364     val = val->mNext;
2365     if (!val) {
2366       break;
2367     }
2368 
2369     if (addSpaceSeparator) {
2370       aResult.Append(char16_t(' '));
2371     }
2372   }
2373 }
2374 
AppendToString(nsCSSPropertyID aProperty,nsAString & aResult) const2375 void nsCSSValueList::AppendToString(nsCSSPropertyID aProperty,
2376                                     nsAString& aResult) const {
2377   if (aProperty == eCSSProperty_grid_template_columns ||
2378       aProperty == eCSSProperty_grid_template_rows) {
2379     AppendGridTemplateToString(this, aProperty, aResult);
2380   } else {
2381     AppendValueListToString(this, aProperty, aResult);
2382   }
2383 }
2384 
Equal(const nsCSSValueList * aList1,const nsCSSValueList * aList2)2385 /* static */ bool nsCSSValueList::Equal(const nsCSSValueList* aList1,
2386                                         const nsCSSValueList* aList2) {
2387   if (aList1 == aList2) {
2388     return true;
2389   }
2390 
2391   const nsCSSValueList *p1 = aList1, *p2 = aList2;
2392   for (; p1 && p2; p1 = p1->mNext, p2 = p2->mNext) {
2393     if (p1->mValue != p2->mValue) return false;
2394   }
2395   return !p1 && !p2;  // true if same length, false otherwise
2396 }
2397 
SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const2398 size_t nsCSSValueList::SizeOfIncludingThis(
2399     mozilla::MallocSizeOf aMallocSizeOf) const {
2400   size_t n = 0;
2401   const nsCSSValueList* v = this;
2402   while (v) {
2403     n += aMallocSizeOf(v);
2404     n += v->mValue.SizeOfExcludingThis(aMallocSizeOf);
2405     v = v->mNext;
2406   }
2407   return n;
2408 }
2409 
SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const2410 size_t nsCSSValueList_heap::SizeOfIncludingThis(
2411     mozilla::MallocSizeOf aMallocSizeOf) const {
2412   // Only measure it if it's unshared, to avoid double-counting.
2413   size_t n = 0;
2414   if (mRefCnt <= 1) {
2415     n += aMallocSizeOf(this);
2416     n += mValue.SizeOfExcludingThis(aMallocSizeOf);
2417     n += mNext ? mNext->SizeOfIncludingThis(aMallocSizeOf) : 0;
2418   }
2419   return n;
2420 }
2421 
2422 // --- nsCSSValueSharedList -----------------
2423 
~nsCSSValueSharedList()2424 nsCSSValueSharedList::~nsCSSValueSharedList() {
2425   if (mHead) {
2426     NS_CSS_DELETE_LIST_MEMBER(nsCSSValueList, mHead, mNext);
2427     delete mHead;
2428   }
2429 }
2430 
AppendToString(nsCSSPropertyID aProperty,nsAString & aResult) const2431 void nsCSSValueSharedList::AppendToString(nsCSSPropertyID aProperty,
2432                                           nsAString& aResult) const {
2433   if (mHead) {
2434     mHead->AppendToString(aProperty, aResult);
2435   }
2436 }
2437 
operator ==(const nsCSSValueSharedList & aOther) const2438 bool nsCSSValueSharedList::operator==(
2439     const nsCSSValueSharedList& aOther) const {
2440   return nsCSSValueList::Equal(mHead, aOther.mHead);
2441 }
2442 
SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const2443 size_t nsCSSValueSharedList::SizeOfIncludingThis(
2444     mozilla::MallocSizeOf aMallocSizeOf) const {
2445   // Only measure it if it's unshared, to avoid double-counting.
2446   size_t n = 0;
2447   if (mRefCnt <= 1) {
2448     n += aMallocSizeOf(this);
2449     n += mHead->SizeOfIncludingThis(aMallocSizeOf);
2450   }
2451   return n;
2452 }
2453 
2454 // --- nsCSSRect -----------------
2455 
nsCSSRect(void)2456 nsCSSRect::nsCSSRect(void) { MOZ_COUNT_CTOR(nsCSSRect); }
2457 
nsCSSRect(const nsCSSRect & aCopy)2458 nsCSSRect::nsCSSRect(const nsCSSRect& aCopy)
2459     : mTop(aCopy.mTop),
2460       mRight(aCopy.mRight),
2461       mBottom(aCopy.mBottom),
2462       mLeft(aCopy.mLeft) {
2463   MOZ_COUNT_CTOR(nsCSSRect);
2464 }
2465 
~nsCSSRect()2466 nsCSSRect::~nsCSSRect() { MOZ_COUNT_DTOR(nsCSSRect); }
2467 
AppendToString(nsCSSPropertyID aProperty,nsAString & aResult) const2468 void nsCSSRect::AppendToString(nsCSSPropertyID aProperty,
2469                                nsAString& aResult) const {
2470   MOZ_ASSERT(mTop.GetUnit() != eCSSUnit_Null &&
2471                  mTop.GetUnit() != eCSSUnit_Inherit &&
2472                  mTop.GetUnit() != eCSSUnit_Initial &&
2473                  mTop.GetUnit() != eCSSUnit_Unset,
2474              "parser should have used a bare value");
2475 
2476   if (eCSSProperty_border_image_slice == aProperty ||
2477       eCSSProperty_border_image_width == aProperty ||
2478       eCSSProperty_border_image_outset == aProperty) {
2479     nsCSSPropertyID props[] = {aProperty, aProperty, aProperty, aProperty};
2480     const nsCSSValue* values[] = {&mTop, &mRight, &mBottom, &mLeft};
2481     nsCSSValue::AppendSidesShorthandToString(props, values, aResult);
2482   } else if (eCSSProperty_DOM == aProperty) {
2483     NS_NAMED_LITERAL_STRING(space, " ");
2484 
2485     mTop.AppendToString(aProperty, aResult);
2486     aResult.Append(space);
2487     mRight.AppendToString(aProperty, aResult);
2488     aResult.Append(space);
2489     mBottom.AppendToString(aProperty, aResult);
2490     aResult.Append(space);
2491     mLeft.AppendToString(aProperty, aResult);
2492   } else {
2493     NS_NAMED_LITERAL_STRING(comma, ", ");
2494 
2495     aResult.AppendLiteral("rect(");
2496     mTop.AppendToString(aProperty, aResult);
2497     aResult.Append(comma);
2498     mRight.AppendToString(aProperty, aResult);
2499     aResult.Append(comma);
2500     mBottom.AppendToString(aProperty, aResult);
2501     aResult.Append(comma);
2502     mLeft.AppendToString(aProperty, aResult);
2503     aResult.Append(char16_t(')'));
2504   }
2505 }
2506 
SetAllSidesTo(const nsCSSValue & aValue)2507 void nsCSSRect::SetAllSidesTo(const nsCSSValue& aValue) {
2508   mTop = aValue;
2509   mRight = aValue;
2510   mBottom = aValue;
2511   mLeft = aValue;
2512 }
2513 
SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const2514 size_t nsCSSRect_heap::SizeOfIncludingThis(
2515     mozilla::MallocSizeOf aMallocSizeOf) const {
2516   // Only measure it if it's unshared, to avoid double-counting.
2517   size_t n = 0;
2518   if (mRefCnt <= 1) {
2519     n += aMallocSizeOf(this);
2520     n += mTop.SizeOfExcludingThis(aMallocSizeOf);
2521     n += mRight.SizeOfExcludingThis(aMallocSizeOf);
2522     n += mBottom.SizeOfExcludingThis(aMallocSizeOf);
2523     n += mLeft.SizeOfExcludingThis(aMallocSizeOf);
2524   }
2525   return n;
2526 }
2527 
2528 static_assert(eSideTop == 0 && eSideRight == 1 && eSideBottom == 2 &&
2529                   eSideLeft == 3,
2530               "box side constants not top/right/bottom/left == 0/1/2/3");
2531 
2532 /* static */ const nsCSSRect::side_type nsCSSRect::sides[4] = {
2533     &nsCSSRect::mTop,
2534     &nsCSSRect::mRight,
2535     &nsCSSRect::mBottom,
2536     &nsCSSRect::mLeft,
2537 };
2538 
2539 // --- nsCSSValuePair -----------------
2540 
AppendToString(nsCSSPropertyID aProperty,nsAString & aResult) const2541 void nsCSSValuePair::AppendToString(nsCSSPropertyID aProperty,
2542                                     nsAString& aResult) const {
2543   mXValue.AppendToString(aProperty, aResult);
2544   if (mYValue.GetUnit() != eCSSUnit_Null) {
2545     aResult.Append(char16_t(' '));
2546     mYValue.AppendToString(aProperty, aResult);
2547   }
2548 }
2549 
SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const2550 size_t nsCSSValuePair::SizeOfExcludingThis(
2551     mozilla::MallocSizeOf aMallocSizeOf) const {
2552   size_t n = 0;
2553   n += mXValue.SizeOfExcludingThis(aMallocSizeOf);
2554   n += mYValue.SizeOfExcludingThis(aMallocSizeOf);
2555   return n;
2556 }
2557 
SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const2558 size_t nsCSSValuePair_heap::SizeOfIncludingThis(
2559     mozilla::MallocSizeOf aMallocSizeOf) const {
2560   // Only measure it if it's unshared, to avoid double-counting.
2561   size_t n = 0;
2562   if (mRefCnt <= 1) {
2563     n += aMallocSizeOf(this);
2564     n += mXValue.SizeOfExcludingThis(aMallocSizeOf);
2565     n += mYValue.SizeOfExcludingThis(aMallocSizeOf);
2566   }
2567   return n;
2568 }
2569 
2570 // --- nsCSSValueTriplet -----------------
2571 
AppendToString(nsCSSPropertyID aProperty,nsAString & aResult) const2572 void nsCSSValueTriplet::AppendToString(nsCSSPropertyID aProperty,
2573                                        nsAString& aResult) const {
2574   mXValue.AppendToString(aProperty, aResult);
2575   if (mYValue.GetUnit() != eCSSUnit_Null) {
2576     aResult.Append(char16_t(' '));
2577     mYValue.AppendToString(aProperty, aResult);
2578     if (mZValue.GetUnit() != eCSSUnit_Null) {
2579       aResult.Append(char16_t(' '));
2580       mZValue.AppendToString(aProperty, aResult);
2581     }
2582   }
2583 }
2584 
SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const2585 size_t nsCSSValueTriplet_heap::SizeOfIncludingThis(
2586     mozilla::MallocSizeOf aMallocSizeOf) const {
2587   // Only measure it if it's unshared, to avoid double-counting.
2588   size_t n = 0;
2589   if (mRefCnt <= 1) {
2590     n += aMallocSizeOf(this);
2591     n += mXValue.SizeOfExcludingThis(aMallocSizeOf);
2592     n += mYValue.SizeOfExcludingThis(aMallocSizeOf);
2593     n += mZValue.SizeOfExcludingThis(aMallocSizeOf);
2594   }
2595   return n;
2596 }
2597 
2598 // --- nsCSSValuePairList -----------------
2599 
~nsCSSValuePairList()2600 nsCSSValuePairList::~nsCSSValuePairList() {
2601   MOZ_COUNT_DTOR(nsCSSValuePairList);
2602   NS_CSS_DELETE_LIST_MEMBER(nsCSSValuePairList, this, mNext);
2603 }
2604 
Clone() const2605 nsCSSValuePairList* nsCSSValuePairList::Clone() const {
2606   nsCSSValuePairList* result = new nsCSSValuePairList(*this);
2607   nsCSSValuePairList* dest = result;
2608   const nsCSSValuePairList* src = this->mNext;
2609   while (src) {
2610     dest->mNext = new nsCSSValuePairList(*src);
2611     dest = dest->mNext;
2612     src = src->mNext;
2613   }
2614 
2615   MOZ_ASSERT(result, "shouldn't return null; supposed to be infallible");
2616   return result;
2617 }
2618 
AppendToString(nsCSSPropertyID aProperty,nsAString & aResult) const2619 void nsCSSValuePairList::AppendToString(nsCSSPropertyID aProperty,
2620                                         nsAString& aResult) const {
2621   const nsCSSValuePairList* item = this;
2622   for (;;) {
2623     MOZ_ASSERT(item->mXValue.GetUnit() != eCSSUnit_Null,
2624                "unexpected null unit");
2625     item->mXValue.AppendToString(aProperty, aResult);
2626     if (item->mXValue.GetUnit() != eCSSUnit_Inherit &&
2627         item->mXValue.GetUnit() != eCSSUnit_Initial &&
2628         item->mXValue.GetUnit() != eCSSUnit_Unset &&
2629         item->mYValue.GetUnit() != eCSSUnit_Null) {
2630       aResult.Append(char16_t(' '));
2631       item->mYValue.AppendToString(aProperty, aResult);
2632     }
2633     item = item->mNext;
2634     if (!item) break;
2635 
2636     if (nsCSSProps::PropHasFlags(aProperty,
2637                                  CSS_PROPERTY_VALUE_LIST_USES_COMMAS) ||
2638         aProperty == eCSSProperty_clip_path ||
2639         aProperty == eCSSProperty_shape_outside)
2640       aResult.Append(char16_t(','));
2641     aResult.Append(char16_t(' '));
2642   }
2643 }
2644 
Equal(const nsCSSValuePairList * aList1,const nsCSSValuePairList * aList2)2645 /* static */ bool nsCSSValuePairList::Equal(const nsCSSValuePairList* aList1,
2646                                             const nsCSSValuePairList* aList2) {
2647   if (aList1 == aList2) {
2648     return true;
2649   }
2650 
2651   const nsCSSValuePairList *p1 = aList1, *p2 = aList2;
2652   for (; p1 && p2; p1 = p1->mNext, p2 = p2->mNext) {
2653     if (p1->mXValue != p2->mXValue || p1->mYValue != p2->mYValue) return false;
2654   }
2655   return !p1 && !p2;  // true if same length, false otherwise
2656 }
2657 
SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const2658 size_t nsCSSValuePairList::SizeOfIncludingThis(
2659     mozilla::MallocSizeOf aMallocSizeOf) const {
2660   size_t n = 0;
2661   const nsCSSValuePairList* v = this;
2662   while (v) {
2663     n += aMallocSizeOf(v);
2664     n += v->mXValue.SizeOfExcludingThis(aMallocSizeOf);
2665     n += v->mYValue.SizeOfExcludingThis(aMallocSizeOf);
2666     v = v->mNext;
2667   }
2668   return n;
2669 }
2670 
SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const2671 size_t nsCSSValuePairList_heap::SizeOfIncludingThis(
2672     mozilla::MallocSizeOf aMallocSizeOf) const {
2673   // Only measure it if it's unshared, to avoid double-counting.
2674   size_t n = 0;
2675   if (mRefCnt <= 1) {
2676     n += aMallocSizeOf(this);
2677     n += mXValue.SizeOfExcludingThis(aMallocSizeOf);
2678     n += mYValue.SizeOfExcludingThis(aMallocSizeOf);
2679     n += mNext ? mNext->SizeOfIncludingThis(aMallocSizeOf) : 0;
2680   }
2681   return n;
2682 }
2683 
SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const2684 size_t nsCSSValue::Array::SizeOfIncludingThis(
2685     mozilla::MallocSizeOf aMallocSizeOf) const {
2686   size_t n = aMallocSizeOf(this);
2687   for (size_t i = 0; i < mCount; i++) {
2688     n += mArray[i].SizeOfExcludingThis(aMallocSizeOf);
2689   }
2690   return n;
2691 }
2692 
URLValueData(already_AddRefed<PtrHolder<nsIURI>> aURI,const nsAString & aString,already_AddRefed<URLExtraData> aExtraData,CORSMode aCORSMode)2693 css::URLValueData::URLValueData(already_AddRefed<PtrHolder<nsIURI>> aURI,
2694                                 const nsAString& aString,
2695                                 already_AddRefed<URLExtraData> aExtraData,
2696                                 CORSMode aCORSMode)
2697     : mURI(Move(aURI)),
2698       mExtraData(Move(aExtraData)),
2699       mURIResolved(true),
2700       mStrings(aString),
2701       mUsingRustString(false),
2702       mCORSMode(aCORSMode) {
2703   MOZ_ASSERT(mExtraData);
2704   MOZ_ASSERT(mExtraData->GetPrincipal());
2705 }
2706 
URLValueData(already_AddRefed<PtrHolder<nsIURI>> aURI,ServoRawOffsetArc<RustString> aString,already_AddRefed<URLExtraData> aExtraData,CORSMode aCORSMode)2707 css::URLValueData::URLValueData(already_AddRefed<PtrHolder<nsIURI>> aURI,
2708                                 ServoRawOffsetArc<RustString> aString,
2709                                 already_AddRefed<URLExtraData> aExtraData,
2710                                 CORSMode aCORSMode)
2711     : mURI(Move(aURI)),
2712       mExtraData(Move(aExtraData)),
2713       mURIResolved(true),
2714       mStrings(aString),
2715       mUsingRustString(true),
2716       mCORSMode(aCORSMode) {
2717   MOZ_ASSERT(mExtraData);
2718   MOZ_ASSERT(mExtraData->GetPrincipal());
2719 }
2720 
URLValueData(const nsAString & aString,already_AddRefed<URLExtraData> aExtraData,CORSMode aCORSMode)2721 css::URLValueData::URLValueData(const nsAString& aString,
2722                                 already_AddRefed<URLExtraData> aExtraData,
2723                                 CORSMode aCORSMode)
2724     : mExtraData(Move(aExtraData)),
2725       mURIResolved(false),
2726       mStrings(aString),
2727       mUsingRustString(false),
2728       mCORSMode(aCORSMode) {
2729   MOZ_ASSERT(mExtraData);
2730   MOZ_ASSERT(mExtraData->GetPrincipal());
2731 }
2732 
URLValueData(ServoRawOffsetArc<RustString> aString,already_AddRefed<URLExtraData> aExtraData,CORSMode aCORSMode)2733 css::URLValueData::URLValueData(ServoRawOffsetArc<RustString> aString,
2734                                 already_AddRefed<URLExtraData> aExtraData,
2735                                 CORSMode aCORSMode)
2736     : mExtraData(Move(aExtraData)),
2737       mURIResolved(false),
2738       mStrings(aString),
2739       mUsingRustString(true),
2740       mCORSMode(aCORSMode) {
2741   MOZ_ASSERT(mExtraData);
2742   MOZ_ASSERT(mExtraData->GetPrincipal());
2743 }
2744 
~URLValueData()2745 css::URLValueData::~URLValueData() {
2746   if (mUsingRustString) {
2747     Servo_ReleaseArcStringData(&mStrings.mRustString);
2748   } else {
2749     mStrings.mString.~nsString();
2750   }
2751 }
2752 
Equals(const URLValueData & aOther) const2753 bool css::URLValueData::Equals(const URLValueData& aOther) const {
2754   MOZ_ASSERT(NS_IsMainThread());
2755 
2756   bool eq;
2757   const URLExtraData* self = mExtraData;
2758   const URLExtraData* other = aOther.mExtraData;
2759   bool stringsEqual;
2760   if (mUsingRustString && aOther.mUsingRustString) {
2761     stringsEqual = GetRustString() == aOther.GetRustString();
2762   } else {
2763     stringsEqual = GetUTF16String() == aOther.GetUTF16String();
2764   }
2765   return stringsEqual &&
2766          (GetURI() == aOther.GetURI() ||  // handles null == null
2767           (mURI && aOther.mURI &&
2768            NS_SUCCEEDED(mURI->Equals(aOther.mURI, &eq)) && eq)) &&
2769          (self->BaseURI() == other->BaseURI() ||
2770           (NS_SUCCEEDED(self->BaseURI()->Equals(other->BaseURI(), &eq)) &&
2771            eq)) &&
2772          (self->GetPrincipal() == other->GetPrincipal() ||
2773           self->GetPrincipal()->Equals(other->GetPrincipal())) &&
2774          IsLocalRef() == aOther.IsLocalRef();
2775 }
2776 
DefinitelyEqualURIs(const URLValueData & aOther) const2777 bool css::URLValueData::DefinitelyEqualURIs(const URLValueData& aOther) const {
2778   if (mExtraData->BaseURI() != aOther.mExtraData->BaseURI()) {
2779     return false;
2780   }
2781   if (mUsingRustString && aOther.mUsingRustString) {
2782     return GetRustString() == aOther.GetRustString();
2783   }
2784   return GetUTF16StringForAnyThread() == aOther.GetUTF16StringForAnyThread();
2785 }
2786 
DefinitelyEqualURIsAndPrincipal(const URLValueData & aOther) const2787 bool css::URLValueData::DefinitelyEqualURIsAndPrincipal(
2788     const URLValueData& aOther) const {
2789   return mExtraData->GetPrincipal() == aOther.mExtraData->GetPrincipal() &&
2790          DefinitelyEqualURIs(aOther);
2791 }
2792 
GetRustString() const2793 nsDependentCSubstring css::URLValueData::GetRustString() const {
2794   const uint8_t* chars;
2795   uint32_t len;
2796   Servo_GetArcStringData(mStrings.mRustString.mPtr, &chars, &len);
2797   return nsDependentCSubstring(reinterpret_cast<const char*>(chars), len);
2798 }
2799 
IsStringEmpty() const2800 bool css::URLValueData::IsStringEmpty() const {
2801   if (mUsingRustString) {
2802     return GetRustString().IsEmpty();
2803   }
2804   return mStrings.mString.IsEmpty();
2805 }
2806 
GetUTF16String() const2807 const nsString& css::URLValueData::GetUTF16String() const {
2808   MOZ_ASSERT(NS_IsMainThread());
2809 
2810   if (mUsingRustString) {
2811     nsDependentCSubstring rust = GetRustString();
2812     nsString converted = NS_ConvertUTF8toUTF16(rust);
2813     Servo_ReleaseArcStringData(&mStrings.mRustString);
2814     new (&mStrings) RustOrGeckoString(converted);
2815     mUsingRustString = false;
2816   }
2817   return mStrings.mString;
2818 }
2819 
GetUTF16StringForAnyThread() const2820 nsString css::URLValueData::GetUTF16StringForAnyThread() const {
2821   if (!mUsingRustString) {
2822     return mStrings.mString;
2823   }
2824   nsDependentCSubstring rust = GetRustString();
2825   return NS_ConvertUTF8toUTF16(rust);
2826 }
2827 
GetURI() const2828 nsIURI* css::URLValueData::GetURI() const {
2829   MOZ_ASSERT(NS_IsMainThread());
2830 
2831   if (!mURIResolved) {
2832     MOZ_ASSERT(!mURI);
2833     nsCOMPtr<nsIURI> newURI;
2834     if (!mUsingRustString) {
2835       NS_NewURI(getter_AddRefs(newURI), NS_ConvertUTF16toUTF8(mStrings.mString),
2836                 nullptr, mExtraData->BaseURI());
2837     } else {
2838       NS_NewURI(getter_AddRefs(newURI), GetRustString(), nullptr,
2839                 mExtraData->BaseURI());
2840     }
2841     mURI = new PtrHolder<nsIURI>("URLValueData::mURI", newURI.forget());
2842     mURIResolved = true;
2843   }
2844 
2845   return mURI;
2846 }
2847 
IsLocalRef() const2848 bool css::URLValueData::IsLocalRef() const {
2849   if (mIsLocalRef.isNothing()) {
2850     // IsLocalRefURL is O(N), use it only when IsLocalRef is called.
2851     if (mUsingRustString) {
2852       mIsLocalRef.emplace(nsContentUtils::IsLocalRefURL(GetRustString()));
2853     } else {
2854       mIsLocalRef.emplace(nsContentUtils::IsLocalRefURL(mStrings.mString));
2855     }
2856   }
2857 
2858   return mIsLocalRef.value();
2859 }
2860 
HasRef() const2861 bool css::URLValueData::HasRef() const {
2862   bool result = false;
2863 
2864   if (IsLocalRef()) {
2865     result = true;
2866   } else {
2867     if (nsIURI* uri = GetURI()) {
2868       nsAutoCString ref;
2869       nsresult rv = uri->GetRef(ref);
2870       if (NS_SUCCEEDED(rv) && !ref.IsEmpty()) {
2871         result = true;
2872       }
2873     }
2874   }
2875 
2876   mMightHaveRef = Some(result);
2877 
2878   return result;
2879 }
2880 
MightHaveRef() const2881 bool css::URLValueData::MightHaveRef() const {
2882   if (mMightHaveRef.isNothing()) {
2883     bool result = mUsingRustString ? ::MightHaveRef(GetRustString())
2884                                    : ::MightHaveRef(mStrings.mString);
2885     if (!ServoStyleSet::IsInServoTraversal()) {
2886       // Can only cache the result if we're not on a style worker thread.
2887       mMightHaveRef.emplace(result);
2888     }
2889     return result;
2890   }
2891 
2892   return mMightHaveRef.value();
2893 }
2894 
ResolveLocalRef(nsIURI * aURI) const2895 already_AddRefed<nsIURI> css::URLValueData::ResolveLocalRef(
2896     nsIURI* aURI) const {
2897   nsCOMPtr<nsIURI> result = GetURI();
2898 
2899   if (result && IsLocalRef()) {
2900     nsCString ref;
2901     mURI->GetRef(ref);
2902 
2903     nsresult rv = NS_MutateURI(aURI).SetRef(ref).Finalize(result);
2904     if (NS_FAILED(rv)) {
2905       // If setting the ref failed, just return a clone.
2906       aURI->Clone(getter_AddRefs(result));
2907     }
2908   }
2909 
2910   return result.forget();
2911 }
2912 
ResolveLocalRef(nsIContent * aContent) const2913 already_AddRefed<nsIURI> css::URLValueData::ResolveLocalRef(
2914     nsIContent* aContent) const {
2915   nsCOMPtr<nsIURI> url = aContent->GetBaseURI();
2916   return ResolveLocalRef(url);
2917 }
2918 
GetSourceString(nsString & aRef) const2919 void css::URLValueData::GetSourceString(nsString& aRef) const {
2920   nsIURI* uri = GetURI();
2921   if (!uri) {
2922     aRef.Truncate();
2923     return;
2924   }
2925 
2926   nsCString cref;
2927   if (IsLocalRef()) {
2928     // XXXheycam It's possible we can just return mString in this case, since
2929     // it should be the "#fragment" string the URLValueData was created with.
2930     uri->GetRef(cref);
2931     cref.Insert('#', 0);
2932   } else {
2933     // It's not entirely clear how to best handle failure here. Ensuring the
2934     // string is empty seems safest.
2935     nsresult rv = uri->GetSpec(cref);
2936     if (NS_FAILED(rv)) {
2937       cref.Truncate();
2938     }
2939   }
2940 
2941   aRef = NS_ConvertUTF8toUTF16(cref);
2942 }
2943 
EqualsExceptRef(nsIURI * aURI) const2944 bool css::URLValueData::EqualsExceptRef(nsIURI* aURI) const {
2945   nsIURI* uri = GetURI();
2946   if (!uri) {
2947     return false;
2948   }
2949 
2950   bool ret = false;
2951   uri->EqualsExceptRef(aURI, &ret);
2952   return ret;
2953 }
2954 
SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const2955 size_t css::URLValueData::SizeOfExcludingThis(
2956     mozilla::MallocSizeOf aMallocSizeOf) const {
2957   size_t n = 0;
2958   if (!mUsingRustString) {
2959     n += mStrings.mString.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
2960   }
2961 
2962   // Measurement of the following members may be added later if DMD finds it
2963   // is worthwhile:
2964   // - mURI
2965   // - mExtraData
2966   return n;
2967 }
2968 
URLValue(const nsAString & aString,nsIURI * aBaseURI,nsIURI * aReferrer,nsIPrincipal * aOriginPrincipal)2969 URLValue::URLValue(const nsAString& aString, nsIURI* aBaseURI,
2970                    nsIURI* aReferrer, nsIPrincipal* aOriginPrincipal)
2971     : URLValueData(
2972           aString,
2973           do_AddRef(new URLExtraData(aBaseURI, aReferrer, aOriginPrincipal)),
2974           CORSMode::CORS_NONE) {
2975   MOZ_ASSERT(NS_IsMainThread());
2976 }
2977 
URLValue(nsIURI * aURI,const nsAString & aString,nsIURI * aBaseURI,nsIURI * aReferrer,nsIPrincipal * aOriginPrincipal)2978 URLValue::URLValue(nsIURI* aURI, const nsAString& aString, nsIURI* aBaseURI,
2979                    nsIURI* aReferrer, nsIPrincipal* aOriginPrincipal)
2980     : URLValueData(
2981           do_AddRef(new PtrHolder<nsIURI>("URLValueData::mURI", aURI)), aString,
2982           do_AddRef(new URLExtraData(aBaseURI, aReferrer, aOriginPrincipal)),
2983           CORSMode::CORS_NONE) {
2984   MOZ_ASSERT(NS_IsMainThread());
2985 }
2986 
SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const2987 size_t css::URLValue::SizeOfIncludingThis(
2988     mozilla::MallocSizeOf aMallocSizeOf) const {
2989   // Only measure it if it's unshared, to avoid double-counting.
2990   size_t n = 0;
2991   if (mRefCnt <= 1) {
2992     n += aMallocSizeOf(this);
2993     n += URLValueData::SizeOfExcludingThis(aMallocSizeOf);
2994   }
2995   return n;
2996 }
2997 
ImageValue(nsIURI * aURI,const nsAString & aString,already_AddRefed<URLExtraData> aExtraData,nsIDocument * aDocument,CORSMode aCORSMode)2998 css::ImageValue::ImageValue(nsIURI* aURI, const nsAString& aString,
2999                             already_AddRefed<URLExtraData> aExtraData,
3000                             nsIDocument* aDocument, CORSMode aCORSMode)
3001     : URLValueData(do_AddRef(new PtrHolder<nsIURI>("URLValueData::mURI", aURI)),
3002                    aString, Move(aExtraData), aCORSMode) {
3003   Initialize(aDocument);
3004 }
3005 
ImageValue(nsIURI * aURI,ServoRawOffsetArc<RustString> aString,already_AddRefed<URLExtraData> aExtraData,nsIDocument * aDocument,CORSMode aCORSMode)3006 css::ImageValue::ImageValue(nsIURI* aURI, ServoRawOffsetArc<RustString> aString,
3007                             already_AddRefed<URLExtraData> aExtraData,
3008                             nsIDocument* aDocument, CORSMode aCORSMode)
3009     : URLValueData(do_AddRef(new PtrHolder<nsIURI>("URLValueData::mURI", aURI)),
3010                    aString, Move(aExtraData), aCORSMode) {
3011   Initialize(aDocument);
3012 }
3013 
ImageValue(const nsAString & aString,already_AddRefed<URLExtraData> aExtraData,CORSMode aCORSMode)3014 css::ImageValue::ImageValue(const nsAString& aString,
3015                             already_AddRefed<URLExtraData> aExtraData,
3016                             CORSMode aCORSMode)
3017     : URLValueData(aString, Move(aExtraData), aCORSMode) {}
3018 
ImageValue(ServoRawOffsetArc<RustString> aString,already_AddRefed<URLExtraData> aExtraData,CORSMode aCORSMode)3019 css::ImageValue::ImageValue(ServoRawOffsetArc<RustString> aString,
3020                             already_AddRefed<URLExtraData> aExtraData,
3021                             CORSMode aCORSMode)
3022     : URLValueData(aString, Move(aExtraData), aCORSMode) {}
3023 
CreateFromURLValue(URLValue * aUrl,nsIDocument * aDocument,CORSMode aCORSMode)3024 /*static*/ css::ImageValue* css::ImageValue::CreateFromURLValue(
3025     URLValue* aUrl, nsIDocument* aDocument, CORSMode aCORSMode) {
3026   if (aUrl->mUsingRustString) {
3027     return new css::ImageValue(
3028         aUrl->GetURI(), Servo_CloneArcStringData(&aUrl->mStrings.mRustString),
3029         do_AddRef(aUrl->mExtraData), aDocument, aCORSMode);
3030   }
3031   return new css::ImageValue(aUrl->GetURI(), aUrl->mStrings.mString,
3032                              do_AddRef(aUrl->mExtraData), aDocument, aCORSMode);
3033 }
3034 
Initialize(nsIDocument * aDocument)3035 void css::ImageValue::Initialize(nsIDocument* aDocument) {
3036   MOZ_ASSERT(NS_IsMainThread());
3037 
3038   // NB: If aDocument is not the original document, we may not be able to load
3039   // images from aDocument.  Instead we do the image load from the original doc
3040   // and clone it to aDocument.
3041   nsIDocument* loadingDoc = aDocument->GetOriginalDocument();
3042   if (!loadingDoc) {
3043     loadingDoc = aDocument;
3044   }
3045 
3046   if (!mLoadedImage) {
3047     loadingDoc->StyleImageLoader()->LoadImage(
3048         GetURI(), mExtraData->GetPrincipal(), mExtraData->GetReferrer(), this,
3049         mCORSMode);
3050 
3051     mLoadedImage = true;
3052   }
3053 
3054   aDocument->StyleImageLoader()->MaybeRegisterCSSImage(this);
3055 }
3056 
~ImageValue()3057 css::ImageValue::~ImageValue() {
3058   MOZ_ASSERT(NS_IsMainThread() || mRequests.Count() == 0,
3059              "Destructor should run on main thread, or on non-main thread "
3060              "when mRequest is empty!");
3061 
3062   for (auto iter = mRequests.Iter(); !iter.Done(); iter.Next()) {
3063     nsIDocument* doc = iter.Key();
3064     RefPtr<imgRequestProxy>& proxy = iter.Data();
3065 
3066     if (doc) {
3067       doc->StyleImageLoader()->DeregisterCSSImage(this);
3068     }
3069 
3070     if (proxy) {
3071       proxy->CancelAndForgetObserver(NS_BINDING_ABORTED);
3072     }
3073 
3074     iter.Remove();
3075   }
3076 }
3077 
SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const3078 size_t css::ImageValue::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
3079   size_t n = aMallocSizeOf(this);
3080   n += css::URLValueData::SizeOfExcludingThis(aMallocSizeOf);
3081   n += mRequests.ShallowSizeOfExcludingThis(aMallocSizeOf);
3082   return n;
3083 }
3084 
SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const3085 size_t css::ComplexColorValue::SizeOfIncludingThis(
3086     MallocSizeOf aMallocSizeOf) const {
3087   // Only measure it if it's unshared, to avoid double-counting.
3088   size_t n = 0;
3089   if (mRefCnt <= 1) {
3090     n += aMallocSizeOf(this);
3091   }
3092   return n;
3093 }
3094 
nsCSSValueGradientStop()3095 nsCSSValueGradientStop::nsCSSValueGradientStop()
3096     : mLocation(eCSSUnit_None),
3097       mColor(eCSSUnit_Null),
3098       mIsInterpolationHint(false) {
3099   MOZ_COUNT_CTOR(nsCSSValueGradientStop);
3100 }
3101 
nsCSSValueGradientStop(const nsCSSValueGradientStop & aOther)3102 nsCSSValueGradientStop::nsCSSValueGradientStop(
3103     const nsCSSValueGradientStop& aOther)
3104     : mLocation(aOther.mLocation),
3105       mColor(aOther.mColor),
3106       mIsInterpolationHint(aOther.mIsInterpolationHint) {
3107   MOZ_COUNT_CTOR(nsCSSValueGradientStop);
3108 }
3109 
~nsCSSValueGradientStop()3110 nsCSSValueGradientStop::~nsCSSValueGradientStop() {
3111   MOZ_COUNT_DTOR(nsCSSValueGradientStop);
3112 }
3113 
SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const3114 size_t nsCSSValueGradientStop::SizeOfExcludingThis(
3115     mozilla::MallocSizeOf aMallocSizeOf) const {
3116   size_t n = 0;
3117   n += mLocation.SizeOfExcludingThis(aMallocSizeOf);
3118   n += mColor.SizeOfExcludingThis(aMallocSizeOf);
3119   return n;
3120 }
3121 
nsCSSValueGradient(bool aIsRadial,bool aIsRepeating)3122 nsCSSValueGradient::nsCSSValueGradient(bool aIsRadial, bool aIsRepeating)
3123     : mIsRadial(aIsRadial),
3124       mIsRepeating(aIsRepeating),
3125       mIsLegacySyntax(false),
3126       mIsMozLegacySyntax(false),
3127       mIsExplicitSize(false),
3128       mBgPos(eCSSUnit_None),
3129       mAngle(eCSSUnit_None) {
3130   mRadialValues[0].SetNoneValue();
3131   mRadialValues[1].SetNoneValue();
3132 }
3133 
SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const3134 size_t nsCSSValueGradient::SizeOfIncludingThis(
3135     mozilla::MallocSizeOf aMallocSizeOf) const {
3136   // Only measure it if it's unshared, to avoid double-counting.
3137   size_t n = 0;
3138   if (mRefCnt <= 1) {
3139     n += aMallocSizeOf(this);
3140     n += mBgPos.SizeOfExcludingThis(aMallocSizeOf);
3141     n += mAngle.SizeOfExcludingThis(aMallocSizeOf);
3142     n += mRadialValues[0].SizeOfExcludingThis(aMallocSizeOf);
3143     n += mRadialValues[1].SizeOfExcludingThis(aMallocSizeOf);
3144     n += mStops.ShallowSizeOfExcludingThis(aMallocSizeOf);
3145     for (uint32_t i = 0; i < mStops.Length(); i++) {
3146       n += mStops[i].SizeOfExcludingThis(aMallocSizeOf);
3147     }
3148   }
3149   return n;
3150 }
3151 
3152 // --- nsCSSValueTokenStream ------------
3153 
nsCSSValueTokenStream()3154 nsCSSValueTokenStream::nsCSSValueTokenStream()
3155     : mPropertyID(eCSSProperty_UNKNOWN),
3156       mShorthandPropertyID(eCSSProperty_UNKNOWN),
3157       mLevel(SheetType::Count) {}
3158 
~nsCSSValueTokenStream()3159 nsCSSValueTokenStream::~nsCSSValueTokenStream() {}
3160 
SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const3161 size_t nsCSSValueTokenStream::SizeOfIncludingThis(
3162     mozilla::MallocSizeOf aMallocSizeOf) const {
3163   // Only measure it if it's unshared, to avoid double-counting.
3164   size_t n = 0;
3165   if (mRefCnt <= 1) {
3166     n += aMallocSizeOf(this);
3167     n += mTokenStream.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
3168   }
3169   return n;
3170 }
3171 
3172 // --- nsCSSValueFloatColor -------------
3173 
operator ==(nsCSSValueFloatColor & aOther) const3174 bool nsCSSValueFloatColor::operator==(nsCSSValueFloatColor& aOther) const {
3175   return mComponent1 == aOther.mComponent1 &&
3176          mComponent2 == aOther.mComponent2 &&
3177          mComponent3 == aOther.mComponent3 && mAlpha == aOther.mAlpha;
3178 }
3179 
GetColorValue(nsCSSUnit aUnit) const3180 nscolor nsCSSValueFloatColor::GetColorValue(nsCSSUnit aUnit) const {
3181   MOZ_ASSERT(nsCSSValue::IsFloatColorUnit(aUnit), "unexpected unit");
3182 
3183   // We should clamp each component value since eCSSUnit_PercentageRGBColor
3184   // and eCSSUnit_PercentageRGBAColor may store values greater than 1.0.
3185   if (aUnit == eCSSUnit_PercentageRGBColor ||
3186       aUnit == eCSSUnit_PercentageRGBAColor) {
3187     return NS_RGBA(
3188         // We need to clamp before multiplying by 255.0f to avoid overflow.
3189         NSToIntRound(mozilla::clamped(mComponent1, 0.0f, 1.0f) * 255.0f),
3190         NSToIntRound(mozilla::clamped(mComponent2, 0.0f, 1.0f) * 255.0f),
3191         NSToIntRound(mozilla::clamped(mComponent3, 0.0f, 1.0f) * 255.0f),
3192         NSToIntRound(mozilla::clamped(mAlpha, 0.0f, 1.0f) * 255.0f));
3193   }
3194 
3195   // HSL color
3196   MOZ_ASSERT(aUnit == eCSSUnit_HSLColor || aUnit == eCSSUnit_HSLAColor);
3197   nscolor hsl = NS_HSL2RGB(mComponent1, mComponent2, mComponent3);
3198   return NS_RGBA(NS_GET_R(hsl), NS_GET_G(hsl), NS_GET_B(hsl),
3199                  NSToIntRound(mAlpha * 255.0f));
3200 }
3201 
IsNonTransparentColor() const3202 bool nsCSSValueFloatColor::IsNonTransparentColor() const {
3203   return mAlpha > 0.0f;
3204 }
3205 
AppendToString(nsCSSUnit aUnit,nsAString & aResult) const3206 void nsCSSValueFloatColor::AppendToString(nsCSSUnit aUnit,
3207                                           nsAString& aResult) const {
3208   // Similar to the rgb()/rgba() case in nsCSSValue::AppendToString. We omit the
3209   // alpha component if it's equal to 1.0f (full opaque). Also, we try to
3210   // preserve the author-specified function name, unless it's rgba()/hsla() and
3211   // we're omitting the alpha component - then we use rgb()/hsl().
3212   MOZ_ASSERT(nsCSSValue::IsFloatColorUnit(aUnit), "unexpected unit");
3213 
3214   bool showAlpha = (mAlpha != 1.0f);
3215   bool isHSL = (aUnit == eCSSUnit_HSLColor || aUnit == eCSSUnit_HSLAColor);
3216 
3217   if (isHSL) {
3218     aResult.AppendLiteral("hsl");
3219   } else {
3220     aResult.AppendLiteral("rgb");
3221   }
3222   if (showAlpha &&
3223       (aUnit == eCSSUnit_HSLAColor || aUnit == eCSSUnit_PercentageRGBAColor)) {
3224     aResult.AppendLiteral("a(");
3225   } else {
3226     aResult.Append('(');
3227   }
3228   if (isHSL) {
3229     aResult.AppendFloat(mComponent1 * 360.0f);
3230     aResult.AppendLiteral(", ");
3231   } else {
3232     aResult.AppendFloat(mComponent1 * 100.0f);
3233     aResult.AppendLiteral("%, ");
3234   }
3235   aResult.AppendFloat(mComponent2 * 100.0f);
3236   aResult.AppendLiteral("%, ");
3237   aResult.AppendFloat(mComponent3 * 100.0f);
3238   if (showAlpha) {
3239     aResult.AppendLiteral("%, ");
3240     aResult.AppendFloat(mAlpha);
3241     aResult.Append(')');
3242   } else {
3243     aResult.AppendLiteral("%)");
3244   }
3245 }
3246 
SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const3247 size_t nsCSSValueFloatColor::SizeOfIncludingThis(
3248     mozilla::MallocSizeOf aMallocSizeOf) const {
3249   // Only measure it if it's unshared, to avoid double-counting.
3250   size_t n = 0;
3251   if (mRefCnt <= 1) {
3252     n += aMallocSizeOf(this);
3253   }
3254   return n;
3255 }
3256 
3257 // --- nsCSSCornerSizes -----------------
3258 
nsCSSCornerSizes(void)3259 nsCSSCornerSizes::nsCSSCornerSizes(void) { MOZ_COUNT_CTOR(nsCSSCornerSizes); }
3260 
nsCSSCornerSizes(const nsCSSCornerSizes & aCopy)3261 nsCSSCornerSizes::nsCSSCornerSizes(const nsCSSCornerSizes& aCopy)
3262     : mTopLeft(aCopy.mTopLeft),
3263       mTopRight(aCopy.mTopRight),
3264       mBottomRight(aCopy.mBottomRight),
3265       mBottomLeft(aCopy.mBottomLeft) {
3266   MOZ_COUNT_CTOR(nsCSSCornerSizes);
3267 }
3268 
~nsCSSCornerSizes()3269 nsCSSCornerSizes::~nsCSSCornerSizes() { MOZ_COUNT_DTOR(nsCSSCornerSizes); }
3270 
Reset()3271 void nsCSSCornerSizes::Reset() {
3272   NS_FOR_CSS_FULL_CORNERS(corner) { this->GetCorner(corner).Reset(); }
3273 }
3274 
3275 static_assert(eCornerTopLeft == 0 && eCornerTopRight == 1 &&
3276                   eCornerBottomRight == 2 && eCornerBottomLeft == 3,
3277               "box corner constants not tl/tr/br/bl == 0/1/2/3");
3278 
3279 /* static */ const nsCSSCornerSizes::corner_type nsCSSCornerSizes::corners[4] =
3280     {
3281         &nsCSSCornerSizes::mTopLeft,
3282         &nsCSSCornerSizes::mTopRight,
3283         &nsCSSCornerSizes::mBottomRight,
3284         &nsCSSCornerSizes::mBottomLeft,
3285 };
3286 
SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const3287 size_t mozilla::css::GridTemplateAreasValue::SizeOfIncludingThis(
3288     mozilla::MallocSizeOf aMallocSizeOf) const {
3289   // Only measure it if it's unshared, to avoid double-counting.
3290   size_t n = 0;
3291   if (mRefCnt <= 1) {
3292     n += aMallocSizeOf(this);
3293     n += mNamedAreas.ShallowSizeOfExcludingThis(aMallocSizeOf);
3294     n += mTemplates.ShallowSizeOfExcludingThis(aMallocSizeOf);
3295   }
3296   return n;
3297 }
3298