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