Back to index

lightning-sunbird  0.9+nobinonly
nsCSSDeclaration.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Daniel Glazman <glazman@netscape.com>
00024  *   Mats Palmgren <mats.palmgren@bredband.net>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either of the GNU General Public License Version 2 or later (the "GPL"),
00028  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 #include "nscore.h"
00040 #include "nsCSSDeclaration.h"
00041 #include "nsString.h"
00042 #include "nsIAtom.h"
00043 #include "nsUnicharUtils.h"
00044 #include "nsReadableUtils.h"
00045 #include "nsCRT.h"
00046 #include "nsCSSProps.h"
00047 #include "nsUnitConversion.h"
00048 #include "nsVoidArray.h"
00049 #include "nsFont.h"
00050 #include "nsReadableUtils.h"
00051 
00052 #include "nsStyleConsts.h"
00053 
00054 #include "nsCOMPtr.h"
00055 
00056 #define B_BORDER_TOP_STYLE    0x001
00057 #define B_BORDER_LEFT_STYLE   0x002
00058 #define B_BORDER_RIGHT_STYLE  0x004
00059 #define B_BORDER_BOTTOM_STYLE 0x008
00060 #define B_BORDER_TOP_COLOR    0x010
00061 #define B_BORDER_LEFT_COLOR   0x020
00062 #define B_BORDER_RIGHT_COLOR  0x040
00063 #define B_BORDER_BOTTOM_COLOR 0x080
00064 #define B_BORDER_TOP_WIDTH    0x100
00065 #define B_BORDER_LEFT_WIDTH   0x200
00066 #define B_BORDER_RIGHT_WIDTH  0x400
00067 #define B_BORDER_BOTTOM_WIDTH 0x800
00068 
00069 #define B_BORDER_STYLE        0x00f
00070 #define B_BORDER_COLOR        0x0f0
00071 #define B_BORDER_WIDTH        0xf00
00072 
00073 #define B_BORDER_TOP          0x111
00074 #define B_BORDER_LEFT         0x222
00075 #define B_BORDER_RIGHT        0x444
00076 #define B_BORDER_BOTTOM       0x888
00077 
00078 #define B_BORDER              0xfff
00079 
00080 MOZ_DECL_CTOR_COUNTER(nsCSSDeclaration)
00081 
00082 nsCSSDeclaration::nsCSSDeclaration() 
00083   : mOrder(eCSSProperty_COUNT_no_shorthands, 8),
00084     mData(nsnull),
00085     mImportantData(nsnull)
00086 {
00087   MOZ_COUNT_CTOR(nsCSSDeclaration);
00088 }
00089 
00090 nsCSSDeclaration::nsCSSDeclaration(const nsCSSDeclaration& aCopy)
00091   : mOrder(eCSSProperty_COUNT_no_shorthands, aCopy.mOrder.Count()),
00092     mData(aCopy.mData ? aCopy.mData->Clone() : nsnull),
00093     mImportantData(aCopy.mImportantData ? aCopy.mImportantData->Clone()
00094                                          : nsnull)
00095 {
00096   MOZ_COUNT_CTOR(nsCSSDeclaration);
00097   mOrder = aCopy.mOrder;
00098 }
00099 
00100 nsCSSDeclaration::~nsCSSDeclaration(void)
00101 {
00102   if (mData) {
00103     mData->Destroy();
00104   }
00105   if (mImportantData) {
00106     mImportantData->Destroy();
00107   }
00108 
00109   MOZ_COUNT_DTOR(nsCSSDeclaration);
00110 }
00111 
00112 nsresult
00113 nsCSSDeclaration::ValueAppended(nsCSSProperty aProperty)
00114 {
00115   // order IS important for CSS, so remove and add to the end
00116   if (nsCSSProps::IsShorthand(aProperty)) {
00117     CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p, aProperty) {
00118       mOrder.RemoveValue(*p);
00119       mOrder.AppendValue(*p);
00120     }
00121   } else {
00122     mOrder.RemoveValue(aProperty);
00123     mOrder.AppendValue(aProperty);
00124   }
00125   return NS_OK;
00126 }
00127 
00128 nsresult
00129 nsCSSDeclaration::RemoveProperty(nsCSSProperty aProperty)
00130 {
00131   nsCSSExpandedDataBlock data;
00132   data.Expand(&mData, &mImportantData);
00133   NS_ASSERTION(!mData && !mImportantData, "Expand didn't null things out");
00134 
00135   if (nsCSSProps::IsShorthand(aProperty)) {
00136     CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p, aProperty) {
00137       data.ClearProperty(*p);
00138       mOrder.RemoveValue(*p);
00139     }
00140   } else {
00141     data.ClearProperty(aProperty);
00142     mOrder.RemoveValue(aProperty);
00143   }
00144 
00145   data.Compress(&mData, &mImportantData);
00146   return NS_OK;
00147 }
00148 
00149 nsresult
00150 nsCSSDeclaration::AppendComment(const nsAString& aComment)
00151 {
00152   return /* NS_ERROR_NOT_IMPLEMENTED, or not any longer that is */ NS_OK;
00153 }
00154 
00155 nsresult
00156 nsCSSDeclaration::GetValueOrImportantValue(nsCSSProperty aProperty, nsCSSValue& aValue) const
00157 {
00158   aValue.Reset();
00159 
00160   NS_ASSERTION(aProperty >= 0, "out of range");
00161   if (aProperty >= eCSSProperty_COUNT_no_shorthands ||
00162       nsCSSProps::kTypeTable[aProperty] != eCSSType_Value) {
00163     NS_ERROR("can't query for shorthand properties");
00164     return NS_ERROR_ILLEGAL_VALUE;
00165   }
00166 
00167   nsCSSCompressedDataBlock *data = GetValueIsImportant(aProperty)
00168                                      ? mImportantData : mData;
00169   const void *storage = data->StorageFor(aProperty);
00170   if (!storage)
00171     return NS_OK;
00172   aValue = *NS_STATIC_CAST(const nsCSSValue*, storage);
00173   return NS_OK;
00174 }
00175 
00176 nsresult
00177 nsCSSDeclaration::GetValue(const nsAString& aProperty,
00178                            nsAString& aValue) const
00179 {
00180   nsCSSProperty propID = nsCSSProps::LookupProperty(aProperty);
00181   return GetValue(propID, aValue);
00182 }
00183 
00184 PRBool nsCSSDeclaration::AppendValueToString(nsCSSProperty aProperty, nsAString& aResult) const
00185 {
00186   nsCSSCompressedDataBlock *data = GetValueIsImportant(aProperty)
00187                                       ? mImportantData : mData;
00188   const void *storage = data->StorageFor(aProperty);
00189   if (storage) {
00190     switch (nsCSSProps::kTypeTable[aProperty]) {
00191       case eCSSType_Value: {
00192         const nsCSSValue *val = NS_STATIC_CAST(const nsCSSValue*, storage);
00193         AppendCSSValueToString(aProperty, *val, aResult);
00194       } break;
00195       case eCSSType_Rect: {
00196         const nsCSSRect *rect = NS_STATIC_CAST(const nsCSSRect*, storage);
00197         if (rect->mTop.GetUnit() == eCSSUnit_Inherit ||
00198             rect->mTop.GetUnit() == eCSSUnit_Initial) {
00199           NS_ASSERTION(rect->mRight.GetUnit() == rect->mTop.GetUnit(),
00200                        "Top inherit or initial, right isn't.  Fix the parser!");
00201           NS_ASSERTION(rect->mBottom.GetUnit() == rect->mTop.GetUnit(),
00202                        "Top inherit or initial, bottom isn't.  Fix the parser!");
00203           NS_ASSERTION(rect->mLeft.GetUnit() == rect->mTop.GetUnit(),
00204                        "Top inherit or initial, left isn't.  Fix the parser!");
00205           AppendCSSValueToString(aProperty, rect->mTop, aResult);
00206         } else {
00207           aResult.AppendLiteral("rect(");
00208           AppendCSSValueToString(aProperty, rect->mTop, aResult);
00209           NS_NAMED_LITERAL_STRING(comma, ", ");
00210           aResult.Append(comma);
00211           AppendCSSValueToString(aProperty, rect->mRight, aResult);
00212           aResult.Append(comma);
00213           AppendCSSValueToString(aProperty, rect->mBottom, aResult);
00214           aResult.Append(comma);
00215           AppendCSSValueToString(aProperty, rect->mLeft, aResult);
00216           aResult.Append(PRUnichar(')'));
00217         }
00218       } break;
00219       case eCSSType_ValuePair: {
00220         const nsCSSValuePair *pair = NS_STATIC_CAST(const nsCSSValuePair*, storage);
00221         AppendCSSValueToString(aProperty, pair->mXValue, aResult);
00222         if (pair->mYValue != pair->mXValue) {
00223           // Only output a Y value if it's different from the X value
00224           aResult.Append(PRUnichar(' '));
00225           AppendCSSValueToString(aProperty, pair->mYValue, aResult);
00226         }
00227       } break;
00228       case eCSSType_ValueList: {
00229         const nsCSSValueList* val =
00230             *NS_STATIC_CAST(nsCSSValueList*const*, storage);
00231         do {
00232           AppendCSSValueToString(aProperty, val->mValue, aResult);
00233           val = val->mNext;
00234           if (val) {
00235             if (aProperty == eCSSProperty_cursor
00236 #ifdef MOZ_SVG
00237                 || aProperty == eCSSProperty_stroke_dasharray
00238 #endif
00239                )
00240               aResult.Append(PRUnichar(','));
00241             aResult.Append(PRUnichar(' '));
00242           }
00243         } while (val);
00244       } break;
00245       case eCSSType_CounterData: {
00246         const nsCSSCounterData* counter =
00247             *NS_STATIC_CAST(nsCSSCounterData*const*, storage);
00248         do {
00249           if (AppendCSSValueToString(aProperty, counter->mCounter, aResult)) {
00250             if (counter->mValue.GetUnit() != eCSSUnit_Null) {
00251               aResult.Append(PRUnichar(' '));
00252               AppendCSSValueToString(aProperty, counter->mValue, aResult);
00253             }
00254           }
00255           counter = counter->mNext;
00256           if (counter) {
00257             aResult.Append(PRUnichar(' '));
00258           }
00259         } while (counter);
00260       } break;
00261       case eCSSType_Quotes: {
00262         const nsCSSQuotes* quotes = 
00263             *NS_STATIC_CAST(nsCSSQuotes*const*, storage);
00264         do {
00265           AppendCSSValueToString(aProperty, quotes->mOpen, aResult);
00266           aResult.Append(PRUnichar(' '));
00267           AppendCSSValueToString(aProperty, quotes->mClose, aResult);
00268           quotes = quotes->mNext;
00269           if (quotes) {
00270             aResult.Append(PRUnichar(' '));
00271           }
00272         } while (quotes);
00273       } break;
00274       case eCSSType_Shadow: {
00275         const nsCSSShadow* shadow =
00276             *NS_STATIC_CAST(nsCSSShadow*const*, storage);
00277         if (shadow->mXOffset.IsLengthUnit()) {
00278           while (shadow) {
00279             if (AppendCSSValueToString(eCSSProperty_color, shadow->mColor,
00280                                        aResult))
00281               aResult.Append(PRUnichar(' '));
00282             if (AppendCSSValueToString(aProperty, shadow->mXOffset, aResult)) {
00283               aResult.Append(PRUnichar(' '));
00284               AppendCSSValueToString(aProperty, shadow->mYOffset, aResult);
00285               aResult.Append(PRUnichar(' '));
00286             }
00287             if (AppendCSSValueToString(aProperty, shadow->mRadius, aResult) &&
00288                 shadow->mNext)
00289               aResult.AppendLiteral(", ");
00290             shadow = shadow->mNext;
00291           }
00292         }
00293         else {  // none or inherit
00294           AppendCSSValueToString(aProperty, shadow->mXOffset, aResult);
00295         }
00296       } break;
00297     }
00298   }
00299   return storage != nsnull;
00300 }
00301 
00302 PRBool nsCSSDeclaration::AppendCSSValueToString(nsCSSProperty aProperty, const nsCSSValue& aValue, nsAString& aResult) const
00303 {
00304   nsCSSUnit unit = aValue.GetUnit();
00305 
00306   if (eCSSUnit_Null == unit) {
00307     return PR_FALSE;
00308   }
00309 
00310   if (eCSSUnit_String <= unit && unit <= eCSSUnit_Attr) {
00311     if (unit == eCSSUnit_Attr) {
00312       aResult.AppendLiteral("attr(");
00313     }
00314     nsAutoString  buffer;
00315     aValue.GetStringValue(buffer);
00316     aResult.Append(buffer);
00317   }
00318   else if (eCSSUnit_Array <= unit && unit <= eCSSUnit_Counters) {
00319     switch (unit) {
00320       case eCSSUnit_Counter:  aResult.AppendLiteral("counter(");  break;
00321       case eCSSUnit_Counters: aResult.AppendLiteral("counters("); break;
00322       default: break;
00323     }
00324 
00325     nsCSSValue::Array *array = aValue.GetArrayValue();
00326     PRBool mark = PR_FALSE;
00327     for (PRUint16 i = 0, i_end = array->Count(); i < i_end; ++i) {
00328       if (mark && array->Item(i).GetUnit() != eCSSUnit_Null) {
00329         if (unit == eCSSUnit_Array)
00330           aResult.AppendLiteral(" ");
00331         else
00332           aResult.AppendLiteral(", ");
00333       }
00334       nsCSSProperty prop =
00335         ((eCSSUnit_Counter <= unit && unit <= eCSSUnit_Counters) &&
00336          i == array->Count() - 1)
00337         ? eCSSProperty_list_style_type : aProperty;
00338       if (AppendCSSValueToString(prop, array->Item(i), aResult)) {
00339         mark = PR_TRUE;
00340       }
00341     }
00342   }
00343   else if (eCSSUnit_Integer == unit) {
00344     switch (aProperty) {
00345       case eCSSProperty_color:
00346       case eCSSProperty_background_color:
00347       case eCSSProperty_border_top_color:
00348       case eCSSProperty_border_bottom_color:
00349       case eCSSProperty_border_left_color:
00350       case eCSSProperty_border_right_color:
00351       case eCSSProperty_outline_color: {
00352         // we can lookup the property in the ColorTable and then
00353         // get a string mapping the name
00354         nsCAutoString str;
00355         if (nsCSSProps::GetColorName(aValue.GetIntValue(), str)){
00356           AppendASCIItoUTF16(str, aResult);
00357         } else {
00358           nsAutoString tmpStr;
00359           tmpStr.AppendInt(aValue.GetIntValue(), 10);
00360           aResult.Append(tmpStr);
00361         }
00362       }
00363       break;
00364 
00365       default:
00366         {
00367           nsAutoString tmpStr;
00368           tmpStr.AppendInt(aValue.GetIntValue(), 10);
00369           aResult.Append(tmpStr);
00370         }
00371       break;
00372     }
00373   }
00374   else if (eCSSUnit_Enumerated == unit) {
00375     if (eCSSProperty_text_decoration == aProperty) {
00376       PRInt32 intValue = aValue.GetIntValue();
00377       if (NS_STYLE_TEXT_DECORATION_NONE != intValue) {
00378         PRInt32 mask;
00379         for (mask = NS_STYLE_TEXT_DECORATION_UNDERLINE;
00380              mask <= NS_STYLE_TEXT_DECORATION_BLINK; 
00381              mask <<= 1) {
00382           if ((mask & intValue) == mask) {
00383             AppendASCIItoUTF16(nsCSSProps::LookupPropertyValue(aProperty, mask), aResult);
00384             intValue &= ~mask;
00385             if (0 != intValue) { // more left
00386               aResult.Append(PRUnichar(' '));
00387             }
00388           }
00389         }
00390       }
00391       else {
00392         AppendASCIItoUTF16(nsCSSProps::LookupPropertyValue(aProperty, NS_STYLE_TEXT_DECORATION_NONE), aResult);
00393       }
00394     }
00395     else if (eCSSProperty_azimuth == aProperty) {
00396       PRInt32 intValue = aValue.GetIntValue();
00397       AppendASCIItoUTF16(nsCSSProps::LookupPropertyValue(aProperty, (intValue & ~NS_STYLE_AZIMUTH_BEHIND)), aResult);
00398       if ((NS_STYLE_AZIMUTH_BEHIND & intValue) != 0) {
00399         aResult.Append(PRUnichar(' '));
00400         AppendASCIItoUTF16(nsCSSProps::LookupPropertyValue(aProperty, NS_STYLE_AZIMUTH_BEHIND), aResult);
00401       }
00402     }
00403     else if (eCSSProperty_marks == aProperty) {
00404       PRInt32 intValue = aValue.GetIntValue();
00405       if ((NS_STYLE_PAGE_MARKS_CROP & intValue) != 0) {
00406         AppendASCIItoUTF16(nsCSSProps::LookupPropertyValue(aProperty, NS_STYLE_PAGE_MARKS_CROP), aResult);
00407       }
00408       if ((NS_STYLE_PAGE_MARKS_REGISTER & intValue) != 0) {
00409         if ((NS_STYLE_PAGE_MARKS_CROP & intValue) != 0) {
00410           aResult.Append(PRUnichar(' '));
00411         }
00412         AppendASCIItoUTF16(nsCSSProps::LookupPropertyValue(aProperty, NS_STYLE_PAGE_MARKS_REGISTER), aResult);
00413       }
00414     }
00415     else {
00416       const nsAFlatCString& name = nsCSSProps::LookupPropertyValue(aProperty, aValue.GetIntValue());
00417       AppendASCIItoUTF16(name, aResult);
00418     }
00419   }
00420   else if (eCSSUnit_Color == unit) {
00421     nsAutoString tmpStr;
00422     nscolor color = aValue.GetColorValue();
00423 
00424     aResult.AppendLiteral("rgb(");
00425 
00426     NS_NAMED_LITERAL_STRING(comma, ", ");
00427 
00428     tmpStr.AppendInt(NS_GET_R(color), 10);
00429     aResult.Append(tmpStr + comma);
00430 
00431     tmpStr.Truncate();
00432     tmpStr.AppendInt(NS_GET_G(color), 10);
00433     aResult.Append(tmpStr + comma);
00434 
00435     tmpStr.Truncate();
00436     tmpStr.AppendInt(NS_GET_B(color), 10);
00437     aResult.Append(tmpStr);
00438 
00439     aResult.Append(PRUnichar(')'));
00440   }
00441   else if (eCSSUnit_URL == unit || eCSSUnit_Image == unit) {
00442     aResult.Append(NS_LITERAL_STRING("url(") +
00443                    nsDependentString(aValue.GetOriginalURLValue()) +
00444                    NS_LITERAL_STRING(")"));
00445   }
00446   else if (eCSSUnit_Percent == unit) {
00447     nsAutoString tmpStr;
00448     tmpStr.AppendFloat(aValue.GetPercentValue() * 100.0f);
00449     aResult.Append(tmpStr);
00450   }
00451   else if (eCSSUnit_Percent < unit) {  // length unit
00452     nsAutoString tmpStr;
00453     tmpStr.AppendFloat(aValue.GetFloatValue());
00454     aResult.Append(tmpStr);
00455   }
00456 
00457   switch (unit) {
00458     case eCSSUnit_Null:         break;
00459     case eCSSUnit_Auto:         aResult.AppendLiteral("auto");     break;
00460     case eCSSUnit_Inherit:      aResult.AppendLiteral("inherit");  break;
00461     case eCSSUnit_Initial:      aResult.AppendLiteral("-moz-initial"); break;
00462     case eCSSUnit_None:         aResult.AppendLiteral("none");     break;
00463     case eCSSUnit_Normal:       aResult.AppendLiteral("normal");   break;
00464 
00465     case eCSSUnit_String:       break;
00466     case eCSSUnit_URL:          break;
00467     case eCSSUnit_Image:        break;
00468     case eCSSUnit_Array:        break;
00469     case eCSSUnit_Attr:
00470     case eCSSUnit_Counter:
00471     case eCSSUnit_Counters:     aResult.Append(PRUnichar(')'));    break;
00472     case eCSSUnit_Integer:      break;
00473     case eCSSUnit_Enumerated:   break;
00474     case eCSSUnit_Color:        break;
00475     case eCSSUnit_Percent:      aResult.Append(PRUnichar('%'));    break;
00476     case eCSSUnit_Number:       break;
00477 
00478     case eCSSUnit_Inch:         aResult.AppendLiteral("in");   break;
00479     case eCSSUnit_Foot:         aResult.AppendLiteral("ft");   break;
00480     case eCSSUnit_Mile:         aResult.AppendLiteral("mi");   break;
00481     case eCSSUnit_Millimeter:   aResult.AppendLiteral("mm");   break;
00482     case eCSSUnit_Centimeter:   aResult.AppendLiteral("cm");   break;
00483     case eCSSUnit_Meter:        aResult.AppendLiteral("m");    break;
00484     case eCSSUnit_Kilometer:    aResult.AppendLiteral("km");   break;
00485     case eCSSUnit_Point:        aResult.AppendLiteral("pt");   break;
00486     case eCSSUnit_Pica:         aResult.AppendLiteral("pc");   break;
00487     case eCSSUnit_Didot:        aResult.AppendLiteral("dt");   break;
00488     case eCSSUnit_Cicero:       aResult.AppendLiteral("cc");   break;
00489 
00490     case eCSSUnit_EM:           aResult.AppendLiteral("em");   break;
00491     case eCSSUnit_EN:           aResult.AppendLiteral("en");   break;
00492     case eCSSUnit_XHeight:      aResult.AppendLiteral("ex");   break;
00493     case eCSSUnit_CapHeight:    aResult.AppendLiteral("cap");  break;
00494     case eCSSUnit_Char:         aResult.AppendLiteral("ch");   break;
00495 
00496     case eCSSUnit_Pixel:        aResult.AppendLiteral("px");   break;
00497 
00498     case eCSSUnit_Proportional: aResult.AppendLiteral("*");   break;
00499 
00500     case eCSSUnit_Degree:       aResult.AppendLiteral("deg");  break;
00501     case eCSSUnit_Grad:         aResult.AppendLiteral("grad"); break;
00502     case eCSSUnit_Radian:       aResult.AppendLiteral("rad");  break;
00503 
00504     case eCSSUnit_Hertz:        aResult.AppendLiteral("Hz");   break;
00505     case eCSSUnit_Kilohertz:    aResult.AppendLiteral("kHz");  break;
00506 
00507     case eCSSUnit_Seconds:      aResult.Append(PRUnichar('s'));    break;
00508     case eCSSUnit_Milliseconds: aResult.AppendLiteral("ms");   break;
00509   }
00510 
00511   return PR_TRUE;
00512 }
00513 
00514 nsresult
00515 nsCSSDeclaration::GetValue(nsCSSProperty aProperty,
00516                            nsAString& aValue) const
00517 {
00518   aValue.Truncate(0);
00519 
00520   // simple properties are easy.
00521   if (!nsCSSProps::IsShorthand(aProperty)) {
00522     AppendValueToString(aProperty, aValue);
00523     return NS_OK;
00524   }
00525 
00526   // shorthands
00527   // XXX What about checking the consistency of '!important'?
00528   // XXXldb Can we share shorthand logic with ToString?
00529   switch (aProperty) {
00530     case eCSSProperty_margin: 
00531     case eCSSProperty_padding: 
00532     case eCSSProperty_border_color: 
00533     case eCSSProperty_border_style: 
00534     case eCSSProperty__moz_border_radius: 
00535     case eCSSProperty__moz_outline_radius: 
00536     case eCSSProperty_border_width: {
00537       const nsCSSProperty* subprops =
00538         nsCSSProps::SubpropertyEntryFor(aProperty);
00539       NS_ASSERTION(nsCSSProps::kTypeTable[subprops[0]] == eCSSType_Value &&
00540                    nsCSSProps::kTypeTable[subprops[1]] == eCSSType_Value &&
00541                    nsCSSProps::kTypeTable[subprops[2]] == eCSSType_Value &&
00542                    nsCSSProps::kTypeTable[subprops[3]] == eCSSType_Value,
00543                    "type mismatch");
00544       if (!AppendValueToString(subprops[0], aValue) ||
00545           !(aValue.Append(PRUnichar(' ')),
00546             AppendValueToString(subprops[1], aValue)) ||
00547           !(aValue.Append(PRUnichar(' ')),
00548             AppendValueToString(subprops[2], aValue)) ||
00549           !(aValue.Append(PRUnichar(' ')),
00550             AppendValueToString(subprops[3], aValue))) {
00551         aValue.Truncate();
00552       }
00553       break;
00554     }
00555     case eCSSProperty_border:
00556       // XXX More consistency checking needed before falling through.
00557       aProperty = eCSSProperty_border_top;
00558     case eCSSProperty_border_top:
00559     case eCSSProperty_border_right:
00560     case eCSSProperty_border_bottom:
00561     case eCSSProperty_border_left:
00562     case eCSSProperty_outline: {
00563       const nsCSSProperty* subprops =
00564         nsCSSProps::SubpropertyEntryFor(aProperty);
00565       NS_ASSERTION(nsCSSProps::kTypeTable[subprops[0]] == eCSSType_Value &&
00566                    nsCSSProps::kTypeTable[subprops[1]] == eCSSType_Value &&
00567                    nsCSSProps::kTypeTable[subprops[2]] == eCSSType_Value,
00568                    "type mismatch");
00569       if (!AppendValueToString(subprops[0], aValue) ||
00570           !(aValue.Append(PRUnichar(' ')),
00571             AppendValueToString(subprops[1], aValue)) ||
00572           !(aValue.Append(PRUnichar(' ')),
00573             AppendValueToString(subprops[2], aValue))) {
00574         aValue.Truncate();
00575       }
00576       break;
00577     }
00578     case eCSSProperty_margin_left:
00579     case eCSSProperty_margin_right:
00580     case eCSSProperty_margin_start:
00581     case eCSSProperty_margin_end:
00582     case eCSSProperty_padding_left:
00583     case eCSSProperty_padding_right:
00584     case eCSSProperty_padding_start:
00585     case eCSSProperty_padding_end: {
00586       const nsCSSProperty* subprops =
00587         nsCSSProps::SubpropertyEntryFor(aProperty);
00588       NS_ASSERTION(subprops[3] == eCSSProperty_UNKNOWN,
00589                    "not box property with physical vs. logical cascading");
00590       AppendValueToString(subprops[0], aValue);
00591       break;
00592     }
00593     case eCSSProperty_background: {
00594       if (AppendValueToString(eCSSProperty_background_color, aValue))
00595         aValue.Append(PRUnichar(' '));
00596       if (AppendValueToString(eCSSProperty_background_image, aValue))
00597         aValue.Append(PRUnichar(' '));
00598       if (AppendValueToString(eCSSProperty_background_repeat, aValue))
00599         aValue.Append(PRUnichar(' '));
00600       if (AppendValueToString(eCSSProperty_background_attachment, aValue))
00601         aValue.Append(PRUnichar(' '));
00602       if (AppendValueToString(eCSSProperty_background_x_position, aValue)) {
00603         aValue.Append(PRUnichar(' '));
00604 #ifdef DEBUG
00605         PRBool check =
00606 #endif
00607           AppendValueToString(eCSSProperty_background_y_position, aValue);
00608         NS_ASSERTION(check, "we parsed half of background-position");
00609       }
00610       break;
00611     }
00612     case eCSSProperty_cue: {
00613       if (AppendValueToString(eCSSProperty_cue_after, aValue)) {
00614         aValue.Append(PRUnichar(' '));
00615         if (!AppendValueToString(eCSSProperty_cue_before, aValue))
00616           aValue.Truncate();
00617       }
00618       break;
00619     }
00620     case eCSSProperty_font: {
00621       if (AppendValueToString(eCSSProperty_font_style, aValue))
00622         aValue.Append(PRUnichar(' '));
00623       if (AppendValueToString(eCSSProperty_font_variant, aValue))
00624         aValue.Append(PRUnichar(' '));
00625       if (AppendValueToString(eCSSProperty_font_weight, aValue))
00626         aValue.Append(PRUnichar(' '));
00627       if (AppendValueToString(eCSSProperty_font_size, aValue)) {
00628           nsAutoString tmp;
00629           if (AppendValueToString(eCSSProperty_line_height, tmp)) {
00630             aValue.Append(PRUnichar('/'));
00631             aValue.Append(tmp);
00632           }
00633           aValue.Append(PRUnichar(' '));
00634           if (!AppendValueToString(eCSSProperty_font_family, aValue))
00635             aValue.Truncate();
00636       } else {
00637         aValue.Truncate();
00638       }
00639       break;
00640     }
00641     case eCSSProperty_list_style:
00642       if (AppendValueToString(eCSSProperty_list_style_type, aValue))
00643         aValue.Append(PRUnichar(' '));
00644       if (AppendValueToString(eCSSProperty_list_style_position, aValue))
00645         aValue.Append(PRUnichar(' '));
00646       AppendValueToString(eCSSProperty_list_style_image, aValue);
00647       break;
00648     case eCSSProperty_overflow: {
00649       nsCSSValue xValue, yValue;
00650       GetValueOrImportantValue(eCSSProperty_overflow_x, xValue);
00651       GetValueOrImportantValue(eCSSProperty_overflow_y, yValue);
00652       if (xValue == yValue)
00653         AppendValueToString(eCSSProperty_overflow_x, aValue);
00654       break;
00655     }
00656     case eCSSProperty_pause: {
00657       if (AppendValueToString(eCSSProperty_pause_after, aValue)) {
00658         aValue.Append(PRUnichar(' '));
00659         if (!AppendValueToString(eCSSProperty_pause_before, aValue))
00660           aValue.Truncate();
00661       }
00662       break;
00663     }
00664     case eCSSProperty_background_position: {
00665       if (AppendValueToString(eCSSProperty_background_x_position, aValue)) {
00666         aValue.Append(PRUnichar(' '));
00667 #ifdef DEBUG
00668         PRBool check =
00669 #endif
00670         AppendValueToString(eCSSProperty_background_y_position, aValue);
00671         NS_ASSERTION(check, "we parsed half of background-position");
00672       }
00673       break;
00674     }
00675 #ifdef MOZ_SVG
00676     case eCSSProperty_marker: {
00677       nsCSSValue endValue, midValue, startValue;
00678       GetValueOrImportantValue(eCSSProperty_marker_end, endValue);
00679       GetValueOrImportantValue(eCSSProperty_marker_mid, midValue);
00680       GetValueOrImportantValue(eCSSProperty_marker_start, startValue);
00681       if (endValue == midValue && midValue == startValue)
00682         AppendValueToString(eCSSProperty_marker_end, aValue);
00683       break;
00684     }
00685 #endif
00686     default:
00687       NS_NOTREACHED("no other shorthands");
00688       break;
00689   }
00690   return NS_OK;
00691 }
00692 
00693 PRBool
00694 nsCSSDeclaration::GetValueIsImportant(const nsAString& aProperty) const
00695 {
00696   nsCSSProperty propID = nsCSSProps::LookupProperty(aProperty);
00697   return GetValueIsImportant(propID);
00698 }
00699 
00700 PRBool
00701 nsCSSDeclaration::GetValueIsImportant(nsCSSProperty aProperty) const
00702 {
00703   if (!mImportantData)
00704     return PR_FALSE;
00705 
00706   // Inefficient, but we can assume '!important' is rare.
00707   return mImportantData->StorageFor(aProperty) != nsnull;
00708 }
00709 
00710 PRBool
00711 nsCSSDeclaration::AllPropertiesSameImportance(PRInt32 aFirst, PRInt32 aSecond,
00712                                               PRInt32 aThird, PRInt32 aFourth,
00713                                               PRInt32 aFifth, PRInt32 aSixth,
00714                                               PRBool & aImportance) const
00715 {
00716   aImportance = GetValueIsImportant(OrderValueAt(aFirst-1));
00717   if ((aSecond && aImportance != GetValueIsImportant(OrderValueAt(aSecond-1))) ||
00718       (aThird && aImportance != GetValueIsImportant(OrderValueAt(aThird-1))) ||
00719       (aFourth && aImportance != GetValueIsImportant(OrderValueAt(aFourth-1))) ||
00720       (aFifth && aImportance != GetValueIsImportant(OrderValueAt(aFifth-1))) ||
00721       (aSixth && aImportance != GetValueIsImportant(OrderValueAt(aSixth-1)))) {
00722     return PR_FALSE;
00723   }
00724   return PR_TRUE;
00725 }
00726 
00727 PRBool
00728 nsCSSDeclaration::AllPropertiesSameValue(PRInt32 aFirst, PRInt32 aSecond,
00729                                          PRInt32 aThird, PRInt32 aFourth) const
00730 {
00731   nsCSSValue firstValue, otherValue;
00732   // TryBorderShorthand does the bounds-checking for us; valid values there
00733   // are > 0; 0 is a flag for "not set".  We here are passed the actual
00734   // index, which comes from finding the value in the mOrder property array.
00735   // Of course, re-getting the mOrder value here is pretty silly.
00736   GetValueOrImportantValue(OrderValueAt(aFirst-1), firstValue);
00737   GetValueOrImportantValue(OrderValueAt(aSecond-1), otherValue);
00738   if (firstValue != otherValue) {
00739     return PR_FALSE;
00740   }
00741   GetValueOrImportantValue(OrderValueAt(aThird-1), otherValue);
00742   if (firstValue != otherValue) {
00743     return PR_FALSE;
00744   }
00745   GetValueOrImportantValue(OrderValueAt(aFourth-1), otherValue);
00746   if (firstValue != otherValue) {
00747     return PR_FALSE;
00748   }
00749   return PR_TRUE;
00750 }
00751 
00752 void
00753 nsCSSDeclaration::AppendImportanceToString(PRBool aIsImportant, nsAString& aString) const
00754 {
00755   if (aIsImportant) {
00756    aString.AppendLiteral(" ! important");
00757   }
00758 }
00759 
00760 void
00761 nsCSSDeclaration::AppendPropertyAndValueToString(nsCSSProperty aProperty,
00762                                                  nsCSSProperty aPropertyName,
00763                                                  nsAString& aResult) const
00764 {
00765   NS_ASSERTION(0 <= aProperty && aProperty < eCSSProperty_COUNT_no_shorthands,
00766                "property enum out of range");
00767   AppendASCIItoUTF16(nsCSSProps::GetStringValue(aPropertyName), aResult);
00768   aResult.AppendLiteral(": ");
00769   AppendValueToString(aProperty, aResult);
00770   PRBool  isImportant = GetValueIsImportant(aProperty);
00771   AppendImportanceToString(isImportant, aResult);
00772   aResult.AppendLiteral("; ");
00773 }
00774 
00775 PRBool
00776 nsCSSDeclaration::TryBorderShorthand(nsAString & aString, PRUint32 aPropertiesSet,
00777                                      PRInt32 aBorderTopWidth,
00778                                      PRInt32 aBorderTopStyle,
00779                                      PRInt32 aBorderTopColor,
00780                                      PRInt32 aBorderBottomWidth,
00781                                      PRInt32 aBorderBottomStyle,
00782                                      PRInt32 aBorderBottomColor,
00783                                      PRInt32 aBorderLeftWidth,
00784                                      PRInt32 aBorderLeftStyle,
00785                                      PRInt32 aBorderLeftColor,
00786                                      PRInt32 aBorderRightWidth,
00787                                      PRInt32 aBorderRightStyle,
00788                                      PRInt32 aBorderRightColor) const
00789 {
00790   PRBool border = PR_FALSE, isImportant = PR_FALSE;
00791   // 0 means not in the mOrder array; otherwise it's index+1
00792   if (B_BORDER == aPropertiesSet
00793       && AllPropertiesSameValue(aBorderTopWidth, aBorderBottomWidth,
00794                                 aBorderLeftWidth, aBorderRightWidth)
00795       && AllPropertiesSameValue(aBorderTopStyle, aBorderBottomStyle,
00796                                 aBorderLeftStyle, aBorderRightStyle)
00797       && AllPropertiesSameValue(aBorderTopColor, aBorderBottomColor,
00798                                 aBorderLeftColor, aBorderRightColor)) {
00799     border = PR_TRUE;
00800   }
00801   if (border) {
00802     border = PR_FALSE;
00803     PRBool  isWidthImportant, isStyleImportant, isColorImportant;
00804     if (AllPropertiesSameImportance(aBorderTopWidth, aBorderBottomWidth,
00805                                     aBorderLeftWidth, aBorderRightWidth,
00806                                     0, 0,
00807                                     isWidthImportant) &&
00808         AllPropertiesSameImportance(aBorderTopStyle, aBorderBottomStyle,
00809                                     aBorderLeftStyle, aBorderRightStyle,
00810                                     0, 0,
00811                                     isStyleImportant) &&
00812         AllPropertiesSameImportance(aBorderTopColor, aBorderBottomColor,
00813                                     aBorderLeftColor, aBorderRightColor,
00814                                     0, 0,
00815                                     isColorImportant)) {
00816       if (isWidthImportant == isStyleImportant && isWidthImportant == isColorImportant) {
00817         border = PR_TRUE;
00818         isImportant = isWidthImportant;
00819       }
00820     }
00821   }
00822   if (border) {
00823     AppendASCIItoUTF16(nsCSSProps::GetStringValue(eCSSProperty_border), aString);
00824     aString.AppendLiteral(": ");
00825 
00826     AppendValueToString(eCSSProperty_border_top_width, aString);
00827     aString.Append(PRUnichar(' '));
00828 
00829     AppendValueToString(eCSSProperty_border_top_style, aString);
00830     aString.Append(PRUnichar(' '));
00831 
00832     nsAutoString valueString;
00833     AppendValueToString(eCSSProperty_border_top_color, valueString);
00834     if (!valueString.EqualsLiteral("-moz-use-text-color")) {
00835       /* don't output this value, it's proprietary Mozilla and  */
00836       /* not intended to be exposed ; we can remove it from the */
00837       /* values of the shorthand since this value represents the */
00838       /* initial value of border-*-color */
00839       aString.Append(valueString);
00840     }
00841     AppendImportanceToString(isImportant, aString);
00842     aString.AppendLiteral("; ");
00843   }
00844   return border;
00845 }
00846 
00847 PRBool
00848 nsCSSDeclaration::TryBorderSideShorthand(nsAString & aString,
00849                                          nsCSSProperty aShorthand,
00850                                          PRInt32 aBorderWidth,
00851                                          PRInt32 aBorderStyle,
00852                                          PRInt32 aBorderColor) const
00853 {
00854   PRBool isImportant;
00855   if (AllPropertiesSameImportance(aBorderWidth, aBorderStyle, aBorderColor,
00856                                   0, 0, 0,
00857                                   isImportant)) {
00858     AppendASCIItoUTF16(nsCSSProps::GetStringValue(aShorthand), aString);
00859     aString.AppendLiteral(": ");
00860 
00861     AppendValueToString(OrderValueAt(aBorderWidth-1), aString);
00862 
00863     aString.Append(PRUnichar(' '));
00864     AppendValueToString(OrderValueAt(aBorderStyle-1), aString);
00865 
00866     nsAutoString valueString;
00867     AppendValueToString(OrderValueAt(aBorderColor-1), valueString);
00868     if (!valueString.EqualsLiteral("-moz-use-text-color")) {
00869       aString.AppendLiteral(" ");
00870       aString.Append(valueString);
00871     }
00872     AppendImportanceToString(isImportant, aString);
00873     aString.AppendLiteral("; ");
00874     return PR_TRUE;
00875   }
00876   return PR_FALSE;
00877 }
00878 
00879 PRBool
00880 nsCSSDeclaration::TryFourSidesShorthand(nsAString & aString,
00881                                         nsCSSProperty aShorthand,
00882                                         PRInt32 & aTop,
00883                                         PRInt32 & aBottom,
00884                                         PRInt32 & aLeft,
00885                                         PRInt32 & aRight,
00886                                         PRBool aClearIndexes) const
00887 {
00888   // 0 means not in the mOrder array; otherwise it's index+1
00889   PRBool isImportant;
00890   if (aTop && aBottom && aLeft && aRight &&
00891       AllPropertiesSameImportance(aTop, aBottom, aLeft, aRight,
00892                                   0, 0,
00893                                   isImportant)) {
00894     // all 4 properties are set, we can output a shorthand
00895     AppendASCIItoUTF16(nsCSSProps::GetStringValue(aShorthand), aString);
00896     aString.AppendLiteral(": ");
00897     nsCSSValue topValue, bottomValue, leftValue, rightValue;
00898     nsCSSProperty topProp    = OrderValueAt(aTop-1);
00899     nsCSSProperty bottomProp = OrderValueAt(aBottom-1);
00900     nsCSSProperty leftProp   = OrderValueAt(aLeft-1);
00901     nsCSSProperty rightProp  = OrderValueAt(aRight-1);
00902     GetValueOrImportantValue(topProp,    topValue);
00903     GetValueOrImportantValue(bottomProp, bottomValue);
00904     GetValueOrImportantValue(leftProp,   leftValue);
00905     GetValueOrImportantValue(rightProp,  rightValue);
00906     AppendCSSValueToString(topProp, topValue, aString);
00907     if (topValue != rightValue || topValue != leftValue || topValue != bottomValue) {
00908       aString.Append(PRUnichar(' '));
00909       AppendCSSValueToString(rightProp, rightValue, aString);
00910       if (topValue != bottomValue || rightValue != leftValue) {
00911         aString.Append(PRUnichar(' '));
00912         AppendCSSValueToString(bottomProp, bottomValue, aString);
00913         if (rightValue != leftValue) {
00914           aString.Append(PRUnichar(' '));
00915           AppendCSSValueToString(leftProp, leftValue, aString);
00916         }
00917       }
00918     }
00919     if (aClearIndexes) {
00920       aTop = 0; aBottom = 0; aLeft = 0; aRight = 0;
00921     }
00922     AppendImportanceToString(isImportant, aString);
00923     aString.AppendLiteral("; ");
00924     return PR_TRUE;
00925   }
00926   return PR_FALSE;
00927 }
00928 
00929 void
00930 nsCSSDeclaration::TryBackgroundShorthand(nsAString & aString,
00931                                          PRInt32 & aBgColor,
00932                                          PRInt32 & aBgImage,
00933                                          PRInt32 & aBgRepeat,
00934                                          PRInt32 & aBgAttachment,
00935                                          PRInt32 & aBgPositionX,
00936                                          PRInt32 & aBgPositionY) const
00937 {
00938   // 0 means not in the mOrder array; otherwise it's index+1
00939   // check if we have at least two properties set; otherwise, no need to
00940   // use a shorthand
00941   PRBool isImportant;
00942   if (aBgColor && aBgImage && aBgRepeat && aBgAttachment && aBgPositionX && aBgPositionY &&
00943       AllPropertiesSameImportance(aBgColor, aBgImage, aBgRepeat, aBgAttachment,
00944                                   aBgPositionX, aBgPositionY, isImportant)) {
00945     AppendASCIItoUTF16(nsCSSProps::GetStringValue(eCSSProperty_background), aString);
00946     aString.AppendLiteral(": ");
00947 
00948     AppendValueToString(eCSSProperty_background_color, aString);
00949     aBgColor = 0;
00950 
00951     aString.Append(PRUnichar(' '));
00952     AppendValueToString(eCSSProperty_background_image, aString);
00953     aBgImage = 0;
00954 
00955     aString.Append(PRUnichar(' '));
00956     AppendValueToString(eCSSProperty_background_repeat, aString);
00957     aBgRepeat = 0;
00958 
00959     aString.Append(PRUnichar(' '));
00960     AppendValueToString(eCSSProperty_background_attachment, aString);
00961     aBgAttachment = 0;
00962 
00963     aString.Append(PRUnichar(' '));
00964     UseBackgroundPosition(aString, aBgPositionX, aBgPositionY);
00965     AppendImportanceToString(isImportant, aString);
00966     aString.AppendLiteral("; ");
00967   }
00968 }
00969 
00970 void
00971 nsCSSDeclaration::UseBackgroundPosition(nsAString & aString,
00972                                         PRInt32 & aBgPositionX,
00973                                         PRInt32 & aBgPositionY) const
00974 {
00975   nsAutoString backgroundXValue, backgroundYValue;
00976   AppendValueToString(eCSSProperty_background_x_position, backgroundXValue);
00977   AppendValueToString(eCSSProperty_background_y_position, backgroundYValue);
00978   aString.Append(backgroundXValue);
00979   if (!backgroundXValue.Equals(backgroundYValue, nsCaseInsensitiveStringComparator())) {
00980     // the two values are different
00981     aString.Append(PRUnichar(' '));
00982     aString.Append(backgroundYValue);
00983   }
00984   aBgPositionX = 0;
00985   aBgPositionY = 0;
00986 }
00987 
00988 void
00989 nsCSSDeclaration::TryOverflowShorthand(nsAString & aString,
00990                                        PRInt32 & aOverflowX,
00991                                        PRInt32 & aOverflowY) const
00992 {
00993   PRBool isImportant;
00994   if (aOverflowX && aOverflowY &&
00995       AllPropertiesSameImportance(aOverflowX, aOverflowY,
00996                                   0, 0, 0, 0, isImportant)) {
00997     nsCSSValue xValue, yValue;
00998     GetValueOrImportantValue(eCSSProperty_overflow_x, xValue);
00999     GetValueOrImportantValue(eCSSProperty_overflow_y, yValue);
01000     if (xValue == yValue) {
01001       AppendASCIItoUTF16(nsCSSProps::GetStringValue(eCSSProperty_overflow),
01002                          aString);
01003       aString.AppendLiteral(": ");
01004 
01005       AppendCSSValueToString(eCSSProperty_overflow_x, xValue, aString);
01006       AppendImportanceToString(isImportant, aString);
01007       aString.AppendLiteral("; ");
01008       aOverflowX = aOverflowY = 0;
01009     }
01010   }
01011 }
01012 
01013 #ifdef MOZ_SVG
01014 void
01015 nsCSSDeclaration::TryMarkerShorthand(nsAString & aString,
01016                                      PRInt32 & aMarkerEnd,
01017                                      PRInt32 & aMarkerMid,
01018                                      PRInt32 & aMarkerStart) const
01019 {
01020   PRBool isImportant;
01021   if (aMarkerEnd && aMarkerMid && aMarkerEnd &&
01022       AllPropertiesSameImportance(aMarkerEnd, aMarkerMid, aMarkerStart,
01023                                   0, 0, 0, isImportant)) {
01024     nsCSSValue endValue, midValue, startValue;
01025     GetValueOrImportantValue(eCSSProperty_marker_end, endValue);
01026     GetValueOrImportantValue(eCSSProperty_marker_mid, midValue);
01027     GetValueOrImportantValue(eCSSProperty_marker_start, startValue);
01028     if (endValue == midValue && midValue == startValue) {
01029       AppendASCIItoUTF16(nsCSSProps::GetStringValue(eCSSProperty_marker),
01030                          aString);
01031       aString.AppendLiteral(": ");
01032 
01033       AppendCSSValueToString(eCSSProperty_marker_end, endValue, aString);
01034       AppendImportanceToString(isImportant, aString);
01035       aString.AppendLiteral("; ");
01036       aMarkerEnd = aMarkerMid = aMarkerStart = 0;
01037     }
01038   }
01039 }
01040 #endif
01041 
01042 #define NS_CASE_OUTPUT_PROPERTY_VALUE(_prop, _index) \
01043 case _prop: \
01044           if (_index) { \
01045             AppendPropertyAndValueToString(property, aString); \
01046             _index = 0; \
01047           } \
01048           break;
01049 
01050 #define NS_CASE_OUTPUT_PROPERTY_VALUE_AS(_prop, _propas, _index) \
01051 case _prop: \
01052           if (_index) { \
01053             AppendPropertyAndValueToString(property, _propas, aString); \
01054             _index = 0; \
01055           } \
01056           break;
01057 
01058 #define NS_CASE_CONDITIONAL_OUTPUT_PROPERTY_VALUE(_condition, _prop, _index) \
01059 case _prop: \
01060           if ((_condition) && _index) { \
01061             AppendPropertyAndValueToString(property, aString); \
01062             _index = 0; \
01063           } \
01064           break;
01065 
01066 void nsCSSDeclaration::PropertyIsSet(PRInt32 & aPropertyIndex, PRInt32 aIndex, PRUint32 & aSet, PRUint32 aValue) const
01067 {
01068   aPropertyIndex = aIndex + 1;
01069   aSet |= aValue;
01070 }
01071 
01072 nsresult
01073 nsCSSDeclaration::ToString(nsAString& aString) const
01074 {
01075   PRInt32 count = mOrder.Count();
01076   PRInt32 index;
01077   // 0 means not in the mOrder array; otherwise it's index+1
01078   PRInt32 borderTopWidth = 0, borderTopStyle = 0, borderTopColor = 0;
01079   PRInt32 borderBottomWidth = 0, borderBottomStyle = 0, borderBottomColor = 0;
01080   PRInt32 borderLeftWidth = 0, borderLeftStyle = 0, borderLeftColor = 0;
01081   PRInt32 borderRightWidth = 0, borderRightStyle = 0, borderRightColor = 0;
01082   PRInt32 marginTop = 0,  marginBottom = 0,  marginLeft = 0,  marginRight = 0;
01083   PRInt32 paddingTop = 0, paddingBottom = 0, paddingLeft = 0, paddingRight = 0;
01084   PRInt32 bgColor = 0, bgImage = 0, bgRepeat = 0, bgAttachment = 0;
01085   PRInt32 bgPositionX = 0, bgPositionY = 0;
01086   PRInt32 overflowX = 0, overflowY = 0;
01087   PRUint32 borderPropertiesSet = 0, finalBorderPropertiesToSet = 0;
01088 #ifdef MOZ_SVG
01089   PRInt32 markerEnd = 0, markerMid = 0, markerStart = 0;
01090 #endif
01091 
01092   for (index = 0; index < count; index++) {
01093     nsCSSProperty property = OrderValueAt(index);
01094     switch (property) {
01095       case eCSSProperty_border_top_width:
01096         PropertyIsSet(borderTopWidth, index, borderPropertiesSet, B_BORDER_TOP_WIDTH);
01097         break;
01098       case eCSSProperty_border_bottom_width:
01099         PropertyIsSet(borderBottomWidth, index, borderPropertiesSet, B_BORDER_BOTTOM_WIDTH);
01100         break;
01101       case eCSSProperty_border_left_width:
01102         PropertyIsSet(borderLeftWidth, index, borderPropertiesSet, B_BORDER_LEFT_WIDTH);
01103         break;
01104       case eCSSProperty_border_right_width:
01105         PropertyIsSet(borderRightWidth, index, borderPropertiesSet, B_BORDER_RIGHT_WIDTH);
01106         break;
01107 
01108       case eCSSProperty_border_top_style:
01109         PropertyIsSet(borderTopStyle, index, borderPropertiesSet, B_BORDER_TOP_STYLE);
01110         break;
01111       case eCSSProperty_border_bottom_style:
01112         PropertyIsSet(borderBottomStyle, index, borderPropertiesSet, B_BORDER_BOTTOM_STYLE);
01113         break;
01114       case eCSSProperty_border_left_style:
01115         PropertyIsSet(borderLeftStyle, index, borderPropertiesSet, B_BORDER_LEFT_STYLE);
01116         break;
01117       case eCSSProperty_border_right_style:
01118         PropertyIsSet(borderRightStyle, index, borderPropertiesSet, B_BORDER_RIGHT_STYLE);
01119         break;
01120 
01121       case eCSSProperty_border_top_color:
01122         PropertyIsSet(borderTopColor, index, borderPropertiesSet, B_BORDER_TOP_COLOR);
01123         break;
01124       case eCSSProperty_border_bottom_color:
01125         PropertyIsSet(borderBottomColor, index, borderPropertiesSet, B_BORDER_BOTTOM_COLOR);
01126         break;
01127       case eCSSProperty_border_left_color:
01128         PropertyIsSet(borderLeftColor, index, borderPropertiesSet, B_BORDER_LEFT_COLOR);
01129         break;
01130       case eCSSProperty_border_right_color:
01131         PropertyIsSet(borderRightColor, index, borderPropertiesSet, B_BORDER_RIGHT_COLOR);
01132         break;
01133 
01134       case eCSSProperty_margin_top:            marginTop     = index+1; break;
01135       case eCSSProperty_margin_bottom:         marginBottom  = index+1; break;
01136       case eCSSProperty_margin_left_value:     marginLeft    = index+1; break;
01137       case eCSSProperty_margin_right_value:    marginRight   = index+1; break;
01138 
01139       case eCSSProperty_padding_top:           paddingTop    = index+1; break;
01140       case eCSSProperty_padding_bottom:        paddingBottom = index+1; break;
01141       case eCSSProperty_padding_left_value:    paddingLeft   = index+1; break;
01142       case eCSSProperty_padding_right_value:   paddingRight  = index+1; break;
01143 
01144       case eCSSProperty_background_color:      bgColor       = index+1; break;
01145       case eCSSProperty_background_image:      bgImage       = index+1; break;
01146       case eCSSProperty_background_repeat:     bgRepeat      = index+1; break;
01147       case eCSSProperty_background_attachment: bgAttachment  = index+1; break;
01148       case eCSSProperty_background_x_position: bgPositionX   = index+1; break;
01149       case eCSSProperty_background_y_position: bgPositionY   = index+1; break;
01150 
01151       case eCSSProperty_overflow_x:            overflowX     = index+1; break;
01152       case eCSSProperty_overflow_y:            overflowY     = index+1; break;
01153 
01154 #ifdef MOZ_SVG
01155       case eCSSProperty_marker_end:            markerEnd     = index+1; break;
01156       case eCSSProperty_marker_mid:            markerMid     = index+1; break;
01157       case eCSSProperty_marker_start:          markerStart   = index+1; break;
01158 #endif
01159 
01160       default: break;
01161     }
01162   }
01163 
01164   if (!TryBorderShorthand(aString, borderPropertiesSet,
01165                           borderTopWidth, borderTopStyle, borderTopColor,
01166                           borderBottomWidth, borderBottomStyle, borderBottomColor,
01167                           borderLeftWidth, borderLeftStyle, borderLeftColor,
01168                           borderRightWidth, borderRightStyle, borderRightColor)) {
01169     PRUint32 borderPropertiesToSet = 0;
01170     if ((borderPropertiesSet & B_BORDER_STYLE) != B_BORDER_STYLE ||
01171         !TryFourSidesShorthand(aString, eCSSProperty_border_style,
01172                                borderTopStyle, borderBottomStyle,
01173                                borderLeftStyle, borderRightStyle,
01174                                PR_FALSE)) {
01175       borderPropertiesToSet |= B_BORDER_STYLE;
01176     }
01177     if ((borderPropertiesSet & B_BORDER_COLOR) != B_BORDER_COLOR ||
01178         !TryFourSidesShorthand(aString, eCSSProperty_border_color,
01179                                borderTopColor, borderBottomColor,
01180                                borderLeftColor, borderRightColor,
01181                                PR_FALSE)) {
01182       borderPropertiesToSet |= B_BORDER_COLOR;
01183     }
01184     if ((borderPropertiesSet & B_BORDER_WIDTH) != B_BORDER_WIDTH ||
01185         !TryFourSidesShorthand(aString, eCSSProperty_border_width,
01186                                borderTopWidth, borderBottomWidth,
01187                                borderLeftWidth, borderRightWidth,
01188                                PR_FALSE)) {
01189       borderPropertiesToSet |= B_BORDER_WIDTH;
01190     }
01191     borderPropertiesToSet &= borderPropertiesSet;
01192     if (borderPropertiesToSet) {
01193       if ((borderPropertiesSet & B_BORDER_TOP) != B_BORDER_TOP ||
01194           !TryBorderSideShorthand(aString, eCSSProperty_border_top,
01195                                   borderTopWidth, borderTopStyle, borderTopColor)) {
01196         finalBorderPropertiesToSet |= B_BORDER_TOP;
01197       }
01198       if ((borderPropertiesSet & B_BORDER_LEFT) != B_BORDER_LEFT ||
01199           !TryBorderSideShorthand(aString, eCSSProperty_border_left,
01200                                   borderLeftWidth, borderLeftStyle, borderLeftColor)) {
01201         finalBorderPropertiesToSet |= B_BORDER_LEFT;
01202       }
01203       if ((borderPropertiesSet & B_BORDER_RIGHT) != B_BORDER_RIGHT ||
01204           !TryBorderSideShorthand(aString, eCSSProperty_border_right,
01205                                   borderRightWidth, borderRightStyle, borderRightColor)) {
01206         finalBorderPropertiesToSet |= B_BORDER_RIGHT;
01207       }
01208       if ((borderPropertiesSet & B_BORDER_BOTTOM) != B_BORDER_BOTTOM ||
01209           !TryBorderSideShorthand(aString, eCSSProperty_border_bottom,
01210                                   borderBottomWidth, borderBottomStyle, borderBottomColor)) {
01211         finalBorderPropertiesToSet |= B_BORDER_BOTTOM;
01212       }
01213       finalBorderPropertiesToSet &= borderPropertiesToSet;
01214     }
01215   }
01216 
01217   TryFourSidesShorthand(aString, eCSSProperty_margin,
01218                         marginTop, marginBottom,
01219                         marginLeft, marginRight,
01220                         PR_TRUE);
01221   TryFourSidesShorthand(aString, eCSSProperty_padding,
01222                         paddingTop, paddingBottom,
01223                         paddingLeft, paddingRight,
01224                         PR_TRUE);
01225   TryBackgroundShorthand(aString,
01226                          bgColor, bgImage, bgRepeat, bgAttachment,
01227                          bgPositionX, bgPositionY);
01228   TryOverflowShorthand(aString, overflowX, overflowY);
01229 #ifdef MOZ_SVG
01230   TryMarkerShorthand(aString, markerEnd, markerMid, markerStart);
01231 #endif
01232 
01233   for (index = 0; index < count; index++) {
01234     nsCSSProperty property = OrderValueAt(index);
01235     switch (property) {
01236 
01237       NS_CASE_CONDITIONAL_OUTPUT_PROPERTY_VALUE(finalBorderPropertiesToSet & B_BORDER_TOP_STYLE,
01238                                                 eCSSProperty_border_top_style, borderTopStyle)
01239       NS_CASE_CONDITIONAL_OUTPUT_PROPERTY_VALUE(finalBorderPropertiesToSet & B_BORDER_LEFT_STYLE,
01240                                                 eCSSProperty_border_left_style, borderLeftStyle)
01241       NS_CASE_CONDITIONAL_OUTPUT_PROPERTY_VALUE(finalBorderPropertiesToSet & B_BORDER_RIGHT_STYLE,
01242                                                 eCSSProperty_border_right_style, borderRightStyle)
01243       NS_CASE_CONDITIONAL_OUTPUT_PROPERTY_VALUE(finalBorderPropertiesToSet & B_BORDER_BOTTOM_STYLE,
01244                                                 eCSSProperty_border_bottom_style, borderBottomStyle)
01245 
01246       NS_CASE_CONDITIONAL_OUTPUT_PROPERTY_VALUE(finalBorderPropertiesToSet & B_BORDER_TOP_COLOR,
01247                                                 eCSSProperty_border_top_color, borderTopColor)
01248       NS_CASE_CONDITIONAL_OUTPUT_PROPERTY_VALUE(finalBorderPropertiesToSet & B_BORDER_LEFT_COLOR,
01249                                                 eCSSProperty_border_left_color, borderLeftColor)
01250       NS_CASE_CONDITIONAL_OUTPUT_PROPERTY_VALUE(finalBorderPropertiesToSet & B_BORDER_RIGHT_COLOR,
01251                                                 eCSSProperty_border_right_color, borderRightColor)
01252       NS_CASE_CONDITIONAL_OUTPUT_PROPERTY_VALUE(finalBorderPropertiesToSet & B_BORDER_BOTTOM_COLOR,
01253                                                 eCSSProperty_border_bottom_color, borderBottomColor)
01254 
01255       NS_CASE_CONDITIONAL_OUTPUT_PROPERTY_VALUE(finalBorderPropertiesToSet & B_BORDER_TOP_WIDTH,
01256                                                 eCSSProperty_border_top_width, borderTopWidth)
01257       NS_CASE_CONDITIONAL_OUTPUT_PROPERTY_VALUE(finalBorderPropertiesToSet & B_BORDER_LEFT_WIDTH,
01258                                                 eCSSProperty_border_left_width, borderLeftWidth)
01259       NS_CASE_CONDITIONAL_OUTPUT_PROPERTY_VALUE(finalBorderPropertiesToSet & B_BORDER_RIGHT_WIDTH,
01260                                                 eCSSProperty_border_right_width, borderRightWidth)
01261       NS_CASE_CONDITIONAL_OUTPUT_PROPERTY_VALUE(finalBorderPropertiesToSet & B_BORDER_BOTTOM_WIDTH,
01262                                                 eCSSProperty_border_bottom_width, borderBottomWidth)
01263 
01264       NS_CASE_OUTPUT_PROPERTY_VALUE(eCSSProperty_margin_top, marginTop)
01265       NS_CASE_OUTPUT_PROPERTY_VALUE(eCSSProperty_margin_bottom, marginBottom)
01266       NS_CASE_OUTPUT_PROPERTY_VALUE_AS(eCSSProperty_margin_left_value,
01267                                        eCSSProperty_margin_left, marginLeft)
01268       NS_CASE_OUTPUT_PROPERTY_VALUE_AS(eCSSProperty_margin_right_value,
01269                                        eCSSProperty_margin_right, marginRight)
01270 
01271       NS_CASE_OUTPUT_PROPERTY_VALUE(eCSSProperty_padding_top, paddingTop)
01272       NS_CASE_OUTPUT_PROPERTY_VALUE(eCSSProperty_padding_bottom, paddingBottom)
01273       NS_CASE_OUTPUT_PROPERTY_VALUE_AS(eCSSProperty_padding_left_value,
01274                                        eCSSProperty_padding_left, paddingLeft)
01275       NS_CASE_OUTPUT_PROPERTY_VALUE_AS(eCSSProperty_padding_right_value,
01276                                        eCSSProperty_padding_right, paddingRight)
01277 
01278       NS_CASE_OUTPUT_PROPERTY_VALUE(eCSSProperty_background_color, bgColor)
01279       NS_CASE_OUTPUT_PROPERTY_VALUE(eCSSProperty_background_image, bgImage)
01280       NS_CASE_OUTPUT_PROPERTY_VALUE(eCSSProperty_background_repeat, bgRepeat)
01281       NS_CASE_OUTPUT_PROPERTY_VALUE(eCSSProperty_background_attachment, bgAttachment)
01282 
01283       case eCSSProperty_background_x_position:
01284       case eCSSProperty_background_y_position: {
01285         // 0 means not in the mOrder array; otherwise it's index+1
01286         PRBool isImportant;
01287         if (bgPositionX && bgPositionY &&
01288             AllPropertiesSameImportance(bgPositionX, bgPositionY,
01289                                         0, 0, 0, 0, isImportant)) {
01290           AppendASCIItoUTF16(nsCSSProps::GetStringValue(eCSSProperty_background_position), aString);
01291           aString.AppendLiteral(": ");
01292           UseBackgroundPosition(aString, bgPositionX, bgPositionY);
01293           AppendImportanceToString(isImportant, aString);
01294           aString.AppendLiteral("; ");
01295         }
01296         else if (eCSSProperty_background_x_position == property && bgPositionX) {
01297           AppendPropertyAndValueToString(eCSSProperty_background_x_position, aString);
01298           bgPositionX = 0;
01299         }
01300         else if (eCSSProperty_background_y_position == property && bgPositionY) {
01301           AppendPropertyAndValueToString(eCSSProperty_background_y_position, aString);
01302           bgPositionY = 0;
01303         }
01304         break;
01305       }
01306 
01307       NS_CASE_OUTPUT_PROPERTY_VALUE(eCSSProperty_overflow_x, overflowX)
01308       NS_CASE_OUTPUT_PROPERTY_VALUE(eCSSProperty_overflow_y, overflowY)
01309 
01310 #ifdef MOZ_SVG
01311       NS_CASE_OUTPUT_PROPERTY_VALUE(eCSSProperty_marker_end, markerEnd)
01312       NS_CASE_OUTPUT_PROPERTY_VALUE(eCSSProperty_marker_mid, markerMid)
01313       NS_CASE_OUTPUT_PROPERTY_VALUE(eCSSProperty_marker_start, markerStart)
01314 #endif
01315 
01316       case eCSSProperty_margin_left_ltr_source:
01317       case eCSSProperty_margin_left_rtl_source:
01318       case eCSSProperty_margin_right_ltr_source:
01319       case eCSSProperty_margin_right_rtl_source:
01320       case eCSSProperty_padding_left_ltr_source:
01321       case eCSSProperty_padding_left_rtl_source:
01322       case eCSSProperty_padding_right_ltr_source:
01323       case eCSSProperty_padding_right_rtl_source:
01324         break;
01325 
01326       case eCSSProperty_margin_start_value:
01327         AppendPropertyAndValueToString(property, eCSSProperty_margin_start,
01328                                        aString);
01329         break;
01330       case eCSSProperty_margin_end_value:
01331         AppendPropertyAndValueToString(property, eCSSProperty_margin_end,
01332                                        aString);
01333         break;
01334       case eCSSProperty_padding_start_value:
01335         AppendPropertyAndValueToString(property, eCSSProperty_padding_start,
01336                                        aString);
01337         break;
01338       case eCSSProperty_padding_end_value:
01339         AppendPropertyAndValueToString(property, eCSSProperty_padding_end,
01340                                        aString);
01341         break;
01342 
01343       default:
01344         if (0 <= property) {
01345           AppendPropertyAndValueToString(property, aString);
01346         }
01347         break;
01348     }
01349   }
01350   if (! aString.IsEmpty()) {
01351     // if the string is not empty, we have a trailing whitespace we should remove
01352     aString.Truncate(aString.Length() - 1);
01353   }
01354   return NS_OK;
01355 }
01356 
01357 #ifdef DEBUG
01358 void nsCSSDeclaration::List(FILE* out, PRInt32 aIndent) const
01359 {
01360   for (PRInt32 index = aIndent; --index >= 0; ) fputs("  ", out);
01361 
01362   fputs("{ ", out);
01363   fputs("nsCSSDeclaration::List not implemented", out);
01364   fputs("}", out);
01365 }
01366 #endif
01367 
01368 PRUint32
01369 nsCSSDeclaration::Count() const
01370 {
01371   return (PRUint32)mOrder.Count();
01372 }
01373 
01374 nsresult
01375 nsCSSDeclaration::GetNthProperty(PRUint32 aIndex, nsAString& aReturn) const
01376 {
01377   aReturn.Truncate();
01378   if (aIndex < (PRUint32)mOrder.Count()) {
01379     nsCSSProperty property = OrderValueAt(aIndex);
01380     if (0 <= property) {
01381       AppendASCIItoUTF16(nsCSSProps::GetStringValue(property), aReturn);
01382     }
01383   }
01384   
01385   return NS_OK;
01386 }
01387 
01388 nsCSSDeclaration*
01389 nsCSSDeclaration::Clone() const
01390 {
01391   return new nsCSSDeclaration(*this);
01392 }
01393 
01394 PRBool
01395 nsCSSDeclaration::InitializeEmpty()
01396 {
01397   NS_ASSERTION(!mData && !mImportantData, "already initialized");
01398   mData = nsCSSCompressedDataBlock::CreateEmptyBlock();
01399   return mData != nsnull;
01400 }