1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
23 * Daniel Glazman <glazman@netscape.com>
24 * Mats Palmgren <mats.palmgren@bredband.net>
26 * Alternatively, the contents of this file may be used under the terms of
27 * either of the GNU General Public License Version 2 or later (the "GPL"),
28 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
41 * representation of a declaration block (or style attribute) in a CSS
47 #include "nsCSSDeclaration.h"
50 #include "nsUnicharUtils.h"
51 #include "nsReadableUtils.h"
53 #include "nsCSSProps.h"
55 #include "nsReadableUtils.h"
56 #include "nsStyleUtil.h"
58 #include "nsStyleConsts.h"
62 #define B_BORDER_TOP_STYLE 0x001
63 #define B_BORDER_LEFT_STYLE 0x002
64 #define B_BORDER_RIGHT_STYLE 0x004
65 #define B_BORDER_BOTTOM_STYLE 0x008
66 #define B_BORDER_TOP_COLOR 0x010
67 #define B_BORDER_LEFT_COLOR 0x020
68 #define B_BORDER_RIGHT_COLOR 0x040
69 #define B_BORDER_BOTTOM_COLOR 0x080
70 #define B_BORDER_TOP_WIDTH 0x100
71 #define B_BORDER_LEFT_WIDTH 0x200
72 #define B_BORDER_RIGHT_WIDTH 0x400
73 #define B_BORDER_BOTTOM_WIDTH 0x800
75 #define B_BORDER_STYLE 0x00f
76 #define B_BORDER_COLOR 0x0f0
77 #define B_BORDER_WIDTH 0xf00
79 #define B_BORDER_TOP 0x111
80 #define B_BORDER_LEFT 0x222
81 #define B_BORDER_RIGHT 0x444
82 #define B_BORDER_BOTTOM 0x888
84 #define B_BORDER 0xfff
86 nsCSSDeclaration::nsCSSDeclaration()
88 mImportantData(nsnull
)
90 // check that we can fit all the CSS properties into a PRUint8
91 // for the mOrder array - if not, might need to use PRUint16!
92 PR_STATIC_ASSERT(eCSSProperty_COUNT_no_shorthands
- 1 <= PR_UINT8_MAX
);
94 MOZ_COUNT_CTOR(nsCSSDeclaration
);
97 nsCSSDeclaration::nsCSSDeclaration(const nsCSSDeclaration
& aCopy
)
98 : mOrder(aCopy
.mOrder
),
99 mData(aCopy
.mData
? aCopy
.mData
->Clone() : nsnull
),
100 mImportantData(aCopy
.mImportantData
? aCopy
.mImportantData
->Clone()
103 MOZ_COUNT_CTOR(nsCSSDeclaration
);
106 nsCSSDeclaration::~nsCSSDeclaration(void)
111 if (mImportantData
) {
112 mImportantData
->Destroy();
115 MOZ_COUNT_DTOR(nsCSSDeclaration
);
119 nsCSSDeclaration::ValueAppended(nsCSSProperty aProperty
)
121 // order IS important for CSS, so remove and add to the end
122 if (nsCSSProps::IsShorthand(aProperty
)) {
123 CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p
, aProperty
) {
124 mOrder
.RemoveElement(*p
);
125 mOrder
.AppendElement(*p
);
128 mOrder
.RemoveElement(aProperty
);
129 mOrder
.AppendElement(aProperty
);
135 nsCSSDeclaration::RemoveProperty(nsCSSProperty aProperty
)
137 nsCSSExpandedDataBlock data
;
138 data
.Expand(&mData
, &mImportantData
);
139 NS_ASSERTION(!mData
&& !mImportantData
, "Expand didn't null things out");
141 if (nsCSSProps::IsShorthand(aProperty
)) {
142 CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p
, aProperty
) {
143 data
.ClearProperty(*p
);
144 mOrder
.RemoveElement(*p
);
147 data
.ClearProperty(aProperty
);
148 mOrder
.RemoveElement(aProperty
);
151 data
.Compress(&mData
, &mImportantData
);
156 nsCSSDeclaration::AppendComment(const nsAString
& aComment
)
158 return /* NS_ERROR_NOT_IMPLEMENTED, or not any longer that is */ NS_OK
;
162 nsCSSDeclaration::GetValueOrImportantValue(nsCSSProperty aProperty
, nsCSSValue
& aValue
) const
166 NS_ASSERTION(aProperty
>= 0, "out of range");
167 if (aProperty
>= eCSSProperty_COUNT_no_shorthands
||
168 nsCSSProps::kTypeTable
[aProperty
] != eCSSType_Value
) {
169 NS_ERROR("can't query for shorthand properties");
170 return NS_ERROR_ILLEGAL_VALUE
;
173 nsCSSCompressedDataBlock
*data
= GetValueIsImportant(aProperty
)
174 ? mImportantData
: mData
;
175 const void *storage
= data
->StorageFor(aProperty
);
178 aValue
= *static_cast<const nsCSSValue
*>(storage
);
182 PRBool
nsCSSDeclaration::AppendValueToString(nsCSSProperty aProperty
, nsAString
& aResult
) const
184 nsCSSCompressedDataBlock
*data
= GetValueIsImportant(aProperty
)
185 ? mImportantData
: mData
;
186 const void *storage
= data
->StorageFor(aProperty
);
188 switch (nsCSSProps::kTypeTable
[aProperty
]) {
189 case eCSSType_Value
: {
190 const nsCSSValue
*val
= static_cast<const nsCSSValue
*>(storage
);
191 AppendCSSValueToString(aProperty
, *val
, aResult
);
193 case eCSSType_Rect
: {
194 const nsCSSRect
*rect
= static_cast<const nsCSSRect
*>(storage
);
195 if (rect
->mTop
.GetUnit() == eCSSUnit_Inherit
||
196 rect
->mTop
.GetUnit() == eCSSUnit_Initial
) {
197 NS_ASSERTION(rect
->mRight
.GetUnit() == rect
->mTop
.GetUnit(),
198 "Top inherit or initial, right isn't. Fix the parser!");
199 NS_ASSERTION(rect
->mBottom
.GetUnit() == rect
->mTop
.GetUnit(),
200 "Top inherit or initial, bottom isn't. Fix the parser!");
201 NS_ASSERTION(rect
->mLeft
.GetUnit() == rect
->mTop
.GetUnit(),
202 "Top inherit or initial, left isn't. Fix the parser!");
203 AppendCSSValueToString(aProperty
, rect
->mTop
, aResult
);
205 aResult
.AppendLiteral("rect(");
206 AppendCSSValueToString(aProperty
, rect
->mTop
, aResult
);
207 NS_NAMED_LITERAL_STRING(comma
, ", ");
208 aResult
.Append(comma
);
209 AppendCSSValueToString(aProperty
, rect
->mRight
, aResult
);
210 aResult
.Append(comma
);
211 AppendCSSValueToString(aProperty
, rect
->mBottom
, aResult
);
212 aResult
.Append(comma
);
213 AppendCSSValueToString(aProperty
, rect
->mLeft
, aResult
);
214 aResult
.Append(PRUnichar(')'));
217 case eCSSType_ValuePair
: {
218 const nsCSSValuePair
*pair
= static_cast<const nsCSSValuePair
*>(storage
);
219 AppendCSSValueToString(aProperty
, pair
->mXValue
, aResult
);
220 if (pair
->mYValue
!= pair
->mXValue
||
221 ((aProperty
== eCSSProperty_background_position
||
222 aProperty
== eCSSProperty__moz_transform_origin
) &&
223 pair
->mXValue
.GetUnit() != eCSSUnit_Inherit
&&
224 pair
->mXValue
.GetUnit() != eCSSUnit_Initial
)) {
225 // Only output a Y value if it's different from the X value
226 // or if it's a background-position value other than 'initial'
227 // or 'inherit' or if it's a -moz-transform-origin value other
228 // than 'initial' or 'inherit'.
229 aResult
.Append(PRUnichar(' '));
230 AppendCSSValueToString(aProperty
, pair
->mYValue
, aResult
);
233 case eCSSType_ValueList
: {
234 const nsCSSValueList
* val
=
235 *static_cast<nsCSSValueList
*const*>(storage
);
237 AppendCSSValueToString(aProperty
, val
->mValue
, aResult
);
240 if (nsCSSProps::PropHasFlags(aProperty
,
241 CSS_PROPERTY_VALUE_LIST_USES_COMMAS
))
242 aResult
.Append(PRUnichar(','));
243 aResult
.Append(PRUnichar(' '));
247 case eCSSType_ValuePairList
: {
248 const nsCSSValuePairList
* item
=
249 *static_cast<nsCSSValuePairList
*const*>(storage
);
251 NS_ASSERTION(item
->mXValue
.GetUnit() != eCSSUnit_Null
,
252 "unexpected null unit");
253 AppendCSSValueToString(aProperty
, item
->mXValue
, aResult
);
254 if (item
->mYValue
.GetUnit() != eCSSUnit_Null
) {
255 aResult
.Append(PRUnichar(' '));
256 AppendCSSValueToString(aProperty
, item
->mYValue
, aResult
);
260 aResult
.Append(PRUnichar(' '));
266 return storage
!= nsnull
;
270 nsCSSDeclaration::AppendCSSValueToString(nsCSSProperty aProperty
,
271 const nsCSSValue
& aValue
,
274 nsCSSUnit unit
= aValue
.GetUnit();
276 if (eCSSUnit_Null
== unit
) {
280 if (eCSSUnit_String
<= unit
&& unit
<= eCSSUnit_Attr
) {
281 if (unit
== eCSSUnit_Attr
) {
282 aResult
.AppendLiteral("attr(");
285 aValue
.GetStringValue(buffer
);
286 aResult
.Append(buffer
);
288 else if (eCSSUnit_Array
<= unit
&& unit
<= eCSSUnit_Counters
) {
290 case eCSSUnit_Counter
: aResult
.AppendLiteral("counter("); break;
291 case eCSSUnit_Counters
: aResult
.AppendLiteral("counters("); break;
295 nsCSSValue::Array
*array
= aValue
.GetArrayValue();
296 PRBool mark
= PR_FALSE
;
297 for (PRUint16 i
= 0, i_end
= array
->Count(); i
< i_end
; ++i
) {
298 if (aProperty
== eCSSProperty_border_image
&& i
>= 5) {
299 if (array
->Item(i
).GetUnit() == eCSSUnit_Null
) {
303 aResult
.AppendLiteral(" /");
306 if (mark
&& array
->Item(i
).GetUnit() != eCSSUnit_Null
) {
307 if (unit
== eCSSUnit_Array
)
308 aResult
.AppendLiteral(" ");
310 aResult
.AppendLiteral(", ");
313 ((eCSSUnit_Counter
<= unit
&& unit
<= eCSSUnit_Counters
) &&
314 i
== array
->Count() - 1)
315 ? eCSSProperty_list_style_type
: aProperty
;
316 if (AppendCSSValueToString(prop
, array
->Item(i
), aResult
)) {
321 /* Although Function is backed by an Array, we'll handle it separately
322 * because it's a bit quirky.
324 else if (eCSSUnit_Function
== unit
) {
325 const nsCSSValue::Array
* array
= aValue
.GetArrayValue();
326 NS_ASSERTION(array
->Count() >= 1, "Functions must have at least one element for the name.");
328 /* Append the function name. */
329 AppendCSSValueToString(aProperty
, array
->Item(0), aResult
);
330 aResult
.AppendLiteral("(");
332 /* Now, step through the function contents, writing each of them as we go. */
333 for (PRUint16 index
= 1; index
< array
->Count(); ++index
) {
334 AppendCSSValueToString(aProperty
, array
->Item(index
), aResult
);
336 /* If we're not at the final element, append a comma. */
337 if (index
+ 1 != array
->Count())
338 aResult
.AppendLiteral(", ");
341 /* Finally, append the closing parenthesis. */
342 aResult
.AppendLiteral(")");
344 else if (eCSSUnit_Integer
== unit
) {
346 tmpStr
.AppendInt(aValue
.GetIntValue(), 10);
347 aResult
.Append(tmpStr
);
349 else if (eCSSUnit_Enumerated
== unit
) {
350 if (eCSSProperty_text_decoration
== aProperty
) {
351 PRInt32 intValue
= aValue
.GetIntValue();
352 if (NS_STYLE_TEXT_DECORATION_NONE
!= intValue
) {
354 for (mask
= NS_STYLE_TEXT_DECORATION_UNDERLINE
;
355 mask
<= NS_STYLE_TEXT_DECORATION_BLINK
;
357 if ((mask
& intValue
) == mask
) {
358 AppendASCIItoUTF16(nsCSSProps::LookupPropertyValue(aProperty
, mask
), aResult
);
360 if (0 != intValue
) { // more left
361 aResult
.Append(PRUnichar(' '));
367 AppendASCIItoUTF16(nsCSSProps::LookupPropertyValue(aProperty
, NS_STYLE_TEXT_DECORATION_NONE
), aResult
);
370 else if (eCSSProperty_azimuth
== aProperty
) {
371 PRInt32 intValue
= aValue
.GetIntValue();
372 AppendASCIItoUTF16(nsCSSProps::LookupPropertyValue(aProperty
, (intValue
& ~NS_STYLE_AZIMUTH_BEHIND
)), aResult
);
373 if ((NS_STYLE_AZIMUTH_BEHIND
& intValue
) != 0) {
374 aResult
.Append(PRUnichar(' '));
375 AppendASCIItoUTF16(nsCSSProps::LookupPropertyValue(aProperty
, NS_STYLE_AZIMUTH_BEHIND
), aResult
);
378 else if (eCSSProperty_marks
== aProperty
) {
379 PRInt32 intValue
= aValue
.GetIntValue();
380 if ((NS_STYLE_PAGE_MARKS_CROP
& intValue
) != 0) {
381 AppendASCIItoUTF16(nsCSSProps::LookupPropertyValue(aProperty
, NS_STYLE_PAGE_MARKS_CROP
), aResult
);
383 if ((NS_STYLE_PAGE_MARKS_REGISTER
& intValue
) != 0) {
384 if ((NS_STYLE_PAGE_MARKS_CROP
& intValue
) != 0) {
385 aResult
.Append(PRUnichar(' '));
387 AppendASCIItoUTF16(nsCSSProps::LookupPropertyValue(aProperty
, NS_STYLE_PAGE_MARKS_REGISTER
), aResult
);
391 const nsAFlatCString
& name
= nsCSSProps::LookupPropertyValue(aProperty
, aValue
.GetIntValue());
392 AppendASCIItoUTF16(name
, aResult
);
395 else if (eCSSUnit_EnumColor
== unit
) {
396 // we can lookup the property in the ColorTable and then
397 // get a string mapping the name
399 if (nsCSSProps::GetColorName(aValue
.GetIntValue(), str
)){
400 AppendASCIItoUTF16(str
, aResult
);
402 NS_NOTREACHED("bad color value");
405 else if (eCSSUnit_Color
== unit
) {
406 nscolor color
= aValue
.GetColorValue();
407 if (color
== NS_RGBA(0, 0, 0, 0)) {
408 // Use the strictest match for 'transparent' so we do correct
409 // round-tripping of all other rgba() values.
410 aResult
.AppendLiteral("transparent");
413 PRUint8 a
= NS_GET_A(color
);
415 tmpStr
.AppendLiteral("rgba(");
417 tmpStr
.AppendLiteral("rgb(");
420 NS_NAMED_LITERAL_STRING(comma
, ", ");
422 tmpStr
.AppendInt(NS_GET_R(color
), 10);
423 tmpStr
.Append(comma
);
424 tmpStr
.AppendInt(NS_GET_G(color
), 10);
425 tmpStr
.Append(comma
);
426 tmpStr
.AppendInt(NS_GET_B(color
), 10);
428 tmpStr
.Append(comma
);
429 tmpStr
.AppendFloat(nsStyleUtil::ColorComponentToFloat(a
));
431 tmpStr
.Append(PRUnichar(')'));
433 aResult
.Append(tmpStr
);
436 else if (eCSSUnit_URL
== unit
|| eCSSUnit_Image
== unit
) {
437 aResult
.Append(NS_LITERAL_STRING("url(") +
438 nsDependentString(aValue
.GetOriginalURLValue()) +
439 NS_LITERAL_STRING(")"));
441 else if (eCSSUnit_Percent
== unit
) {
443 tmpStr
.AppendFloat(aValue
.GetPercentValue() * 100.0f
);
444 aResult
.Append(tmpStr
);
446 else if (eCSSUnit_Percent
< unit
) { // length unit
448 tmpStr
.AppendFloat(aValue
.GetFloatValue());
449 aResult
.Append(tmpStr
);
453 case eCSSUnit_Null
: break;
454 case eCSSUnit_Auto
: aResult
.AppendLiteral("auto"); break;
455 case eCSSUnit_Inherit
: aResult
.AppendLiteral("inherit"); break;
456 case eCSSUnit_Initial
: aResult
.AppendLiteral("-moz-initial"); break;
457 case eCSSUnit_None
: aResult
.AppendLiteral("none"); break;
458 case eCSSUnit_Normal
: aResult
.AppendLiteral("normal"); break;
459 case eCSSUnit_System_Font
: aResult
.AppendLiteral("-moz-use-system-font"); break;
460 case eCSSUnit_Dummy
: break;
462 case eCSSUnit_String
: break;
463 case eCSSUnit_URL
: break;
464 case eCSSUnit_Image
: break;
465 case eCSSUnit_Array
: break;
467 case eCSSUnit_Counter
:
468 case eCSSUnit_Counters
: aResult
.Append(PRUnichar(')')); break;
469 case eCSSUnit_Local_Font
: break;
470 case eCSSUnit_Font_Format
: break;
471 case eCSSUnit_Function
: break;
472 case eCSSUnit_Integer
: break;
473 case eCSSUnit_Enumerated
: break;
474 case eCSSUnit_EnumColor
: break;
475 case eCSSUnit_Color
: break;
476 case eCSSUnit_Percent
: aResult
.Append(PRUnichar('%')); break;
477 case eCSSUnit_Number
: break;
479 case eCSSUnit_Inch
: aResult
.AppendLiteral("in"); break;
480 case eCSSUnit_Foot
: aResult
.AppendLiteral("ft"); break;
481 case eCSSUnit_Mile
: aResult
.AppendLiteral("mi"); break;
482 case eCSSUnit_Millimeter
: aResult
.AppendLiteral("mm"); break;
483 case eCSSUnit_Centimeter
: aResult
.AppendLiteral("cm"); break;
484 case eCSSUnit_Meter
: aResult
.AppendLiteral("m"); break;
485 case eCSSUnit_Kilometer
: aResult
.AppendLiteral("km"); break;
486 case eCSSUnit_Point
: aResult
.AppendLiteral("pt"); break;
487 case eCSSUnit_Pica
: aResult
.AppendLiteral("pc"); break;
488 case eCSSUnit_Didot
: aResult
.AppendLiteral("dt"); break;
489 case eCSSUnit_Cicero
: aResult
.AppendLiteral("cc"); break;
491 case eCSSUnit_EM
: aResult
.AppendLiteral("em"); break;
492 case eCSSUnit_EN
: aResult
.AppendLiteral("en"); break;
493 case eCSSUnit_XHeight
: aResult
.AppendLiteral("ex"); break;
494 case eCSSUnit_CapHeight
: aResult
.AppendLiteral("cap"); break;
495 case eCSSUnit_Char
: aResult
.AppendLiteral("ch"); break;
497 case eCSSUnit_Pixel
: aResult
.AppendLiteral("px"); break;
499 case eCSSUnit_Degree
: aResult
.AppendLiteral("deg"); break;
500 case eCSSUnit_Grad
: aResult
.AppendLiteral("grad"); break;
501 case eCSSUnit_Radian
: aResult
.AppendLiteral("rad"); break;
503 case eCSSUnit_Hertz
: aResult
.AppendLiteral("Hz"); break;
504 case eCSSUnit_Kilohertz
: aResult
.AppendLiteral("kHz"); break;
506 case eCSSUnit_Seconds
: aResult
.Append(PRUnichar('s')); break;
507 case eCSSUnit_Milliseconds
: aResult
.AppendLiteral("ms"); break;
514 nsCSSDeclaration::GetValue(nsCSSProperty aProperty
,
515 nsAString
& aValue
) const
519 // simple properties are easy.
520 if (!nsCSSProps::IsShorthand(aProperty
)) {
521 AppendValueToString(aProperty
, aValue
);
525 // DOM Level 2 Style says (when describing CSS2Properties, although
526 // not CSSStyleDeclaration.getPropertyValue):
527 // However, if there is no shorthand declaration that could be added
528 // to the ruleset without changing in any way the rules already
529 // declared in the ruleset (i.e., by adding longhand rules that were
530 // previously not declared in the ruleset), then the empty string
531 // should be returned for the shorthand property.
532 // This means we need to check a number of cases:
533 // (1) Since a shorthand sets all sub-properties, if some of its
534 // subproperties were not specified, we must return the empty
536 // (2) Since 'inherit' and 'initial' can only be specified as the
537 // values for entire properties, we need to return the empty
538 // string if some but not all of the subproperties have one of
540 // (3) Since a single value only makes sense with or without
541 // !important, we return the empty string if some values are
542 // !important and some are not.
543 // Since we're doing this check for 'inherit' and 'initial' up front,
544 // we can also simplify the property serialization code by serializing
545 // those values up front as well.
546 PRUint32 totalCount
= 0, importantCount
= 0,
547 initialCount
= 0, inheritCount
= 0;
548 CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p
, aProperty
) {
549 if (*p
== eCSSProperty__x_system_font
||
550 nsCSSProps::PropHasFlags(*p
, CSS_PROPERTY_DIRECTIONAL_SOURCE
)) {
551 // The system-font subproperty and the *-source properties don't count.
555 const void *storage
= mData
->StorageFor(*p
);
556 NS_ASSERTION(!storage
|| !mImportantData
|| !mImportantData
->StorageFor(*p
),
557 "can't be in both blocks");
558 if (!storage
&& mImportantData
) {
560 storage
= mImportantData
->StorageFor(*p
);
563 // Case (1) above: some subproperties not specified.
567 switch (nsCSSProps::kTypeTable
[*p
]) {
568 case eCSSType_Value
: {
569 const nsCSSValue
*val
= static_cast<const nsCSSValue
*>(storage
);
570 unit
= val
->GetUnit();
572 case eCSSType_Rect
: {
573 const nsCSSRect
*rect
= static_cast<const nsCSSRect
*>(storage
);
574 unit
= rect
->mTop
.GetUnit();
576 case eCSSType_ValuePair
: {
577 const nsCSSValuePair
*pair
= static_cast<const nsCSSValuePair
*>(storage
);
578 unit
= pair
->mXValue
.GetUnit();
580 case eCSSType_ValueList
: {
581 const nsCSSValueList
* item
=
582 *static_cast<nsCSSValueList
*const*>(storage
);
584 unit
= item
->mValue
.GetUnit();
586 unit
= eCSSUnit_Null
;
589 case eCSSType_ValuePairList
: {
590 const nsCSSValuePairList
* item
=
591 *static_cast<nsCSSValuePairList
*const*>(storage
);
593 unit
= item
->mXValue
.GetUnit();
595 unit
= eCSSUnit_Null
;
599 if (unit
== eCSSUnit_Inherit
) {
601 } else if (unit
== eCSSUnit_Initial
) {
605 if (importantCount
!= 0 && importantCount
!= totalCount
) {
606 // Case (3), no consistent importance.
609 if (initialCount
== totalCount
) {
610 // Simplify serialization below by serializing initial up-front.
611 AppendCSSValueToString(eCSSProperty_UNKNOWN
, nsCSSValue(eCSSUnit_Initial
),
615 if (inheritCount
== totalCount
) {
616 // Simplify serialization below by serializing inherit up-front.
617 AppendCSSValueToString(eCSSProperty_UNKNOWN
, nsCSSValue(eCSSUnit_Inherit
),
621 if (initialCount
!= 0 || inheritCount
!= 0) {
622 // Case (2): partially initial or inherit.
627 // XXX What about checking the consistency of '!important'?
628 // XXX What about checking that we don't serialize inherit,
629 // -moz-initial, or other illegal values?
630 // XXXldb Can we share shorthand logic with ToString?
632 case eCSSProperty_margin
:
633 case eCSSProperty_padding
:
634 case eCSSProperty_border_color
:
635 case eCSSProperty_border_style
:
636 case eCSSProperty_border_width
: {
637 const nsCSSProperty
* subprops
=
638 nsCSSProps::SubpropertyEntryFor(aProperty
);
639 NS_ASSERTION(nsCSSProps::kTypeTable
[subprops
[0]] == eCSSType_Value
&&
640 nsCSSProps::kTypeTable
[subprops
[1]] == eCSSType_Value
&&
641 nsCSSProps::kTypeTable
[subprops
[2]] == eCSSType_Value
&&
642 nsCSSProps::kTypeTable
[subprops
[3]] == eCSSType_Value
,
644 if (!AppendValueToString(subprops
[0], aValue
) ||
645 !(aValue
.Append(PRUnichar(' ')),
646 AppendValueToString(subprops
[1], aValue
)) ||
647 !(aValue
.Append(PRUnichar(' ')),
648 AppendValueToString(subprops
[2], aValue
)) ||
649 !(aValue
.Append(PRUnichar(' ')),
650 AppendValueToString(subprops
[3], aValue
))) {
655 case eCSSProperty__moz_border_radius
:
656 case eCSSProperty__moz_outline_radius
: {
657 const nsCSSProperty
* subprops
=
658 nsCSSProps::SubpropertyEntryFor(aProperty
);
659 NS_ASSERTION(nsCSSProps::kTypeTable
[subprops
[0]] == eCSSType_ValuePair
&&
660 nsCSSProps::kTypeTable
[subprops
[1]] == eCSSType_ValuePair
&&
661 nsCSSProps::kTypeTable
[subprops
[2]] == eCSSType_ValuePair
&&
662 nsCSSProps::kTypeTable
[subprops
[3]] == eCSSType_ValuePair
,
664 nsCSSCompressedDataBlock
*data
= GetValueIsImportant(aProperty
)
665 ? mImportantData
: mData
;
666 const nsCSSValuePair
* vals
[4] = {
667 static_cast<const nsCSSValuePair
*>(data
->StorageFor(subprops
[0])),
668 static_cast<const nsCSSValuePair
*>(data
->StorageFor(subprops
[1])),
669 static_cast<const nsCSSValuePair
*>(data
->StorageFor(subprops
[2])),
670 static_cast<const nsCSSValuePair
*>(data
->StorageFor(subprops
[3]))
673 AppendCSSValueToString(aProperty
, vals
[0]->mXValue
, aValue
);
674 aValue
.Append(PRUnichar(' '));
675 AppendCSSValueToString(aProperty
, vals
[1]->mXValue
, aValue
);
676 aValue
.Append(PRUnichar(' '));
677 AppendCSSValueToString(aProperty
, vals
[2]->mXValue
, aValue
);
678 aValue
.Append(PRUnichar(' '));
679 AppendCSSValueToString(aProperty
, vals
[3]->mXValue
, aValue
);
681 // For compatibility, only write a slash and the y-values
682 // if they're not identical to the x-values.
683 if (vals
[0]->mXValue
!= vals
[0]->mYValue
||
684 vals
[1]->mXValue
!= vals
[1]->mYValue
||
685 vals
[2]->mXValue
!= vals
[2]->mYValue
||
686 vals
[3]->mXValue
!= vals
[3]->mYValue
) {
687 aValue
.AppendLiteral(" / ");
688 AppendCSSValueToString(aProperty
, vals
[0]->mYValue
, aValue
);
689 aValue
.Append(PRUnichar(' '));
690 AppendCSSValueToString(aProperty
, vals
[1]->mYValue
, aValue
);
691 aValue
.Append(PRUnichar(' '));
692 AppendCSSValueToString(aProperty
, vals
[2]->mYValue
, aValue
);
693 aValue
.Append(PRUnichar(' '));
694 AppendCSSValueToString(aProperty
, vals
[3]->mYValue
, aValue
);
698 case eCSSProperty_border
:
699 // XXX More consistency checking needed before falling through.
700 aProperty
= eCSSProperty_border_top
;
701 case eCSSProperty_border_top
:
702 case eCSSProperty_border_right
:
703 case eCSSProperty_border_bottom
:
704 case eCSSProperty_border_left
:
705 case eCSSProperty_border_start
:
706 case eCSSProperty_border_end
:
707 case eCSSProperty__moz_column_rule
:
708 case eCSSProperty_outline
: {
709 const nsCSSProperty
* subprops
=
710 nsCSSProps::SubpropertyEntryFor(aProperty
);
711 NS_ASSERTION(nsCSSProps::kTypeTable
[subprops
[0]] == eCSSType_Value
&&
712 nsCSSProps::kTypeTable
[subprops
[1]] == eCSSType_Value
&&
713 nsCSSProps::kTypeTable
[subprops
[2]] == eCSSType_Value
,
715 if (!AppendValueToString(subprops
[0], aValue
) ||
716 !(aValue
.Append(PRUnichar(' ')),
717 AppendValueToString(subprops
[1], aValue
)) ||
718 !(aValue
.Append(PRUnichar(' ')),
719 AppendValueToString(subprops
[2], aValue
))) {
724 case eCSSProperty_margin_left
:
725 case eCSSProperty_margin_right
:
726 case eCSSProperty_margin_start
:
727 case eCSSProperty_margin_end
:
728 case eCSSProperty_padding_left
:
729 case eCSSProperty_padding_right
:
730 case eCSSProperty_padding_start
:
731 case eCSSProperty_padding_end
:
732 case eCSSProperty_border_left_color
:
733 case eCSSProperty_border_left_style
:
734 case eCSSProperty_border_left_width
:
735 case eCSSProperty_border_right_color
:
736 case eCSSProperty_border_right_style
:
737 case eCSSProperty_border_right_width
:
738 case eCSSProperty_border_start_color
:
739 case eCSSProperty_border_start_style
:
740 case eCSSProperty_border_start_width
:
741 case eCSSProperty_border_end_color
:
742 case eCSSProperty_border_end_style
:
743 case eCSSProperty_border_end_width
: {
744 const nsCSSProperty
* subprops
=
745 nsCSSProps::SubpropertyEntryFor(aProperty
);
746 NS_ASSERTION(subprops
[3] == eCSSProperty_UNKNOWN
,
747 "not box property with physical vs. logical cascading");
748 AppendValueToString(subprops
[0], aValue
);
751 case eCSSProperty_background
: {
752 PRBool appendedSomething
= PR_FALSE
;
753 if (AppendValueToString(eCSSProperty_background_color
, aValue
)) {
754 appendedSomething
= PR_TRUE
;
755 aValue
.Append(PRUnichar(' '));
757 if (AppendValueToString(eCSSProperty_background_image
, aValue
)) {
758 aValue
.Append(PRUnichar(' '));
759 appendedSomething
= PR_TRUE
;
761 if (AppendValueToString(eCSSProperty_background_repeat
, aValue
)) {
762 aValue
.Append(PRUnichar(' '));
763 appendedSomething
= PR_TRUE
;
765 if (AppendValueToString(eCSSProperty_background_attachment
, aValue
)) {
766 aValue
.Append(PRUnichar(' '));
767 appendedSomething
= PR_TRUE
;
769 if (!AppendValueToString(eCSSProperty_background_position
, aValue
) &&
771 NS_ASSERTION(!aValue
.IsEmpty() && aValue
.Last() == PRUnichar(' '),
772 "We appended a space before!");
773 // We appended an extra space. Let's get rid of it
774 aValue
.Truncate(aValue
.Length() - 1);
778 case eCSSProperty_cue
: {
779 if (AppendValueToString(eCSSProperty_cue_before
, aValue
)) {
780 aValue
.Append(PRUnichar(' '));
781 if (!AppendValueToString(eCSSProperty_cue_after
, aValue
))
786 case eCSSProperty_font
: {
787 nsCSSValue style
, variant
, weight
, size
, lh
, family
, systemFont
;
788 GetValueOrImportantValue(eCSSProperty__x_system_font
, systemFont
);
789 GetValueOrImportantValue(eCSSProperty_font_style
, style
);
790 GetValueOrImportantValue(eCSSProperty_font_variant
, variant
);
791 GetValueOrImportantValue(eCSSProperty_font_weight
, weight
);
792 GetValueOrImportantValue(eCSSProperty_font_size
, size
);
793 GetValueOrImportantValue(eCSSProperty_line_height
, lh
);
794 GetValueOrImportantValue(eCSSProperty_font_family
, family
);
796 if (systemFont
.GetUnit() != eCSSUnit_None
&&
797 systemFont
.GetUnit() != eCSSUnit_Null
) {
798 AppendCSSValueToString(eCSSProperty__x_system_font
, systemFont
, aValue
);
800 if (style
.GetUnit() != eCSSUnit_Normal
) {
801 AppendCSSValueToString(eCSSProperty_font_style
, style
, aValue
);
802 aValue
.Append(PRUnichar(' '));
804 if (variant
.GetUnit() != eCSSUnit_Normal
) {
805 AppendCSSValueToString(eCSSProperty_font_variant
, variant
, aValue
);
806 aValue
.Append(PRUnichar(' '));
808 if (weight
.GetUnit() != eCSSUnit_Normal
) {
809 AppendCSSValueToString(eCSSProperty_font_weight
, weight
, aValue
);
810 aValue
.Append(PRUnichar(' '));
812 AppendCSSValueToString(eCSSProperty_font_size
, size
, aValue
);
813 if (lh
.GetUnit() != eCSSUnit_Normal
) {
814 aValue
.Append(PRUnichar('/'));
815 AppendCSSValueToString(eCSSProperty_line_height
, lh
, aValue
);
817 aValue
.Append(PRUnichar(' '));
818 AppendCSSValueToString(eCSSProperty_font_family
, family
, aValue
);
822 case eCSSProperty_list_style
:
823 if (AppendValueToString(eCSSProperty_list_style_type
, aValue
))
824 aValue
.Append(PRUnichar(' '));
825 if (AppendValueToString(eCSSProperty_list_style_position
, aValue
))
826 aValue
.Append(PRUnichar(' '));
827 AppendValueToString(eCSSProperty_list_style_image
, aValue
);
829 case eCSSProperty_overflow
: {
830 nsCSSValue xValue
, yValue
;
831 GetValueOrImportantValue(eCSSProperty_overflow_x
, xValue
);
832 GetValueOrImportantValue(eCSSProperty_overflow_y
, yValue
);
833 if (xValue
== yValue
)
834 AppendValueToString(eCSSProperty_overflow_x
, aValue
);
837 case eCSSProperty_pause
: {
838 if (AppendValueToString(eCSSProperty_pause_before
, aValue
)) {
839 aValue
.Append(PRUnichar(' '));
840 if (!AppendValueToString(eCSSProperty_pause_after
, aValue
))
846 case eCSSProperty_marker
: {
847 nsCSSValue endValue
, midValue
, startValue
;
848 GetValueOrImportantValue(eCSSProperty_marker_end
, endValue
);
849 GetValueOrImportantValue(eCSSProperty_marker_mid
, midValue
);
850 GetValueOrImportantValue(eCSSProperty_marker_start
, startValue
);
851 if (endValue
== midValue
&& midValue
== startValue
)
852 AppendValueToString(eCSSProperty_marker_end
, aValue
);
857 NS_NOTREACHED("no other shorthands");
864 nsCSSDeclaration::GetValueIsImportant(const nsAString
& aProperty
) const
866 nsCSSProperty propID
= nsCSSProps::LookupProperty(aProperty
);
867 return GetValueIsImportant(propID
);
871 nsCSSDeclaration::GetValueIsImportant(nsCSSProperty aProperty
) const
876 // Calling StorageFor is inefficient, but we can assume '!important'
879 if (nsCSSProps::IsShorthand(aProperty
)) {
880 CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p
, aProperty
) {
881 if (*p
== eCSSProperty__x_system_font
) {
882 // The system_font subproperty doesn't count.
885 if (!mImportantData
->StorageFor(*p
)) {
892 return mImportantData
->StorageFor(aProperty
) != nsnull
;
895 // XXXldb Bug 376075 All callers of AllPropertiesSameImportance also
896 // need to check for 'inherit' and 'initial' values, since you can't
897 // output a mix of either mixed with other values in the same shorthand!
899 nsCSSDeclaration::AllPropertiesSameImportance(PRInt32 aFirst
, PRInt32 aSecond
,
900 PRInt32 aThird
, PRInt32 aFourth
,
902 PRBool
& aImportance
) const
904 aImportance
= GetValueIsImportant(OrderValueAt(aFirst
-1));
905 if ((aSecond
&& aImportance
!= GetValueIsImportant(OrderValueAt(aSecond
-1))) ||
906 (aThird
&& aImportance
!= GetValueIsImportant(OrderValueAt(aThird
-1))) ||
907 (aFourth
&& aImportance
!= GetValueIsImportant(OrderValueAt(aFourth
-1))) ||
908 (aFifth
&& aImportance
!= GetValueIsImportant(OrderValueAt(aFifth
-1)))) {
915 nsCSSDeclaration::AllPropertiesSameValue(PRInt32 aFirst
, PRInt32 aSecond
,
916 PRInt32 aThird
, PRInt32 aFourth
) const
918 nsCSSValue firstValue
, otherValue
;
919 // TryBorderShorthand does the bounds-checking for us; valid values there
920 // are > 0; 0 is a flag for "not set". We here are passed the actual
921 // index, which comes from finding the value in the mOrder property array.
922 // Of course, re-getting the mOrder value here is pretty silly.
923 GetValueOrImportantValue(OrderValueAt(aFirst
-1), firstValue
);
924 GetValueOrImportantValue(OrderValueAt(aSecond
-1), otherValue
);
925 if (firstValue
!= otherValue
) {
928 GetValueOrImportantValue(OrderValueAt(aThird
-1), otherValue
);
929 if (firstValue
!= otherValue
) {
932 GetValueOrImportantValue(OrderValueAt(aFourth
-1), otherValue
);
933 if (firstValue
!= otherValue
) {
940 nsCSSDeclaration::AppendImportanceToString(PRBool aIsImportant
,
944 aString
.AppendLiteral(" ! important");
949 nsCSSDeclaration::AppendPropertyAndValueToString(nsCSSProperty aProperty
,
950 nsCSSProperty aPropertyName
,
951 nsAString
& aResult
) const
953 NS_ASSERTION(0 <= aProperty
&& aProperty
< eCSSProperty_COUNT_no_shorthands
,
954 "property enum out of range");
955 AppendASCIItoUTF16(nsCSSProps::GetStringValue(aPropertyName
), aResult
);
956 aResult
.AppendLiteral(": ");
957 AppendValueToString(aProperty
, aResult
);
958 PRBool isImportant
= GetValueIsImportant(aProperty
);
959 AppendImportanceToString(isImportant
, aResult
);
960 aResult
.AppendLiteral("; ");
964 nsCSSDeclaration::TryBorderShorthand(nsAString
& aString
, PRUint32 aPropertiesSet
,
965 PRInt32 aBorderTopWidth
,
966 PRInt32 aBorderTopStyle
,
967 PRInt32 aBorderTopColor
,
968 PRInt32 aBorderBottomWidth
,
969 PRInt32 aBorderBottomStyle
,
970 PRInt32 aBorderBottomColor
,
971 PRInt32 aBorderLeftWidth
,
972 PRInt32 aBorderLeftStyle
,
973 PRInt32 aBorderLeftColor
,
974 PRInt32 aBorderRightWidth
,
975 PRInt32 aBorderRightStyle
,
976 PRInt32 aBorderRightColor
) const
978 PRBool border
= PR_FALSE
, isImportant
= PR_FALSE
;
979 // 0 means not in the mOrder array; otherwise it's index+1
980 if (B_BORDER
== aPropertiesSet
981 && AllPropertiesSameValue(aBorderTopWidth
, aBorderBottomWidth
,
982 aBorderLeftWidth
, aBorderRightWidth
)
983 && AllPropertiesSameValue(aBorderTopStyle
, aBorderBottomStyle
,
984 aBorderLeftStyle
, aBorderRightStyle
)
985 && AllPropertiesSameValue(aBorderTopColor
, aBorderBottomColor
,
986 aBorderLeftColor
, aBorderRightColor
)) {
991 PRBool isWidthImportant
, isStyleImportant
, isColorImportant
;
992 if (AllPropertiesSameImportance(aBorderTopWidth
, aBorderBottomWidth
,
993 aBorderLeftWidth
, aBorderRightWidth
,
996 AllPropertiesSameImportance(aBorderTopStyle
, aBorderBottomStyle
,
997 aBorderLeftStyle
, aBorderRightStyle
,
1000 AllPropertiesSameImportance(aBorderTopColor
, aBorderBottomColor
,
1001 aBorderLeftColor
, aBorderRightColor
,
1003 isColorImportant
)) {
1004 if (isWidthImportant
== isStyleImportant
&& isWidthImportant
== isColorImportant
) {
1006 isImportant
= isWidthImportant
;
1011 AppendASCIItoUTF16(nsCSSProps::GetStringValue(eCSSProperty_border
), aString
);
1012 aString
.AppendLiteral(": ");
1014 AppendValueToString(eCSSProperty_border_top_width
, aString
);
1015 aString
.Append(PRUnichar(' '));
1017 AppendValueToString(eCSSProperty_border_top_style
, aString
);
1018 aString
.Append(PRUnichar(' '));
1020 nsAutoString valueString
;
1021 AppendValueToString(eCSSProperty_border_top_color
, valueString
);
1022 if (!valueString
.EqualsLiteral("-moz-use-text-color")) {
1023 /* don't output this value, it's proprietary Mozilla and */
1024 /* not intended to be exposed ; we can remove it from the */
1025 /* values of the shorthand since this value represents the */
1026 /* initial value of border-*-color */
1027 aString
.Append(valueString
);
1029 AppendImportanceToString(isImportant
, aString
);
1030 aString
.AppendLiteral("; ");
1036 nsCSSDeclaration::TryBorderSideShorthand(nsAString
& aString
,
1037 nsCSSProperty aShorthand
,
1038 PRInt32 aBorderWidth
,
1039 PRInt32 aBorderStyle
,
1040 PRInt32 aBorderColor
) const
1043 if (AllPropertiesSameImportance(aBorderWidth
, aBorderStyle
, aBorderColor
,
1046 AppendASCIItoUTF16(nsCSSProps::GetStringValue(aShorthand
), aString
);
1047 aString
.AppendLiteral(": ");
1049 AppendValueToString(OrderValueAt(aBorderWidth
-1), aString
);
1051 aString
.Append(PRUnichar(' '));
1052 AppendValueToString(OrderValueAt(aBorderStyle
-1), aString
);
1054 nsAutoString valueString
;
1055 AppendValueToString(OrderValueAt(aBorderColor
-1), valueString
);
1056 if (!valueString
.EqualsLiteral("-moz-use-text-color")) {
1057 aString
.AppendLiteral(" ");
1058 aString
.Append(valueString
);
1060 AppendImportanceToString(isImportant
, aString
);
1061 aString
.AppendLiteral("; ");
1068 nsCSSDeclaration::TryFourSidesShorthand(nsAString
& aString
,
1069 nsCSSProperty aShorthand
,
1074 PRBool aClearIndexes
) const
1076 // 0 means not in the mOrder array; otherwise it's index+1
1078 if (aTop
&& aBottom
&& aLeft
&& aRight
&&
1079 AllPropertiesSameImportance(aTop
, aBottom
, aLeft
, aRight
,
1082 // all 4 properties are set, we can output a shorthand
1083 AppendASCIItoUTF16(nsCSSProps::GetStringValue(aShorthand
), aString
);
1084 aString
.AppendLiteral(": ");
1085 nsCSSValue topValue
, bottomValue
, leftValue
, rightValue
;
1086 nsCSSProperty topProp
= OrderValueAt(aTop
-1);
1087 nsCSSProperty bottomProp
= OrderValueAt(aBottom
-1);
1088 nsCSSProperty leftProp
= OrderValueAt(aLeft
-1);
1089 nsCSSProperty rightProp
= OrderValueAt(aRight
-1);
1090 GetValueOrImportantValue(topProp
, topValue
);
1091 GetValueOrImportantValue(bottomProp
, bottomValue
);
1092 GetValueOrImportantValue(leftProp
, leftValue
);
1093 GetValueOrImportantValue(rightProp
, rightValue
);
1094 AppendCSSValueToString(topProp
, topValue
, aString
);
1095 if (topValue
!= rightValue
|| topValue
!= leftValue
|| topValue
!= bottomValue
) {
1096 aString
.Append(PRUnichar(' '));
1097 AppendCSSValueToString(rightProp
, rightValue
, aString
);
1098 if (topValue
!= bottomValue
|| rightValue
!= leftValue
) {
1099 aString
.Append(PRUnichar(' '));
1100 AppendCSSValueToString(bottomProp
, bottomValue
, aString
);
1101 if (rightValue
!= leftValue
) {
1102 aString
.Append(PRUnichar(' '));
1103 AppendCSSValueToString(leftProp
, leftValue
, aString
);
1107 if (aClearIndexes
) {
1108 aTop
= 0; aBottom
= 0; aLeft
= 0; aRight
= 0;
1110 AppendImportanceToString(isImportant
, aString
);
1111 aString
.AppendLiteral("; ");
1118 nsCSSDeclaration::TryBackgroundShorthand(nsAString
& aString
,
1121 PRInt32
& aBgRepeat
,
1122 PRInt32
& aBgAttachment
,
1123 PRInt32
& aBgPosition
) const
1125 // 0 means not in the mOrder array; otherwise it's index+1
1126 // check if we have at least two properties set; otherwise, no need to
1129 if (aBgColor
&& aBgImage
&& aBgRepeat
&& aBgAttachment
&& aBgPosition
&&
1130 AllPropertiesSameImportance(aBgColor
, aBgImage
, aBgRepeat
, aBgAttachment
,
1131 aBgPosition
, isImportant
)) {
1132 AppendASCIItoUTF16(nsCSSProps::GetStringValue(eCSSProperty_background
), aString
);
1133 aString
.AppendLiteral(": ");
1135 AppendValueToString(eCSSProperty_background_color
, aString
);
1138 aString
.Append(PRUnichar(' '));
1139 AppendValueToString(eCSSProperty_background_image
, aString
);
1142 aString
.Append(PRUnichar(' '));
1143 AppendValueToString(eCSSProperty_background_repeat
, aString
);
1146 aString
.Append(PRUnichar(' '));
1147 AppendValueToString(eCSSProperty_background_attachment
, aString
);
1150 aString
.Append(PRUnichar(' '));
1151 AppendValueToString(eCSSProperty_background_position
, aString
);
1154 AppendImportanceToString(isImportant
, aString
);
1155 aString
.AppendLiteral("; ");
1160 nsCSSDeclaration::TryOverflowShorthand(nsAString
& aString
,
1161 PRInt32
& aOverflowX
,
1162 PRInt32
& aOverflowY
) const
1165 if (aOverflowX
&& aOverflowY
&&
1166 AllPropertiesSameImportance(aOverflowX
, aOverflowY
,
1167 0, 0, 0, isImportant
)) {
1168 nsCSSValue xValue
, yValue
;
1169 GetValueOrImportantValue(eCSSProperty_overflow_x
, xValue
);
1170 GetValueOrImportantValue(eCSSProperty_overflow_y
, yValue
);
1171 if (xValue
== yValue
) {
1172 AppendASCIItoUTF16(nsCSSProps::GetStringValue(eCSSProperty_overflow
),
1174 aString
.AppendLiteral(": ");
1176 AppendCSSValueToString(eCSSProperty_overflow_x
, xValue
, aString
);
1177 AppendImportanceToString(isImportant
, aString
);
1178 aString
.AppendLiteral("; ");
1179 aOverflowX
= aOverflowY
= 0;
1186 nsCSSDeclaration::TryMarkerShorthand(nsAString
& aString
,
1187 PRInt32
& aMarkerEnd
,
1188 PRInt32
& aMarkerMid
,
1189 PRInt32
& aMarkerStart
) const
1192 if (aMarkerEnd
&& aMarkerMid
&& aMarkerEnd
&&
1193 AllPropertiesSameImportance(aMarkerEnd
, aMarkerMid
, aMarkerStart
,
1194 0, 0, isImportant
)) {
1195 nsCSSValue endValue
, midValue
, startValue
;
1196 GetValueOrImportantValue(eCSSProperty_marker_end
, endValue
);
1197 GetValueOrImportantValue(eCSSProperty_marker_mid
, midValue
);
1198 GetValueOrImportantValue(eCSSProperty_marker_start
, startValue
);
1199 if (endValue
== midValue
&& midValue
== startValue
) {
1200 AppendASCIItoUTF16(nsCSSProps::GetStringValue(eCSSProperty_marker
),
1202 aString
.AppendLiteral(": ");
1204 AppendCSSValueToString(eCSSProperty_marker_end
, endValue
, aString
);
1205 AppendImportanceToString(isImportant
, aString
);
1206 aString
.AppendLiteral("; ");
1207 aMarkerEnd
= aMarkerMid
= aMarkerStart
= 0;
1213 #define NS_CASE_OUTPUT_PROPERTY_VALUE(_prop, _index) \
1216 AppendPropertyAndValueToString(property, aString); \
1221 #define NS_CASE_OUTPUT_PROPERTY_VALUE_AS(_prop, _propas, _index) \
1224 AppendPropertyAndValueToString(property, _propas, aString); \
1229 #define NS_CASE_CONDITIONAL_OUTPUT_PROPERTY_VALUE(_condition, _prop, _index) \
1231 if ((_condition) && _index) { \
1232 AppendPropertyAndValueToString(property, aString); \
1237 #define NS_CASE_CONDITIONAL_OUTPUT_PROPERTY_VALUE_AS(_condition, _prop, _propas, _index) \
1239 if ((_condition) && _index) { \
1240 AppendPropertyAndValueToString(property, _propas, aString); \
1245 void nsCSSDeclaration::PropertyIsSet(PRInt32
& aPropertyIndex
, PRInt32 aIndex
, PRUint32
& aSet
, PRUint32 aValue
) const
1247 aPropertyIndex
= aIndex
+ 1;
1252 nsCSSDeclaration::ToString(nsAString
& aString
) const
1254 PRInt32 count
= mOrder
.Length();
1256 // 0 means not in the mOrder array; otherwise it's index+1
1257 PRInt32 borderTopWidth
= 0, borderTopStyle
= 0, borderTopColor
= 0;
1258 PRInt32 borderBottomWidth
= 0, borderBottomStyle
= 0, borderBottomColor
= 0;
1259 PRInt32 borderLeftWidth
= 0, borderLeftStyle
= 0, borderLeftColor
= 0;
1260 PRInt32 borderRightWidth
= 0, borderRightStyle
= 0, borderRightColor
= 0;
1261 PRInt32 borderStartWidth
= 0, borderStartStyle
= 0, borderStartColor
= 0;
1262 PRInt32 borderEndWidth
= 0, borderEndStyle
= 0, borderEndColor
= 0;
1263 PRInt32 marginTop
= 0, marginBottom
= 0, marginLeft
= 0, marginRight
= 0;
1264 PRInt32 paddingTop
= 0, paddingBottom
= 0, paddingLeft
= 0, paddingRight
= 0;
1265 PRInt32 bgColor
= 0, bgImage
= 0, bgRepeat
= 0, bgAttachment
= 0;
1266 PRInt32 bgPosition
= 0;
1267 PRInt32 overflowX
= 0, overflowY
= 0;
1268 PRInt32 columnRuleWidth
= 0, columnRuleStyle
= 0, columnRuleColor
= 0;
1269 PRUint32 borderPropertiesSet
= 0, finalBorderPropertiesToSet
= 0;
1271 PRInt32 markerEnd
= 0, markerMid
= 0, markerStart
= 0;
1274 for (index
= 0; index
< count
; index
++) {
1275 nsCSSProperty property
= OrderValueAt(index
);
1277 case eCSSProperty_border_top_width
:
1278 PropertyIsSet(borderTopWidth
, index
, borderPropertiesSet
, B_BORDER_TOP_WIDTH
);
1280 case eCSSProperty_border_bottom_width
:
1281 PropertyIsSet(borderBottomWidth
, index
, borderPropertiesSet
, B_BORDER_BOTTOM_WIDTH
);
1283 case eCSSProperty_border_left_width_value
:
1284 PropertyIsSet(borderLeftWidth
, index
, borderPropertiesSet
, B_BORDER_LEFT_WIDTH
);
1286 case eCSSProperty_border_right_width_value
:
1287 PropertyIsSet(borderRightWidth
, index
, borderPropertiesSet
, B_BORDER_RIGHT_WIDTH
);
1289 case eCSSProperty_border_start_width_value
:
1290 borderStartWidth
= index
+1;
1292 case eCSSProperty_border_end_width_value
:
1293 borderEndWidth
= index
+1;
1296 case eCSSProperty_border_top_style
:
1297 PropertyIsSet(borderTopStyle
, index
, borderPropertiesSet
, B_BORDER_TOP_STYLE
);
1299 case eCSSProperty_border_bottom_style
:
1300 PropertyIsSet(borderBottomStyle
, index
, borderPropertiesSet
, B_BORDER_BOTTOM_STYLE
);
1302 case eCSSProperty_border_left_style_value
:
1303 PropertyIsSet(borderLeftStyle
, index
, borderPropertiesSet
, B_BORDER_LEFT_STYLE
);
1305 case eCSSProperty_border_right_style_value
:
1306 PropertyIsSet(borderRightStyle
, index
, borderPropertiesSet
, B_BORDER_RIGHT_STYLE
);
1308 case eCSSProperty_border_start_style_value
:
1309 borderStartStyle
= index
+1;
1311 case eCSSProperty_border_end_style_value
:
1312 borderEndStyle
= index
+1;
1315 case eCSSProperty_border_top_color
:
1316 PropertyIsSet(borderTopColor
, index
, borderPropertiesSet
, B_BORDER_TOP_COLOR
);
1318 case eCSSProperty_border_bottom_color
:
1319 PropertyIsSet(borderBottomColor
, index
, borderPropertiesSet
, B_BORDER_BOTTOM_COLOR
);
1321 case eCSSProperty_border_left_color_value
:
1322 PropertyIsSet(borderLeftColor
, index
, borderPropertiesSet
, B_BORDER_LEFT_COLOR
);
1324 case eCSSProperty_border_right_color_value
:
1325 PropertyIsSet(borderRightColor
, index
, borderPropertiesSet
, B_BORDER_RIGHT_COLOR
);
1327 case eCSSProperty_border_start_color_value
:
1328 borderStartColor
= index
+1;
1330 case eCSSProperty_border_end_color_value
:
1331 borderEndColor
= index
+1;
1334 case eCSSProperty_margin_top
: marginTop
= index
+1; break;
1335 case eCSSProperty_margin_bottom
: marginBottom
= index
+1; break;
1336 case eCSSProperty_margin_left_value
: marginLeft
= index
+1; break;
1337 case eCSSProperty_margin_right_value
: marginRight
= index
+1; break;
1339 case eCSSProperty_padding_top
: paddingTop
= index
+1; break;
1340 case eCSSProperty_padding_bottom
: paddingBottom
= index
+1; break;
1341 case eCSSProperty_padding_left_value
: paddingLeft
= index
+1; break;
1342 case eCSSProperty_padding_right_value
: paddingRight
= index
+1; break;
1344 case eCSSProperty_background_color
: bgColor
= index
+1; break;
1345 case eCSSProperty_background_image
: bgImage
= index
+1; break;
1346 case eCSSProperty_background_repeat
: bgRepeat
= index
+1; break;
1347 case eCSSProperty_background_attachment
: bgAttachment
= index
+1; break;
1348 case eCSSProperty_background_position
: bgPosition
= index
+1; break;
1350 case eCSSProperty_overflow_x
: overflowX
= index
+1; break;
1351 case eCSSProperty_overflow_y
: overflowY
= index
+1; break;
1353 case eCSSProperty__moz_column_rule_width
: columnRuleWidth
= index
+1; break;
1354 case eCSSProperty__moz_column_rule_style
: columnRuleStyle
= index
+1; break;
1355 case eCSSProperty__moz_column_rule_color
: columnRuleColor
= index
+1; break;
1358 case eCSSProperty_marker_end
: markerEnd
= index
+1; break;
1359 case eCSSProperty_marker_mid
: markerMid
= index
+1; break;
1360 case eCSSProperty_marker_start
: markerStart
= index
+1; break;
1367 if (!TryBorderShorthand(aString
, borderPropertiesSet
,
1368 borderTopWidth
, borderTopStyle
, borderTopColor
,
1369 borderBottomWidth
, borderBottomStyle
, borderBottomColor
,
1370 borderLeftWidth
, borderLeftStyle
, borderLeftColor
,
1371 borderRightWidth
, borderRightStyle
, borderRightColor
)) {
1372 PRUint32 borderPropertiesToSet
= 0;
1373 if ((borderPropertiesSet
& B_BORDER_STYLE
) != B_BORDER_STYLE
||
1374 !TryFourSidesShorthand(aString
, eCSSProperty_border_style
,
1375 borderTopStyle
, borderBottomStyle
,
1376 borderLeftStyle
, borderRightStyle
,
1378 borderPropertiesToSet
|= B_BORDER_STYLE
;
1380 if ((borderPropertiesSet
& B_BORDER_COLOR
) != B_BORDER_COLOR
||
1381 !TryFourSidesShorthand(aString
, eCSSProperty_border_color
,
1382 borderTopColor
, borderBottomColor
,
1383 borderLeftColor
, borderRightColor
,
1385 borderPropertiesToSet
|= B_BORDER_COLOR
;
1387 if ((borderPropertiesSet
& B_BORDER_WIDTH
) != B_BORDER_WIDTH
||
1388 !TryFourSidesShorthand(aString
, eCSSProperty_border_width
,
1389 borderTopWidth
, borderBottomWidth
,
1390 borderLeftWidth
, borderRightWidth
,
1392 borderPropertiesToSet
|= B_BORDER_WIDTH
;
1394 borderPropertiesToSet
&= borderPropertiesSet
;
1395 if (borderPropertiesToSet
) {
1396 if ((borderPropertiesSet
& B_BORDER_TOP
) != B_BORDER_TOP
||
1397 !TryBorderSideShorthand(aString
, eCSSProperty_border_top
,
1398 borderTopWidth
, borderTopStyle
, borderTopColor
)) {
1399 finalBorderPropertiesToSet
|= B_BORDER_TOP
;
1401 if ((borderPropertiesSet
& B_BORDER_LEFT
) != B_BORDER_LEFT
||
1402 !TryBorderSideShorthand(aString
, eCSSProperty_border_left
,
1403 borderLeftWidth
, borderLeftStyle
, borderLeftColor
)) {
1404 finalBorderPropertiesToSet
|= B_BORDER_LEFT
;
1406 if ((borderPropertiesSet
& B_BORDER_RIGHT
) != B_BORDER_RIGHT
||
1407 !TryBorderSideShorthand(aString
, eCSSProperty_border_right
,
1408 borderRightWidth
, borderRightStyle
, borderRightColor
)) {
1409 finalBorderPropertiesToSet
|= B_BORDER_RIGHT
;
1411 if ((borderPropertiesSet
& B_BORDER_BOTTOM
) != B_BORDER_BOTTOM
||
1412 !TryBorderSideShorthand(aString
, eCSSProperty_border_bottom
,
1413 borderBottomWidth
, borderBottomStyle
, borderBottomColor
)) {
1414 finalBorderPropertiesToSet
|= B_BORDER_BOTTOM
;
1416 finalBorderPropertiesToSet
&= borderPropertiesToSet
;
1420 TryFourSidesShorthand(aString
, eCSSProperty_margin
,
1421 marginTop
, marginBottom
,
1422 marginLeft
, marginRight
,
1424 TryFourSidesShorthand(aString
, eCSSProperty_padding
,
1425 paddingTop
, paddingBottom
,
1426 paddingLeft
, paddingRight
,
1428 TryBackgroundShorthand(aString
,
1429 bgColor
, bgImage
, bgRepeat
, bgAttachment
,
1431 TryOverflowShorthand(aString
, overflowX
, overflowY
);
1433 TryMarkerShorthand(aString
, markerEnd
, markerMid
, markerStart
);
1436 if (columnRuleColor
&& columnRuleStyle
&& columnRuleWidth
) {
1437 TryBorderSideShorthand(aString
, eCSSProperty__moz_column_rule
,
1438 columnRuleWidth
, columnRuleStyle
, columnRuleColor
);
1439 columnRuleWidth
= columnRuleStyle
= columnRuleColor
= 0;
1442 // FIXME The order of the declarations should depend on the *-source
1444 if (borderStartWidth
&& borderStartStyle
&& borderStartColor
&&
1445 TryBorderSideShorthand(aString
, eCSSProperty_border_start
,
1446 borderStartWidth
, borderStartStyle
, borderStartColor
))
1447 borderStartWidth
= borderStartStyle
= borderStartColor
= 0;
1448 if (borderEndWidth
&& borderEndStyle
&& borderEndColor
&&
1449 TryBorderSideShorthand(aString
, eCSSProperty_border_end
,
1450 borderEndWidth
, borderEndStyle
, borderEndColor
))
1451 borderEndWidth
= borderEndStyle
= borderEndColor
= 0;
1453 for (index
= 0; index
< count
; index
++) {
1454 nsCSSProperty property
= OrderValueAt(index
);
1457 NS_CASE_CONDITIONAL_OUTPUT_PROPERTY_VALUE(finalBorderPropertiesToSet
& B_BORDER_TOP_STYLE
,
1458 eCSSProperty_border_top_style
, borderTopStyle
)
1459 NS_CASE_CONDITIONAL_OUTPUT_PROPERTY_VALUE_AS(finalBorderPropertiesToSet
& B_BORDER_LEFT_STYLE
,
1460 eCSSProperty_border_left_style_value
,
1461 eCSSProperty_border_left_style
, borderLeftStyle
)
1462 NS_CASE_CONDITIONAL_OUTPUT_PROPERTY_VALUE_AS(finalBorderPropertiesToSet
& B_BORDER_RIGHT_STYLE
,
1463 eCSSProperty_border_right_style_value
,
1464 eCSSProperty_border_right_style
, borderRightStyle
)
1465 NS_CASE_CONDITIONAL_OUTPUT_PROPERTY_VALUE(finalBorderPropertiesToSet
& B_BORDER_BOTTOM_STYLE
,
1466 eCSSProperty_border_bottom_style
, borderBottomStyle
)
1467 NS_CASE_OUTPUT_PROPERTY_VALUE_AS(eCSSProperty_border_start_style_value
,
1468 eCSSProperty_border_start_style
, borderStartStyle
)
1469 NS_CASE_OUTPUT_PROPERTY_VALUE_AS(eCSSProperty_border_end_style_value
,
1470 eCSSProperty_border_end_style
, borderEndStyle
)
1472 NS_CASE_CONDITIONAL_OUTPUT_PROPERTY_VALUE(finalBorderPropertiesToSet
& B_BORDER_TOP_COLOR
,
1473 eCSSProperty_border_top_color
, borderTopColor
)
1474 NS_CASE_CONDITIONAL_OUTPUT_PROPERTY_VALUE_AS(finalBorderPropertiesToSet
& B_BORDER_LEFT_COLOR
,
1475 eCSSProperty_border_left_color_value
,
1476 eCSSProperty_border_left_color
, borderLeftColor
)
1477 NS_CASE_CONDITIONAL_OUTPUT_PROPERTY_VALUE_AS(finalBorderPropertiesToSet
& B_BORDER_RIGHT_COLOR
,
1478 eCSSProperty_border_right_color_value
,
1479 eCSSProperty_border_right_color
, borderRightColor
)
1480 NS_CASE_CONDITIONAL_OUTPUT_PROPERTY_VALUE(finalBorderPropertiesToSet
& B_BORDER_BOTTOM_COLOR
,
1481 eCSSProperty_border_bottom_color
, borderBottomColor
)
1482 NS_CASE_OUTPUT_PROPERTY_VALUE_AS(eCSSProperty_border_start_color_value
,
1483 eCSSProperty_border_start_color
, borderStartColor
)
1484 NS_CASE_OUTPUT_PROPERTY_VALUE_AS(eCSSProperty_border_end_color_value
,
1485 eCSSProperty_border_end_color
, borderEndColor
)
1487 NS_CASE_CONDITIONAL_OUTPUT_PROPERTY_VALUE(finalBorderPropertiesToSet
& B_BORDER_TOP_WIDTH
,
1488 eCSSProperty_border_top_width
, borderTopWidth
)
1489 NS_CASE_CONDITIONAL_OUTPUT_PROPERTY_VALUE_AS(finalBorderPropertiesToSet
& B_BORDER_LEFT_WIDTH
,
1490 eCSSProperty_border_left_width_value
,
1491 eCSSProperty_border_left_width
, borderLeftWidth
)
1492 NS_CASE_CONDITIONAL_OUTPUT_PROPERTY_VALUE_AS(finalBorderPropertiesToSet
& B_BORDER_RIGHT_WIDTH
,
1493 eCSSProperty_border_right_width_value
,
1494 eCSSProperty_border_right_width
, borderRightWidth
)
1495 NS_CASE_CONDITIONAL_OUTPUT_PROPERTY_VALUE(finalBorderPropertiesToSet
& B_BORDER_BOTTOM_WIDTH
,
1496 eCSSProperty_border_bottom_width
, borderBottomWidth
)
1497 NS_CASE_OUTPUT_PROPERTY_VALUE_AS(eCSSProperty_border_start_width_value
,
1498 eCSSProperty_border_start_width
, borderStartWidth
)
1499 NS_CASE_OUTPUT_PROPERTY_VALUE_AS(eCSSProperty_border_end_width_value
,
1500 eCSSProperty_border_end_width
, borderEndWidth
)
1502 NS_CASE_OUTPUT_PROPERTY_VALUE(eCSSProperty_margin_top
, marginTop
)
1503 NS_CASE_OUTPUT_PROPERTY_VALUE(eCSSProperty_margin_bottom
, marginBottom
)
1504 NS_CASE_OUTPUT_PROPERTY_VALUE_AS(eCSSProperty_margin_left_value
,
1505 eCSSProperty_margin_left
, marginLeft
)
1506 NS_CASE_OUTPUT_PROPERTY_VALUE_AS(eCSSProperty_margin_right_value
,
1507 eCSSProperty_margin_right
, marginRight
)
1509 NS_CASE_OUTPUT_PROPERTY_VALUE(eCSSProperty_padding_top
, paddingTop
)
1510 NS_CASE_OUTPUT_PROPERTY_VALUE(eCSSProperty_padding_bottom
, paddingBottom
)
1511 NS_CASE_OUTPUT_PROPERTY_VALUE_AS(eCSSProperty_padding_left_value
,
1512 eCSSProperty_padding_left
, paddingLeft
)
1513 NS_CASE_OUTPUT_PROPERTY_VALUE_AS(eCSSProperty_padding_right_value
,
1514 eCSSProperty_padding_right
, paddingRight
)
1516 NS_CASE_OUTPUT_PROPERTY_VALUE(eCSSProperty_background_color
, bgColor
)
1517 NS_CASE_OUTPUT_PROPERTY_VALUE(eCSSProperty_background_image
, bgImage
)
1518 NS_CASE_OUTPUT_PROPERTY_VALUE(eCSSProperty_background_repeat
, bgRepeat
)
1519 NS_CASE_OUTPUT_PROPERTY_VALUE(eCSSProperty_background_attachment
, bgAttachment
)
1520 NS_CASE_OUTPUT_PROPERTY_VALUE(eCSSProperty_background_position
, bgPosition
)
1522 NS_CASE_OUTPUT_PROPERTY_VALUE(eCSSProperty_overflow_x
, overflowX
)
1523 NS_CASE_OUTPUT_PROPERTY_VALUE(eCSSProperty_overflow_y
, overflowY
)
1526 NS_CASE_OUTPUT_PROPERTY_VALUE(eCSSProperty_marker_end
, markerEnd
)
1527 NS_CASE_OUTPUT_PROPERTY_VALUE(eCSSProperty_marker_mid
, markerMid
)
1528 NS_CASE_OUTPUT_PROPERTY_VALUE(eCSSProperty_marker_start
, markerStart
)
1531 NS_CASE_OUTPUT_PROPERTY_VALUE(eCSSProperty__moz_column_rule_width
, columnRuleWidth
)
1532 NS_CASE_OUTPUT_PROPERTY_VALUE(eCSSProperty__moz_column_rule_style
, columnRuleStyle
)
1533 NS_CASE_OUTPUT_PROPERTY_VALUE(eCSSProperty__moz_column_rule_color
, columnRuleColor
)
1535 case eCSSProperty_margin_left_ltr_source
:
1536 case eCSSProperty_margin_left_rtl_source
:
1537 case eCSSProperty_margin_right_ltr_source
:
1538 case eCSSProperty_margin_right_rtl_source
:
1539 case eCSSProperty_padding_left_ltr_source
:
1540 case eCSSProperty_padding_left_rtl_source
:
1541 case eCSSProperty_padding_right_ltr_source
:
1542 case eCSSProperty_padding_right_rtl_source
:
1543 case eCSSProperty_border_left_color_ltr_source
:
1544 case eCSSProperty_border_left_color_rtl_source
:
1545 case eCSSProperty_border_left_style_ltr_source
:
1546 case eCSSProperty_border_left_style_rtl_source
:
1547 case eCSSProperty_border_left_width_ltr_source
:
1548 case eCSSProperty_border_left_width_rtl_source
:
1549 case eCSSProperty_border_right_color_ltr_source
:
1550 case eCSSProperty_border_right_color_rtl_source
:
1551 case eCSSProperty_border_right_style_ltr_source
:
1552 case eCSSProperty_border_right_style_rtl_source
:
1553 case eCSSProperty_border_right_width_ltr_source
:
1554 case eCSSProperty_border_right_width_rtl_source
:
1557 case eCSSProperty_margin_start_value
:
1558 AppendPropertyAndValueToString(property
, eCSSProperty_margin_start
,
1561 case eCSSProperty_margin_end_value
:
1562 AppendPropertyAndValueToString(property
, eCSSProperty_margin_end
,
1565 case eCSSProperty_padding_start_value
:
1566 AppendPropertyAndValueToString(property
, eCSSProperty_padding_start
,
1569 case eCSSProperty_padding_end_value
:
1570 AppendPropertyAndValueToString(property
, eCSSProperty_padding_end
,
1575 if (0 <= property
) {
1576 AppendPropertyAndValueToString(property
, aString
);
1581 if (! aString
.IsEmpty()) {
1582 // if the string is not empty, we have a trailing whitespace we should remove
1583 aString
.Truncate(aString
.Length() - 1);
1589 void nsCSSDeclaration::List(FILE* out
, PRInt32 aIndent
) const
1591 for (PRInt32 index
= aIndent
; --index
>= 0; ) fputs(" ", out
);
1596 fputs(NS_ConvertUTF16toUTF8(s
).get(), out
);
1602 nsCSSDeclaration::GetNthProperty(PRUint32 aIndex
, nsAString
& aReturn
) const
1605 if (aIndex
< mOrder
.Length()) {
1606 nsCSSProperty property
= OrderValueAt(aIndex
);
1607 if (0 <= property
) {
1608 AppendASCIItoUTF16(nsCSSProps::GetStringValue(property
), aReturn
);
1616 nsCSSDeclaration::Clone() const
1618 return new nsCSSDeclaration(*this);
1622 nsCSSDeclaration::InitializeEmpty()
1624 NS_ASSERTION(!mData
&& !mImportantData
, "already initialized");
1625 mData
= nsCSSCompressedDataBlock::CreateEmptyBlock();
1626 return mData
!= nsnull
;