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
);
118 Declaration::GetValue(nsCSSProperty aProperty
, nsAString
& aValue
) const
120 GetValue(aProperty
, aValue
, nsCSSValue::eNormalized
);
124 Declaration::GetAuthoredValue(nsCSSProperty aProperty
, nsAString
& aValue
) const
126 GetValue(aProperty
, aValue
, nsCSSValue::eAuthorSpecified
);
130 Declaration::GetValue(nsCSSProperty aProperty
, nsAString
& aValue
,
131 nsCSSValue::Serialization aSerialization
) const
135 // simple properties are easy.
136 if (!nsCSSProps::IsShorthand(aProperty
)) {
137 AppendValueToString(aProperty
, aValue
, aSerialization
);
141 // DOM Level 2 Style says (when describing CSS2Properties, although
142 // not CSSStyleDeclaration.getPropertyValue):
143 // However, if there is no shorthand declaration that could be added
144 // to the ruleset without changing in any way the rules already
145 // declared in the ruleset (i.e., by adding longhand rules that were
146 // previously not declared in the ruleset), then the empty string
147 // should be returned for the shorthand property.
148 // This means we need to check a number of cases:
149 // (1) Since a shorthand sets all sub-properties, if some of its
150 // subproperties were not specified, we must return the empty
152 // (2) Since 'inherit', 'initial' and 'unset' can only be specified
153 // as the values for entire properties, we need to return the
154 // empty string if some but not all of the subproperties have one
156 // (3) Since a single value only makes sense with or without
157 // !important, we return the empty string if some values are
158 // !important and some are not.
159 // Since we're doing this check for 'inherit' and 'initial' up front,
160 // we can also simplify the property serialization code by serializing
161 // those values up front as well.
163 // Additionally, if a shorthand property was set using a value with a
164 // variable reference and none of its component longhand properties were
165 // then overridden on the declaration, we return the token stream
166 // assigned to the shorthand.
167 const nsCSSValue
* tokenStream
= nullptr;
168 uint32_t totalCount
= 0, importantCount
= 0,
169 initialCount
= 0, inheritCount
= 0, unsetCount
= 0,
170 matchingTokenStreamCount
= 0, nonMatchingTokenStreamCount
= 0;
171 CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p
, aProperty
) {
172 if (*p
== eCSSProperty__x_system_font
||
173 nsCSSProps::PropHasFlags(*p
, CSS_PROPERTY_DIRECTIONAL_SOURCE
)) {
174 // The system-font subproperty and the *-source properties don't count.
178 const nsCSSValue
*val
= mData
->ValueFor(*p
);
179 NS_ABORT_IF_FALSE(!val
|| !mImportantData
|| !mImportantData
->ValueFor(*p
),
180 "can't be in both blocks");
181 if (!val
&& mImportantData
) {
183 val
= mImportantData
->ValueFor(*p
);
186 // Case (1) above: some subproperties not specified.
189 if (val
->GetUnit() == eCSSUnit_Inherit
) {
191 } else if (val
->GetUnit() == eCSSUnit_Initial
) {
193 } else if (val
->GetUnit() == eCSSUnit_Unset
) {
195 } else if (val
->GetUnit() == eCSSUnit_TokenStream
) {
196 if (val
->GetTokenStreamValue()->mShorthandPropertyID
== aProperty
) {
198 ++matchingTokenStreamCount
;
200 ++nonMatchingTokenStreamCount
;
204 if (importantCount
!= 0 && importantCount
!= totalCount
) {
205 // Case (3), no consistent importance.
208 if (initialCount
== totalCount
) {
209 // Simplify serialization below by serializing initial up-front.
210 nsCSSValue(eCSSUnit_Initial
).AppendToString(eCSSProperty_UNKNOWN
, aValue
,
211 nsCSSValue::eNormalized
);
214 if (inheritCount
== totalCount
) {
215 // Simplify serialization below by serializing inherit up-front.
216 nsCSSValue(eCSSUnit_Inherit
).AppendToString(eCSSProperty_UNKNOWN
, aValue
,
217 nsCSSValue::eNormalized
);
220 if (unsetCount
== totalCount
) {
221 // Simplify serialization below by serializing unset up-front.
222 nsCSSValue(eCSSUnit_Unset
).AppendToString(eCSSProperty_UNKNOWN
, aValue
,
223 nsCSSValue::eNormalized
);
226 if (initialCount
!= 0 || inheritCount
!= 0 ||
227 unsetCount
!= 0 || nonMatchingTokenStreamCount
!= 0) {
228 // Case (2): partially initial, inherit, unset or token stream.
232 if (matchingTokenStreamCount
== totalCount
) {
233 // Shorthand was specified using variable references and all of its
234 // longhand components were set by the shorthand.
235 aValue
.Append(tokenStream
->GetTokenStreamValue()->mTokenStream
);
237 // In all other cases, serialize to the empty string.
242 nsCSSCompressedDataBlock
*data
= importantCount
? mImportantData
: mData
;
244 case eCSSProperty_margin
:
245 case eCSSProperty_padding
:
246 case eCSSProperty_border_color
:
247 case eCSSProperty_border_style
:
248 case eCSSProperty_border_width
: {
249 const nsCSSProperty
* subprops
=
250 nsCSSProps::SubpropertyEntryFor(aProperty
);
251 NS_ABORT_IF_FALSE(nsCSSProps::GetStringValue(subprops
[0]).Find("-top") !=
252 kNotFound
, "first subprop must be top");
253 NS_ABORT_IF_FALSE(nsCSSProps::GetStringValue(subprops
[1]).Find("-right") !=
254 kNotFound
, "second subprop must be right");
255 NS_ABORT_IF_FALSE(nsCSSProps::GetStringValue(subprops
[2]).Find("-bottom") !=
256 kNotFound
, "third subprop must be bottom");
257 NS_ABORT_IF_FALSE(nsCSSProps::GetStringValue(subprops
[3]).Find("-left") !=
258 kNotFound
, "fourth subprop must be left");
259 const nsCSSValue
* vals
[4] = {
260 data
->ValueFor(subprops
[0]),
261 data
->ValueFor(subprops
[1]),
262 data
->ValueFor(subprops
[2]),
263 data
->ValueFor(subprops
[3])
265 nsCSSValue::AppendSidesShorthandToString(subprops
, vals
, aValue
,
269 case eCSSProperty_border_radius
:
270 case eCSSProperty__moz_outline_radius
: {
271 const nsCSSProperty
* subprops
=
272 nsCSSProps::SubpropertyEntryFor(aProperty
);
273 const nsCSSValue
* vals
[4] = {
274 data
->ValueFor(subprops
[0]),
275 data
->ValueFor(subprops
[1]),
276 data
->ValueFor(subprops
[2]),
277 data
->ValueFor(subprops
[3])
279 nsCSSValue::AppendBasicShapeRadiusToString(subprops
, vals
, aValue
,
283 case eCSSProperty_border_image
: {
284 // Even though there are some cases where we could omit
285 // 'border-image-source' (when it's none), it's probably not a
286 // good idea since it's likely to be confusing. It would also
287 // require adding the extra check that we serialize *something*.
288 AppendValueToString(eCSSProperty_border_image_source
, aValue
,
291 bool sliceDefault
= data
->HasDefaultBorderImageSlice();
292 bool widthDefault
= data
->HasDefaultBorderImageWidth();
293 bool outsetDefault
= data
->HasDefaultBorderImageOutset();
295 if (!sliceDefault
|| !widthDefault
|| !outsetDefault
) {
296 aValue
.Append(char16_t(' '));
297 AppendValueToString(eCSSProperty_border_image_slice
, aValue
,
299 if (!widthDefault
|| !outsetDefault
) {
300 aValue
.AppendLiteral(" /");
302 aValue
.Append(char16_t(' '));
303 AppendValueToString(eCSSProperty_border_image_width
, aValue
,
306 if (!outsetDefault
) {
307 aValue
.AppendLiteral(" / ");
308 AppendValueToString(eCSSProperty_border_image_outset
, aValue
,
314 bool repeatDefault
= data
->HasDefaultBorderImageRepeat();
315 if (!repeatDefault
) {
316 aValue
.Append(char16_t(' '));
317 AppendValueToString(eCSSProperty_border_image_repeat
, aValue
,
322 case eCSSProperty_border
: {
323 // If we have a non-default value for any of the properties that
324 // this shorthand sets but cannot specify, we have to return the
326 if (data
->ValueFor(eCSSProperty_border_image_source
)->GetUnit() !=
328 !data
->HasDefaultBorderImageSlice() ||
329 !data
->HasDefaultBorderImageWidth() ||
330 !data
->HasDefaultBorderImageOutset() ||
331 !data
->HasDefaultBorderImageRepeat() ||
332 data
->ValueFor(eCSSProperty_border_top_colors
)->GetUnit() !=
334 data
->ValueFor(eCSSProperty_border_right_colors
)->GetUnit() !=
336 data
->ValueFor(eCSSProperty_border_bottom_colors
)->GetUnit() !=
338 data
->ValueFor(eCSSProperty_border_left_colors
)->GetUnit() !=
343 const nsCSSProperty
* subproptables
[3] = {
344 nsCSSProps::SubpropertyEntryFor(eCSSProperty_border_color
),
345 nsCSSProps::SubpropertyEntryFor(eCSSProperty_border_style
),
346 nsCSSProps::SubpropertyEntryFor(eCSSProperty_border_width
)
349 for (const nsCSSProperty
** subprops
= subproptables
,
350 **subprops_end
= ArrayEnd(subproptables
);
351 subprops
< subprops_end
; ++subprops
) {
352 // Check only the first four subprops in each table, since the
353 // others are extras for dimensional box properties.
354 const nsCSSValue
*firstSide
= data
->ValueFor((*subprops
)[0]);
355 for (int32_t side
= 1; side
< 4; ++side
) {
356 const nsCSSValue
*otherSide
=
357 data
->ValueFor((*subprops
)[side
]);
358 if (*firstSide
!= *otherSide
)
363 // We can't express what we have in the border shorthand
366 // tweak aProperty and fall through
367 aProperty
= eCSSProperty_border_top
;
369 case eCSSProperty_border_top
:
370 case eCSSProperty_border_right
:
371 case eCSSProperty_border_bottom
:
372 case eCSSProperty_border_left
:
373 case eCSSProperty_border_start
:
374 case eCSSProperty_border_end
:
375 case eCSSProperty__moz_column_rule
:
376 case eCSSProperty_outline
: {
377 const nsCSSProperty
* subprops
=
378 nsCSSProps::SubpropertyEntryFor(aProperty
);
379 NS_ABORT_IF_FALSE(StringEndsWith(nsCSSProps::GetStringValue(subprops
[2]),
380 NS_LITERAL_CSTRING("-color")) ||
381 StringEndsWith(nsCSSProps::GetStringValue(subprops
[2]),
382 NS_LITERAL_CSTRING("-color-value")),
383 "third subprop must be the color property");
384 const nsCSSValue
*colorValue
= data
->ValueFor(subprops
[2]);
385 bool isMozUseTextColor
=
386 colorValue
->GetUnit() == eCSSUnit_Enumerated
&&
387 colorValue
->GetIntValue() == NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR
;
388 if (!AppendValueToString(subprops
[0], aValue
, aSerialization
) ||
389 !(aValue
.Append(char16_t(' ')),
390 AppendValueToString(subprops
[1], aValue
, aSerialization
)) ||
391 // Don't output a third value when it's -moz-use-text-color.
392 !(isMozUseTextColor
||
393 (aValue
.Append(char16_t(' ')),
394 AppendValueToString(subprops
[2], aValue
, aSerialization
)))) {
399 case eCSSProperty_margin_left
:
400 case eCSSProperty_margin_right
:
401 case eCSSProperty_margin_start
:
402 case eCSSProperty_margin_end
:
403 case eCSSProperty_padding_left
:
404 case eCSSProperty_padding_right
:
405 case eCSSProperty_padding_start
:
406 case eCSSProperty_padding_end
:
407 case eCSSProperty_border_left_color
:
408 case eCSSProperty_border_left_style
:
409 case eCSSProperty_border_left_width
:
410 case eCSSProperty_border_right_color
:
411 case eCSSProperty_border_right_style
:
412 case eCSSProperty_border_right_width
:
413 case eCSSProperty_border_start_color
:
414 case eCSSProperty_border_start_style
:
415 case eCSSProperty_border_start_width
:
416 case eCSSProperty_border_end_color
:
417 case eCSSProperty_border_end_style
:
418 case eCSSProperty_border_end_width
: {
419 const nsCSSProperty
* subprops
=
420 nsCSSProps::SubpropertyEntryFor(aProperty
);
421 NS_ABORT_IF_FALSE(subprops
[3] == eCSSProperty_UNKNOWN
,
422 "not box property with physical vs. logical cascading");
423 AppendValueToString(subprops
[0], aValue
, aSerialization
);
426 case eCSSProperty_background
: {
427 // We know from above that all subproperties were specified.
428 // However, we still can't represent that in the shorthand unless
429 // they're all lists of the same length. So if they're different
430 // lengths, we need to bail out.
431 // We also need to bail out if an item has background-clip and
432 // background-origin that are different and not the default
433 // values. (We omit them if they're both default.)
434 const nsCSSValueList
*image
=
435 data
->ValueFor(eCSSProperty_background_image
)->
437 const nsCSSValuePairList
*repeat
=
438 data
->ValueFor(eCSSProperty_background_repeat
)->
440 const nsCSSValueList
*attachment
=
441 data
->ValueFor(eCSSProperty_background_attachment
)->
443 const nsCSSValueList
*position
=
444 data
->ValueFor(eCSSProperty_background_position
)->
446 const nsCSSValueList
*clip
=
447 data
->ValueFor(eCSSProperty_background_clip
)->
449 const nsCSSValueList
*origin
=
450 data
->ValueFor(eCSSProperty_background_origin
)->
452 const nsCSSValuePairList
*size
=
453 data
->ValueFor(eCSSProperty_background_size
)->
456 image
->mValue
.AppendToString(eCSSProperty_background_image
, aValue
,
458 aValue
.Append(char16_t(' '));
459 repeat
->mXValue
.AppendToString(eCSSProperty_background_repeat
, aValue
,
461 if (repeat
->mYValue
.GetUnit() != eCSSUnit_Null
) {
462 repeat
->mYValue
.AppendToString(eCSSProperty_background_repeat
, aValue
,
465 aValue
.Append(char16_t(' '));
466 attachment
->mValue
.AppendToString(eCSSProperty_background_attachment
,
467 aValue
, aSerialization
);
468 aValue
.Append(char16_t(' '));
469 position
->mValue
.AppendToString(eCSSProperty_background_position
,
470 aValue
, aSerialization
);
472 if (size
->mXValue
.GetUnit() != eCSSUnit_Auto
||
473 size
->mYValue
.GetUnit() != eCSSUnit_Auto
) {
474 aValue
.Append(char16_t(' '));
475 aValue
.Append(char16_t('/'));
476 aValue
.Append(char16_t(' '));
477 size
->mXValue
.AppendToString(eCSSProperty_background_size
, aValue
,
479 aValue
.Append(char16_t(' '));
480 size
->mYValue
.AppendToString(eCSSProperty_background_size
, aValue
,
484 NS_ABORT_IF_FALSE(clip
->mValue
.GetUnit() == eCSSUnit_Enumerated
&&
485 origin
->mValue
.GetUnit() == eCSSUnit_Enumerated
,
486 "should not have inherit/initial within list");
488 if (clip
->mValue
.GetIntValue() != NS_STYLE_BG_CLIP_BORDER
||
489 origin
->mValue
.GetIntValue() != NS_STYLE_BG_ORIGIN_PADDING
) {
490 MOZ_ASSERT(nsCSSProps::kKeywordTableTable
[
491 eCSSProperty_background_origin
] ==
492 nsCSSProps::kBackgroundOriginKTable
);
493 MOZ_ASSERT(nsCSSProps::kKeywordTableTable
[
494 eCSSProperty_background_clip
] ==
495 nsCSSProps::kBackgroundOriginKTable
);
496 static_assert(NS_STYLE_BG_CLIP_BORDER
==
497 NS_STYLE_BG_ORIGIN_BORDER
&&
498 NS_STYLE_BG_CLIP_PADDING
==
499 NS_STYLE_BG_ORIGIN_PADDING
&&
500 NS_STYLE_BG_CLIP_CONTENT
==
501 NS_STYLE_BG_ORIGIN_CONTENT
,
502 "bg-clip and bg-origin style constants must agree");
503 aValue
.Append(char16_t(' '));
504 origin
->mValue
.AppendToString(eCSSProperty_background_origin
, aValue
,
507 if (clip
->mValue
!= origin
->mValue
) {
508 aValue
.Append(char16_t(' '));
509 clip
->mValue
.AppendToString(eCSSProperty_background_clip
, aValue
,
514 image
= image
->mNext
;
515 repeat
= repeat
->mNext
;
516 attachment
= attachment
->mNext
;
517 position
= position
->mNext
;
519 origin
= origin
->mNext
;
523 if (repeat
|| attachment
|| position
|| clip
|| origin
|| size
) {
524 // Uneven length lists, so can't be serialized as shorthand.
530 if (!repeat
|| !attachment
|| !position
|| !clip
|| !origin
|| !size
) {
531 // Uneven length lists, so can't be serialized as shorthand.
535 aValue
.Append(char16_t(','));
536 aValue
.Append(char16_t(' '));
539 aValue
.Append(char16_t(' '));
540 AppendValueToString(eCSSProperty_background_color
, aValue
,
544 case eCSSProperty_font
: {
545 // systemFont might not be present; other values are guaranteed to be
546 // available based on the shorthand check at the beginning of the
547 // function, as long as the prop is enabled
548 const nsCSSValue
*systemFont
=
549 data
->ValueFor(eCSSProperty__x_system_font
);
550 const nsCSSValue
*style
=
551 data
->ValueFor(eCSSProperty_font_style
);
552 const nsCSSValue
*weight
=
553 data
->ValueFor(eCSSProperty_font_weight
);
554 const nsCSSValue
*size
=
555 data
->ValueFor(eCSSProperty_font_size
);
556 const nsCSSValue
*lh
=
557 data
->ValueFor(eCSSProperty_line_height
);
558 const nsCSSValue
*family
=
559 data
->ValueFor(eCSSProperty_font_family
);
560 const nsCSSValue
*stretch
=
561 data
->ValueFor(eCSSProperty_font_stretch
);
562 const nsCSSValue
*sizeAdjust
=
563 data
->ValueFor(eCSSProperty_font_size_adjust
);
564 const nsCSSValue
*featureSettings
=
565 data
->ValueFor(eCSSProperty_font_feature_settings
);
566 const nsCSSValue
*languageOverride
=
567 data
->ValueFor(eCSSProperty_font_language_override
);
568 const nsCSSValue
*fontKerning
=
569 data
->ValueFor(eCSSProperty_font_kerning
);
570 const nsCSSValue
*fontSynthesis
=
571 data
->ValueFor(eCSSProperty_font_synthesis
);
572 const nsCSSValue
*fontVariantAlternates
=
573 data
->ValueFor(eCSSProperty_font_variant_alternates
);
574 const nsCSSValue
*fontVariantCaps
=
575 data
->ValueFor(eCSSProperty_font_variant_caps
);
576 const nsCSSValue
*fontVariantEastAsian
=
577 data
->ValueFor(eCSSProperty_font_variant_east_asian
);
578 const nsCSSValue
*fontVariantLigatures
=
579 data
->ValueFor(eCSSProperty_font_variant_ligatures
);
580 const nsCSSValue
*fontVariantNumeric
=
581 data
->ValueFor(eCSSProperty_font_variant_numeric
);
582 const nsCSSValue
*fontVariantPosition
=
583 data
->ValueFor(eCSSProperty_font_variant_position
);
586 systemFont
->GetUnit() != eCSSUnit_None
&&
587 systemFont
->GetUnit() != eCSSUnit_Null
) {
588 if (style
->GetUnit() != eCSSUnit_System_Font
||
589 weight
->GetUnit() != eCSSUnit_System_Font
||
590 size
->GetUnit() != eCSSUnit_System_Font
||
591 lh
->GetUnit() != eCSSUnit_System_Font
||
592 family
->GetUnit() != eCSSUnit_System_Font
||
593 stretch
->GetUnit() != eCSSUnit_System_Font
||
594 sizeAdjust
->GetUnit() != eCSSUnit_System_Font
||
595 featureSettings
->GetUnit() != eCSSUnit_System_Font
||
596 languageOverride
->GetUnit() != eCSSUnit_System_Font
||
597 fontKerning
->GetUnit() != eCSSUnit_System_Font
||
598 fontSynthesis
->GetUnit() != eCSSUnit_System_Font
||
599 fontVariantAlternates
->GetUnit() != eCSSUnit_System_Font
||
600 fontVariantCaps
->GetUnit() != eCSSUnit_System_Font
||
601 fontVariantEastAsian
->GetUnit() != eCSSUnit_System_Font
||
602 fontVariantLigatures
->GetUnit() != eCSSUnit_System_Font
||
603 fontVariantNumeric
->GetUnit() != eCSSUnit_System_Font
||
604 fontVariantPosition
->GetUnit() != eCSSUnit_System_Font
) {
605 // This can't be represented as a shorthand.
608 systemFont
->AppendToString(eCSSProperty__x_system_font
, aValue
,
611 // properties reset by this shorthand property to their
612 // initial values but not represented in its syntax
613 if (stretch
->GetUnit() != eCSSUnit_Enumerated
||
614 stretch
->GetIntValue() != NS_STYLE_FONT_STRETCH_NORMAL
||
615 sizeAdjust
->GetUnit() != eCSSUnit_None
||
616 featureSettings
->GetUnit() != eCSSUnit_Normal
||
617 languageOverride
->GetUnit() != eCSSUnit_Normal
||
618 fontKerning
->GetIntValue() != NS_FONT_KERNING_AUTO
||
619 fontSynthesis
->GetUnit() != eCSSUnit_Enumerated
||
620 fontSynthesis
->GetIntValue() !=
621 (NS_FONT_SYNTHESIS_WEIGHT
| NS_FONT_SYNTHESIS_STYLE
) ||
622 fontVariantAlternates
->GetUnit() != eCSSUnit_Normal
||
623 fontVariantEastAsian
->GetUnit() != eCSSUnit_Normal
||
624 fontVariantLigatures
->GetUnit() != eCSSUnit_Normal
||
625 fontVariantNumeric
->GetUnit() != eCSSUnit_Normal
||
626 fontVariantPosition
->GetUnit() != eCSSUnit_Normal
) {
630 // only a normal or small-caps values of font-variant-caps can
631 // be represented in the font shorthand
632 if (fontVariantCaps
->GetUnit() != eCSSUnit_Normal
&&
633 (fontVariantCaps
->GetUnit() != eCSSUnit_Enumerated
||
634 fontVariantCaps
->GetIntValue() != NS_FONT_VARIANT_CAPS_SMALLCAPS
)) {
638 if (style
->GetUnit() != eCSSUnit_Enumerated
||
639 style
->GetIntValue() != NS_FONT_STYLE_NORMAL
) {
640 style
->AppendToString(eCSSProperty_font_style
, aValue
,
642 aValue
.Append(char16_t(' '));
644 if (fontVariantCaps
->GetUnit() != eCSSUnit_Normal
) {
645 fontVariantCaps
->AppendToString(eCSSProperty_font_variant_caps
, aValue
,
647 aValue
.Append(char16_t(' '));
649 if (weight
->GetUnit() != eCSSUnit_Enumerated
||
650 weight
->GetIntValue() != NS_FONT_WEIGHT_NORMAL
) {
651 weight
->AppendToString(eCSSProperty_font_weight
, aValue
,
653 aValue
.Append(char16_t(' '));
655 size
->AppendToString(eCSSProperty_font_size
, aValue
, aSerialization
);
656 if (lh
->GetUnit() != eCSSUnit_Normal
) {
657 aValue
.Append(char16_t('/'));
658 lh
->AppendToString(eCSSProperty_line_height
, aValue
, aSerialization
);
660 aValue
.Append(char16_t(' '));
661 family
->AppendToString(eCSSProperty_font_family
, aValue
,
666 case eCSSProperty_font_variant
: {
667 const nsCSSProperty
*subprops
=
668 nsCSSProps::SubpropertyEntryFor(aProperty
);
669 const nsCSSValue
*fontVariantLigatures
=
670 data
->ValueFor(eCSSProperty_font_variant_ligatures
);
672 // all subproperty values normal? system font?
673 bool normalLigs
= true, normalNonLigs
= true, systemFont
= true,
675 for (const nsCSSProperty
*sp
= subprops
; *sp
!= eCSSProperty_UNKNOWN
; sp
++) {
676 const nsCSSValue
*spVal
= data
->ValueFor(*sp
);
677 bool isNormal
= (spVal
->GetUnit() == eCSSUnit_Normal
);
678 if (*sp
== eCSSProperty_font_variant_ligatures
) {
679 normalLigs
= normalLigs
&& isNormal
;
681 normalNonLigs
= normalNonLigs
&& isNormal
;
683 bool isSystem
= (spVal
->GetUnit() == eCSSUnit_System_Font
);
684 systemFont
= systemFont
&& isSystem
;
685 hasSystem
= hasSystem
|| isSystem
;
689 fontVariantLigatures
->GetUnit() == eCSSUnit_None
;
691 // normal, none, or system font ==> single value
692 if ((normalLigs
&& normalNonLigs
) ||
693 (normalNonLigs
&& ligsNone
) ||
695 fontVariantLigatures
->AppendToString(eCSSProperty_font_variant_ligatures
,
698 } else if (ligsNone
|| hasSystem
) {
699 // ligatures none but other values are non-normal ==> empty
700 // at least one but not all values are system font ==> empty
703 // iterate over and append non-normal values
704 bool appendSpace
= false;
705 for (const nsCSSProperty
*sp
= subprops
;
706 *sp
!= eCSSProperty_UNKNOWN
; sp
++) {
707 const nsCSSValue
*spVal
= data
->ValueFor(*sp
);
708 if (spVal
&& spVal
->GetUnit() != eCSSUnit_Normal
) {
710 aValue
.Append(char16_t(' '));
714 spVal
->AppendToString(*sp
, aValue
, aSerialization
);
720 case eCSSProperty_list_style
:
721 if (AppendValueToString(eCSSProperty_list_style_position
, aValue
,
723 aValue
.Append(char16_t(' '));
725 if (AppendValueToString(eCSSProperty_list_style_image
, aValue
,
727 aValue
.Append(char16_t(' '));
729 AppendValueToString(eCSSProperty_list_style_type
, aValue
,
732 case eCSSProperty_overflow
: {
733 const nsCSSValue
&xValue
=
734 *data
->ValueFor(eCSSProperty_overflow_x
);
735 const nsCSSValue
&yValue
=
736 *data
->ValueFor(eCSSProperty_overflow_y
);
737 if (xValue
== yValue
)
738 xValue
.AppendToString(eCSSProperty_overflow_x
, aValue
, aSerialization
);
741 case eCSSProperty_text_decoration
: {
742 const nsCSSValue
*decorationColor
=
743 data
->ValueFor(eCSSProperty_text_decoration_color
);
744 const nsCSSValue
*decorationStyle
=
745 data
->ValueFor(eCSSProperty_text_decoration_style
);
747 NS_ABORT_IF_FALSE(decorationStyle
->GetUnit() == eCSSUnit_Enumerated
,
748 nsPrintfCString("bad text-decoration-style unit %d",
749 decorationStyle
->GetUnit()).get());
751 AppendValueToString(eCSSProperty_text_decoration_line
, aValue
,
753 if (decorationStyle
->GetIntValue() !=
754 NS_STYLE_TEXT_DECORATION_STYLE_SOLID
) {
755 aValue
.Append(char16_t(' '));
756 AppendValueToString(eCSSProperty_text_decoration_style
, aValue
,
759 if (decorationColor
->GetUnit() != eCSSUnit_Enumerated
||
760 decorationColor
->GetIntValue() != NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR
) {
761 aValue
.Append(char16_t(' '));
762 AppendValueToString(eCSSProperty_text_decoration_color
, aValue
,
767 case eCSSProperty_transition
: {
768 const nsCSSValue
*transProp
=
769 data
->ValueFor(eCSSProperty_transition_property
);
770 const nsCSSValue
*transDuration
=
771 data
->ValueFor(eCSSProperty_transition_duration
);
772 const nsCSSValue
*transTiming
=
773 data
->ValueFor(eCSSProperty_transition_timing_function
);
774 const nsCSSValue
*transDelay
=
775 data
->ValueFor(eCSSProperty_transition_delay
);
777 NS_ABORT_IF_FALSE(transDuration
->GetUnit() == eCSSUnit_List
||
778 transDuration
->GetUnit() == eCSSUnit_ListDep
,
779 nsPrintfCString("bad t-duration unit %d",
780 transDuration
->GetUnit()).get());
781 NS_ABORT_IF_FALSE(transTiming
->GetUnit() == eCSSUnit_List
||
782 transTiming
->GetUnit() == eCSSUnit_ListDep
,
783 nsPrintfCString("bad t-timing unit %d",
784 transTiming
->GetUnit()).get());
785 NS_ABORT_IF_FALSE(transDelay
->GetUnit() == eCSSUnit_List
||
786 transDelay
->GetUnit() == eCSSUnit_ListDep
,
787 nsPrintfCString("bad t-delay unit %d",
788 transDelay
->GetUnit()).get());
790 const nsCSSValueList
* dur
= transDuration
->GetListValue();
791 const nsCSSValueList
* tim
= transTiming
->GetListValue();
792 const nsCSSValueList
* del
= transDelay
->GetListValue();
794 if (transProp
->GetUnit() == eCSSUnit_None
||
795 transProp
->GetUnit() == eCSSUnit_All
) {
796 // If any of the other three lists has more than one element,
797 // we can't use the shorthand.
798 if (!dur
->mNext
&& !tim
->mNext
&& !del
->mNext
) {
799 transProp
->AppendToString(eCSSProperty_transition_property
, aValue
,
801 aValue
.Append(char16_t(' '));
802 dur
->mValue
.AppendToString(eCSSProperty_transition_duration
,aValue
,
804 aValue
.Append(char16_t(' '));
805 tim
->mValue
.AppendToString(eCSSProperty_transition_timing_function
,
806 aValue
, aSerialization
);
807 aValue
.Append(char16_t(' '));
808 del
->mValue
.AppendToString(eCSSProperty_transition_delay
, aValue
,
810 aValue
.Append(char16_t(' '));
815 NS_ABORT_IF_FALSE(transProp
->GetUnit() == eCSSUnit_List
||
816 transProp
->GetUnit() == eCSSUnit_ListDep
,
817 nsPrintfCString("bad t-prop unit %d",
818 transProp
->GetUnit()).get());
819 const nsCSSValueList
* pro
= transProp
->GetListValue();
821 pro
->mValue
.AppendToString(eCSSProperty_transition_property
,
822 aValue
, aSerialization
);
823 aValue
.Append(char16_t(' '));
824 dur
->mValue
.AppendToString(eCSSProperty_transition_duration
,
825 aValue
, aSerialization
);
826 aValue
.Append(char16_t(' '));
827 tim
->mValue
.AppendToString(eCSSProperty_transition_timing_function
,
828 aValue
, aSerialization
);
829 aValue
.Append(char16_t(' '));
830 del
->mValue
.AppendToString(eCSSProperty_transition_delay
,
831 aValue
, aSerialization
);
836 if (!pro
|| !dur
|| !tim
|| !del
) {
839 aValue
.AppendLiteral(", ");
841 if (pro
|| dur
|| tim
|| del
) {
842 // Lists not all the same length, can't use shorthand.
848 case eCSSProperty_animation
: {
849 const nsCSSProperty
* subprops
=
850 nsCSSProps::SubpropertyEntryFor(eCSSProperty_animation
);
851 static const size_t numProps
= 8;
852 NS_ABORT_IF_FALSE(subprops
[numProps
] == eCSSProperty_UNKNOWN
,
853 "unexpected number of subproperties");
854 const nsCSSValue
* values
[numProps
];
855 const nsCSSValueList
* lists
[numProps
];
857 for (uint32_t i
= 0; i
< numProps
; ++i
) {
858 values
[i
] = data
->ValueFor(subprops
[i
]);
859 NS_ABORT_IF_FALSE(values
[i
]->GetUnit() == eCSSUnit_List
||
860 values
[i
]->GetUnit() == eCSSUnit_ListDep
,
861 nsPrintfCString("bad a-duration unit %d",
862 values
[i
]->GetUnit()).get());
863 lists
[i
] = values
[i
]->GetListValue();
867 // We must serialize 'animation-name' last in case it has
868 // a value that conflicts with one of the other keyword properties.
869 NS_ABORT_IF_FALSE(subprops
[numProps
- 1] ==
870 eCSSProperty_animation_name
,
871 "animation-name must be last");
873 for (uint32_t i
= 0;;) {
874 lists
[i
]->mValue
.AppendToString(subprops
[i
], aValue
, aSerialization
);
875 lists
[i
] = lists
[i
]->mNext
;
879 if (++i
== numProps
) {
882 aValue
.Append(char16_t(' '));
887 aValue
.AppendLiteral(", ");
889 for (uint32_t i
= 0; i
< numProps
; ++i
) {
891 // Lists not all the same length, can't use shorthand.
898 case eCSSProperty_marker
: {
899 const nsCSSValue
&endValue
=
900 *data
->ValueFor(eCSSProperty_marker_end
);
901 const nsCSSValue
&midValue
=
902 *data
->ValueFor(eCSSProperty_marker_mid
);
903 const nsCSSValue
&startValue
=
904 *data
->ValueFor(eCSSProperty_marker_start
);
905 if (endValue
== midValue
&& midValue
== startValue
)
906 AppendValueToString(eCSSProperty_marker_end
, aValue
, aSerialization
);
909 case eCSSProperty__moz_columns
: {
910 // Two values, column-count and column-width, separated by a space.
911 const nsCSSProperty
* subprops
=
912 nsCSSProps::SubpropertyEntryFor(aProperty
);
913 AppendValueToString(subprops
[0], aValue
, aSerialization
);
914 aValue
.Append(char16_t(' '));
915 AppendValueToString(subprops
[1], aValue
, aSerialization
);
918 case eCSSProperty_flex
: {
919 // flex-grow, flex-shrink, flex-basis, separated by single space
920 const nsCSSProperty
* subprops
=
921 nsCSSProps::SubpropertyEntryFor(aProperty
);
923 AppendValueToString(subprops
[0], aValue
, aSerialization
);
924 aValue
.Append(char16_t(' '));
925 AppendValueToString(subprops
[1], aValue
, aSerialization
);
926 aValue
.Append(char16_t(' '));
927 AppendValueToString(subprops
[2], aValue
, aSerialization
);
930 case eCSSProperty_flex_flow
: {
931 // flex-direction, flex-wrap, separated by single space
932 const nsCSSProperty
* subprops
=
933 nsCSSProps::SubpropertyEntryFor(aProperty
);
934 NS_ABORT_IF_FALSE(subprops
[2] == eCSSProperty_UNKNOWN
,
935 "must have exactly two subproperties");
937 AppendValueToString(subprops
[0], aValue
, aSerialization
);
938 aValue
.Append(char16_t(' '));
939 AppendValueToString(subprops
[1], aValue
, aSerialization
);
942 case eCSSProperty_grid_row
:
943 case eCSSProperty_grid_column
: {
944 // grid-{row,column}-start, grid-{row,column}-end, separated by a slash
945 const nsCSSProperty
* subprops
=
946 nsCSSProps::SubpropertyEntryFor(aProperty
);
947 NS_ABORT_IF_FALSE(subprops
[2] == eCSSProperty_UNKNOWN
,
948 "must have exactly two subproperties");
950 // TODO: should we simplify when possible?
951 AppendValueToString(subprops
[0], aValue
, aSerialization
);
952 aValue
.AppendLiteral(" / ");
953 AppendValueToString(subprops
[1], aValue
, aSerialization
);
956 case eCSSProperty_grid_area
: {
957 const nsCSSProperty
* subprops
=
958 nsCSSProps::SubpropertyEntryFor(aProperty
);
959 NS_ABORT_IF_FALSE(subprops
[4] == eCSSProperty_UNKNOWN
,
960 "must have exactly four subproperties");
962 // TODO: should we simplify when possible?
963 AppendValueToString(subprops
[0], aValue
, aSerialization
);
964 aValue
.AppendLiteral(" / ");
965 AppendValueToString(subprops
[1], aValue
, aSerialization
);
966 aValue
.AppendLiteral(" / ");
967 AppendValueToString(subprops
[2], aValue
, aSerialization
);
968 aValue
.AppendLiteral(" / ");
969 AppendValueToString(subprops
[3], aValue
, aSerialization
);
973 // This can express either grid-template-{areas,columns,rows}
974 // or grid-auto-{flow,columns,rows}, but not both.
975 case eCSSProperty_grid
: {
976 const nsCSSValue
& areasValue
=
977 *data
->ValueFor(eCSSProperty_grid_template_areas
);
978 const nsCSSValue
& columnsValue
=
979 *data
->ValueFor(eCSSProperty_grid_template_columns
);
980 const nsCSSValue
& rowsValue
=
981 *data
->ValueFor(eCSSProperty_grid_template_rows
);
983 const nsCSSValue
& autoFlowValue
=
984 *data
->ValueFor(eCSSProperty_grid_auto_flow
);
985 const nsCSSValue
& autoColumnsValue
=
986 *data
->ValueFor(eCSSProperty_grid_auto_columns
);
987 const nsCSSValue
& autoRowsValue
=
988 *data
->ValueFor(eCSSProperty_grid_auto_rows
);
990 if (areasValue
.GetUnit() == eCSSUnit_None
&&
991 columnsValue
.GetUnit() == eCSSUnit_None
&&
992 rowsValue
.GetUnit() == eCSSUnit_None
) {
993 AppendValueToString(eCSSProperty_grid_auto_flow
,
994 aValue
, aSerialization
);
995 aValue
.Append(char16_t(' '));
996 AppendValueToString(eCSSProperty_grid_auto_columns
,
997 aValue
, aSerialization
);
998 aValue
.AppendLiteral(" / ");
999 AppendValueToString(eCSSProperty_grid_auto_rows
,
1000 aValue
, aSerialization
);
1002 } else if (!(autoFlowValue
.GetUnit() == eCSSUnit_Enumerated
&&
1003 autoFlowValue
.GetIntValue() == NS_STYLE_GRID_AUTO_FLOW_ROW
&&
1004 autoColumnsValue
.GetUnit() == eCSSUnit_Auto
&&
1005 autoRowsValue
.GetUnit() == eCSSUnit_Auto
)) {
1006 // Not serializable, bail.
1009 // Fall through to eCSSProperty_grid_template
1011 case eCSSProperty_grid_template
: {
1012 const nsCSSValue
& areasValue
=
1013 *data
->ValueFor(eCSSProperty_grid_template_areas
);
1014 const nsCSSValue
& columnsValue
=
1015 *data
->ValueFor(eCSSProperty_grid_template_columns
);
1016 const nsCSSValue
& rowsValue
=
1017 *data
->ValueFor(eCSSProperty_grid_template_rows
);
1018 if (areasValue
.GetUnit() == eCSSUnit_None
) {
1019 AppendValueToString(eCSSProperty_grid_template_columns
,
1020 aValue
, aSerialization
);
1021 aValue
.AppendLiteral(" / ");
1022 AppendValueToString(eCSSProperty_grid_template_rows
,
1023 aValue
, aSerialization
);
1026 if (columnsValue
.GetUnit() == eCSSUnit_List
||
1027 columnsValue
.GetUnit() == eCSSUnit_ListDep
) {
1028 const nsCSSValueList
* columnsItem
= columnsValue
.GetListValue();
1029 if (columnsItem
->mValue
.GetUnit() == eCSSUnit_Enumerated
&&
1030 columnsItem
->mValue
.GetIntValue() == NS_STYLE_GRID_TEMPLATE_SUBGRID
) {
1031 // We have "grid-template-areas:[something]; grid-template-columns:subgrid"
1032 // which isn't a value that the shorthand can express. Bail.
1036 if (rowsValue
.GetUnit() != eCSSUnit_List
&&
1037 rowsValue
.GetUnit() != eCSSUnit_ListDep
) {
1038 // We have "grid-template-areas:[something]; grid-template-rows:none"
1039 // which isn't a value that the shorthand can express. Bail.
1042 const nsCSSValueList
* rowsItem
= rowsValue
.GetListValue();
1043 if (rowsItem
->mValue
.GetUnit() == eCSSUnit_Enumerated
&&
1044 rowsItem
->mValue
.GetIntValue() == NS_STYLE_GRID_TEMPLATE_SUBGRID
) {
1045 // We have "grid-template-areas:[something]; grid-template-rows:subgrid"
1046 // which isn't a value that the shorthand can express. Bail.
1049 const GridTemplateAreasValue
* areas
= areasValue
.GetGridTemplateAreas();
1050 uint32_t nRowItems
= 0;
1053 rowsItem
= rowsItem
->mNext
;
1055 MOZ_ASSERT(nRowItems
% 2 == 1, "expected an odd number of items");
1056 if ((nRowItems
- 1) / 2 != areas
->NRows()) {
1057 // Not serializable, bail.
1060 if (columnsValue
.GetUnit() != eCSSUnit_None
) {
1061 AppendValueToString(eCSSProperty_grid_template_columns
,
1062 aValue
, aSerialization
);
1063 aValue
.AppendLiteral(" / ");
1065 rowsItem
= rowsValue
.GetListValue();
1068 bool addSpaceSeparator
= true;
1069 nsCSSUnit unit
= rowsItem
->mValue
.GetUnit();
1071 if (unit
== eCSSUnit_Null
) {
1072 // Empty or omitted <line-names>. Serializes to nothing.
1073 addSpaceSeparator
= false; // Avoid a double space.
1075 } else if (unit
== eCSSUnit_List
|| unit
== eCSSUnit_ListDep
) {
1076 // Non-empty <line-names>
1078 rowsItem
->mValue
.AppendToString(eCSSProperty_grid_template_rows
,
1079 aValue
, aSerialization
);
1083 nsStyleUtil::AppendEscapedCSSString(areas
->mTemplates
[row
++], aValue
);
1084 aValue
.Append(char16_t(' '));
1087 rowsItem
->mValue
.AppendToString(eCSSProperty_grid_template_rows
,
1088 aValue
, aSerialization
);
1089 if (rowsItem
->mNext
&&
1090 rowsItem
->mNext
->mValue
.GetUnit() == eCSSUnit_Null
&&
1091 !rowsItem
->mNext
->mNext
) {
1092 // Break out of the loop early to avoid a trailing space.
1097 rowsItem
= rowsItem
->mNext
;
1102 if (addSpaceSeparator
) {
1103 aValue
.Append(char16_t(' '));
1108 case eCSSProperty__moz_transform
: {
1109 // shorthands that are just aliases with different parsing rules
1110 const nsCSSProperty
* subprops
=
1111 nsCSSProps::SubpropertyEntryFor(aProperty
);
1112 NS_ABORT_IF_FALSE(subprops
[1] == eCSSProperty_UNKNOWN
,
1113 "must have exactly one subproperty");
1114 AppendValueToString(subprops
[0], aValue
, aSerialization
);
1117 case eCSSProperty_all
:
1118 // If we got here, then we didn't have all "inherit" or "initial" or
1119 // "unset" values for all of the longhand property components of 'all'.
1120 // There is no other possible value that is valid for all properties,
1121 // so serialize as the empty string.
1124 NS_ABORT_IF_FALSE(false, "no other shorthands");
1130 Declaration::GetValueIsImportant(const nsAString
& aProperty
) const
1132 nsCSSProperty propID
=
1133 nsCSSProps::LookupProperty(aProperty
, nsCSSProps::eIgnoreEnabledState
);
1134 if (propID
== eCSSProperty_UNKNOWN
) {
1137 if (propID
== eCSSPropertyExtra_variable
) {
1138 const nsSubstring
& variableName
=
1139 Substring(aProperty
, CSS_CUSTOM_NAME_PREFIX_LENGTH
);
1140 return GetVariableValueIsImportant(variableName
);
1142 return GetValueIsImportant(propID
);
1146 Declaration::GetValueIsImportant(nsCSSProperty aProperty
) const
1148 if (!mImportantData
)
1151 // Calling ValueFor is inefficient, but we can assume '!important' is rare.
1153 if (!nsCSSProps::IsShorthand(aProperty
)) {
1154 return mImportantData
->ValueFor(aProperty
) != nullptr;
1157 CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p
, aProperty
) {
1158 if (*p
== eCSSProperty__x_system_font
) {
1159 // The system_font subproperty doesn't count.
1162 if (!mImportantData
->ValueFor(*p
)) {
1170 Declaration::AppendPropertyAndValueToString(nsCSSProperty aProperty
,
1171 nsAutoString
& aValue
,
1172 nsAString
& aResult
) const
1174 NS_ABORT_IF_FALSE(0 <= aProperty
&& aProperty
< eCSSProperty_COUNT
,
1175 "property enum out of range");
1176 NS_ABORT_IF_FALSE((aProperty
< eCSSProperty_COUNT_no_shorthands
) ==
1178 "aValue should be given for shorthands but not longhands");
1179 AppendASCIItoUTF16(nsCSSProps::GetStringValue(aProperty
), aResult
);
1180 aResult
.AppendLiteral(": ");
1181 if (aValue
.IsEmpty())
1182 AppendValueToString(aProperty
, aResult
, nsCSSValue::eNormalized
);
1184 aResult
.Append(aValue
);
1185 if (GetValueIsImportant(aProperty
)) {
1186 aResult
.AppendLiteral(" ! important");
1188 aResult
.AppendLiteral("; ");
1192 Declaration::AppendVariableAndValueToString(const nsAString
& aName
,
1193 nsAString
& aResult
) const
1195 aResult
.AppendLiteral("--");
1196 aResult
.Append(aName
);
1197 CSSVariableDeclarations::Type type
;
1201 if (mImportantVariables
&& mImportantVariables
->Get(aName
, type
, value
)) {
1204 MOZ_ASSERT(mVariables
);
1205 MOZ_ASSERT(mVariables
->Has(aName
));
1206 mVariables
->Get(aName
, type
, value
);
1211 case CSSVariableDeclarations::eTokenStream
:
1212 if (value
.IsEmpty()) {
1213 aResult
.Append(':');
1215 aResult
.AppendLiteral(": ");
1216 aResult
.Append(value
);
1220 case CSSVariableDeclarations::eInitial
:
1221 aResult
.AppendLiteral("initial");
1224 case CSSVariableDeclarations::eInherit
:
1225 aResult
.AppendLiteral("inherit");
1228 case CSSVariableDeclarations::eUnset
:
1229 aResult
.AppendLiteral("unset");
1233 MOZ_ASSERT(false, "unexpected variable value type");
1237 aResult
.AppendLiteral("! important");
1239 aResult
.AppendLiteral("; ");
1243 Declaration::ToString(nsAString
& aString
) const
1245 // Someone cares about this declaration's contents, so don't let it
1246 // change from under them. See e.g. bug 338679.
1249 nsCSSCompressedDataBlock
*systemFontData
=
1250 GetValueIsImportant(eCSSProperty__x_system_font
) ? mImportantData
: mData
;
1251 const nsCSSValue
*systemFont
=
1252 systemFontData
->ValueFor(eCSSProperty__x_system_font
);
1253 const bool haveSystemFont
= systemFont
&&
1254 systemFont
->GetUnit() != eCSSUnit_None
&&
1255 systemFont
->GetUnit() != eCSSUnit_Null
;
1256 bool didSystemFont
= false;
1258 int32_t count
= mOrder
.Length();
1260 nsAutoTArray
<nsCSSProperty
, 16> shorthandsUsed
;
1261 for (index
= 0; index
< count
; index
++) {
1262 nsCSSProperty property
= GetPropertyAt(index
);
1264 if (property
== eCSSPropertyExtra_variable
) {
1265 uint32_t variableIndex
= mOrder
[index
] - eCSSProperty_COUNT
;
1266 AppendVariableAndValueToString(mVariableOrder
[variableIndex
], aString
);
1270 if (!nsCSSProps::IsEnabled(property
)) {
1273 bool doneProperty
= false;
1275 // If we already used this property in a shorthand, skip it.
1276 if (shorthandsUsed
.Length() > 0) {
1277 for (const nsCSSProperty
*shorthands
=
1278 nsCSSProps::ShorthandsContaining(property
);
1279 *shorthands
!= eCSSProperty_UNKNOWN
; ++shorthands
) {
1280 if (shorthandsUsed
.Contains(*shorthands
)) {
1281 doneProperty
= true;
1289 // Try to use this property in a shorthand.
1291 for (const nsCSSProperty
*shorthands
=
1292 nsCSSProps::ShorthandsContaining(property
);
1293 *shorthands
!= eCSSProperty_UNKNOWN
; ++shorthands
) {
1294 // ShorthandsContaining returns the shorthands in order from those
1295 // that contain the most subproperties to those that contain the
1296 // least, which is exactly the order we want to test them.
1297 nsCSSProperty shorthand
= *shorthands
;
1299 GetValue(shorthand
, value
);
1301 // in the system font case, skip over font-variant shorthand, since all
1302 // subproperties are already dealt with via the font shorthand
1303 if (shorthand
== eCSSProperty_font_variant
&&
1304 value
.EqualsLiteral("-moz-use-system-font")) {
1308 // If GetValue gives us a non-empty string back, we can use that
1309 // value; otherwise it's not possible to use this shorthand.
1310 if (!value
.IsEmpty()) {
1311 AppendPropertyAndValueToString(shorthand
, value
, aString
);
1312 shorthandsUsed
.AppendElement(shorthand
);
1313 doneProperty
= true;
1317 if (shorthand
== eCSSProperty_font
) {
1318 if (haveSystemFont
&& !didSystemFont
) {
1319 // Output the shorthand font declaration that we will
1320 // partially override later. But don't add it to
1321 // |shorthandsUsed|, since we will have to override it.
1322 systemFont
->AppendToString(eCSSProperty__x_system_font
, value
,
1323 nsCSSValue::eNormalized
);
1324 AppendPropertyAndValueToString(eCSSProperty_font
, value
, aString
);
1326 didSystemFont
= true;
1329 // That we output the system font is enough for this property if:
1330 // (1) it's the hidden system font subproperty (which either
1331 // means we output it or we don't have it), or
1332 // (2) its value is the hidden system font value and it matches
1333 // the hidden system font subproperty in importance, and
1334 // we output the system font subproperty.
1335 const nsCSSValue
*val
= systemFontData
->ValueFor(property
);
1336 if (property
== eCSSProperty__x_system_font
||
1337 (haveSystemFont
&& val
&& val
->GetUnit() == eCSSUnit_System_Font
)) {
1338 doneProperty
= true;
1346 NS_ABORT_IF_FALSE(value
.IsEmpty(), "value should be empty now");
1347 AppendPropertyAndValueToString(property
, value
, aString
);
1349 if (! aString
.IsEmpty()) {
1350 // if the string is not empty, we have trailing whitespace we
1352 aString
.Truncate(aString
.Length() - 1);
1358 Declaration::List(FILE* out
, int32_t aIndent
) const
1361 for (int32_t index
= aIndent
; --index
>= 0; ) {
1362 str
.AppendLiteral(" ");
1365 str
.AppendLiteral("{ ");
1368 AppendUTF16toUTF8(s
, str
);
1369 str
.AppendLiteral("}\n");
1370 fprintf_stderr(out
, "%s", str
.get());
1375 Declaration::GetNthProperty(uint32_t aIndex
, nsAString
& aReturn
) const
1378 if (aIndex
< mOrder
.Length()) {
1379 nsCSSProperty property
= GetPropertyAt(aIndex
);
1380 if (property
== eCSSPropertyExtra_variable
) {
1381 GetCustomPropertyNameAt(aIndex
, aReturn
);
1384 if (0 <= property
) {
1385 AppendASCIItoUTF16(nsCSSProps::GetStringValue(property
), aReturn
);
1393 Declaration::InitializeEmpty()
1395 NS_ABORT_IF_FALSE(!mData
&& !mImportantData
, "already initialized");
1396 mData
= nsCSSCompressedDataBlock::CreateEmptyBlock();
1400 Declaration::EnsureMutable()
1402 NS_ABORT_IF_FALSE(mData
, "should only be called when not expanded");
1404 return new Declaration(*this);
1411 Declaration::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf
) const
1413 size_t n
= aMallocSizeOf(this);
1414 n
+= mOrder
.SizeOfExcludingThis(aMallocSizeOf
);
1415 n
+= mData
? mData
->SizeOfIncludingThis(aMallocSizeOf
) : 0;
1416 n
+= mImportantData
? mImportantData
->SizeOfIncludingThis(aMallocSizeOf
) : 0;
1418 n
+= mVariables
->SizeOfIncludingThis(aMallocSizeOf
);
1420 if (mImportantVariables
) {
1421 n
+= mImportantVariables
->SizeOfIncludingThis(aMallocSizeOf
);
1427 Declaration::HasVariableDeclaration(const nsAString
& aName
) const
1429 return (mVariables
&& mVariables
->Has(aName
)) ||
1430 (mImportantVariables
&& mImportantVariables
->Has(aName
));
1434 Declaration::GetVariableDeclaration(const nsAString
& aName
,
1435 nsAString
& aValue
) const
1439 CSSVariableDeclarations::Type type
;
1442 if ((mImportantVariables
&& mImportantVariables
->Get(aName
, type
, value
)) ||
1443 (mVariables
&& mVariables
->Get(aName
, type
, value
))) {
1445 case CSSVariableDeclarations::eTokenStream
:
1446 aValue
.Append(value
);
1449 case CSSVariableDeclarations::eInitial
:
1450 aValue
.AppendLiteral("initial");
1453 case CSSVariableDeclarations::eInherit
:
1454 aValue
.AppendLiteral("inherit");
1457 case CSSVariableDeclarations::eUnset
:
1458 aValue
.AppendLiteral("unset");
1462 MOZ_ASSERT(false, "unexpected variable value type");
1468 Declaration::AddVariableDeclaration(const nsAString
& aName
,
1469 CSSVariableDeclarations::Type aType
,
1470 const nsString
& aValue
,
1472 bool aOverrideImportant
)
1474 MOZ_ASSERT(IsMutable());
1476 nsTArray
<nsString
>::index_type index
= mVariableOrder
.IndexOf(aName
);
1477 if (index
== nsTArray
<nsString
>::NoIndex
) {
1478 index
= mVariableOrder
.Length();
1479 mVariableOrder
.AppendElement(aName
);
1482 if (!aIsImportant
&& !aOverrideImportant
&&
1483 mImportantVariables
&& mImportantVariables
->Has(aName
)) {
1487 CSSVariableDeclarations
* variables
;
1490 mVariables
->Remove(aName
);
1492 if (!mImportantVariables
) {
1493 mImportantVariables
= new CSSVariableDeclarations
;
1495 variables
= mImportantVariables
;
1497 if (mImportantVariables
) {
1498 mImportantVariables
->Remove(aName
);
1501 mVariables
= new CSSVariableDeclarations
;
1503 variables
= mVariables
;
1507 case CSSVariableDeclarations::eTokenStream
:
1508 variables
->PutTokenStream(aName
, aValue
);
1511 case CSSVariableDeclarations::eInitial
:
1512 MOZ_ASSERT(aValue
.IsEmpty());
1513 variables
->PutInitial(aName
);
1516 case CSSVariableDeclarations::eInherit
:
1517 MOZ_ASSERT(aValue
.IsEmpty());
1518 variables
->PutInherit(aName
);
1521 case CSSVariableDeclarations::eUnset
:
1522 MOZ_ASSERT(aValue
.IsEmpty());
1523 variables
->PutUnset(aName
);
1527 MOZ_ASSERT(false, "unexpected aType value");
1530 uint32_t propertyIndex
= index
+ eCSSProperty_COUNT
;
1531 mOrder
.RemoveElement(propertyIndex
);
1532 mOrder
.AppendElement(propertyIndex
);
1536 Declaration::RemoveVariableDeclaration(const nsAString
& aName
)
1539 mVariables
->Remove(aName
);
1541 if (mImportantVariables
) {
1542 mImportantVariables
->Remove(aName
);
1544 nsTArray
<nsString
>::index_type index
= mVariableOrder
.IndexOf(aName
);
1545 if (index
!= nsTArray
<nsString
>::NoIndex
) {
1546 mOrder
.RemoveElement(index
+ eCSSProperty_COUNT
);
1551 Declaration::GetVariableValueIsImportant(const nsAString
& aName
) const
1553 return mImportantVariables
&& mImportantVariables
->Has(aName
);
1556 } // namespace mozilla::css
1557 } // namespace mozilla