1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 * representation of a declaration block (or style attribute) in a CSS
11 #include "mozilla/ArrayUtils.h"
12 #include "mozilla/MemoryReporting.h"
14 #include "mozilla/css/Declaration.h"
15 #include "nsPrintfCString.h"
16 #include "gfxFontConstants.h"
17 #include "nsStyleUtil.h"
22 Declaration::Declaration()
25 MOZ_COUNT_CTOR(mozilla::css::Declaration
);
28 Declaration::Declaration(const Declaration
& aCopy
)
29 : mOrder(aCopy
.mOrder
),
30 mVariableOrder(aCopy
.mVariableOrder
),
31 mData(aCopy
.mData
? aCopy
.mData
->Clone() : nullptr),
32 mImportantData(aCopy
.mImportantData
?
33 aCopy
.mImportantData
->Clone() : nullptr),
34 mVariables(aCopy
.mVariables
?
35 new CSSVariableDeclarations(*aCopy
.mVariables
) :
37 mImportantVariables(aCopy
.mImportantVariables
?
38 new CSSVariableDeclarations(*aCopy
.mImportantVariables
) :
42 MOZ_COUNT_CTOR(mozilla::css::Declaration
);
45 Declaration::~Declaration()
47 MOZ_COUNT_DTOR(mozilla::css::Declaration
);
51 Declaration::ValueAppended(nsCSSProperty aProperty
)
53 NS_ABORT_IF_FALSE(!mData
&& !mImportantData
,
54 "should only be called while expanded");
55 NS_ABORT_IF_FALSE(!nsCSSProps::IsShorthand(aProperty
),
56 "shorthands forbidden");
57 // order IS important for CSS, so remove and add to the end
58 mOrder
.RemoveElement(static_cast<uint32_t>(aProperty
));
59 mOrder
.AppendElement(static_cast<uint32_t>(aProperty
));
63 Declaration::RemoveProperty(nsCSSProperty aProperty
)
65 MOZ_ASSERT(0 <= aProperty
&& aProperty
< eCSSProperty_COUNT
);
67 nsCSSExpandedDataBlock data
;
69 NS_ABORT_IF_FALSE(!mData
&& !mImportantData
, "Expand didn't null things out");
71 if (nsCSSProps::IsShorthand(aProperty
)) {
72 CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p
, aProperty
) {
73 data
.ClearLonghandProperty(*p
);
74 mOrder
.RemoveElement(static_cast<uint32_t>(*p
));
77 data
.ClearLonghandProperty(aProperty
);
78 mOrder
.RemoveElement(static_cast<uint32_t>(aProperty
));
85 Declaration::HasProperty(nsCSSProperty aProperty
) const
87 NS_ABORT_IF_FALSE(0 <= aProperty
&&
88 aProperty
< eCSSProperty_COUNT_no_shorthands
,
89 "property ID out of range");
91 nsCSSCompressedDataBlock
*data
= GetValueIsImportant(aProperty
)
92 ? mImportantData
: mData
;
93 const nsCSSValue
*val
= data
->ValueFor(aProperty
);
98 Declaration::AppendValueToString(nsCSSProperty aProperty
,
100 nsCSSValue::Serialization aSerialization
) const
102 NS_ABORT_IF_FALSE(0 <= aProperty
&&
103 aProperty
< eCSSProperty_COUNT_no_shorthands
,
104 "property ID out of range");
106 nsCSSCompressedDataBlock
*data
= GetValueIsImportant(aProperty
)
107 ? mImportantData
: mData
;
108 const nsCSSValue
*val
= data
->ValueFor(aProperty
);
113 val
->AppendToString(aProperty
, aResult
, aSerialization
);
117 // Helper to append |aString| with the shorthand sides notation used in e.g.
118 // 'padding'. |aProperties| and |aValues| are expected to have 4 elements.
120 AppendSidesShorthandToString(const nsCSSProperty aProperties
[],
121 const nsCSSValue
* aValues
[],
123 nsCSSValue::Serialization aSerialization
)
125 const nsCSSValue
& value1
= *aValues
[0];
126 const nsCSSValue
& value2
= *aValues
[1];
127 const nsCSSValue
& value3
= *aValues
[2];
128 const nsCSSValue
& value4
= *aValues
[3];
130 NS_ABORT_IF_FALSE(value1
.GetUnit() != eCSSUnit_Null
, "null value 1");
131 value1
.AppendToString(aProperties
[0], aString
, aSerialization
);
132 if (value1
!= value2
|| value1
!= value3
|| value1
!= value4
) {
133 aString
.Append(char16_t(' '));
134 NS_ABORT_IF_FALSE(value2
.GetUnit() != eCSSUnit_Null
, "null value 2");
135 value2
.AppendToString(aProperties
[1], aString
, aSerialization
);
136 if (value1
!= value3
|| value2
!= value4
) {
137 aString
.Append(char16_t(' '));
138 NS_ABORT_IF_FALSE(value3
.GetUnit() != eCSSUnit_Null
, "null value 3");
139 value3
.AppendToString(aProperties
[2], aString
, aSerialization
);
140 if (value2
!= value4
) {
141 aString
.Append(char16_t(' '));
142 NS_ABORT_IF_FALSE(value4
.GetUnit() != eCSSUnit_Null
, "null value 4");
143 value4
.AppendToString(aProperties
[3], aString
, aSerialization
);
150 Declaration::GetValue(nsCSSProperty aProperty
, nsAString
& aValue
) const
152 GetValue(aProperty
, aValue
, nsCSSValue::eNormalized
);
156 Declaration::GetAuthoredValue(nsCSSProperty aProperty
, nsAString
& aValue
) const
158 GetValue(aProperty
, aValue
, nsCSSValue::eAuthorSpecified
);
162 Declaration::GetValue(nsCSSProperty aProperty
, nsAString
& aValue
,
163 nsCSSValue::Serialization aSerialization
) const
167 // simple properties are easy.
168 if (!nsCSSProps::IsShorthand(aProperty
)) {
169 AppendValueToString(aProperty
, aValue
, aSerialization
);
173 // DOM Level 2 Style says (when describing CSS2Properties, although
174 // not CSSStyleDeclaration.getPropertyValue):
175 // However, if there is no shorthand declaration that could be added
176 // to the ruleset without changing in any way the rules already
177 // declared in the ruleset (i.e., by adding longhand rules that were
178 // previously not declared in the ruleset), then the empty string
179 // should be returned for the shorthand property.
180 // This means we need to check a number of cases:
181 // (1) Since a shorthand sets all sub-properties, if some of its
182 // subproperties were not specified, we must return the empty
184 // (2) Since 'inherit', 'initial' and 'unset' can only be specified
185 // as the values for entire properties, we need to return the
186 // empty string if some but not all of the subproperties have one
188 // (3) Since a single value only makes sense with or without
189 // !important, we return the empty string if some values are
190 // !important and some are not.
191 // Since we're doing this check for 'inherit' and 'initial' up front,
192 // we can also simplify the property serialization code by serializing
193 // those values up front as well.
195 // Additionally, if a shorthand property was set using a value with a
196 // variable reference and none of its component longhand properties were
197 // then overridden on the declaration, we return the token stream
198 // assigned to the shorthand.
199 const nsCSSValue
* tokenStream
= nullptr;
200 uint32_t totalCount
= 0, importantCount
= 0,
201 initialCount
= 0, inheritCount
= 0, unsetCount
= 0,
202 matchingTokenStreamCount
= 0, nonMatchingTokenStreamCount
= 0;
203 CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p
, aProperty
) {
204 if (*p
== eCSSProperty__x_system_font
||
205 nsCSSProps::PropHasFlags(*p
, CSS_PROPERTY_DIRECTIONAL_SOURCE
)) {
206 // The system-font subproperty and the *-source properties don't count.
210 const nsCSSValue
*val
= mData
->ValueFor(*p
);
211 NS_ABORT_IF_FALSE(!val
|| !mImportantData
|| !mImportantData
->ValueFor(*p
),
212 "can't be in both blocks");
213 if (!val
&& mImportantData
) {
215 val
= mImportantData
->ValueFor(*p
);
218 // Case (1) above: some subproperties not specified.
221 if (val
->GetUnit() == eCSSUnit_Inherit
) {
223 } else if (val
->GetUnit() == eCSSUnit_Initial
) {
225 } else if (val
->GetUnit() == eCSSUnit_Unset
) {
227 } else if (val
->GetUnit() == eCSSUnit_TokenStream
) {
228 if (val
->GetTokenStreamValue()->mShorthandPropertyID
== aProperty
) {
230 ++matchingTokenStreamCount
;
232 ++nonMatchingTokenStreamCount
;
236 if (importantCount
!= 0 && importantCount
!= totalCount
) {
237 // Case (3), no consistent importance.
240 if (initialCount
== totalCount
) {
241 // Simplify serialization below by serializing initial up-front.
242 nsCSSValue(eCSSUnit_Initial
).AppendToString(eCSSProperty_UNKNOWN
, aValue
,
243 nsCSSValue::eNormalized
);
246 if (inheritCount
== totalCount
) {
247 // Simplify serialization below by serializing inherit up-front.
248 nsCSSValue(eCSSUnit_Inherit
).AppendToString(eCSSProperty_UNKNOWN
, aValue
,
249 nsCSSValue::eNormalized
);
252 if (unsetCount
== totalCount
) {
253 // Simplify serialization below by serializing unset up-front.
254 nsCSSValue(eCSSUnit_Unset
).AppendToString(eCSSProperty_UNKNOWN
, aValue
,
255 nsCSSValue::eNormalized
);
258 if (initialCount
!= 0 || inheritCount
!= 0 ||
259 unsetCount
!= 0 || nonMatchingTokenStreamCount
!= 0) {
260 // Case (2): partially initial, inherit, unset or token stream.
264 if (matchingTokenStreamCount
== totalCount
) {
265 // Shorthand was specified using variable references and all of its
266 // longhand components were set by the shorthand.
267 aValue
.Append(tokenStream
->GetTokenStreamValue()->mTokenStream
);
269 // In all other cases, serialize to the empty string.
274 nsCSSCompressedDataBlock
*data
= importantCount
? mImportantData
: mData
;
276 case eCSSProperty_margin
:
277 case eCSSProperty_padding
:
278 case eCSSProperty_border_color
:
279 case eCSSProperty_border_style
:
280 case eCSSProperty_border_width
: {
281 const nsCSSProperty
* subprops
=
282 nsCSSProps::SubpropertyEntryFor(aProperty
);
283 NS_ABORT_IF_FALSE(nsCSSProps::GetStringValue(subprops
[0]).Find("-top") !=
284 kNotFound
, "first subprop must be top");
285 NS_ABORT_IF_FALSE(nsCSSProps::GetStringValue(subprops
[1]).Find("-right") !=
286 kNotFound
, "second subprop must be right");
287 NS_ABORT_IF_FALSE(nsCSSProps::GetStringValue(subprops
[2]).Find("-bottom") !=
288 kNotFound
, "third subprop must be bottom");
289 NS_ABORT_IF_FALSE(nsCSSProps::GetStringValue(subprops
[3]).Find("-left") !=
290 kNotFound
, "fourth subprop must be left");
291 const nsCSSValue
* vals
[4] = {
292 data
->ValueFor(subprops
[0]),
293 data
->ValueFor(subprops
[1]),
294 data
->ValueFor(subprops
[2]),
295 data
->ValueFor(subprops
[3])
297 AppendSidesShorthandToString(subprops
, vals
, aValue
, aSerialization
);
300 case eCSSProperty_border_radius
:
301 case eCSSProperty__moz_outline_radius
: {
302 const nsCSSProperty
* subprops
=
303 nsCSSProps::SubpropertyEntryFor(aProperty
);
304 const nsCSSValue
* vals
[4] = {
305 data
->ValueFor(subprops
[0]),
306 data
->ValueFor(subprops
[1]),
307 data
->ValueFor(subprops
[2]),
308 data
->ValueFor(subprops
[3])
311 // For compatibility, only write a slash and the y-values
312 // if they're not identical to the x-values.
314 const nsCSSValue
* xVals
[4];
315 const nsCSSValue
* yVals
[4];
316 for (int i
= 0; i
< 4; i
++) {
317 if (vals
[i
]->GetUnit() == eCSSUnit_Pair
) {
319 xVals
[i
] = &vals
[i
]->GetPairValue().mXValue
;
320 yVals
[i
] = &vals
[i
]->GetPairValue().mYValue
;
322 xVals
[i
] = yVals
[i
] = vals
[i
];
326 AppendSidesShorthandToString(subprops
, xVals
, aValue
, aSerialization
);
328 aValue
.AppendLiteral(" / ");
329 AppendSidesShorthandToString(subprops
, yVals
, aValue
, aSerialization
);
333 case eCSSProperty_border_image
: {
334 // Even though there are some cases where we could omit
335 // 'border-image-source' (when it's none), it's probably not a
336 // good idea since it's likely to be confusing. It would also
337 // require adding the extra check that we serialize *something*.
338 AppendValueToString(eCSSProperty_border_image_source
, aValue
,
341 bool sliceDefault
= data
->HasDefaultBorderImageSlice();
342 bool widthDefault
= data
->HasDefaultBorderImageWidth();
343 bool outsetDefault
= data
->HasDefaultBorderImageOutset();
345 if (!sliceDefault
|| !widthDefault
|| !outsetDefault
) {
346 aValue
.Append(char16_t(' '));
347 AppendValueToString(eCSSProperty_border_image_slice
, aValue
,
349 if (!widthDefault
|| !outsetDefault
) {
350 aValue
.AppendLiteral(" /");
352 aValue
.Append(char16_t(' '));
353 AppendValueToString(eCSSProperty_border_image_width
, aValue
,
356 if (!outsetDefault
) {
357 aValue
.AppendLiteral(" / ");
358 AppendValueToString(eCSSProperty_border_image_outset
, aValue
,
364 bool repeatDefault
= data
->HasDefaultBorderImageRepeat();
365 if (!repeatDefault
) {
366 aValue
.Append(char16_t(' '));
367 AppendValueToString(eCSSProperty_border_image_repeat
, aValue
,
372 case eCSSProperty_border
: {
373 // If we have a non-default value for any of the properties that
374 // this shorthand sets but cannot specify, we have to return the
376 if (data
->ValueFor(eCSSProperty_border_image_source
)->GetUnit() !=
378 !data
->HasDefaultBorderImageSlice() ||
379 !data
->HasDefaultBorderImageWidth() ||
380 !data
->HasDefaultBorderImageOutset() ||
381 !data
->HasDefaultBorderImageRepeat() ||
382 data
->ValueFor(eCSSProperty_border_top_colors
)->GetUnit() !=
384 data
->ValueFor(eCSSProperty_border_right_colors
)->GetUnit() !=
386 data
->ValueFor(eCSSProperty_border_bottom_colors
)->GetUnit() !=
388 data
->ValueFor(eCSSProperty_border_left_colors
)->GetUnit() !=
393 const nsCSSProperty
* subproptables
[3] = {
394 nsCSSProps::SubpropertyEntryFor(eCSSProperty_border_color
),
395 nsCSSProps::SubpropertyEntryFor(eCSSProperty_border_style
),
396 nsCSSProps::SubpropertyEntryFor(eCSSProperty_border_width
)
399 for (const nsCSSProperty
** subprops
= subproptables
,
400 **subprops_end
= ArrayEnd(subproptables
);
401 subprops
< subprops_end
; ++subprops
) {
402 // Check only the first four subprops in each table, since the
403 // others are extras for dimensional box properties.
404 const nsCSSValue
*firstSide
= data
->ValueFor((*subprops
)[0]);
405 for (int32_t side
= 1; side
< 4; ++side
) {
406 const nsCSSValue
*otherSide
=
407 data
->ValueFor((*subprops
)[side
]);
408 if (*firstSide
!= *otherSide
)
413 // We can't express what we have in the border shorthand
416 // tweak aProperty and fall through
417 aProperty
= eCSSProperty_border_top
;
419 case eCSSProperty_border_top
:
420 case eCSSProperty_border_right
:
421 case eCSSProperty_border_bottom
:
422 case eCSSProperty_border_left
:
423 case eCSSProperty_border_start
:
424 case eCSSProperty_border_end
:
425 case eCSSProperty__moz_column_rule
:
426 case eCSSProperty_outline
: {
427 const nsCSSProperty
* subprops
=
428 nsCSSProps::SubpropertyEntryFor(aProperty
);
429 NS_ABORT_IF_FALSE(StringEndsWith(nsCSSProps::GetStringValue(subprops
[2]),
430 NS_LITERAL_CSTRING("-color")) ||
431 StringEndsWith(nsCSSProps::GetStringValue(subprops
[2]),
432 NS_LITERAL_CSTRING("-color-value")),
433 "third subprop must be the color property");
434 const nsCSSValue
*colorValue
= data
->ValueFor(subprops
[2]);
435 bool isMozUseTextColor
=
436 colorValue
->GetUnit() == eCSSUnit_Enumerated
&&
437 colorValue
->GetIntValue() == NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR
;
438 if (!AppendValueToString(subprops
[0], aValue
, aSerialization
) ||
439 !(aValue
.Append(char16_t(' ')),
440 AppendValueToString(subprops
[1], aValue
, aSerialization
)) ||
441 // Don't output a third value when it's -moz-use-text-color.
442 !(isMozUseTextColor
||
443 (aValue
.Append(char16_t(' ')),
444 AppendValueToString(subprops
[2], aValue
, aSerialization
)))) {
449 case eCSSProperty_margin_left
:
450 case eCSSProperty_margin_right
:
451 case eCSSProperty_margin_start
:
452 case eCSSProperty_margin_end
:
453 case eCSSProperty_padding_left
:
454 case eCSSProperty_padding_right
:
455 case eCSSProperty_padding_start
:
456 case eCSSProperty_padding_end
:
457 case eCSSProperty_border_left_color
:
458 case eCSSProperty_border_left_style
:
459 case eCSSProperty_border_left_width
:
460 case eCSSProperty_border_right_color
:
461 case eCSSProperty_border_right_style
:
462 case eCSSProperty_border_right_width
:
463 case eCSSProperty_border_start_color
:
464 case eCSSProperty_border_start_style
:
465 case eCSSProperty_border_start_width
:
466 case eCSSProperty_border_end_color
:
467 case eCSSProperty_border_end_style
:
468 case eCSSProperty_border_end_width
: {
469 const nsCSSProperty
* subprops
=
470 nsCSSProps::SubpropertyEntryFor(aProperty
);
471 NS_ABORT_IF_FALSE(subprops
[3] == eCSSProperty_UNKNOWN
,
472 "not box property with physical vs. logical cascading");
473 AppendValueToString(subprops
[0], aValue
, aSerialization
);
476 case eCSSProperty_background
: {
477 // We know from above that all subproperties were specified.
478 // However, we still can't represent that in the shorthand unless
479 // they're all lists of the same length. So if they're different
480 // lengths, we need to bail out.
481 // We also need to bail out if an item has background-clip and
482 // background-origin that are different and not the default
483 // values. (We omit them if they're both default.)
484 const nsCSSValueList
*image
=
485 data
->ValueFor(eCSSProperty_background_image
)->
487 const nsCSSValuePairList
*repeat
=
488 data
->ValueFor(eCSSProperty_background_repeat
)->
490 const nsCSSValueList
*attachment
=
491 data
->ValueFor(eCSSProperty_background_attachment
)->
493 const nsCSSValueList
*position
=
494 data
->ValueFor(eCSSProperty_background_position
)->
496 const nsCSSValueList
*clip
=
497 data
->ValueFor(eCSSProperty_background_clip
)->
499 const nsCSSValueList
*origin
=
500 data
->ValueFor(eCSSProperty_background_origin
)->
502 const nsCSSValuePairList
*size
=
503 data
->ValueFor(eCSSProperty_background_size
)->
506 image
->mValue
.AppendToString(eCSSProperty_background_image
, aValue
,
508 aValue
.Append(char16_t(' '));
509 repeat
->mXValue
.AppendToString(eCSSProperty_background_repeat
, aValue
,
511 if (repeat
->mYValue
.GetUnit() != eCSSUnit_Null
) {
512 repeat
->mYValue
.AppendToString(eCSSProperty_background_repeat
, aValue
,
515 aValue
.Append(char16_t(' '));
516 attachment
->mValue
.AppendToString(eCSSProperty_background_attachment
,
517 aValue
, aSerialization
);
518 aValue
.Append(char16_t(' '));
519 position
->mValue
.AppendToString(eCSSProperty_background_position
,
520 aValue
, aSerialization
);
522 if (size
->mXValue
.GetUnit() != eCSSUnit_Auto
||
523 size
->mYValue
.GetUnit() != eCSSUnit_Auto
) {
524 aValue
.Append(char16_t(' '));
525 aValue
.Append(char16_t('/'));
526 aValue
.Append(char16_t(' '));
527 size
->mXValue
.AppendToString(eCSSProperty_background_size
, aValue
,
529 aValue
.Append(char16_t(' '));
530 size
->mYValue
.AppendToString(eCSSProperty_background_size
, aValue
,
534 NS_ABORT_IF_FALSE(clip
->mValue
.GetUnit() == eCSSUnit_Enumerated
&&
535 origin
->mValue
.GetUnit() == eCSSUnit_Enumerated
,
536 "should not have inherit/initial within list");
538 if (clip
->mValue
.GetIntValue() != NS_STYLE_BG_CLIP_BORDER
||
539 origin
->mValue
.GetIntValue() != NS_STYLE_BG_ORIGIN_PADDING
) {
540 MOZ_ASSERT(nsCSSProps::kKeywordTableTable
[
541 eCSSProperty_background_origin
] ==
542 nsCSSProps::kBackgroundOriginKTable
);
543 MOZ_ASSERT(nsCSSProps::kKeywordTableTable
[
544 eCSSProperty_background_clip
] ==
545 nsCSSProps::kBackgroundOriginKTable
);
546 static_assert(NS_STYLE_BG_CLIP_BORDER
==
547 NS_STYLE_BG_ORIGIN_BORDER
&&
548 NS_STYLE_BG_CLIP_PADDING
==
549 NS_STYLE_BG_ORIGIN_PADDING
&&
550 NS_STYLE_BG_CLIP_CONTENT
==
551 NS_STYLE_BG_ORIGIN_CONTENT
,
552 "bg-clip and bg-origin style constants must agree");
553 aValue
.Append(char16_t(' '));
554 origin
->mValue
.AppendToString(eCSSProperty_background_origin
, aValue
,
557 if (clip
->mValue
!= origin
->mValue
) {
558 aValue
.Append(char16_t(' '));
559 clip
->mValue
.AppendToString(eCSSProperty_background_clip
, aValue
,
564 image
= image
->mNext
;
565 repeat
= repeat
->mNext
;
566 attachment
= attachment
->mNext
;
567 position
= position
->mNext
;
569 origin
= origin
->mNext
;
573 if (repeat
|| attachment
|| position
|| clip
|| origin
|| size
) {
574 // Uneven length lists, so can't be serialized as shorthand.
580 if (!repeat
|| !attachment
|| !position
|| !clip
|| !origin
|| !size
) {
581 // Uneven length lists, so can't be serialized as shorthand.
585 aValue
.Append(char16_t(','));
586 aValue
.Append(char16_t(' '));
589 aValue
.Append(char16_t(' '));
590 AppendValueToString(eCSSProperty_background_color
, aValue
,
594 case eCSSProperty_font
: {
595 // systemFont might not be present; other values are guaranteed to be
596 // available based on the shorthand check at the beginning of the
597 // function, as long as the prop is enabled
598 const nsCSSValue
*systemFont
=
599 data
->ValueFor(eCSSProperty__x_system_font
);
600 const nsCSSValue
*style
=
601 data
->ValueFor(eCSSProperty_font_style
);
602 const nsCSSValue
*weight
=
603 data
->ValueFor(eCSSProperty_font_weight
);
604 const nsCSSValue
*size
=
605 data
->ValueFor(eCSSProperty_font_size
);
606 const nsCSSValue
*lh
=
607 data
->ValueFor(eCSSProperty_line_height
);
608 const nsCSSValue
*family
=
609 data
->ValueFor(eCSSProperty_font_family
);
610 const nsCSSValue
*stretch
=
611 data
->ValueFor(eCSSProperty_font_stretch
);
612 const nsCSSValue
*sizeAdjust
=
613 data
->ValueFor(eCSSProperty_font_size_adjust
);
614 const nsCSSValue
*featureSettings
=
615 data
->ValueFor(eCSSProperty_font_feature_settings
);
616 const nsCSSValue
*languageOverride
=
617 data
->ValueFor(eCSSProperty_font_language_override
);
618 const nsCSSValue
*fontKerning
=
619 data
->ValueFor(eCSSProperty_font_kerning
);
620 const nsCSSValue
*fontSynthesis
=
621 data
->ValueFor(eCSSProperty_font_synthesis
);
622 const nsCSSValue
*fontVariantAlternates
=
623 data
->ValueFor(eCSSProperty_font_variant_alternates
);
624 const nsCSSValue
*fontVariantCaps
=
625 data
->ValueFor(eCSSProperty_font_variant_caps
);
626 const nsCSSValue
*fontVariantEastAsian
=
627 data
->ValueFor(eCSSProperty_font_variant_east_asian
);
628 const nsCSSValue
*fontVariantLigatures
=
629 data
->ValueFor(eCSSProperty_font_variant_ligatures
);
630 const nsCSSValue
*fontVariantNumeric
=
631 data
->ValueFor(eCSSProperty_font_variant_numeric
);
632 const nsCSSValue
*fontVariantPosition
=
633 data
->ValueFor(eCSSProperty_font_variant_position
);
636 systemFont
->GetUnit() != eCSSUnit_None
&&
637 systemFont
->GetUnit() != eCSSUnit_Null
) {
638 if (style
->GetUnit() != eCSSUnit_System_Font
||
639 weight
->GetUnit() != eCSSUnit_System_Font
||
640 size
->GetUnit() != eCSSUnit_System_Font
||
641 lh
->GetUnit() != eCSSUnit_System_Font
||
642 family
->GetUnit() != eCSSUnit_System_Font
||
643 stretch
->GetUnit() != eCSSUnit_System_Font
||
644 sizeAdjust
->GetUnit() != eCSSUnit_System_Font
||
645 featureSettings
->GetUnit() != eCSSUnit_System_Font
||
646 languageOverride
->GetUnit() != eCSSUnit_System_Font
||
647 fontKerning
->GetUnit() != eCSSUnit_System_Font
||
648 fontSynthesis
->GetUnit() != eCSSUnit_System_Font
||
649 fontVariantAlternates
->GetUnit() != eCSSUnit_System_Font
||
650 fontVariantCaps
->GetUnit() != eCSSUnit_System_Font
||
651 fontVariantEastAsian
->GetUnit() != eCSSUnit_System_Font
||
652 fontVariantLigatures
->GetUnit() != eCSSUnit_System_Font
||
653 fontVariantNumeric
->GetUnit() != eCSSUnit_System_Font
||
654 fontVariantPosition
->GetUnit() != eCSSUnit_System_Font
) {
655 // This can't be represented as a shorthand.
658 systemFont
->AppendToString(eCSSProperty__x_system_font
, aValue
,
661 // properties reset by this shorthand property to their
662 // initial values but not represented in its syntax
663 if (stretch
->GetUnit() != eCSSUnit_Enumerated
||
664 stretch
->GetIntValue() != NS_STYLE_FONT_STRETCH_NORMAL
||
665 sizeAdjust
->GetUnit() != eCSSUnit_None
||
666 featureSettings
->GetUnit() != eCSSUnit_Normal
||
667 languageOverride
->GetUnit() != eCSSUnit_Normal
||
668 fontKerning
->GetIntValue() != NS_FONT_KERNING_AUTO
||
669 fontSynthesis
->GetUnit() != eCSSUnit_Enumerated
||
670 fontSynthesis
->GetIntValue() !=
671 (NS_FONT_SYNTHESIS_WEIGHT
| NS_FONT_SYNTHESIS_STYLE
) ||
672 fontVariantAlternates
->GetUnit() != eCSSUnit_Normal
||
673 fontVariantEastAsian
->GetUnit() != eCSSUnit_Normal
||
674 fontVariantLigatures
->GetUnit() != eCSSUnit_Normal
||
675 fontVariantNumeric
->GetUnit() != eCSSUnit_Normal
||
676 fontVariantPosition
->GetUnit() != eCSSUnit_Normal
) {
680 // only a normal or small-caps values of font-variant-caps can
681 // be represented in the font shorthand
682 if (fontVariantCaps
->GetUnit() != eCSSUnit_Normal
&&
683 (fontVariantCaps
->GetUnit() != eCSSUnit_Enumerated
||
684 fontVariantCaps
->GetIntValue() != NS_FONT_VARIANT_CAPS_SMALLCAPS
)) {
688 if (style
->GetUnit() != eCSSUnit_Enumerated
||
689 style
->GetIntValue() != NS_FONT_STYLE_NORMAL
) {
690 style
->AppendToString(eCSSProperty_font_style
, aValue
,
692 aValue
.Append(char16_t(' '));
694 if (fontVariantCaps
->GetUnit() != eCSSUnit_Normal
) {
695 fontVariantCaps
->AppendToString(eCSSProperty_font_variant_caps
, aValue
,
697 aValue
.Append(char16_t(' '));
699 if (weight
->GetUnit() != eCSSUnit_Enumerated
||
700 weight
->GetIntValue() != NS_FONT_WEIGHT_NORMAL
) {
701 weight
->AppendToString(eCSSProperty_font_weight
, aValue
,
703 aValue
.Append(char16_t(' '));
705 size
->AppendToString(eCSSProperty_font_size
, aValue
, aSerialization
);
706 if (lh
->GetUnit() != eCSSUnit_Normal
) {
707 aValue
.Append(char16_t('/'));
708 lh
->AppendToString(eCSSProperty_line_height
, aValue
, aSerialization
);
710 aValue
.Append(char16_t(' '));
711 family
->AppendToString(eCSSProperty_font_family
, aValue
,
716 case eCSSProperty_font_variant
: {
717 const nsCSSProperty
*subprops
=
718 nsCSSProps::SubpropertyEntryFor(aProperty
);
719 const nsCSSValue
*fontVariantLigatures
=
720 data
->ValueFor(eCSSProperty_font_variant_ligatures
);
722 // all subproperty values normal? system font?
723 bool normalLigs
= true, normalNonLigs
= true, systemFont
= true,
725 for (const nsCSSProperty
*sp
= subprops
; *sp
!= eCSSProperty_UNKNOWN
; sp
++) {
726 const nsCSSValue
*spVal
= data
->ValueFor(*sp
);
727 bool isNormal
= (spVal
->GetUnit() == eCSSUnit_Normal
);
728 if (*sp
== eCSSProperty_font_variant_ligatures
) {
729 normalLigs
= normalLigs
&& isNormal
;
731 normalNonLigs
= normalNonLigs
&& isNormal
;
733 bool isSystem
= (spVal
->GetUnit() == eCSSUnit_System_Font
);
734 systemFont
= systemFont
&& isSystem
;
735 hasSystem
= hasSystem
|| isSystem
;
739 fontVariantLigatures
->GetUnit() == eCSSUnit_None
;
741 // normal, none, or system font ==> single value
742 if ((normalLigs
&& normalNonLigs
) ||
743 (normalNonLigs
&& ligsNone
) ||
745 fontVariantLigatures
->AppendToString(eCSSProperty_font_variant_ligatures
,
748 } else if (ligsNone
|| hasSystem
) {
749 // ligatures none but other values are non-normal ==> empty
750 // at least one but not all values are system font ==> empty
753 // iterate over and append non-normal values
754 bool appendSpace
= false;
755 for (const nsCSSProperty
*sp
= subprops
;
756 *sp
!= eCSSProperty_UNKNOWN
; sp
++) {
757 const nsCSSValue
*spVal
= data
->ValueFor(*sp
);
758 if (spVal
&& spVal
->GetUnit() != eCSSUnit_Normal
) {
760 aValue
.Append(char16_t(' '));
764 spVal
->AppendToString(*sp
, aValue
, aSerialization
);
770 case eCSSProperty_list_style
:
771 if (AppendValueToString(eCSSProperty_list_style_position
, aValue
,
773 aValue
.Append(char16_t(' '));
775 if (AppendValueToString(eCSSProperty_list_style_image
, aValue
,
777 aValue
.Append(char16_t(' '));
779 AppendValueToString(eCSSProperty_list_style_type
, aValue
,
782 case eCSSProperty_overflow
: {
783 const nsCSSValue
&xValue
=
784 *data
->ValueFor(eCSSProperty_overflow_x
);
785 const nsCSSValue
&yValue
=
786 *data
->ValueFor(eCSSProperty_overflow_y
);
787 if (xValue
== yValue
)
788 xValue
.AppendToString(eCSSProperty_overflow_x
, aValue
, aSerialization
);
791 case eCSSProperty_text_decoration
: {
792 // If text-decoration-color or text-decoration-style isn't initial value,
793 // we cannot serialize the text-decoration shorthand value.
794 const nsCSSValue
*decorationColor
=
795 data
->ValueFor(eCSSProperty_text_decoration_color
);
796 const nsCSSValue
*decorationStyle
=
797 data
->ValueFor(eCSSProperty_text_decoration_style
);
799 NS_ABORT_IF_FALSE(decorationStyle
->GetUnit() == eCSSUnit_Enumerated
,
800 nsPrintfCString("bad text-decoration-style unit %d",
801 decorationStyle
->GetUnit()).get());
803 if (decorationColor
->GetUnit() != eCSSUnit_Enumerated
||
804 decorationColor
->GetIntValue() != NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR
||
805 decorationStyle
->GetIntValue() !=
806 NS_STYLE_TEXT_DECORATION_STYLE_SOLID
) {
810 AppendValueToString(eCSSProperty_text_decoration_line
, aValue
,
814 case eCSSProperty_transition
: {
815 const nsCSSValue
*transProp
=
816 data
->ValueFor(eCSSProperty_transition_property
);
817 const nsCSSValue
*transDuration
=
818 data
->ValueFor(eCSSProperty_transition_duration
);
819 const nsCSSValue
*transTiming
=
820 data
->ValueFor(eCSSProperty_transition_timing_function
);
821 const nsCSSValue
*transDelay
=
822 data
->ValueFor(eCSSProperty_transition_delay
);
824 NS_ABORT_IF_FALSE(transDuration
->GetUnit() == eCSSUnit_List
||
825 transDuration
->GetUnit() == eCSSUnit_ListDep
,
826 nsPrintfCString("bad t-duration unit %d",
827 transDuration
->GetUnit()).get());
828 NS_ABORT_IF_FALSE(transTiming
->GetUnit() == eCSSUnit_List
||
829 transTiming
->GetUnit() == eCSSUnit_ListDep
,
830 nsPrintfCString("bad t-timing unit %d",
831 transTiming
->GetUnit()).get());
832 NS_ABORT_IF_FALSE(transDelay
->GetUnit() == eCSSUnit_List
||
833 transDelay
->GetUnit() == eCSSUnit_ListDep
,
834 nsPrintfCString("bad t-delay unit %d",
835 transDelay
->GetUnit()).get());
837 const nsCSSValueList
* dur
= transDuration
->GetListValue();
838 const nsCSSValueList
* tim
= transTiming
->GetListValue();
839 const nsCSSValueList
* del
= transDelay
->GetListValue();
841 if (transProp
->GetUnit() == eCSSUnit_None
||
842 transProp
->GetUnit() == eCSSUnit_All
) {
843 // If any of the other three lists has more than one element,
844 // we can't use the shorthand.
845 if (!dur
->mNext
&& !tim
->mNext
&& !del
->mNext
) {
846 transProp
->AppendToString(eCSSProperty_transition_property
, aValue
,
848 aValue
.Append(char16_t(' '));
849 dur
->mValue
.AppendToString(eCSSProperty_transition_duration
,aValue
,
851 aValue
.Append(char16_t(' '));
852 tim
->mValue
.AppendToString(eCSSProperty_transition_timing_function
,
853 aValue
, aSerialization
);
854 aValue
.Append(char16_t(' '));
855 del
->mValue
.AppendToString(eCSSProperty_transition_delay
, aValue
,
857 aValue
.Append(char16_t(' '));
862 NS_ABORT_IF_FALSE(transProp
->GetUnit() == eCSSUnit_List
||
863 transProp
->GetUnit() == eCSSUnit_ListDep
,
864 nsPrintfCString("bad t-prop unit %d",
865 transProp
->GetUnit()).get());
866 const nsCSSValueList
* pro
= transProp
->GetListValue();
868 pro
->mValue
.AppendToString(eCSSProperty_transition_property
,
869 aValue
, aSerialization
);
870 aValue
.Append(char16_t(' '));
871 dur
->mValue
.AppendToString(eCSSProperty_transition_duration
,
872 aValue
, aSerialization
);
873 aValue
.Append(char16_t(' '));
874 tim
->mValue
.AppendToString(eCSSProperty_transition_timing_function
,
875 aValue
, aSerialization
);
876 aValue
.Append(char16_t(' '));
877 del
->mValue
.AppendToString(eCSSProperty_transition_delay
,
878 aValue
, aSerialization
);
883 if (!pro
|| !dur
|| !tim
|| !del
) {
886 aValue
.AppendLiteral(", ");
888 if (pro
|| dur
|| tim
|| del
) {
889 // Lists not all the same length, can't use shorthand.
895 case eCSSProperty_animation
: {
896 const nsCSSProperty
* subprops
=
897 nsCSSProps::SubpropertyEntryFor(eCSSProperty_animation
);
898 static const size_t numProps
= 8;
899 NS_ABORT_IF_FALSE(subprops
[numProps
] == eCSSProperty_UNKNOWN
,
900 "unexpected number of subproperties");
901 const nsCSSValue
* values
[numProps
];
902 const nsCSSValueList
* lists
[numProps
];
904 for (uint32_t i
= 0; i
< numProps
; ++i
) {
905 values
[i
] = data
->ValueFor(subprops
[i
]);
906 NS_ABORT_IF_FALSE(values
[i
]->GetUnit() == eCSSUnit_List
||
907 values
[i
]->GetUnit() == eCSSUnit_ListDep
,
908 nsPrintfCString("bad a-duration unit %d",
909 values
[i
]->GetUnit()).get());
910 lists
[i
] = values
[i
]->GetListValue();
914 // We must serialize 'animation-name' last in case it has
915 // a value that conflicts with one of the other keyword properties.
916 NS_ABORT_IF_FALSE(subprops
[numProps
- 1] ==
917 eCSSProperty_animation_name
,
918 "animation-name must be last");
920 for (uint32_t i
= 0;;) {
921 lists
[i
]->mValue
.AppendToString(subprops
[i
], aValue
, aSerialization
);
922 lists
[i
] = lists
[i
]->mNext
;
926 if (++i
== numProps
) {
929 aValue
.Append(char16_t(' '));
934 aValue
.AppendLiteral(", ");
936 for (uint32_t i
= 0; i
< numProps
; ++i
) {
938 // Lists not all the same length, can't use shorthand.
945 case eCSSProperty_marker
: {
946 const nsCSSValue
&endValue
=
947 *data
->ValueFor(eCSSProperty_marker_end
);
948 const nsCSSValue
&midValue
=
949 *data
->ValueFor(eCSSProperty_marker_mid
);
950 const nsCSSValue
&startValue
=
951 *data
->ValueFor(eCSSProperty_marker_start
);
952 if (endValue
== midValue
&& midValue
== startValue
)
953 AppendValueToString(eCSSProperty_marker_end
, aValue
, aSerialization
);
956 case eCSSProperty__moz_columns
: {
957 // Two values, column-count and column-width, separated by a space.
958 const nsCSSProperty
* subprops
=
959 nsCSSProps::SubpropertyEntryFor(aProperty
);
960 AppendValueToString(subprops
[0], aValue
, aSerialization
);
961 aValue
.Append(char16_t(' '));
962 AppendValueToString(subprops
[1], aValue
, aSerialization
);
965 case eCSSProperty_flex
: {
966 // flex-grow, flex-shrink, flex-basis, separated by single space
967 const nsCSSProperty
* subprops
=
968 nsCSSProps::SubpropertyEntryFor(aProperty
);
970 AppendValueToString(subprops
[0], aValue
, aSerialization
);
971 aValue
.Append(char16_t(' '));
972 AppendValueToString(subprops
[1], aValue
, aSerialization
);
973 aValue
.Append(char16_t(' '));
974 AppendValueToString(subprops
[2], aValue
, aSerialization
);
977 case eCSSProperty_flex_flow
: {
978 // flex-direction, flex-wrap, separated by single space
979 const nsCSSProperty
* subprops
=
980 nsCSSProps::SubpropertyEntryFor(aProperty
);
981 NS_ABORT_IF_FALSE(subprops
[2] == eCSSProperty_UNKNOWN
,
982 "must have exactly two subproperties");
984 AppendValueToString(subprops
[0], aValue
, aSerialization
);
985 aValue
.Append(char16_t(' '));
986 AppendValueToString(subprops
[1], aValue
, aSerialization
);
989 case eCSSProperty_grid_row
:
990 case eCSSProperty_grid_column
: {
991 // grid-{row,column}-start, grid-{row,column}-end, separated by a slash
992 const nsCSSProperty
* subprops
=
993 nsCSSProps::SubpropertyEntryFor(aProperty
);
994 NS_ABORT_IF_FALSE(subprops
[2] == eCSSProperty_UNKNOWN
,
995 "must have exactly two subproperties");
997 // TODO: should we simplify when possible?
998 AppendValueToString(subprops
[0], aValue
, aSerialization
);
999 aValue
.AppendLiteral(" / ");
1000 AppendValueToString(subprops
[1], aValue
, aSerialization
);
1003 case eCSSProperty_grid_area
: {
1004 const nsCSSProperty
* subprops
=
1005 nsCSSProps::SubpropertyEntryFor(aProperty
);
1006 NS_ABORT_IF_FALSE(subprops
[4] == eCSSProperty_UNKNOWN
,
1007 "must have exactly four subproperties");
1009 // TODO: should we simplify when possible?
1010 AppendValueToString(subprops
[0], aValue
, aSerialization
);
1011 aValue
.AppendLiteral(" / ");
1012 AppendValueToString(subprops
[1], aValue
, aSerialization
);
1013 aValue
.AppendLiteral(" / ");
1014 AppendValueToString(subprops
[2], aValue
, aSerialization
);
1015 aValue
.AppendLiteral(" / ");
1016 AppendValueToString(subprops
[3], aValue
, aSerialization
);
1020 // This can express either grid-template-{areas,columns,rows}
1021 // or grid-auto-{flow,columns,rows}, but not both.
1022 case eCSSProperty_grid
: {
1023 const nsCSSValue
& areasValue
=
1024 *data
->ValueFor(eCSSProperty_grid_template_areas
);
1025 const nsCSSValue
& columnsValue
=
1026 *data
->ValueFor(eCSSProperty_grid_template_columns
);
1027 const nsCSSValue
& rowsValue
=
1028 *data
->ValueFor(eCSSProperty_grid_template_rows
);
1030 const nsCSSValue
& autoFlowValue
=
1031 *data
->ValueFor(eCSSProperty_grid_auto_flow
);
1032 const nsCSSValue
& autoColumnsValue
=
1033 *data
->ValueFor(eCSSProperty_grid_auto_columns
);
1034 const nsCSSValue
& autoRowsValue
=
1035 *data
->ValueFor(eCSSProperty_grid_auto_rows
);
1037 if (areasValue
.GetUnit() == eCSSUnit_None
&&
1038 columnsValue
.GetUnit() == eCSSUnit_None
&&
1039 rowsValue
.GetUnit() == eCSSUnit_None
) {
1040 AppendValueToString(eCSSProperty_grid_auto_flow
,
1041 aValue
, aSerialization
);
1042 aValue
.Append(char16_t(' '));
1043 AppendValueToString(eCSSProperty_grid_auto_columns
,
1044 aValue
, aSerialization
);
1045 aValue
.AppendLiteral(" / ");
1046 AppendValueToString(eCSSProperty_grid_auto_rows
,
1047 aValue
, aSerialization
);
1049 } else if (!(autoFlowValue
.GetUnit() == eCSSUnit_Enumerated
&&
1050 autoFlowValue
.GetIntValue() == NS_STYLE_GRID_AUTO_FLOW_ROW
&&
1051 autoColumnsValue
.GetUnit() == eCSSUnit_Auto
&&
1052 autoRowsValue
.GetUnit() == eCSSUnit_Auto
)) {
1053 // Not serializable, bail.
1056 // Fall through to eCSSProperty_grid_template
1058 case eCSSProperty_grid_template
: {
1059 const nsCSSValue
& areasValue
=
1060 *data
->ValueFor(eCSSProperty_grid_template_areas
);
1061 const nsCSSValue
& columnsValue
=
1062 *data
->ValueFor(eCSSProperty_grid_template_columns
);
1063 const nsCSSValue
& rowsValue
=
1064 *data
->ValueFor(eCSSProperty_grid_template_rows
);
1065 if (areasValue
.GetUnit() == eCSSUnit_None
) {
1066 AppendValueToString(eCSSProperty_grid_template_columns
,
1067 aValue
, aSerialization
);
1068 aValue
.AppendLiteral(" / ");
1069 AppendValueToString(eCSSProperty_grid_template_rows
,
1070 aValue
, aSerialization
);
1073 if (columnsValue
.GetUnit() == eCSSUnit_List
||
1074 columnsValue
.GetUnit() == eCSSUnit_ListDep
) {
1075 const nsCSSValueList
* columnsItem
= columnsValue
.GetListValue();
1076 if (columnsItem
->mValue
.GetUnit() == eCSSUnit_Enumerated
&&
1077 columnsItem
->mValue
.GetIntValue() == NS_STYLE_GRID_TEMPLATE_SUBGRID
) {
1078 // We have "grid-template-areas:[something]; grid-template-columns:subgrid"
1079 // which isn't a value that the shorthand can express. Bail.
1083 if (rowsValue
.GetUnit() != eCSSUnit_List
&&
1084 rowsValue
.GetUnit() != eCSSUnit_ListDep
) {
1085 // We have "grid-template-areas:[something]; grid-template-rows:none"
1086 // which isn't a value that the shorthand can express. Bail.
1089 const nsCSSValueList
* rowsItem
= rowsValue
.GetListValue();
1090 if (rowsItem
->mValue
.GetUnit() == eCSSUnit_Enumerated
&&
1091 rowsItem
->mValue
.GetIntValue() == NS_STYLE_GRID_TEMPLATE_SUBGRID
) {
1092 // We have "grid-template-areas:[something]; grid-template-rows:subgrid"
1093 // which isn't a value that the shorthand can express. Bail.
1096 const GridTemplateAreasValue
* areas
= areasValue
.GetGridTemplateAreas();
1097 uint32_t nRowItems
= 0;
1100 rowsItem
= rowsItem
->mNext
;
1102 MOZ_ASSERT(nRowItems
% 2 == 1, "expected an odd number of items");
1103 if ((nRowItems
- 1) / 2 != areas
->NRows()) {
1104 // Not serializable, bail.
1107 if (columnsValue
.GetUnit() != eCSSUnit_None
) {
1108 AppendValueToString(eCSSProperty_grid_template_columns
,
1109 aValue
, aSerialization
);
1110 aValue
.AppendLiteral(" / ");
1112 rowsItem
= rowsValue
.GetListValue();
1115 bool addSpaceSeparator
= true;
1116 nsCSSUnit unit
= rowsItem
->mValue
.GetUnit();
1118 if (unit
== eCSSUnit_Null
) {
1119 // Empty or omitted <line-names>. Serializes to nothing.
1120 addSpaceSeparator
= false; // Avoid a double space.
1122 } else if (unit
== eCSSUnit_List
|| unit
== eCSSUnit_ListDep
) {
1123 // Non-empty <line-names>
1125 rowsItem
->mValue
.AppendToString(eCSSProperty_grid_template_rows
,
1126 aValue
, aSerialization
);
1130 nsStyleUtil::AppendEscapedCSSString(areas
->mTemplates
[row
++], aValue
);
1131 aValue
.Append(char16_t(' '));
1134 rowsItem
->mValue
.AppendToString(eCSSProperty_grid_template_rows
,
1135 aValue
, aSerialization
);
1136 if (rowsItem
->mNext
&&
1137 rowsItem
->mNext
->mValue
.GetUnit() == eCSSUnit_Null
&&
1138 !rowsItem
->mNext
->mNext
) {
1139 // Break out of the loop early to avoid a trailing space.
1144 rowsItem
= rowsItem
->mNext
;
1149 if (addSpaceSeparator
) {
1150 aValue
.Append(char16_t(' '));
1155 case eCSSProperty__moz_transform
: {
1156 // shorthands that are just aliases with different parsing rules
1157 const nsCSSProperty
* subprops
=
1158 nsCSSProps::SubpropertyEntryFor(aProperty
);
1159 NS_ABORT_IF_FALSE(subprops
[1] == eCSSProperty_UNKNOWN
,
1160 "must have exactly one subproperty");
1161 AppendValueToString(subprops
[0], aValue
, aSerialization
);
1164 case eCSSProperty_all
:
1165 // If we got here, then we didn't have all "inherit" or "initial" or
1166 // "unset" values for all of the longhand property components of 'all'.
1167 // There is no other possible value that is valid for all properties,
1168 // so serialize as the empty string.
1171 NS_ABORT_IF_FALSE(false, "no other shorthands");
1177 Declaration::GetValueIsImportant(const nsAString
& aProperty
) const
1179 nsCSSProperty propID
=
1180 nsCSSProps::LookupProperty(aProperty
, nsCSSProps::eIgnoreEnabledState
);
1181 if (propID
== eCSSProperty_UNKNOWN
) {
1184 if (propID
== eCSSPropertyExtra_variable
) {
1185 const nsSubstring
& variableName
=
1186 Substring(aProperty
, CSS_CUSTOM_NAME_PREFIX_LENGTH
);
1187 return GetVariableValueIsImportant(variableName
);
1189 return GetValueIsImportant(propID
);
1193 Declaration::GetValueIsImportant(nsCSSProperty aProperty
) const
1195 if (!mImportantData
)
1198 // Calling ValueFor is inefficient, but we can assume '!important' is rare.
1200 if (!nsCSSProps::IsShorthand(aProperty
)) {
1201 return mImportantData
->ValueFor(aProperty
) != nullptr;
1204 CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p
, aProperty
) {
1205 if (*p
== eCSSProperty__x_system_font
) {
1206 // The system_font subproperty doesn't count.
1209 if (!mImportantData
->ValueFor(*p
)) {
1217 Declaration::AppendPropertyAndValueToString(nsCSSProperty aProperty
,
1218 nsAutoString
& aValue
,
1219 nsAString
& aResult
) const
1221 NS_ABORT_IF_FALSE(0 <= aProperty
&& aProperty
< eCSSProperty_COUNT
,
1222 "property enum out of range");
1223 NS_ABORT_IF_FALSE((aProperty
< eCSSProperty_COUNT_no_shorthands
) ==
1225 "aValue should be given for shorthands but not longhands");
1226 AppendASCIItoUTF16(nsCSSProps::GetStringValue(aProperty
), aResult
);
1227 aResult
.AppendLiteral(": ");
1228 if (aValue
.IsEmpty())
1229 AppendValueToString(aProperty
, aResult
, nsCSSValue::eNormalized
);
1231 aResult
.Append(aValue
);
1232 if (GetValueIsImportant(aProperty
)) {
1233 aResult
.AppendLiteral(" ! important");
1235 aResult
.AppendLiteral("; ");
1239 Declaration::AppendVariableAndValueToString(const nsAString
& aName
,
1240 nsAString
& aResult
) const
1242 aResult
.AppendLiteral("--");
1243 aResult
.Append(aName
);
1244 CSSVariableDeclarations::Type type
;
1248 if (mImportantVariables
&& mImportantVariables
->Get(aName
, type
, value
)) {
1251 MOZ_ASSERT(mVariables
);
1252 MOZ_ASSERT(mVariables
->Has(aName
));
1253 mVariables
->Get(aName
, type
, value
);
1258 case CSSVariableDeclarations::eTokenStream
:
1259 if (value
.IsEmpty()) {
1260 aResult
.Append(':');
1262 aResult
.AppendLiteral(": ");
1263 aResult
.Append(value
);
1267 case CSSVariableDeclarations::eInitial
:
1268 aResult
.AppendLiteral("initial");
1271 case CSSVariableDeclarations::eInherit
:
1272 aResult
.AppendLiteral("inherit");
1275 case CSSVariableDeclarations::eUnset
:
1276 aResult
.AppendLiteral("unset");
1280 MOZ_ASSERT(false, "unexpected variable value type");
1284 aResult
.AppendLiteral("! important");
1286 aResult
.AppendLiteral("; ");
1290 Declaration::ToString(nsAString
& aString
) const
1292 // Someone cares about this declaration's contents, so don't let it
1293 // change from under them. See e.g. bug 338679.
1296 nsCSSCompressedDataBlock
*systemFontData
=
1297 GetValueIsImportant(eCSSProperty__x_system_font
) ? mImportantData
: mData
;
1298 const nsCSSValue
*systemFont
=
1299 systemFontData
->ValueFor(eCSSProperty__x_system_font
);
1300 const bool haveSystemFont
= systemFont
&&
1301 systemFont
->GetUnit() != eCSSUnit_None
&&
1302 systemFont
->GetUnit() != eCSSUnit_Null
;
1303 bool didSystemFont
= false;
1305 int32_t count
= mOrder
.Length();
1307 nsAutoTArray
<nsCSSProperty
, 16> shorthandsUsed
;
1308 for (index
= 0; index
< count
; index
++) {
1309 nsCSSProperty property
= GetPropertyAt(index
);
1311 if (property
== eCSSPropertyExtra_variable
) {
1312 uint32_t variableIndex
= mOrder
[index
] - eCSSProperty_COUNT
;
1313 AppendVariableAndValueToString(mVariableOrder
[variableIndex
], aString
);
1317 if (!nsCSSProps::IsEnabled(property
)) {
1320 bool doneProperty
= false;
1322 // If we already used this property in a shorthand, skip it.
1323 if (shorthandsUsed
.Length() > 0) {
1324 for (const nsCSSProperty
*shorthands
=
1325 nsCSSProps::ShorthandsContaining(property
);
1326 *shorthands
!= eCSSProperty_UNKNOWN
; ++shorthands
) {
1327 if (shorthandsUsed
.Contains(*shorthands
)) {
1328 doneProperty
= true;
1336 // Try to use this property in a shorthand.
1338 for (const nsCSSProperty
*shorthands
=
1339 nsCSSProps::ShorthandsContaining(property
);
1340 *shorthands
!= eCSSProperty_UNKNOWN
; ++shorthands
) {
1341 // ShorthandsContaining returns the shorthands in order from those
1342 // that contain the most subproperties to those that contain the
1343 // least, which is exactly the order we want to test them.
1344 nsCSSProperty shorthand
= *shorthands
;
1346 GetValue(shorthand
, value
);
1348 // in the system font case, skip over font-variant shorthand, since all
1349 // subproperties are already dealt with via the font shorthand
1350 if (shorthand
== eCSSProperty_font_variant
&&
1351 value
.EqualsLiteral("-moz-use-system-font")) {
1355 // If GetValue gives us a non-empty string back, we can use that
1356 // value; otherwise it's not possible to use this shorthand.
1357 if (!value
.IsEmpty()) {
1358 AppendPropertyAndValueToString(shorthand
, value
, aString
);
1359 shorthandsUsed
.AppendElement(shorthand
);
1360 doneProperty
= true;
1364 if (shorthand
== eCSSProperty_font
) {
1365 if (haveSystemFont
&& !didSystemFont
) {
1366 // Output the shorthand font declaration that we will
1367 // partially override later. But don't add it to
1368 // |shorthandsUsed|, since we will have to override it.
1369 systemFont
->AppendToString(eCSSProperty__x_system_font
, value
,
1370 nsCSSValue::eNormalized
);
1371 AppendPropertyAndValueToString(eCSSProperty_font
, value
, aString
);
1373 didSystemFont
= true;
1376 // That we output the system font is enough for this property if:
1377 // (1) it's the hidden system font subproperty (which either
1378 // means we output it or we don't have it), or
1379 // (2) its value is the hidden system font value and it matches
1380 // the hidden system font subproperty in importance, and
1381 // we output the system font subproperty.
1382 const nsCSSValue
*val
= systemFontData
->ValueFor(property
);
1383 if (property
== eCSSProperty__x_system_font
||
1384 (haveSystemFont
&& val
&& val
->GetUnit() == eCSSUnit_System_Font
)) {
1385 doneProperty
= true;
1393 NS_ABORT_IF_FALSE(value
.IsEmpty(), "value should be empty now");
1394 AppendPropertyAndValueToString(property
, value
, aString
);
1396 if (! aString
.IsEmpty()) {
1397 // if the string is not empty, we have trailing whitespace we
1399 aString
.Truncate(aString
.Length() - 1);
1405 Declaration::List(FILE* out
, int32_t aIndent
) const
1407 for (int32_t index
= aIndent
; --index
>= 0; ) fputs(" ", out
);
1412 fputs(NS_ConvertUTF16toUTF8(s
).get(), out
);
1418 Declaration::GetNthProperty(uint32_t aIndex
, nsAString
& aReturn
) const
1421 if (aIndex
< mOrder
.Length()) {
1422 nsCSSProperty property
= GetPropertyAt(aIndex
);
1423 if (property
== eCSSPropertyExtra_variable
) {
1424 GetCustomPropertyNameAt(aIndex
, aReturn
);
1427 if (0 <= property
) {
1428 AppendASCIItoUTF16(nsCSSProps::GetStringValue(property
), aReturn
);
1436 Declaration::InitializeEmpty()
1438 NS_ABORT_IF_FALSE(!mData
&& !mImportantData
, "already initialized");
1439 mData
= nsCSSCompressedDataBlock::CreateEmptyBlock();
1443 Declaration::EnsureMutable()
1445 NS_ABORT_IF_FALSE(mData
, "should only be called when not expanded");
1447 return new Declaration(*this);
1454 Declaration::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf
) const
1456 size_t n
= aMallocSizeOf(this);
1457 n
+= mOrder
.SizeOfExcludingThis(aMallocSizeOf
);
1458 n
+= mData
? mData
->SizeOfIncludingThis(aMallocSizeOf
) : 0;
1459 n
+= mImportantData
? mImportantData
->SizeOfIncludingThis(aMallocSizeOf
) : 0;
1461 n
+= mVariables
->SizeOfIncludingThis(aMallocSizeOf
);
1463 if (mImportantVariables
) {
1464 n
+= mImportantVariables
->SizeOfIncludingThis(aMallocSizeOf
);
1470 Declaration::HasVariableDeclaration(const nsAString
& aName
) const
1472 return (mVariables
&& mVariables
->Has(aName
)) ||
1473 (mImportantVariables
&& mImportantVariables
->Has(aName
));
1477 Declaration::GetVariableDeclaration(const nsAString
& aName
,
1478 nsAString
& aValue
) const
1482 CSSVariableDeclarations::Type type
;
1485 if ((mImportantVariables
&& mImportantVariables
->Get(aName
, type
, value
)) ||
1486 (mVariables
&& mVariables
->Get(aName
, type
, value
))) {
1488 case CSSVariableDeclarations::eTokenStream
:
1489 aValue
.Append(value
);
1492 case CSSVariableDeclarations::eInitial
:
1493 aValue
.AppendLiteral("initial");
1496 case CSSVariableDeclarations::eInherit
:
1497 aValue
.AppendLiteral("inherit");
1500 case CSSVariableDeclarations::eUnset
:
1501 aValue
.AppendLiteral("unset");
1505 MOZ_ASSERT(false, "unexpected variable value type");
1511 Declaration::AddVariableDeclaration(const nsAString
& aName
,
1512 CSSVariableDeclarations::Type aType
,
1513 const nsString
& aValue
,
1515 bool aOverrideImportant
)
1517 MOZ_ASSERT(IsMutable());
1519 nsTArray
<nsString
>::index_type index
= mVariableOrder
.IndexOf(aName
);
1520 if (index
== nsTArray
<nsString
>::NoIndex
) {
1521 index
= mVariableOrder
.Length();
1522 mVariableOrder
.AppendElement(aName
);
1525 if (!aIsImportant
&& !aOverrideImportant
&&
1526 mImportantVariables
&& mImportantVariables
->Has(aName
)) {
1530 CSSVariableDeclarations
* variables
;
1533 mVariables
->Remove(aName
);
1535 if (!mImportantVariables
) {
1536 mImportantVariables
= new CSSVariableDeclarations
;
1538 variables
= mImportantVariables
;
1540 if (mImportantVariables
) {
1541 mImportantVariables
->Remove(aName
);
1544 mVariables
= new CSSVariableDeclarations
;
1546 variables
= mVariables
;
1550 case CSSVariableDeclarations::eTokenStream
:
1551 variables
->PutTokenStream(aName
, aValue
);
1554 case CSSVariableDeclarations::eInitial
:
1555 MOZ_ASSERT(aValue
.IsEmpty());
1556 variables
->PutInitial(aName
);
1559 case CSSVariableDeclarations::eInherit
:
1560 MOZ_ASSERT(aValue
.IsEmpty());
1561 variables
->PutInherit(aName
);
1564 case CSSVariableDeclarations::eUnset
:
1565 MOZ_ASSERT(aValue
.IsEmpty());
1566 variables
->PutUnset(aName
);
1570 MOZ_ASSERT(false, "unexpected aType value");
1573 uint32_t propertyIndex
= index
+ eCSSProperty_COUNT
;
1574 mOrder
.RemoveElement(propertyIndex
);
1575 mOrder
.AppendElement(propertyIndex
);
1579 Declaration::RemoveVariableDeclaration(const nsAString
& aName
)
1582 mVariables
->Remove(aName
);
1584 if (mImportantVariables
) {
1585 mImportantVariables
->Remove(aName
);
1587 nsTArray
<nsString
>::index_type index
= mVariableOrder
.IndexOf(aName
);
1588 if (index
!= nsTArray
<nsString
>::NoIndex
) {
1589 mOrder
.RemoveElement(index
+ eCSSProperty_COUNT
);
1594 Declaration::GetVariableValueIsImportant(const nsAString
& aName
) const
1596 return mImportantVariables
&& mImportantVariables
->Has(aName
);
1599 } // namespace mozilla::css
1600 } // namespace mozilla