LCOV - code coverage report
Current view: top level - layout/style - Declaration.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 87 1048 8.3 %
Date: 2017-07-14 16:53:18 Functions: 18 54 33.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : /*
       7             :  * representation of a declaration block (or style attribute) in a CSS
       8             :  * stylesheet
       9             :  */
      10             : 
      11             : #include "mozilla/css/Declaration.h"
      12             : 
      13             : #include "mozilla/ArrayUtils.h"
      14             : #include "mozilla/MemoryReporting.h"
      15             : #include "mozilla/ServoStyleSet.h"
      16             : 
      17             : #include "mozilla/css/Rule.h"
      18             : #include "nsPrintfCString.h"
      19             : #include "gfxFontConstants.h"
      20             : #include "nsStyleUtil.h"
      21             : 
      22             : namespace mozilla {
      23             : namespace css {
      24             : 
      25        1210 : NS_IMPL_QUERY_INTERFACE(ImportantStyleData, nsIStyleRule)
      26         310 : NS_IMPL_ADDREF_USING_AGGREGATOR(ImportantStyleData, Declaration())
      27         217 : NS_IMPL_RELEASE_USING_AGGREGATOR(ImportantStyleData, Declaration())
      28             : 
      29             : /* virtual */ void
      30        2460 : ImportantStyleData::MapRuleInfoInto(nsRuleData* aRuleData)
      31             : {
      32        2460 :   Declaration()->MapImportantRuleInfoInto(aRuleData);
      33        2460 : }
      34             : 
      35             : /* virtual */ bool
      36          35 : ImportantStyleData::MightMapInheritedStyleData()
      37             : {
      38          35 :   return Declaration()->MapsImportantInheritedStyleData();
      39             : }
      40             : 
      41             : /* virtual */ bool
      42           0 : ImportantStyleData::GetDiscretelyAnimatedCSSValue(nsCSSPropertyID aProperty,
      43             :                                                   nsCSSValue* aValue)
      44             : {
      45           0 :   return Declaration()->GetDiscretelyAnimatedCSSValue(aProperty, aValue);
      46             : }
      47             : 
      48             : 
      49             : #ifdef DEBUG
      50             : /* virtual */ void
      51           0 : ImportantStyleData::List(FILE* out, int32_t aIndent) const
      52             : {
      53             :   // Indent
      54           0 :   nsAutoCString str;
      55           0 :   for (int32_t index = aIndent; --index >= 0; ) {
      56           0 :     str.AppendLiteral("  ");
      57             :   }
      58             : 
      59           0 :   str.AppendLiteral("! important rule\n");
      60           0 :   fprintf_stderr(out, "%s", str.get());
      61           0 : }
      62             : #endif
      63             : 
      64          15 : Declaration::Declaration(const Declaration& aCopy)
      65             :   : DeclarationBlock(aCopy),
      66             :     mOrder(aCopy.mOrder),
      67             :     mVariableOrder(aCopy.mVariableOrder),
      68          30 :     mData(aCopy.mData ? aCopy.mData->Clone() : nullptr),
      69             :     mImportantData(aCopy.mImportantData ?
      70          15 :                      aCopy.mImportantData->Clone() : nullptr),
      71             :     mVariables(aCopy.mVariables ?
      72           0 :         new CSSVariableDeclarations(*aCopy.mVariables) :
      73          15 :         nullptr),
      74             :     mImportantVariables(aCopy.mImportantVariables ?
      75           0 :         new CSSVariableDeclarations(*aCopy.mImportantVariables) :
      76          75 :         nullptr)
      77             : {
      78          15 : }
      79             : 
      80          25 : Declaration::~Declaration()
      81             : {
      82          25 : }
      83             : 
      84       23588 : NS_INTERFACE_MAP_BEGIN(Declaration)
      85       23588 :   if (aIID.Equals(NS_GET_IID(mozilla::css::Declaration))) {
      86       21808 :     *aInstancePtr = this;
      87       21808 :     NS_ADDREF_THIS();
      88       21808 :     return NS_OK;
      89             :   }
      90             :   else
      91        1780 :   NS_INTERFACE_MAP_ENTRY(nsIStyleRule)
      92           0 :   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIStyleRule)
      93           0 : NS_INTERFACE_MAP_END
      94             : 
      95       31741 : NS_IMPL_ADDREF(Declaration)
      96       27681 : NS_IMPL_RELEASE(Declaration)
      97             : 
      98             : /* virtual */ void
      99       29444 : Declaration::MapRuleInfoInto(nsRuleData* aRuleData)
     100             : {
     101       29444 :   MOZ_ASSERT(mData, "must call only while compressed");
     102       29444 :   mData->MapRuleInfoInto(aRuleData);
     103       29444 :   if (mVariables) {
     104         735 :     mVariables->MapRuleInfoInto(aRuleData);
     105             :   }
     106       29444 : }
     107             : 
     108             : /* virtual */ bool
     109         282 : Declaration::MightMapInheritedStyleData()
     110             : {
     111         282 :   MOZ_ASSERT(mData, "must call only while compressed");
     112         282 :   if (mVariables && mVariables->Count() != 0) {
     113           1 :     return true;
     114             :   }
     115         281 :   return mData->HasInheritedStyleData();
     116             : }
     117             : 
     118             : /* virtual */ bool
     119           0 : Declaration::GetDiscretelyAnimatedCSSValue(nsCSSPropertyID aProperty,
     120             :                                            nsCSSValue* aValue)
     121             : {
     122           0 :   nsCSSCompressedDataBlock* data = GetPropertyIsImportantByID(aProperty)
     123           0 :                                    ? mImportantData : mData;
     124           0 :   const nsCSSValue* value = data->ValueFor(aProperty);
     125           0 :   if (!value) {
     126           0 :     return false;
     127             :   }
     128           0 :   *aValue = *value;
     129           0 :   return true;
     130             : }
     131             : 
     132             : 
     133             : bool
     134          35 : Declaration::MapsImportantInheritedStyleData() const
     135             : {
     136          35 :   MOZ_ASSERT(mData, "must call only while compressed");
     137          35 :   MOZ_ASSERT(HasImportantData(), "must only be called for Declarations with "
     138             :                                  "important data");
     139          35 :   if (mImportantVariables && mImportantVariables->Count() != 0) {
     140           0 :     return true;
     141             :   }
     142          35 :   return mImportantData ? mImportantData->HasInheritedStyleData() : false;
     143             : }
     144             : 
     145             : void
     146       13008 : Declaration::ValueAppended(nsCSSPropertyID aProperty)
     147             : {
     148       13008 :   MOZ_ASSERT(!mData && !mImportantData,
     149             :              "should only be called while expanded");
     150       13008 :   MOZ_ASSERT(!nsCSSProps::IsShorthand(aProperty),
     151             :              "shorthands forbidden");
     152             :   // order IS important for CSS, so remove and add to the end
     153       13008 :   mOrder.RemoveElement(static_cast<uint32_t>(aProperty));
     154       13008 :   mOrder.AppendElement(static_cast<uint32_t>(aProperty));
     155       13008 : }
     156             : 
     157             : template<typename PropFunc, typename CustomPropFunc>
     158             : inline void
     159           0 : DispatchPropertyOperation(const nsAString& aProperty,
     160             :                           PropFunc aPropFunc, CustomPropFunc aCustomPropFunc)
     161             : {
     162             :   nsCSSPropertyID propID =
     163           0 :     nsCSSProps::LookupProperty(aProperty, CSSEnabledState::eForAllContent);
     164           0 :   if (propID != eCSSProperty_UNKNOWN) {
     165           0 :     if (propID != eCSSPropertyExtra_variable) {
     166           0 :       aPropFunc(propID);
     167             :     } else {
     168           0 :       aCustomPropFunc(Substring(aProperty, CSS_CUSTOM_NAME_PREFIX_LENGTH));
     169             :     }
     170             :   }
     171           0 : }
     172             : 
     173             : void
     174           0 : Declaration::GetPropertyValue(const nsAString& aProperty,
     175             :                               nsAString& aValue) const
     176             : {
     177             :   DispatchPropertyOperation(aProperty,
     178           0 :     [&](nsCSSPropertyID propID) { GetPropertyValueByID(propID, aValue); },
     179           0 :     [&](const nsAString& name) { GetVariableValue(name, aValue); });
     180           0 : }
     181             : 
     182             : void
     183           0 : Declaration::GetPropertyValueByID(nsCSSPropertyID aPropID,
     184             :                                   nsAString& aValue) const
     185             : {
     186           0 :   GetPropertyValueInternal(aPropID, aValue, nsCSSValue::eNormalized);
     187           0 : }
     188             : 
     189             : void
     190           0 : Declaration::GetAuthoredPropertyValue(const nsAString& aProperty,
     191             :                                       nsAString& aValue) const
     192             : {
     193             :   DispatchPropertyOperation(aProperty,
     194           0 :     [&](nsCSSPropertyID propID) {
     195           0 :       GetPropertyValueInternal(propID, aValue, nsCSSValue::eAuthorSpecified);
     196           0 :     },
     197           0 :     [&](const nsAString& name) { GetVariableValue(name, aValue); });
     198           0 : }
     199             : 
     200             : bool
     201           0 : Declaration::GetPropertyIsImportant(const nsAString& aProperty) const
     202             : {
     203           0 :   bool r = false;
     204             :   DispatchPropertyOperation(aProperty,
     205           0 :     [&](nsCSSPropertyID propID) { r = GetPropertyIsImportantByID(propID); },
     206           0 :     [&](const nsAString& name) { r = GetVariableIsImportant(name); });
     207           0 :   return r;
     208             : }
     209             : 
     210             : void
     211           0 : Declaration::RemoveProperty(const nsAString& aProperty)
     212             : {
     213             :   DispatchPropertyOperation(aProperty,
     214           0 :     [&](nsCSSPropertyID propID) { RemovePropertyByID(propID); },
     215           0 :     [&](const nsAString& name) { RemoveVariable(name); });
     216           0 : }
     217             : 
     218             : void
     219           1 : Declaration::RemovePropertyByID(nsCSSPropertyID aProperty)
     220             : {
     221           1 :   MOZ_ASSERT(0 <= aProperty && aProperty < eCSSProperty_COUNT);
     222             : 
     223           2 :   nsCSSExpandedDataBlock data;
     224           1 :   ExpandTo(&data);
     225           1 :   MOZ_ASSERT(!mData && !mImportantData, "Expand didn't null things out");
     226             : 
     227           1 :   if (nsCSSProps::IsShorthand(aProperty)) {
     228           0 :     CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p, aProperty,
     229             :                                          CSSEnabledState::eForAllContent) {
     230           0 :       data.ClearLonghandProperty(*p);
     231           0 :       mOrder.RemoveElement(static_cast<uint32_t>(*p));
     232             :     }
     233             :   } else {
     234           1 :     data.ClearLonghandProperty(aProperty);
     235           1 :     mOrder.RemoveElement(static_cast<uint32_t>(aProperty));
     236             :   }
     237             : 
     238           1 :   CompressFrom(&data);
     239           1 : }
     240             : 
     241             : bool
     242           0 : Declaration::HasProperty(nsCSSPropertyID aProperty) const
     243             : {
     244           0 :   MOZ_ASSERT(0 <= aProperty && aProperty < eCSSProperty_COUNT_no_shorthands,
     245             :              "property ID out of range");
     246             : 
     247           0 :   nsCSSCompressedDataBlock *data = GetPropertyIsImportantByID(aProperty)
     248           0 :                                       ? mImportantData : mData;
     249           0 :   const nsCSSValue *val = data->ValueFor(aProperty);
     250           0 :   return !!val;
     251             : }
     252             : 
     253             : bool
     254           0 : Declaration::AppendValueToString(nsCSSPropertyID aProperty,
     255             :                                  nsAString& aResult,
     256             :                                  nsCSSValue::Serialization aSerialization,
     257             :                                  bool* aIsTokenStream) const
     258             : {
     259           0 :   MOZ_ASSERT(0 <= aProperty && aProperty < eCSSProperty_COUNT_no_shorthands,
     260             :              "property ID out of range");
     261             : 
     262           0 :   nsCSSCompressedDataBlock *data = GetPropertyIsImportantByID(aProperty)
     263           0 :                                       ? mImportantData : mData;
     264           0 :   const nsCSSValue *val = data->ValueFor(aProperty);
     265           0 :   if (!val) {
     266           0 :     return false;
     267             :   }
     268             : 
     269           0 :   if (aIsTokenStream) {
     270           0 :     *aIsTokenStream = val->GetUnit() == eCSSUnit_TokenStream;
     271             :   }
     272           0 :   val->AppendToString(aProperty, aResult, aSerialization);
     273           0 :   return true;
     274             : }
     275             : 
     276             : static void
     277           0 : AppendSingleImageLayerPositionValue(const nsCSSValue& aPositionX,
     278             :                                     const nsCSSValue& aPositionY,
     279             :                                     const nsCSSPropertyID aTable[],
     280             :                                     nsAString& aValue,
     281             :                                     nsCSSValue::Serialization aSerialization)
     282             : {
     283             :   // We need to make sure that we don't serialize to an invalid 3-value form.
     284             :   // The 3-value form is only valid if both edges are present.
     285           0 :   const nsCSSValue &xEdge = aPositionX.GetArrayValue()->Item(0);
     286           0 :   const nsCSSValue &xOffset = aPositionX.GetArrayValue()->Item(1);
     287           0 :   const nsCSSValue &yEdge = aPositionY.GetArrayValue()->Item(0);
     288           0 :   const nsCSSValue &yOffset = aPositionY.GetArrayValue()->Item(1);
     289           0 :   bool xHasEdge = (eCSSUnit_Enumerated == xEdge.GetUnit());
     290           0 :   bool xHasBoth = xHasEdge && (eCSSUnit_Null != xOffset.GetUnit());
     291           0 :   bool yHasEdge = (eCSSUnit_Enumerated == yEdge.GetUnit());
     292           0 :   bool yHasBoth = yHasEdge && (eCSSUnit_Null != yOffset.GetUnit());
     293             : 
     294           0 :   if (yHasBoth && !xHasEdge) {
     295             :     // Output 4-value form by adding the x edge.
     296           0 :     aValue.AppendLiteral("left ");
     297             :   }
     298           0 :   aPositionX.AppendToString(aTable[nsStyleImageLayers::positionX],
     299           0 :                             aValue, aSerialization);
     300             : 
     301           0 :   aValue.Append(char16_t(' '));
     302             : 
     303           0 :   if (xHasBoth && !yHasEdge) {
     304             :     // Output 4-value form by adding the y edge.
     305           0 :     aValue.AppendLiteral("top ");
     306             :   }
     307           0 :   aPositionY.AppendToString(aTable[nsStyleImageLayers::positionY],
     308           0 :                             aValue, aSerialization);
     309           0 : }
     310             : 
     311             : void
     312           0 : Declaration::GetImageLayerValue(
     313             :                    nsCSSCompressedDataBlock *data,
     314             :                    nsAString& aValue,
     315             :                    nsCSSValue::Serialization aSerialization,
     316             :                    const nsCSSPropertyID aTable[]) const
     317             : {
     318             :   // We know from our caller that all subproperties were specified.
     319             :   // However, we still can't represent that in the shorthand unless
     320             :   // they're all lists of the same length.  So if they're different
     321             :   // lengths, we need to bail out.
     322             :   // We also need to bail out if an item has background-clip and
     323             :   // background-origin that are different and not the default
     324             :   // values.  (We omit them if they're both default.)
     325             : 
     326             :   // Common CSS properties for both background & mask layer.
     327             :   const nsCSSValueList *image =
     328           0 :     data->ValueFor(aTable[nsStyleImageLayers::image])->GetListValue();
     329             :   const nsCSSValuePairList *repeat =
     330           0 :     data->ValueFor(aTable[nsStyleImageLayers::repeat])->GetPairListValue();
     331             :   const nsCSSValueList *positionX =
     332           0 :     data->ValueFor(aTable[nsStyleImageLayers::positionX])->GetListValue();
     333             :   const nsCSSValueList *positionY =
     334           0 :     data->ValueFor(aTable[nsStyleImageLayers::positionY])->GetListValue();
     335             :   const nsCSSValueList *clip =
     336           0 :     data->ValueFor(aTable[nsStyleImageLayers::clip])->GetListValue();
     337             :   const nsCSSValueList *origin =
     338           0 :     data->ValueFor(aTable[nsStyleImageLayers::origin])->GetListValue();
     339             :   const nsCSSValuePairList *size =
     340           0 :     data->ValueFor(aTable[nsStyleImageLayers::size])->GetPairListValue();
     341             : 
     342             :   // Background layer property.
     343             :   const nsCSSValueList *attachment =
     344           0 :     (aTable[nsStyleImageLayers::attachment] ==  eCSSProperty_UNKNOWN)?
     345             :       nullptr :
     346           0 :       data->ValueFor(aTable[nsStyleImageLayers::attachment])->GetListValue();
     347             : 
     348             :   // Mask layer properties.
     349             :   const nsCSSValueList *composite =
     350           0 :     (aTable[nsStyleImageLayers::composite] ==  eCSSProperty_UNKNOWN)?
     351             :       nullptr :
     352           0 :       data->ValueFor(aTable[nsStyleImageLayers::composite])->GetListValue();
     353             :   const nsCSSValueList *mode =
     354           0 :     (aTable[nsStyleImageLayers::maskMode] ==  eCSSProperty_UNKNOWN)?
     355             :       nullptr :
     356           0 :       data->ValueFor(aTable[nsStyleImageLayers::maskMode])->GetListValue();
     357             : 
     358             :   for (;;) {
     359             :     // Serialize background-color at the beginning of the last item.
     360           0 :     if (!image->mNext) {
     361           0 :       if (aTable[nsStyleImageLayers::color] != eCSSProperty_UNKNOWN) {
     362           0 :         AppendValueToString(aTable[nsStyleImageLayers::color], aValue,
     363           0 :                             aSerialization);
     364           0 :         aValue.Append(char16_t(' '));
     365             :       }
     366             :     }
     367             : 
     368           0 :     image->mValue.AppendToString(aTable[nsStyleImageLayers::image], aValue,
     369           0 :                                  aSerialization);
     370             : 
     371           0 :     aValue.Append(char16_t(' '));
     372           0 :     repeat->mXValue.AppendToString(aTable[nsStyleImageLayers::repeat], aValue,
     373           0 :                                    aSerialization);
     374           0 :     if (repeat->mYValue.GetUnit() != eCSSUnit_Null) {
     375           0 :       repeat->mYValue.AppendToString(aTable[nsStyleImageLayers::repeat], aValue,
     376           0 :                                      aSerialization);
     377             :     }
     378             : 
     379           0 :     if (attachment) {
     380           0 :       aValue.Append(char16_t(' '));
     381           0 :           attachment->mValue.AppendToString(aTable[nsStyleImageLayers::attachment],
     382           0 :                                             aValue, aSerialization);
     383             :     }
     384             : 
     385           0 :     aValue.Append(char16_t(' '));
     386           0 :     AppendSingleImageLayerPositionValue(positionX->mValue, positionY->mValue,
     387           0 :                                         aTable, aValue, aSerialization);
     388             : 
     389           0 :     if (size->mXValue.GetUnit() != eCSSUnit_Auto ||
     390           0 :         size->mYValue.GetUnit() != eCSSUnit_Auto) {
     391           0 :       aValue.Append(char16_t(' '));
     392           0 :       aValue.Append(char16_t('/'));
     393           0 :       aValue.Append(char16_t(' '));
     394           0 :       size->mXValue.AppendToString(aTable[nsStyleImageLayers::size], aValue,
     395           0 :                                    aSerialization);
     396           0 :       aValue.Append(char16_t(' '));
     397           0 :       size->mYValue.AppendToString(aTable[nsStyleImageLayers::size], aValue,
     398           0 :                                    aSerialization);
     399             :     }
     400             : 
     401           0 :     MOZ_ASSERT(clip->mValue.GetUnit() == eCSSUnit_Enumerated &&
     402             :                origin->mValue.GetUnit() == eCSSUnit_Enumerated,
     403             :                "should not have inherit/initial within list");
     404             : 
     405             :     StyleGeometryBox originDefaultValue =
     406             :       (aTable == nsStyleImageLayers::kBackgroundLayerTable)
     407           0 :       ? StyleGeometryBox::PaddingBox : StyleGeometryBox::BorderBox;
     408           0 :     if (static_cast<StyleGeometryBox>(clip->mValue.GetIntValue()) !=
     409           0 :         StyleGeometryBox::BorderBox ||
     410           0 :         static_cast<StyleGeometryBox>(origin->mValue.GetIntValue()) !=
     411             :         originDefaultValue) {
     412             : #ifdef DEBUG
     413           0 :       const nsCSSProps::KTableEntry* originTable = nsCSSProps::kKeywordTableTable[aTable[nsStyleImageLayers::origin]];
     414           0 :       const nsCSSProps::KTableEntry* clipTable = nsCSSProps::kKeywordTableTable[aTable[nsStyleImageLayers::clip]];
     415           0 :       for (size_t i = 0; originTable[i].mValue != -1; i++) {
     416             :         // For each keyword & value in kOriginKTable, ensure that
     417             :         // kBackgroundKTable has a matching entry at the same position.
     418           0 :         MOZ_ASSERT(originTable[i].mKeyword == clipTable[i].mKeyword);
     419           0 :         MOZ_ASSERT(originTable[i].mValue == clipTable[i].mValue);
     420             :       }
     421             : #endif
     422           0 :       aValue.Append(char16_t(' '));
     423           0 :       origin->mValue.AppendToString(aTable[nsStyleImageLayers::origin], aValue,
     424           0 :                                     aSerialization);
     425             : 
     426           0 :       if (clip->mValue != origin->mValue) {
     427           0 :         aValue.Append(char16_t(' '));
     428           0 :         clip->mValue.AppendToString(aTable[nsStyleImageLayers::clip], aValue,
     429           0 :                                     aSerialization);
     430             :       }
     431             :     }
     432             : 
     433           0 :     if (composite) {
     434           0 :       aValue.Append(char16_t(' '));
     435           0 :       composite->mValue.AppendToString(aTable[nsStyleImageLayers::composite],
     436           0 :                                        aValue, aSerialization);
     437             :     }
     438             : 
     439           0 :     if (mode) {
     440           0 :       aValue.Append(char16_t(' '));
     441           0 :       mode->mValue.AppendToString(aTable[nsStyleImageLayers::maskMode],
     442           0 :                                   aValue, aSerialization);
     443             :     }
     444             : 
     445           0 :     image = image->mNext;
     446           0 :     repeat = repeat->mNext;
     447           0 :     positionX = positionX->mNext;
     448           0 :     positionY = positionY->mNext;
     449           0 :     clip = clip->mNext;
     450           0 :     origin = origin->mNext;
     451           0 :     size = size->mNext;
     452           0 :     attachment = attachment ? attachment->mNext : nullptr;
     453           0 :     composite = composite ? composite->mNext : nullptr;
     454           0 :     mode = mode ? mode->mNext : nullptr;
     455             : 
     456           0 :     if (!image) {
     457             :       // This layer is an background layer
     458           0 :       if (aTable == nsStyleImageLayers::kBackgroundLayerTable) {
     459           0 :         if (repeat || positionX || positionY || clip || origin || size ||
     460             :             attachment) {
     461             :           // Uneven length lists, so can't be serialized as shorthand.
     462           0 :           aValue.Truncate();
     463           0 :           return;
     464             :         }
     465             :       // This layer is an mask layer
     466             :       } else {
     467             : #ifdef MOZ_ENABLE_MASK_AS_SHORTHAND
     468           0 :         MOZ_ASSERT(aTable == nsStyleImageLayers::kMaskLayerTable);
     469             : #else
     470             :         MOZ_ASSERT_UNREACHABLE("Should never get here when mask-as-shorthand is disable");
     471             : #endif
     472           0 :         if (repeat || positionX || positionY || clip || origin || size ||
     473           0 :             composite || mode) {
     474             :           // Uneven length lists, so can't be serialized as shorthand.
     475           0 :           aValue.Truncate();
     476           0 :           return;
     477             :         }
     478             :       }
     479           0 :       break;
     480             :     }
     481             : 
     482             :     // This layer is an background layer
     483           0 :     if (aTable == nsStyleImageLayers::kBackgroundLayerTable) {
     484           0 :       if (!repeat || !positionX || !positionY || !clip || !origin || !size ||
     485             :           !attachment) {
     486             :         // Uneven length lists, so can't be serialized as shorthand.
     487           0 :         aValue.Truncate();
     488           0 :         return;
     489             :       }
     490             :     // This layer is an mask layer
     491             :     } else {
     492             : #ifdef MOZ_ENABLE_MASK_AS_SHORTHAND
     493           0 :       MOZ_ASSERT(aTable == nsStyleImageLayers::kMaskLayerTable);
     494             : #else
     495             :       MOZ_ASSERT_UNREACHABLE("Should never get here when mask-as-shorthand is disable");
     496             : #endif
     497           0 :       if (!repeat || !positionX || !positionY || !clip || !origin || !size ||
     498           0 :           !composite || !mode) {
     499             :         // Uneven length lists, so can't be serialized as shorthand.
     500           0 :         aValue.Truncate();
     501           0 :         return;
     502             :       }
     503             :     }
     504           0 :     aValue.Append(char16_t(','));
     505           0 :     aValue.Append(char16_t(' '));
     506           0 :   }
     507             : }
     508             : 
     509             : void
     510           0 : Declaration::GetImageLayerPositionValue(
     511             :                    nsCSSCompressedDataBlock *data,
     512             :                    nsAString& aValue,
     513             :                    nsCSSValue::Serialization aSerialization,
     514             :                    const nsCSSPropertyID aTable[]) const
     515             : {
     516             :   // We know from above that all subproperties were specified.
     517             :   // However, we still can't represent that in the shorthand unless
     518             :   // they're all lists of the same length.  So if they're different
     519             :   // lengths, we need to bail out.
     520             :   const nsCSSValueList *positionX =
     521           0 :     data->ValueFor(aTable[nsStyleImageLayers::positionX])->GetListValue();
     522             :   const nsCSSValueList *positionY =
     523           0 :     data->ValueFor(aTable[nsStyleImageLayers::positionY])->GetListValue();
     524             :   for (;;) {
     525           0 :     AppendSingleImageLayerPositionValue(positionX->mValue, positionY->mValue,
     526           0 :                                         aTable, aValue, aSerialization);
     527           0 :     positionX = positionX->mNext;
     528           0 :     positionY = positionY->mNext;
     529             : 
     530           0 :     if (!positionX || !positionY) {
     531           0 :       if (positionX || positionY) {
     532             :         // Uneven length lists, so can't be serialized as shorthand.
     533           0 :         aValue.Truncate();
     534             :       }
     535           0 :       return;
     536             :     }
     537           0 :     aValue.Append(char16_t(','));
     538           0 :     aValue.Append(char16_t(' '));
     539             :   }
     540             : }
     541             : 
     542             : void
     543           0 : Declaration::GetPropertyValueInternal(
     544             :     nsCSSPropertyID aProperty, nsAString& aValue,
     545             :     nsCSSValue::Serialization aSerialization, bool* aIsTokenStream) const
     546             : {
     547           0 :   aValue.Truncate(0);
     548           0 :   if (aIsTokenStream) {
     549           0 :     *aIsTokenStream = false;
     550             :   }
     551             : 
     552             :   // simple properties are easy.
     553           0 :   if (!nsCSSProps::IsShorthand(aProperty)) {
     554           0 :     AppendValueToString(aProperty, aValue, aSerialization, aIsTokenStream);
     555           0 :     return;
     556             :   }
     557             : 
     558             :   // DOM Level 2 Style says (when describing CSS2Properties, although
     559             :   // not CSSStyleDeclaration.getPropertyValue):
     560             :   //   However, if there is no shorthand declaration that could be added
     561             :   //   to the ruleset without changing in any way the rules already
     562             :   //   declared in the ruleset (i.e., by adding longhand rules that were
     563             :   //   previously not declared in the ruleset), then the empty string
     564             :   //   should be returned for the shorthand property.
     565             :   // This means we need to check a number of cases:
     566             :   //   (1) Since a shorthand sets all sub-properties, if some of its
     567             :   //       subproperties were not specified, we must return the empty
     568             :   //       string.
     569             :   //   (2) Since 'inherit', 'initial' and 'unset' can only be specified
     570             :   //       as the values for entire properties, we need to return the
     571             :   //       empty string if some but not all of the subproperties have one
     572             :   //       of those values.
     573             :   //   (3) Since a single value only makes sense with or without
     574             :   //       !important, we return the empty string if some values are
     575             :   //       !important and some are not.
     576             :   // Since we're doing this check for 'inherit' and 'initial' up front,
     577             :   // we can also simplify the property serialization code by serializing
     578             :   // those values up front as well.
     579             :   //
     580             :   // Additionally, if a shorthand property was set using a value with a
     581             :   // variable reference and none of its component longhand properties were
     582             :   // then overridden on the declaration, we return the token stream
     583             :   // assigned to the shorthand.
     584           0 :   const nsCSSValue* tokenStream = nullptr;
     585           0 :   uint32_t totalCount = 0, importantCount = 0,
     586           0 :            initialCount = 0, inheritCount = 0, unsetCount = 0,
     587           0 :            matchingTokenStreamCount = 0, nonMatchingTokenStreamCount = 0;
     588           0 :   CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p, aProperty,
     589             :                                        CSSEnabledState::eForAllContent) {
     590           0 :     if (*p == eCSSProperty__x_system_font) {
     591             :       // The system-font subproperty doesn't count.
     592           0 :       continue;
     593             :     }
     594           0 :     ++totalCount;
     595           0 :     const nsCSSValue *val = mData->ValueFor(*p);
     596           0 :     MOZ_ASSERT(!val || !mImportantData || !mImportantData->ValueFor(*p),
     597             :                "can't be in both blocks");
     598           0 :     if (!val && mImportantData) {
     599           0 :       ++importantCount;
     600           0 :       val = mImportantData->ValueFor(*p);
     601             :     }
     602           0 :     if (!val) {
     603             :       // Case (1) above: some subproperties not specified.
     604           0 :       return;
     605             :     }
     606           0 :     if (val->GetUnit() == eCSSUnit_Inherit) {
     607           0 :       ++inheritCount;
     608           0 :     } else if (val->GetUnit() == eCSSUnit_Initial) {
     609           0 :       ++initialCount;
     610           0 :     } else if (val->GetUnit() == eCSSUnit_Unset) {
     611           0 :       ++unsetCount;
     612           0 :     } else if (val->GetUnit() == eCSSUnit_TokenStream) {
     613           0 :       if (val->GetTokenStreamValue()->mShorthandPropertyID == aProperty) {
     614           0 :         tokenStream = val;
     615           0 :         ++matchingTokenStreamCount;
     616             :       } else {
     617           0 :         ++nonMatchingTokenStreamCount;
     618             :       }
     619             :     }
     620             :   }
     621           0 :   if (importantCount != 0 && importantCount != totalCount) {
     622             :     // Case (3), no consistent importance.
     623           0 :     return;
     624             :   }
     625           0 :   if (initialCount == totalCount) {
     626             :     // Simplify serialization below by serializing initial up-front.
     627           0 :     nsCSSValue(eCSSUnit_Initial).AppendToString(eCSSProperty_UNKNOWN, aValue,
     628           0 :                                                 nsCSSValue::eNormalized);
     629           0 :     return;
     630             :   }
     631           0 :   if (inheritCount == totalCount) {
     632             :     // Simplify serialization below by serializing inherit up-front.
     633           0 :     nsCSSValue(eCSSUnit_Inherit).AppendToString(eCSSProperty_UNKNOWN, aValue,
     634           0 :                                                 nsCSSValue::eNormalized);
     635           0 :     return;
     636             :   }
     637           0 :   if (unsetCount == totalCount) {
     638             :     // Simplify serialization below by serializing unset up-front.
     639           0 :     nsCSSValue(eCSSUnit_Unset).AppendToString(eCSSProperty_UNKNOWN, aValue,
     640           0 :                                               nsCSSValue::eNormalized);
     641           0 :     return;
     642             :   }
     643           0 :   if (initialCount != 0 || inheritCount != 0 ||
     644           0 :       unsetCount != 0 || nonMatchingTokenStreamCount != 0) {
     645             :     // Case (2): partially initial, inherit, unset or token stream.
     646           0 :     return;
     647             :   }
     648           0 :   if (tokenStream) {
     649           0 :     if (matchingTokenStreamCount == totalCount) {
     650             :       // Shorthand was specified using variable references and all of its
     651             :       // longhand components were set by the shorthand.
     652           0 :       if (aIsTokenStream) {
     653           0 :         *aIsTokenStream = true;
     654             :       }
     655           0 :       aValue.Append(tokenStream->GetTokenStreamValue()->mTokenStream);
     656             :     } else {
     657             :       // In all other cases, serialize to the empty string.
     658             :     }
     659           0 :     return;
     660             :   }
     661             : 
     662           0 :   nsCSSCompressedDataBlock *data = importantCount ? mImportantData : mData;
     663           0 :   switch (aProperty) {
     664             :     case eCSSProperty_margin:
     665             :     case eCSSProperty_padding:
     666             :     case eCSSProperty_border_color:
     667             :     case eCSSProperty_border_style:
     668             :     case eCSSProperty_border_width: {
     669             :       const nsCSSPropertyID* subprops =
     670           0 :         nsCSSProps::SubpropertyEntryFor(aProperty);
     671           0 :       MOZ_ASSERT(nsCSSProps::GetStringValue(subprops[0]).Find("-top") !=
     672             :                  kNotFound, "first subprop must be top");
     673           0 :       MOZ_ASSERT(nsCSSProps::GetStringValue(subprops[1]).Find("-right") !=
     674             :                  kNotFound, "second subprop must be right");
     675           0 :       MOZ_ASSERT(nsCSSProps::GetStringValue(subprops[2]).Find("-bottom") !=
     676             :                  kNotFound, "third subprop must be bottom");
     677           0 :       MOZ_ASSERT(nsCSSProps::GetStringValue(subprops[3]).Find("-left") !=
     678             :                  kNotFound, "fourth subprop must be left");
     679             :       const nsCSSValue* vals[4] = {
     680           0 :         data->ValueFor(subprops[0]),
     681           0 :         data->ValueFor(subprops[1]),
     682           0 :         data->ValueFor(subprops[2]),
     683           0 :         data->ValueFor(subprops[3])
     684           0 :       };
     685             :       nsCSSValue::AppendSidesShorthandToString(subprops, vals, aValue,
     686           0 :                                                aSerialization);
     687           0 :       break;
     688             :     }
     689             :     case eCSSProperty_border_radius:
     690             :     case eCSSProperty__moz_outline_radius: {
     691             :       const nsCSSPropertyID* subprops =
     692           0 :         nsCSSProps::SubpropertyEntryFor(aProperty);
     693             :       const nsCSSValue* vals[4] = {
     694           0 :         data->ValueFor(subprops[0]),
     695           0 :         data->ValueFor(subprops[1]),
     696           0 :         data->ValueFor(subprops[2]),
     697           0 :         data->ValueFor(subprops[3])
     698           0 :       };
     699             :       nsCSSValue::AppendBasicShapeRadiusToString(subprops, vals, aValue,
     700           0 :                                                  aSerialization);
     701           0 :       break;
     702             :     }
     703             :     case eCSSProperty_border_image: {
     704             :       // Even though there are some cases where we could omit
     705             :       // 'border-image-source' (when it's none), it's probably not a
     706             :       // good idea since it's likely to be confusing.  It would also
     707             :       // require adding the extra check that we serialize *something*.
     708             :       AppendValueToString(eCSSProperty_border_image_source, aValue,
     709           0 :                           aSerialization);
     710             : 
     711           0 :       bool sliceDefault = data->HasDefaultBorderImageSlice();
     712           0 :       bool widthDefault = data->HasDefaultBorderImageWidth();
     713           0 :       bool outsetDefault = data->HasDefaultBorderImageOutset();
     714             : 
     715           0 :       if (!sliceDefault || !widthDefault || !outsetDefault) {
     716           0 :         aValue.Append(char16_t(' '));
     717             :         AppendValueToString(eCSSProperty_border_image_slice, aValue,
     718           0 :                             aSerialization);
     719           0 :         if (!widthDefault || !outsetDefault) {
     720           0 :           aValue.AppendLiteral(" /");
     721           0 :           if (!widthDefault) {
     722           0 :             aValue.Append(char16_t(' '));
     723             :             AppendValueToString(eCSSProperty_border_image_width, aValue,
     724           0 :                                 aSerialization);
     725             :           }
     726           0 :           if (!outsetDefault) {
     727           0 :             aValue.AppendLiteral(" / ");
     728             :             AppendValueToString(eCSSProperty_border_image_outset, aValue,
     729           0 :                                 aSerialization);
     730             :           }
     731             :         }
     732             :       }
     733             : 
     734           0 :       bool repeatDefault = data->HasDefaultBorderImageRepeat();
     735           0 :       if (!repeatDefault) {
     736           0 :         aValue.Append(char16_t(' '));
     737             :         AppendValueToString(eCSSProperty_border_image_repeat, aValue,
     738           0 :                             aSerialization);
     739             :       }
     740           0 :       break;
     741             :     }
     742             :     case eCSSProperty_border: {
     743             :       // If we have a non-default value for any of the properties that
     744             :       // this shorthand sets but cannot specify, we have to return the
     745             :       // empty string.
     746           0 :       if (data->ValueFor(eCSSProperty_border_image_source)->GetUnit() !=
     747           0 :             eCSSUnit_None ||
     748           0 :           !data->HasDefaultBorderImageSlice() ||
     749           0 :           !data->HasDefaultBorderImageWidth() ||
     750           0 :           !data->HasDefaultBorderImageOutset() ||
     751           0 :           !data->HasDefaultBorderImageRepeat() ||
     752           0 :           data->ValueFor(eCSSProperty__moz_border_top_colors)->GetUnit() !=
     753           0 :             eCSSUnit_None ||
     754           0 :           data->ValueFor(eCSSProperty__moz_border_right_colors)->GetUnit() !=
     755           0 :             eCSSUnit_None ||
     756           0 :           data->ValueFor(eCSSProperty__moz_border_bottom_colors)->GetUnit() !=
     757           0 :             eCSSUnit_None ||
     758           0 :           data->ValueFor(eCSSProperty__moz_border_left_colors)->GetUnit() !=
     759             :             eCSSUnit_None) {
     760           0 :         break;
     761             :       }
     762             : 
     763             :       const nsCSSPropertyID* subproptables[3] = {
     764           0 :         nsCSSProps::SubpropertyEntryFor(eCSSProperty_border_color),
     765           0 :         nsCSSProps::SubpropertyEntryFor(eCSSProperty_border_style),
     766           0 :         nsCSSProps::SubpropertyEntryFor(eCSSProperty_border_width)
     767           0 :       };
     768           0 :       bool match = true;
     769           0 :       for (const nsCSSPropertyID** subprops = subproptables,
     770           0 :                **subprops_end = ArrayEnd(subproptables);
     771           0 :            subprops < subprops_end; ++subprops) {
     772           0 :         const nsCSSValue *firstSide = data->ValueFor((*subprops)[0]);
     773           0 :         for (int32_t side = 1; side < 4; ++side) {
     774             :           const nsCSSValue *otherSide =
     775           0 :             data->ValueFor((*subprops)[side]);
     776           0 :           if (*firstSide != *otherSide)
     777           0 :             match = false;
     778             :         }
     779             :       }
     780           0 :       if (!match) {
     781             :         // We can't express what we have in the border shorthand
     782           0 :         break;
     783             :       }
     784             :       // tweak aProperty and fall through
     785           0 :       aProperty = eCSSProperty_border_top;
     786             :       MOZ_FALLTHROUGH;
     787             :     }
     788             :     case eCSSProperty_border_top:
     789             :     case eCSSProperty_border_right:
     790             :     case eCSSProperty_border_bottom:
     791             :     case eCSSProperty_border_left:
     792             :     case eCSSProperty_border_inline_start:
     793             :     case eCSSProperty_border_inline_end:
     794             :     case eCSSProperty_border_block_start:
     795             :     case eCSSProperty_border_block_end:
     796             :     case eCSSProperty_column_rule:
     797             :     case eCSSProperty_outline: {
     798             :       const nsCSSPropertyID* subprops =
     799           0 :         nsCSSProps::SubpropertyEntryFor(aProperty);
     800           0 :       MOZ_ASSERT(StringEndsWith(nsCSSProps::GetStringValue(subprops[2]),
     801             :                                 NS_LITERAL_CSTRING("-color")),
     802             :                  "third subprop must be the color property");
     803             : 
     804           0 :       bool ok = AppendValueToString(subprops[0], aValue, aSerialization);
     805           0 :       if (ok) {
     806           0 :         aValue.Append(u' ');
     807           0 :         ok = AppendValueToString(subprops[1], aValue, aSerialization);
     808           0 :         if (ok) {
     809           0 :           const nsCSSValue *colorValue = data->ValueFor(subprops[2]);
     810             :           bool isCurrentColor =
     811           0 :             colorValue->GetUnit() == eCSSUnit_EnumColor &&
     812           0 :             colorValue->GetIntValue() == NS_COLOR_CURRENTCOLOR;
     813             : 
     814             :           // Don't output a third value when it's currentcolor.
     815           0 :           if (!isCurrentColor) {
     816           0 :             aValue.Append(u' ');
     817           0 :             ok = AppendValueToString(subprops[2], aValue, aSerialization);
     818             :           }
     819             :         }
     820             :       }
     821             : 
     822           0 :       if (!ok) {
     823           0 :         aValue.Truncate();
     824             :       }
     825           0 :       break;
     826             :     }
     827             :     case eCSSProperty_background: {
     828             :       GetImageLayerValue(data, aValue, aSerialization,
     829           0 :                          nsStyleImageLayers::kBackgroundLayerTable);
     830           0 :       break;
     831             :     }
     832             :     case eCSSProperty_background_position: {
     833             :       GetImageLayerPositionValue(data, aValue, aSerialization,
     834           0 :                                  nsStyleImageLayers::kBackgroundLayerTable);
     835           0 :       break;
     836             :     }
     837             : #ifdef MOZ_ENABLE_MASK_AS_SHORTHAND
     838             :     case eCSSProperty_mask: {
     839             :       GetImageLayerValue(data, aValue, aSerialization,
     840           0 :                          nsStyleImageLayers::kMaskLayerTable);
     841           0 :       break;
     842             :     }
     843             :     case eCSSProperty_mask_position: {
     844             :       GetImageLayerPositionValue(data, aValue, aSerialization,
     845           0 :                                  nsStyleImageLayers::kMaskLayerTable);
     846           0 :       break;
     847             :     }
     848             : #endif
     849             :     case eCSSProperty_font: {
     850             :       // systemFont might not be present; other values are guaranteed to be
     851             :       // available based on the shorthand check at the beginning of the
     852             :       // function, as long as the prop is enabled
     853             :       const nsCSSValue *systemFont =
     854           0 :         data->ValueFor(eCSSProperty__x_system_font);
     855             :       const nsCSSValue *style =
     856           0 :         data->ValueFor(eCSSProperty_font_style);
     857             :       const nsCSSValue *weight =
     858           0 :         data->ValueFor(eCSSProperty_font_weight);
     859             :       const nsCSSValue *size =
     860           0 :         data->ValueFor(eCSSProperty_font_size);
     861             :       const nsCSSValue *lh =
     862           0 :         data->ValueFor(eCSSProperty_line_height);
     863             :       const nsCSSValue *family =
     864           0 :         data->ValueFor(eCSSProperty_font_family);
     865             :       const nsCSSValue *stretch =
     866           0 :         data->ValueFor(eCSSProperty_font_stretch);
     867             :       const nsCSSValue *sizeAdjust =
     868           0 :         data->ValueFor(eCSSProperty_font_size_adjust);
     869             :       const nsCSSValue *featureSettings =
     870           0 :         data->ValueFor(eCSSProperty_font_feature_settings);
     871             :       const nsCSSValue *languageOverride =
     872           0 :         data->ValueFor(eCSSProperty_font_language_override);
     873             :       const nsCSSValue *fontKerning =
     874           0 :         data->ValueFor(eCSSProperty_font_kerning);
     875             :       const nsCSSValue *fontVariantAlternates =
     876           0 :         data->ValueFor(eCSSProperty_font_variant_alternates);
     877             :       const nsCSSValue *fontVariantCaps =
     878           0 :         data->ValueFor(eCSSProperty_font_variant_caps);
     879             :       const nsCSSValue *fontVariantEastAsian =
     880           0 :         data->ValueFor(eCSSProperty_font_variant_east_asian);
     881             :       const nsCSSValue *fontVariantLigatures =
     882           0 :         data->ValueFor(eCSSProperty_font_variant_ligatures);
     883             :       const nsCSSValue *fontVariantNumeric =
     884           0 :         data->ValueFor(eCSSProperty_font_variant_numeric);
     885             :       const nsCSSValue *fontVariantPosition =
     886           0 :         data->ValueFor(eCSSProperty_font_variant_position);
     887             : 
     888           0 :       if (systemFont &&
     889           0 :           systemFont->GetUnit() != eCSSUnit_None &&
     890           0 :           systemFont->GetUnit() != eCSSUnit_Null) {
     891           0 :         if (style->GetUnit() != eCSSUnit_System_Font ||
     892           0 :             weight->GetUnit() != eCSSUnit_System_Font ||
     893           0 :             size->GetUnit() != eCSSUnit_System_Font ||
     894           0 :             lh->GetUnit() != eCSSUnit_System_Font ||
     895           0 :             family->GetUnit() != eCSSUnit_System_Font ||
     896           0 :             stretch->GetUnit() != eCSSUnit_System_Font ||
     897           0 :             sizeAdjust->GetUnit() != eCSSUnit_System_Font ||
     898           0 :             featureSettings->GetUnit() != eCSSUnit_System_Font ||
     899           0 :             languageOverride->GetUnit() != eCSSUnit_System_Font ||
     900           0 :             fontKerning->GetUnit() != eCSSUnit_System_Font ||
     901           0 :             fontVariantAlternates->GetUnit() != eCSSUnit_System_Font ||
     902           0 :             fontVariantCaps->GetUnit() != eCSSUnit_System_Font ||
     903           0 :             fontVariantEastAsian->GetUnit() != eCSSUnit_System_Font ||
     904           0 :             fontVariantLigatures->GetUnit() != eCSSUnit_System_Font ||
     905           0 :             fontVariantNumeric->GetUnit() != eCSSUnit_System_Font ||
     906           0 :             fontVariantPosition->GetUnit() != eCSSUnit_System_Font) {
     907             :           // This can't be represented as a shorthand.
     908           0 :           return;
     909             :         }
     910             :         systemFont->AppendToString(eCSSProperty__x_system_font, aValue,
     911           0 :                                    aSerialization);
     912             :       } else {
     913             :         // properties reset by this shorthand property to their
     914             :         // initial values but not represented in its syntax
     915           0 :         if (sizeAdjust->GetUnit() != eCSSUnit_None ||
     916           0 :             featureSettings->GetUnit() != eCSSUnit_Normal ||
     917           0 :             languageOverride->GetUnit() != eCSSUnit_Normal ||
     918           0 :             fontKerning->GetIntValue() != NS_FONT_KERNING_AUTO ||
     919           0 :             fontVariantAlternates->GetUnit() != eCSSUnit_Normal ||
     920           0 :             fontVariantEastAsian->GetUnit() != eCSSUnit_Normal ||
     921           0 :             fontVariantLigatures->GetUnit() != eCSSUnit_Normal ||
     922           0 :             fontVariantNumeric->GetUnit() != eCSSUnit_Normal ||
     923           0 :             fontVariantPosition->GetUnit() != eCSSUnit_Normal) {
     924           0 :           return;
     925             :         }
     926             : 
     927             :         // only a normal or small-caps values of font-variant-caps can
     928             :         // be represented in the font shorthand
     929           0 :         if (fontVariantCaps->GetUnit() != eCSSUnit_Normal &&
     930           0 :             (fontVariantCaps->GetUnit() != eCSSUnit_Enumerated ||
     931           0 :              fontVariantCaps->GetIntValue() != NS_FONT_VARIANT_CAPS_SMALLCAPS)) {
     932           0 :           return;
     933             :         }
     934             : 
     935           0 :         if (style->GetUnit() != eCSSUnit_Enumerated ||
     936           0 :             style->GetIntValue() != NS_FONT_STYLE_NORMAL) {
     937             :           style->AppendToString(eCSSProperty_font_style, aValue,
     938           0 :                                 aSerialization);
     939           0 :           aValue.Append(char16_t(' '));
     940             :         }
     941           0 :         if (fontVariantCaps->GetUnit() != eCSSUnit_Normal) {
     942             :           fontVariantCaps->AppendToString(eCSSProperty_font_variant_caps, aValue,
     943           0 :                                   aSerialization);
     944           0 :           aValue.Append(char16_t(' '));
     945             :         }
     946           0 :         if (weight->GetUnit() != eCSSUnit_Enumerated ||
     947           0 :             weight->GetIntValue() != NS_FONT_WEIGHT_NORMAL) {
     948             :           weight->AppendToString(eCSSProperty_font_weight, aValue,
     949           0 :                                  aSerialization);
     950           0 :           aValue.Append(char16_t(' '));
     951             :         }
     952           0 :         if (stretch->GetUnit() != eCSSUnit_Enumerated ||
     953           0 :             stretch->GetIntValue() != NS_FONT_STRETCH_NORMAL) {
     954             :           stretch->AppendToString(eCSSProperty_font_stretch, aValue,
     955           0 :                                   aSerialization);
     956           0 :           aValue.Append(char16_t(' '));
     957             :         }
     958           0 :         size->AppendToString(eCSSProperty_font_size, aValue, aSerialization);
     959           0 :         if (lh->GetUnit() != eCSSUnit_Normal) {
     960           0 :           aValue.Append(char16_t('/'));
     961           0 :           lh->AppendToString(eCSSProperty_line_height, aValue, aSerialization);
     962             :         }
     963           0 :         aValue.Append(char16_t(' '));
     964             :         family->AppendToString(eCSSProperty_font_family, aValue,
     965           0 :                                aSerialization);
     966             :       }
     967           0 :       break;
     968             :     }
     969             :     case eCSSProperty_font_variant: {
     970             :       const nsCSSPropertyID *subprops =
     971           0 :         nsCSSProps::SubpropertyEntryFor(aProperty);
     972             :       const nsCSSValue *fontVariantLigatures =
     973           0 :         data->ValueFor(eCSSProperty_font_variant_ligatures);
     974             : 
     975             :       // all subproperty values normal? system font?
     976           0 :       bool normalLigs = true, normalNonLigs = true, systemFont = true,
     977           0 :            hasSystem = false;
     978           0 :       for (const nsCSSPropertyID *sp = subprops; *sp != eCSSProperty_UNKNOWN; sp++) {
     979           0 :         const nsCSSValue *spVal = data->ValueFor(*sp);
     980           0 :         bool isNormal = (spVal->GetUnit() == eCSSUnit_Normal);
     981           0 :         if (*sp == eCSSProperty_font_variant_ligatures) {
     982           0 :           normalLigs = normalLigs && isNormal;
     983             :         } else {
     984           0 :           normalNonLigs = normalNonLigs && isNormal;
     985             :         }
     986           0 :         bool isSystem = (spVal->GetUnit() == eCSSUnit_System_Font);
     987           0 :         systemFont = systemFont && isSystem;
     988           0 :         hasSystem = hasSystem || isSystem;
     989             :       }
     990             : 
     991             :       bool ligsNone =
     992           0 :         fontVariantLigatures->GetUnit() == eCSSUnit_None;
     993             : 
     994             :       // normal, none, or system font ==> single value
     995           0 :       if ((normalLigs && normalNonLigs) ||
     996           0 :           (normalNonLigs && ligsNone) ||
     997             :           systemFont) {
     998             :         fontVariantLigatures->AppendToString(eCSSProperty_font_variant_ligatures,
     999             :                                              aValue,
    1000           0 :                                              aSerialization);
    1001           0 :       } else if (ligsNone || hasSystem) {
    1002             :         // ligatures none but other values are non-normal ==> empty
    1003             :         // at least one but not all values are system font ==> empty
    1004           0 :         return;
    1005             :       } else {
    1006             :         // iterate over and append non-normal values
    1007           0 :         bool appendSpace = false;
    1008           0 :         for (const nsCSSPropertyID *sp = subprops;
    1009           0 :              *sp != eCSSProperty_UNKNOWN; sp++) {
    1010           0 :           const nsCSSValue *spVal = data->ValueFor(*sp);
    1011           0 :           if (spVal && spVal->GetUnit() != eCSSUnit_Normal) {
    1012           0 :             if (appendSpace) {
    1013           0 :               aValue.Append(char16_t(' '));
    1014             :             } else {
    1015           0 :               appendSpace = true;
    1016             :             }
    1017           0 :             spVal->AppendToString(*sp, aValue, aSerialization);
    1018             :           }
    1019             :         }
    1020             :       }
    1021           0 :       break;
    1022             :     }
    1023             :     case eCSSProperty_list_style:
    1024           0 :       if (AppendValueToString(eCSSProperty_list_style_position, aValue,
    1025             :                               aSerialization)) {
    1026           0 :         aValue.Append(char16_t(' '));
    1027             :       }
    1028           0 :       if (AppendValueToString(eCSSProperty_list_style_image, aValue,
    1029             :                               aSerialization)) {
    1030           0 :         aValue.Append(char16_t(' '));
    1031             :       }
    1032             :       AppendValueToString(eCSSProperty_list_style_type, aValue,
    1033           0 :                           aSerialization);
    1034           0 :       break;
    1035             :     case eCSSProperty_overflow: {
    1036             :       const nsCSSValue &xValue =
    1037           0 :         *data->ValueFor(eCSSProperty_overflow_x);
    1038             :       const nsCSSValue &yValue =
    1039           0 :         *data->ValueFor(eCSSProperty_overflow_y);
    1040           0 :       if (xValue == yValue)
    1041           0 :         xValue.AppendToString(eCSSProperty_overflow_x, aValue, aSerialization);
    1042           0 :       break;
    1043             :     }
    1044             :     case eCSSProperty_text_decoration: {
    1045             :       const nsCSSValue *decorationColor =
    1046           0 :         data->ValueFor(eCSSProperty_text_decoration_color);
    1047             :       const nsCSSValue *decorationStyle =
    1048           0 :         data->ValueFor(eCSSProperty_text_decoration_style);
    1049             : 
    1050           0 :       MOZ_ASSERT(decorationStyle->GetUnit() == eCSSUnit_Enumerated,
    1051             :                  "bad text-decoration-style unit");
    1052             : 
    1053             :       AppendValueToString(eCSSProperty_text_decoration_line, aValue,
    1054           0 :                           aSerialization);
    1055           0 :       if (decorationStyle->GetIntValue() !=
    1056             :             NS_STYLE_TEXT_DECORATION_STYLE_SOLID) {
    1057           0 :         aValue.Append(char16_t(' '));
    1058             :         AppendValueToString(eCSSProperty_text_decoration_style, aValue,
    1059           0 :                             aSerialization);
    1060             :       }
    1061           0 :       if (decorationColor->GetUnit() != eCSSUnit_EnumColor ||
    1062           0 :           decorationColor->GetIntValue() != NS_COLOR_CURRENTCOLOR) {
    1063           0 :         aValue.Append(char16_t(' '));
    1064             :         AppendValueToString(eCSSProperty_text_decoration_color, aValue,
    1065           0 :                             aSerialization);
    1066             :       }
    1067           0 :       break;
    1068             :     }
    1069             :     case eCSSProperty_transition: {
    1070             :       const nsCSSValue *transProp =
    1071           0 :         data->ValueFor(eCSSProperty_transition_property);
    1072             :       const nsCSSValue *transDuration =
    1073           0 :         data->ValueFor(eCSSProperty_transition_duration);
    1074             :       const nsCSSValue *transTiming =
    1075           0 :         data->ValueFor(eCSSProperty_transition_timing_function);
    1076             :       const nsCSSValue *transDelay =
    1077           0 :         data->ValueFor(eCSSProperty_transition_delay);
    1078             : 
    1079           0 :       MOZ_ASSERT(transDuration->GetUnit() == eCSSUnit_List ||
    1080             :                  transDuration->GetUnit() == eCSSUnit_ListDep,
    1081             :                  "bad t-duration unit");
    1082           0 :       MOZ_ASSERT(transTiming->GetUnit() == eCSSUnit_List ||
    1083             :                  transTiming->GetUnit() == eCSSUnit_ListDep,
    1084             :                  "bad t-timing unit");
    1085           0 :       MOZ_ASSERT(transDelay->GetUnit() == eCSSUnit_List ||
    1086             :                  transDelay->GetUnit() == eCSSUnit_ListDep,
    1087             :                  "bad t-delay unit");
    1088             : 
    1089           0 :       const nsCSSValueList* dur = transDuration->GetListValue();
    1090           0 :       const nsCSSValueList* tim = transTiming->GetListValue();
    1091           0 :       const nsCSSValueList* del = transDelay->GetListValue();
    1092             : 
    1093           0 :       if (transProp->GetUnit() == eCSSUnit_None ||
    1094           0 :           transProp->GetUnit() == eCSSUnit_All) {
    1095             :         // If any of the other three lists has more than one element,
    1096             :         // we can't use the shorthand.
    1097           0 :         if (!dur->mNext && !tim->mNext && !del->mNext) {
    1098             :           transProp->AppendToString(eCSSProperty_transition_property, aValue,
    1099           0 :                                     aSerialization);
    1100           0 :           aValue.Append(char16_t(' '));
    1101           0 :           dur->mValue.AppendToString(eCSSProperty_transition_duration,aValue,
    1102           0 :                                      aSerialization);
    1103           0 :           aValue.Append(char16_t(' '));
    1104           0 :           tim->mValue.AppendToString(eCSSProperty_transition_timing_function,
    1105           0 :                                      aValue, aSerialization);
    1106           0 :           aValue.Append(char16_t(' '));
    1107           0 :           del->mValue.AppendToString(eCSSProperty_transition_delay, aValue,
    1108           0 :                                      aSerialization);
    1109           0 :           aValue.Append(char16_t(' '));
    1110             :         } else {
    1111           0 :           aValue.Truncate();
    1112             :         }
    1113             :       } else {
    1114           0 :         MOZ_ASSERT(transProp->GetUnit() == eCSSUnit_List ||
    1115             :                    transProp->GetUnit() == eCSSUnit_ListDep,
    1116             :                    "bad t-prop unit");
    1117           0 :         const nsCSSValueList* pro = transProp->GetListValue();
    1118             :         for (;;) {
    1119           0 :           pro->mValue.AppendToString(eCSSProperty_transition_property,
    1120           0 :                                         aValue, aSerialization);
    1121           0 :           aValue.Append(char16_t(' '));
    1122           0 :           dur->mValue.AppendToString(eCSSProperty_transition_duration,
    1123           0 :                                         aValue, aSerialization);
    1124           0 :           aValue.Append(char16_t(' '));
    1125           0 :           tim->mValue.AppendToString(eCSSProperty_transition_timing_function,
    1126           0 :                                         aValue, aSerialization);
    1127           0 :           aValue.Append(char16_t(' '));
    1128           0 :           del->mValue.AppendToString(eCSSProperty_transition_delay,
    1129           0 :                                         aValue, aSerialization);
    1130           0 :           pro = pro->mNext;
    1131           0 :           dur = dur->mNext;
    1132           0 :           tim = tim->mNext;
    1133           0 :           del = del->mNext;
    1134           0 :           if (!pro || !dur || !tim || !del) {
    1135             :             break;
    1136             :           }
    1137           0 :           aValue.AppendLiteral(", ");
    1138             :         }
    1139           0 :         if (pro || dur || tim || del) {
    1140             :           // Lists not all the same length, can't use shorthand.
    1141           0 :           aValue.Truncate();
    1142             :         }
    1143             :       }
    1144           0 :       break;
    1145             :     }
    1146             :     case eCSSProperty_animation: {
    1147             :       const nsCSSPropertyID* subprops =
    1148           0 :         nsCSSProps::SubpropertyEntryFor(eCSSProperty_animation);
    1149             :       static const size_t numProps = 8;
    1150           0 :       MOZ_ASSERT(subprops[numProps] == eCSSProperty_UNKNOWN,
    1151             :                  "unexpected number of subproperties");
    1152             :       const nsCSSValue* values[numProps];
    1153             :       const nsCSSValueList* lists[numProps];
    1154             : 
    1155           0 :       for (uint32_t i = 0; i < numProps; ++i) {
    1156           0 :         values[i] = data->ValueFor(subprops[i]);
    1157           0 :         MOZ_ASSERT(values[i]->GetUnit() == eCSSUnit_List ||
    1158             :                    values[i]->GetUnit() == eCSSUnit_ListDep,
    1159             :                    "bad a-duration unit");
    1160           0 :         lists[i] = values[i]->GetListValue();
    1161             :       }
    1162             : 
    1163             :       for (;;) {
    1164             :         // We must serialize 'animation-name' last in case it has
    1165             :         // a value that conflicts with one of the other keyword properties.
    1166           0 :         MOZ_ASSERT(subprops[numProps - 1] == eCSSProperty_animation_name,
    1167             :                    "animation-name must be last");
    1168           0 :         bool done = false;
    1169           0 :         for (uint32_t i = 0;;) {
    1170           0 :           lists[i]->mValue.AppendToString(subprops[i], aValue, aSerialization);
    1171           0 :           lists[i] = lists[i]->mNext;
    1172           0 :           if (!lists[i]) {
    1173           0 :             done = true;
    1174             :           }
    1175           0 :           if (++i == numProps) {
    1176           0 :             break;
    1177             :           }
    1178           0 :           aValue.Append(char16_t(' '));
    1179             :         }
    1180           0 :         if (done) {
    1181           0 :           break;
    1182             :         }
    1183           0 :         aValue.AppendLiteral(", ");
    1184           0 :       }
    1185           0 :       for (uint32_t i = 0; i < numProps; ++i) {
    1186           0 :         if (lists[i]) {
    1187             :           // Lists not all the same length, can't use shorthand.
    1188           0 :           aValue.Truncate();
    1189           0 :           break;
    1190             :         }
    1191             :       }
    1192           0 :       break;
    1193             :     }
    1194             :     case eCSSProperty_marker: {
    1195             :       const nsCSSValue &endValue =
    1196           0 :         *data->ValueFor(eCSSProperty_marker_end);
    1197             :       const nsCSSValue &midValue =
    1198           0 :         *data->ValueFor(eCSSProperty_marker_mid);
    1199             :       const nsCSSValue &startValue =
    1200           0 :         *data->ValueFor(eCSSProperty_marker_start);
    1201           0 :       if (endValue == midValue && midValue == startValue)
    1202           0 :         AppendValueToString(eCSSProperty_marker_end, aValue, aSerialization);
    1203           0 :       break;
    1204             :     }
    1205             :     case eCSSProperty_columns: {
    1206             :       // Two values, column-count and column-width, separated by a space.
    1207             :       const nsCSSPropertyID* subprops =
    1208           0 :         nsCSSProps::SubpropertyEntryFor(aProperty);
    1209           0 :       AppendValueToString(subprops[0], aValue, aSerialization);
    1210           0 :       aValue.Append(char16_t(' '));
    1211           0 :       AppendValueToString(subprops[1], aValue, aSerialization);
    1212           0 :       break;
    1213             :     }
    1214             :     case eCSSProperty_flex: {
    1215             :       // flex-grow, flex-shrink, flex-basis, separated by single space
    1216             :       const nsCSSPropertyID* subprops =
    1217           0 :         nsCSSProps::SubpropertyEntryFor(aProperty);
    1218             : 
    1219           0 :       AppendValueToString(subprops[0], aValue, aSerialization);
    1220           0 :       aValue.Append(char16_t(' '));
    1221           0 :       AppendValueToString(subprops[1], aValue, aSerialization);
    1222           0 :       aValue.Append(char16_t(' '));
    1223           0 :       AppendValueToString(subprops[2], aValue, aSerialization);
    1224           0 :       break;
    1225             :     }
    1226             :     case eCSSProperty_flex_flow: {
    1227             :       // flex-direction, flex-wrap, separated by single space
    1228             :       const nsCSSPropertyID* subprops =
    1229           0 :         nsCSSProps::SubpropertyEntryFor(aProperty);
    1230           0 :       MOZ_ASSERT(subprops[2] == eCSSProperty_UNKNOWN,
    1231             :                  "must have exactly two subproperties");
    1232             : 
    1233           0 :       AppendValueToString(subprops[0], aValue, aSerialization);
    1234           0 :       aValue.Append(char16_t(' '));
    1235           0 :       AppendValueToString(subprops[1], aValue, aSerialization);
    1236           0 :       break;
    1237             :     }
    1238             :     case eCSSProperty_grid_row:
    1239             :     case eCSSProperty_grid_column: {
    1240             :       // grid-{row,column}-start, grid-{row,column}-end, separated by a slash
    1241             :       const nsCSSPropertyID* subprops =
    1242           0 :         nsCSSProps::SubpropertyEntryFor(aProperty);
    1243           0 :       MOZ_ASSERT(subprops[2] == eCSSProperty_UNKNOWN,
    1244             :                  "must have exactly two subproperties");
    1245             : 
    1246             :       // TODO: should we simplify when possible?
    1247           0 :       AppendValueToString(subprops[0], aValue, aSerialization);
    1248           0 :       aValue.AppendLiteral(" / ");
    1249           0 :       AppendValueToString(subprops[1], aValue, aSerialization);
    1250           0 :       break;
    1251             :     }
    1252             :     case eCSSProperty_grid_area: {
    1253             :       const nsCSSPropertyID* subprops =
    1254           0 :         nsCSSProps::SubpropertyEntryFor(aProperty);
    1255           0 :       MOZ_ASSERT(subprops[4] == eCSSProperty_UNKNOWN,
    1256             :                  "must have exactly four subproperties");
    1257             : 
    1258             :       // TODO: should we simplify when possible?
    1259           0 :       AppendValueToString(subprops[0], aValue, aSerialization);
    1260           0 :       aValue.AppendLiteral(" / ");
    1261           0 :       AppendValueToString(subprops[1], aValue, aSerialization);
    1262           0 :       aValue.AppendLiteral(" / ");
    1263           0 :       AppendValueToString(subprops[2], aValue, aSerialization);
    1264           0 :       aValue.AppendLiteral(" / ");
    1265           0 :       AppendValueToString(subprops[3], aValue, aSerialization);
    1266           0 :       break;
    1267             :     }
    1268             : 
    1269             :     // The 'grid' shorthand has 3 different possibilities for syntax:
    1270             :     // #1 <'grid-template'>
    1271             :     // #2 <'grid-template-rows'> / [ auto-flow && dense? ] <'grid-auto-columns'>?
    1272             :     // #3 [ auto-flow && dense? ] <'grid-auto-rows'>? / <'grid-template-columns'>
    1273             :     case eCSSProperty_grid: {
    1274             :       const nsCSSValue& columnGapValue =
    1275           0 :         *data->ValueFor(eCSSProperty_grid_column_gap);
    1276           0 :       if (columnGapValue.GetUnit() != eCSSUnit_Pixel ||
    1277           0 :           columnGapValue.GetFloatValue() != 0.0f) {
    1278           0 :         return; // Not serializable, bail.
    1279             :       }
    1280             :       const nsCSSValue& rowGapValue =
    1281           0 :         *data->ValueFor(eCSSProperty_grid_row_gap);
    1282           0 :       if (rowGapValue.GetUnit() != eCSSUnit_Pixel ||
    1283           0 :           rowGapValue.GetFloatValue() != 0.0f) {
    1284           0 :         return; // Not serializable, bail.
    1285             :       }
    1286             :       const nsCSSValue& areasValue =
    1287           0 :         *data->ValueFor(eCSSProperty_grid_template_areas);
    1288             :       const nsCSSValue& columnsValue =
    1289           0 :         *data->ValueFor(eCSSProperty_grid_template_columns);
    1290             :       const nsCSSValue& rowsValue =
    1291           0 :         *data->ValueFor(eCSSProperty_grid_template_rows);
    1292             : 
    1293             :       const nsCSSValue& autoFlowValue =
    1294           0 :         *data->ValueFor(eCSSProperty_grid_auto_flow);
    1295             :       const nsCSSValue& autoColumnsValue =
    1296           0 :         *data->ValueFor(eCSSProperty_grid_auto_columns);
    1297             :       const nsCSSValue& autoRowsValue =
    1298           0 :         *data->ValueFor(eCSSProperty_grid_auto_rows);
    1299             : 
    1300             :       // grid-template-rows/areas:none + default grid-auto-columns +
    1301             :       // non-default row grid-auto-flow or grid-auto-rows.
    1302             :       // --> serialize as 'grid' syntax #3.
    1303             :       // (for default grid-auto-flow/rows we prefer to serialize to
    1304             :       // "none ['/' ...]" instead using syntax #2 or #1 below)
    1305           0 :       if (rowsValue.GetUnit() == eCSSUnit_None &&
    1306           0 :           areasValue.GetUnit() == eCSSUnit_None &&
    1307           0 :           autoColumnsValue.GetUnit() == eCSSUnit_Auto &&
    1308           0 :           autoFlowValue.GetUnit() == eCSSUnit_Enumerated &&
    1309           0 :           (autoFlowValue.GetIntValue() & NS_STYLE_GRID_AUTO_FLOW_ROW) &&
    1310           0 :           (autoFlowValue.GetIntValue() != NS_STYLE_GRID_AUTO_FLOW_ROW ||
    1311           0 :            autoRowsValue.GetUnit() != eCSSUnit_Auto)) {
    1312           0 :         aValue.AppendLiteral("auto-flow");
    1313           0 :         if (autoFlowValue.GetIntValue() & NS_STYLE_GRID_AUTO_FLOW_DENSE) {
    1314           0 :           aValue.AppendLiteral(" dense");
    1315             :         }
    1316           0 :         if (autoRowsValue.GetUnit() != eCSSUnit_Auto) {
    1317           0 :           aValue.Append(' ');
    1318             :           AppendValueToString(eCSSProperty_grid_auto_rows,
    1319           0 :                               aValue, aSerialization);
    1320             :         }
    1321           0 :         aValue.AppendLiteral(" / ");
    1322             :         AppendValueToString(eCSSProperty_grid_template_columns,
    1323           0 :                             aValue, aSerialization);
    1324           0 :         break;
    1325             :       }
    1326             : 
    1327             :       // grid-template-columns/areas:none + column grid-auto-flow +
    1328             :       // default grid-auto-rows.
    1329             :       // --> serialize as 'grid' syntax #2.
    1330           0 :       if (columnsValue.GetUnit() == eCSSUnit_None &&
    1331           0 :           areasValue.GetUnit() == eCSSUnit_None &&
    1332           0 :           autoRowsValue.GetUnit() == eCSSUnit_Auto &&
    1333           0 :           autoFlowValue.GetUnit() == eCSSUnit_Enumerated &&
    1334           0 :           (autoFlowValue.GetIntValue() & NS_STYLE_GRID_AUTO_FLOW_COLUMN)) {
    1335             :         AppendValueToString(eCSSProperty_grid_template_rows,
    1336           0 :                             aValue, aSerialization);
    1337           0 :         aValue.AppendLiteral(" / auto-flow ");
    1338           0 :         if (autoFlowValue.GetIntValue() & NS_STYLE_GRID_AUTO_FLOW_DENSE) {
    1339           0 :           aValue.AppendLiteral("dense ");
    1340             :         }
    1341             :         AppendValueToString(eCSSProperty_grid_auto_columns,
    1342           0 :                             aValue, aSerialization);
    1343           0 :         break;
    1344             :       }
    1345             : 
    1346           0 :       if (!(autoFlowValue.GetUnit() == eCSSUnit_Enumerated &&
    1347           0 :             autoFlowValue.GetIntValue() == NS_STYLE_GRID_AUTO_FLOW_ROW &&
    1348           0 :             autoColumnsValue.GetUnit() == eCSSUnit_Auto &&
    1349           0 :             autoRowsValue.GetUnit() == eCSSUnit_Auto)) {
    1350             :         // Not serializable, bail.
    1351           0 :         return;
    1352             :       }
    1353             :       // Fall through to eCSSProperty_grid_template (syntax #1)
    1354             :       MOZ_FALLTHROUGH;
    1355             :     }
    1356             :     case eCSSProperty_grid_template: {
    1357             :       const nsCSSValue& areasValue =
    1358           0 :         *data->ValueFor(eCSSProperty_grid_template_areas);
    1359             :       const nsCSSValue& columnsValue =
    1360           0 :         *data->ValueFor(eCSSProperty_grid_template_columns);
    1361             :       const nsCSSValue& rowsValue =
    1362           0 :         *data->ValueFor(eCSSProperty_grid_template_rows);
    1363           0 :       if (areasValue.GetUnit() == eCSSUnit_None) {
    1364             :         AppendValueToString(eCSSProperty_grid_template_rows,
    1365           0 :                             aValue, aSerialization);
    1366           0 :         aValue.AppendLiteral(" / ");
    1367             :         AppendValueToString(eCSSProperty_grid_template_columns,
    1368           0 :                             aValue, aSerialization);
    1369           0 :         break;
    1370             :       }
    1371           0 :       if (columnsValue.GetUnit() == eCSSUnit_List ||
    1372           0 :           columnsValue.GetUnit() == eCSSUnit_ListDep) {
    1373           0 :         const nsCSSValueList* columnsItem = columnsValue.GetListValue();
    1374           0 :         if (columnsItem->mValue.GetUnit() == eCSSUnit_Enumerated &&
    1375           0 :             columnsItem->mValue.GetIntValue() == NS_STYLE_GRID_TEMPLATE_SUBGRID) {
    1376             :           // We have "grid-template-areas:[something]; grid-template-columns:subgrid"
    1377             :           // which isn't a value that the shorthand can express. Bail.
    1378           0 :           return;
    1379             :         }
    1380             :       }
    1381           0 :       if (rowsValue.GetUnit() != eCSSUnit_List &&
    1382           0 :           rowsValue.GetUnit() != eCSSUnit_ListDep) {
    1383             :         // We have "grid-template-areas:[something]; grid-template-rows:none"
    1384             :         // which isn't a value that the shorthand can express. Bail.
    1385           0 :         return;
    1386             :       }
    1387           0 :       const nsCSSValueList* rowsItem = rowsValue.GetListValue();
    1388           0 :       if (rowsItem->mValue.GetUnit() == eCSSUnit_Enumerated &&
    1389           0 :           rowsItem->mValue.GetIntValue() == NS_STYLE_GRID_TEMPLATE_SUBGRID) {
    1390             :         // We have "grid-template-areas:[something]; grid-template-rows:subgrid"
    1391             :         // which isn't a value that the shorthand can express. Bail.
    1392           0 :         return;
    1393             :       }
    1394           0 :       const GridTemplateAreasValue* areas = areasValue.GetGridTemplateAreas();
    1395           0 :       uint32_t nRowItems = 0;
    1396           0 :       while (rowsItem) {
    1397           0 :         nRowItems++;
    1398           0 :         rowsItem = rowsItem->mNext;
    1399             :       }
    1400           0 :       MOZ_ASSERT(nRowItems % 2 == 1, "expected an odd number of items");
    1401           0 :       if ((nRowItems - 1) / 2 != areas->NRows()) {
    1402             :         // Not serializable, bail.
    1403           0 :         return;
    1404             :       }
    1405           0 :       rowsItem = rowsValue.GetListValue();
    1406           0 :       uint32_t row = 0;
    1407             :       for (;;) {
    1408           0 :         bool addSpaceSeparator = true;
    1409           0 :         nsCSSUnit unit = rowsItem->mValue.GetUnit();
    1410             : 
    1411           0 :         if (unit == eCSSUnit_Null) {
    1412             :           // Empty or omitted <line-names>. Serializes to nothing.
    1413           0 :           addSpaceSeparator = false;  // Avoid a double space.
    1414             : 
    1415           0 :         } else if (unit == eCSSUnit_List || unit == eCSSUnit_ListDep) {
    1416             :           // Non-empty <line-names>
    1417           0 :           aValue.Append('[');
    1418           0 :           rowsItem->mValue.AppendToString(eCSSProperty_grid_template_rows,
    1419           0 :                                           aValue, aSerialization);
    1420           0 :           aValue.Append(']');
    1421             : 
    1422             :         } else {
    1423           0 :           nsStyleUtil::AppendEscapedCSSString(areas->mTemplates[row++], aValue);
    1424           0 :           aValue.Append(char16_t(' '));
    1425             : 
    1426             :           // <track-size>
    1427           0 :           if (unit == eCSSUnit_Pair) {
    1428             :             // 'repeat()' isn't allowed with non-default 'grid-template-areas'.
    1429           0 :             aValue.Truncate();
    1430           0 :             return;
    1431             :           }
    1432           0 :           rowsItem->mValue.AppendToString(eCSSProperty_grid_template_rows,
    1433           0 :                                           aValue, aSerialization);
    1434           0 :           if (rowsItem->mNext &&
    1435           0 :               rowsItem->mNext->mValue.GetUnit() == eCSSUnit_Null &&
    1436           0 :               !rowsItem->mNext->mNext) {
    1437             :             // Break out of the loop early to avoid a trailing space.
    1438           0 :             break;
    1439             :           }
    1440             :         }
    1441             : 
    1442           0 :         rowsItem = rowsItem->mNext;
    1443           0 :         if (!rowsItem) {
    1444           0 :           break;
    1445             :         }
    1446             : 
    1447           0 :         if (addSpaceSeparator) {
    1448           0 :           aValue.Append(char16_t(' '));
    1449             :         }
    1450           0 :       }
    1451           0 :       if (columnsValue.GetUnit() != eCSSUnit_None) {
    1452           0 :         const nsCSSValueList* colsItem = columnsValue.GetListValue();
    1453           0 :         colsItem = colsItem->mNext; // first value is <line-names>
    1454           0 :         for (; colsItem; colsItem = colsItem->mNext) {
    1455           0 :           if (colsItem->mValue.GetUnit() == eCSSUnit_Pair) {
    1456             :             // 'repeat()' isn't allowed with non-default 'grid-template-areas'.
    1457           0 :             aValue.Truncate();
    1458           0 :             return;
    1459             :           }
    1460           0 :           colsItem = colsItem->mNext; // skip <line-names>
    1461             :         }
    1462           0 :         aValue.AppendLiteral(" / ");
    1463             :         AppendValueToString(eCSSProperty_grid_template_columns,
    1464           0 :                             aValue, aSerialization);
    1465             :       }
    1466           0 :       break;
    1467             :     }
    1468             :     case eCSSProperty_place_content:
    1469             :     case eCSSProperty_place_items:
    1470             :     case eCSSProperty_place_self: {
    1471             :       const nsCSSPropertyID* subprops =
    1472           0 :         nsCSSProps::SubpropertyEntryFor(aProperty);
    1473           0 :       MOZ_ASSERT(subprops[2] == eCSSProperty_UNKNOWN,
    1474             :                  "must have exactly two subproperties");
    1475           0 :       auto IsSingleValue = [] (const nsCSSValue& aValue) {
    1476           0 :         switch (aValue.GetUnit()) {
    1477             :           case eCSSUnit_Auto:
    1478             :           case eCSSUnit_Inherit:
    1479             :           case eCSSUnit_Initial:
    1480             :           case eCSSUnit_Unset:
    1481           0 :             return true;
    1482             :           case eCSSUnit_Enumerated:
    1483             :             // return false if there is a fallback value or <overflow-position>
    1484           0 :             return aValue.GetIntValue() <= NS_STYLE_JUSTIFY_SPACE_EVENLY;
    1485             :           default:
    1486           0 :             MOZ_ASSERT_UNREACHABLE("Unexpected unit for CSS Align property val");
    1487             :             return false;
    1488             :         }
    1489             :       };
    1490             :       // Each value must be a single value (i.e. no fallback value and no
    1491             :       // <overflow-position>), otherwise it can't be represented as a shorthand
    1492             :       // value. ('first|last baseline' counts as a single value)
    1493           0 :       const nsCSSValue* align = data->ValueFor(subprops[0]);
    1494           0 :       const nsCSSValue* justify = data->ValueFor(subprops[1]);
    1495           0 :       if (!align || !IsSingleValue(*align) ||
    1496           0 :           !justify || !IsSingleValue(*justify)) {
    1497           0 :         return; // Not serializable, bail.
    1498             :       }
    1499             :       MOZ_FALLTHROUGH;
    1500             :     }
    1501             :     case eCSSProperty_grid_gap: {
    1502             :       const nsCSSPropertyID* subprops =
    1503           0 :         nsCSSProps::SubpropertyEntryFor(aProperty);
    1504           0 :       MOZ_ASSERT(subprops[2] == eCSSProperty_UNKNOWN,
    1505             :                  "must have exactly two subproperties");
    1506             : 
    1507           0 :       nsAutoString val1, val2;
    1508           0 :       AppendValueToString(subprops[0], val1, aSerialization);
    1509           0 :       AppendValueToString(subprops[1], val2, aSerialization);
    1510           0 :       if (val1 == val2) {
    1511           0 :         aValue.Append(val1);
    1512             :       } else {
    1513           0 :         aValue.Append(val1);
    1514           0 :         aValue.Append(' ');
    1515           0 :         aValue.Append(val2);
    1516             :       }
    1517           0 :       break;
    1518             :     }
    1519             :     case eCSSProperty_text_emphasis: {
    1520             :       const nsCSSValue* emphasisStyle =
    1521           0 :         data->ValueFor(eCSSProperty_text_emphasis_style);
    1522             :       const nsCSSValue* emphasisColor =
    1523           0 :         data->ValueFor(eCSSProperty_text_emphasis_color);
    1524           0 :       bool isDefaultColor = emphasisColor->GetUnit() == eCSSUnit_EnumColor &&
    1525           0 :         emphasisColor->GetIntValue() == NS_COLOR_CURRENTCOLOR;
    1526             : 
    1527           0 :       if (emphasisStyle->GetUnit() != eCSSUnit_None || isDefaultColor) {
    1528             :         AppendValueToString(eCSSProperty_text_emphasis_style,
    1529           0 :                             aValue, aSerialization);
    1530           0 :         if (!isDefaultColor) {
    1531           0 :           aValue.Append(char16_t(' '));
    1532             :         }
    1533             :       }
    1534           0 :       if (!isDefaultColor) {
    1535             :         AppendValueToString(eCSSProperty_text_emphasis_color,
    1536           0 :                             aValue, aSerialization);
    1537             :       }
    1538           0 :       break;
    1539             :     }
    1540             :     case eCSSProperty__moz_transform: {
    1541             :       // shorthands that are just aliases with different parsing rules
    1542             :       const nsCSSPropertyID* subprops =
    1543           0 :         nsCSSProps::SubpropertyEntryFor(aProperty);
    1544           0 :       MOZ_ASSERT(subprops[1] == eCSSProperty_UNKNOWN,
    1545             :                  "must have exactly one subproperty");
    1546           0 :       AppendValueToString(subprops[0], aValue, aSerialization);
    1547           0 :       break;
    1548             :     }
    1549             :     case eCSSProperty_scroll_snap_type: {
    1550             :       const nsCSSValue& xValue =
    1551           0 :         *data->ValueFor(eCSSProperty_scroll_snap_type_x);
    1552             :       const nsCSSValue& yValue =
    1553           0 :         *data->ValueFor(eCSSProperty_scroll_snap_type_y);
    1554           0 :       if (xValue == yValue) {
    1555             :         AppendValueToString(eCSSProperty_scroll_snap_type_x, aValue,
    1556           0 :                             aSerialization);
    1557             :       }
    1558             :       // If scroll-snap-type-x and scroll-snap-type-y are not equal,
    1559             :       // we don't have a shorthand that can express. Bail.
    1560           0 :       break;
    1561             :     }
    1562             :     case eCSSProperty__webkit_text_stroke: {
    1563             :       const nsCSSValue* strokeWidth =
    1564           0 :         data->ValueFor(eCSSProperty__webkit_text_stroke_width);
    1565             :       const nsCSSValue* strokeColor =
    1566           0 :         data->ValueFor(eCSSProperty__webkit_text_stroke_color);
    1567           0 :       bool isDefaultColor = strokeColor->GetUnit() == eCSSUnit_EnumColor &&
    1568           0 :         strokeColor->GetIntValue() == NS_COLOR_CURRENTCOLOR;
    1569             : 
    1570           0 :       if (strokeWidth->GetUnit() != eCSSUnit_Integer ||
    1571           0 :           strokeWidth->GetIntValue() != 0 || isDefaultColor) {
    1572             :         AppendValueToString(eCSSProperty__webkit_text_stroke_width,
    1573           0 :                             aValue, aSerialization);
    1574           0 :         if (!isDefaultColor) {
    1575           0 :           aValue.Append(char16_t(' '));
    1576             :         }
    1577             :       }
    1578           0 :       if (!isDefaultColor) {
    1579             :         AppendValueToString(eCSSProperty__webkit_text_stroke_color,
    1580           0 :                             aValue, aSerialization);
    1581             :       }
    1582           0 :       break;
    1583             :     }
    1584             :     case eCSSProperty_all:
    1585             :       // If we got here, then we didn't have all "inherit" or "initial" or
    1586             :       // "unset" values for all of the longhand property components of 'all'.
    1587             :       // There is no other possible value that is valid for all properties,
    1588             :       // so serialize as the empty string.
    1589           0 :       break;
    1590             :     default:
    1591           0 :       MOZ_ASSERT(false, "no other shorthands");
    1592             :       break;
    1593             :   }
    1594             : }
    1595             : 
    1596             : bool
    1597           0 : Declaration::GetPropertyIsImportantByID(nsCSSPropertyID aProperty) const
    1598             : {
    1599           0 :   if (!mImportantData)
    1600           0 :     return false;
    1601             : 
    1602             :   // Calling ValueFor is inefficient, but we can assume '!important' is rare.
    1603             : 
    1604           0 :   if (!nsCSSProps::IsShorthand(aProperty)) {
    1605           0 :     return mImportantData->ValueFor(aProperty) != nullptr;
    1606             :   }
    1607             : 
    1608           0 :   CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p, aProperty,
    1609             :                                        CSSEnabledState::eForAllContent) {
    1610           0 :     if (*p == eCSSProperty__x_system_font) {
    1611             :       // The system_font subproperty doesn't count.
    1612           0 :       continue;
    1613             :     }
    1614           0 :     if (!mImportantData->ValueFor(*p)) {
    1615           0 :       return false;
    1616             :     }
    1617             :   }
    1618           0 :   return true;
    1619             : }
    1620             : 
    1621             : void
    1622           0 : Declaration::AppendPropertyAndValueToString(nsCSSPropertyID aProperty,
    1623             :                                             nsAString& aResult,
    1624             :                                             nsAutoString& aValue,
    1625             :                                             bool aValueIsTokenStream) const
    1626             : {
    1627           0 :   MOZ_ASSERT(0 <= aProperty && aProperty < eCSSProperty_COUNT,
    1628             :              "property enum out of range");
    1629           0 :   MOZ_ASSERT((aProperty < eCSSProperty_COUNT_no_shorthands) == aValue.IsEmpty(),
    1630             :              "aValue should be given for shorthands but not longhands");
    1631           0 :   AppendASCIItoUTF16(nsCSSProps::GetStringValue(aProperty), aResult);
    1632           0 :   if (aValue.IsEmpty()) {
    1633           0 :     AppendValueToString(aProperty, aValue,
    1634           0 :                         nsCSSValue::eNormalized, &aValueIsTokenStream);
    1635             :   }
    1636           0 :   aResult.Append(':');
    1637           0 :   if (!aValueIsTokenStream) {
    1638           0 :     aResult.Append(' ');
    1639             :   }
    1640           0 :   aResult.Append(aValue);
    1641           0 :   if (GetPropertyIsImportantByID(aProperty)) {
    1642           0 :     if (!aValueIsTokenStream) {
    1643           0 :       aResult.Append(' ');
    1644             :     }
    1645           0 :     aResult.AppendLiteral("!important");
    1646             :   }
    1647           0 :   aResult.AppendLiteral("; ");
    1648           0 : }
    1649             : 
    1650             : void
    1651           0 : Declaration::AppendVariableAndValueToString(const nsAString& aName,
    1652             :                                             nsAString& aResult) const
    1653             : {
    1654           0 :   nsAutoString localName;
    1655           0 :   localName.AppendLiteral("--");
    1656           0 :   localName.Append(aName);
    1657           0 :   nsStyleUtil::AppendEscapedCSSIdent(localName, aResult);
    1658             :   CSSVariableDeclarations::Type type;
    1659           0 :   nsString value;
    1660             :   bool important;
    1661             : 
    1662           0 :   if (mImportantVariables && mImportantVariables->Get(aName, type, value)) {
    1663           0 :     important = true;
    1664             :   } else {
    1665           0 :     MOZ_ASSERT(mVariables);
    1666           0 :     MOZ_ASSERT(mVariables->Has(aName));
    1667           0 :     mVariables->Get(aName, type, value);
    1668           0 :     important = false;
    1669             :   }
    1670             : 
    1671           0 :   bool isTokenStream = type == CSSVariableDeclarations::eTokenStream;
    1672           0 :   aResult.Append(':');
    1673           0 :   if (!isTokenStream) {
    1674           0 :     aResult.Append(' ');
    1675             :   }
    1676           0 :   switch (type) {
    1677             :     case CSSVariableDeclarations::eTokenStream:
    1678           0 :       aResult.Append(value);
    1679           0 :       break;
    1680             : 
    1681             :     case CSSVariableDeclarations::eInitial:
    1682           0 :       aResult.AppendLiteral("initial");
    1683           0 :       break;
    1684             : 
    1685             :     case CSSVariableDeclarations::eInherit:
    1686           0 :       aResult.AppendLiteral("inherit");
    1687           0 :       break;
    1688             : 
    1689             :     case CSSVariableDeclarations::eUnset:
    1690           0 :       aResult.AppendLiteral("unset");
    1691           0 :       break;
    1692             : 
    1693             :     default:
    1694           0 :       MOZ_ASSERT(false, "unexpected variable value type");
    1695             :   }
    1696             : 
    1697           0 :   if (important) {
    1698           0 :     if (!isTokenStream) {
    1699           0 :       aResult.Append(' ');
    1700             :     }
    1701           0 :     aResult.AppendLiteral("!important");
    1702             :   }
    1703           0 :   aResult.AppendLiteral("; ");
    1704           0 : }
    1705             : 
    1706             : void
    1707           0 : Declaration::ToString(nsAString& aString) const
    1708             : {
    1709             :   // Tell the static analysis not to worry about thread-unsafe things here
    1710             :   // because because this function isn't reached during parallel style traversal.
    1711           0 :   MOZ_ASSERT(!ServoStyleSet::IsInServoTraversal());
    1712             : 
    1713             :   nsCSSCompressedDataBlock *systemFontData =
    1714           0 :     GetPropertyIsImportantByID(eCSSProperty__x_system_font) ? mImportantData
    1715           0 :                                                             : mData;
    1716             :   const nsCSSValue *systemFont =
    1717           0 :     systemFontData->ValueFor(eCSSProperty__x_system_font);
    1718           0 :   const bool haveSystemFont = systemFont &&
    1719           0 :                                 systemFont->GetUnit() != eCSSUnit_None &&
    1720           0 :                                 systemFont->GetUnit() != eCSSUnit_Null;
    1721           0 :   bool didSystemFont = false;
    1722             : 
    1723           0 :   int32_t count = mOrder.Length();
    1724             :   int32_t index;
    1725           0 :   AutoTArray<nsCSSPropertyID, 16> shorthandsUsed;
    1726           0 :   for (index = 0; index < count; index++) {
    1727           0 :     nsCSSPropertyID property = GetPropertyAt(index);
    1728             : 
    1729           0 :     if (property == eCSSPropertyExtra_variable) {
    1730           0 :       uint32_t variableIndex = mOrder[index] - eCSSProperty_COUNT;
    1731           0 :       AppendVariableAndValueToString(mVariableOrder[variableIndex], aString);
    1732           0 :       continue;
    1733             :     }
    1734             : 
    1735           0 :     if (!nsCSSProps::IsEnabled(property, CSSEnabledState::eForAllContent)) {
    1736           0 :       continue;
    1737             :     }
    1738           0 :     bool doneProperty = false;
    1739             : 
    1740             :     // If we already used this property in a shorthand, skip it.
    1741           0 :     if (shorthandsUsed.Length() > 0) {
    1742           0 :       for (const nsCSSPropertyID *shorthands =
    1743           0 :              nsCSSProps::ShorthandsContaining(property);
    1744           0 :            *shorthands != eCSSProperty_UNKNOWN; ++shorthands) {
    1745           0 :         if (shorthandsUsed.Contains(*shorthands)) {
    1746           0 :           doneProperty = true;
    1747           0 :           break;
    1748             :         }
    1749             :       }
    1750           0 :       if (doneProperty)
    1751           0 :         continue;
    1752             :     }
    1753             : 
    1754             :     // Try to use this property in a shorthand.
    1755           0 :     nsAutoString value;
    1756           0 :     for (const nsCSSPropertyID *shorthands =
    1757           0 :            nsCSSProps::ShorthandsContaining(property);
    1758           0 :          *shorthands != eCSSProperty_UNKNOWN; ++shorthands) {
    1759             :       // ShorthandsContaining returns the shorthands in order from those
    1760             :       // that contain the most subproperties to those that contain the
    1761             :       // least, which is exactly the order we want to test them.
    1762           0 :       nsCSSPropertyID shorthand = *shorthands;
    1763             : 
    1764             :       bool isTokenStream;
    1765             :       GetPropertyValueInternal(shorthand, value,
    1766           0 :                                nsCSSValue::eNormalized, &isTokenStream);
    1767             : 
    1768             :       // in the system font case, skip over font-variant shorthand, since all
    1769             :       // subproperties are already dealt with via the font shorthand
    1770           0 :       if (shorthand == eCSSProperty_font_variant &&
    1771           0 :           value.EqualsLiteral("-moz-use-system-font")) {
    1772           0 :         continue;
    1773             :       }
    1774             : 
    1775             :       // If GetPropertyValueInternal gives us a non-empty string back, we can
    1776             :       // use that value; otherwise it's not possible to use this shorthand.
    1777           0 :       if (!value.IsEmpty()) {
    1778           0 :         AppendPropertyAndValueToString(shorthand, aString,
    1779           0 :                                        value, isTokenStream);
    1780           0 :         shorthandsUsed.AppendElement(shorthand);
    1781           0 :         doneProperty = true;
    1782           0 :         break;
    1783             :       }
    1784             : 
    1785           0 :       if (shorthand == eCSSProperty_font) {
    1786           0 :         if (haveSystemFont && !didSystemFont) {
    1787             :           // Output the shorthand font declaration that we will
    1788             :           // partially override later.  But don't add it to
    1789             :           // |shorthandsUsed|, since we will have to override it.
    1790             :           systemFont->AppendToString(eCSSProperty__x_system_font, value,
    1791           0 :                                      nsCSSValue::eNormalized);
    1792           0 :           isTokenStream = systemFont->GetUnit() == eCSSUnit_TokenStream;
    1793           0 :           AppendPropertyAndValueToString(eCSSProperty_font, aString,
    1794           0 :                                          value, isTokenStream);
    1795           0 :           value.Truncate();
    1796           0 :           didSystemFont = true;
    1797             :         }
    1798             : 
    1799             :         // That we output the system font is enough for this property if:
    1800             :         //   (1) it's the hidden system font subproperty (which either
    1801             :         //       means we output it or we don't have it), or
    1802             :         //   (2) its value is the hidden system font value and it matches
    1803             :         //       the hidden system font subproperty in importance, and
    1804             :         //       we output the system font subproperty.
    1805           0 :         const nsCSSValue *val = systemFontData->ValueFor(property);
    1806           0 :         if (property == eCSSProperty__x_system_font ||
    1807           0 :             (haveSystemFont && val && val->GetUnit() == eCSSUnit_System_Font)) {
    1808           0 :           doneProperty = true;
    1809           0 :           break;
    1810             :         }
    1811             :       }
    1812             :     }
    1813           0 :     if (doneProperty)
    1814           0 :       continue;
    1815             : 
    1816           0 :     MOZ_ASSERT(value.IsEmpty(), "value should be empty now");
    1817           0 :     AppendPropertyAndValueToString(property, aString, value, false);
    1818             :   }
    1819           0 :   if (! aString.IsEmpty()) {
    1820             :     // if the string is not empty, we have trailing whitespace we
    1821             :     // should remove
    1822           0 :     aString.Truncate(aString.Length() - 1);
    1823             :   }
    1824           0 : }
    1825             : 
    1826             : #ifdef DEBUG
    1827             : /* virtual */ void
    1828           0 : Declaration::List(FILE* out, int32_t aIndent) const
    1829             : {
    1830           0 :   const Rule* owningRule = GetOwningRule();
    1831           0 :   if (owningRule) {
    1832             :     // More useful to print the selector and sheet URI too.
    1833           0 :     owningRule->List(out, aIndent);
    1834           0 :     return;
    1835             :   }
    1836             : 
    1837           0 :   nsAutoCString str;
    1838           0 :   for (int32_t index = aIndent; --index >= 0; ) {
    1839           0 :     str.AppendLiteral("  ");
    1840             :   }
    1841             : 
    1842           0 :   str.AppendLiteral("{ ");
    1843           0 :   nsAutoString s;
    1844           0 :   ToString(s);
    1845           0 :   AppendUTF16toUTF8(s, str);
    1846           0 :   str.AppendLiteral("}\n");
    1847           0 :   fprintf_stderr(out, "%s", str.get());
    1848             : }
    1849             : #endif
    1850             : 
    1851             : bool
    1852           0 : Declaration::GetNthProperty(uint32_t aIndex, nsAString& aReturn) const
    1853             : {
    1854           0 :   aReturn.Truncate();
    1855           0 :   if (aIndex < mOrder.Length()) {
    1856           0 :     nsCSSPropertyID property = GetPropertyAt(aIndex);
    1857           0 :     if (property == eCSSPropertyExtra_variable) {
    1858           0 :       GetCustomPropertyNameAt(aIndex, aReturn);
    1859           0 :       return true;
    1860             :     }
    1861           0 :     if (0 <= property) {
    1862           0 :       AppendASCIItoUTF16(nsCSSProps::GetStringValue(property), aReturn);
    1863           0 :       return true;
    1864             :     }
    1865             :   }
    1866           0 :   return false;
    1867             : }
    1868             : 
    1869             : void
    1870          84 : Declaration::InitializeEmpty()
    1871             : {
    1872          84 :   MOZ_ASSERT(!mData && !mImportantData, "already initialized");
    1873          84 :   mData = nsCSSCompressedDataBlock::CreateEmptyBlock();
    1874          84 : }
    1875             : 
    1876             : size_t
    1877          14 : Declaration::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
    1878             : {
    1879          14 :   size_t n = aMallocSizeOf(this);
    1880          14 :   n += mOrder.ShallowSizeOfExcludingThis(aMallocSizeOf);
    1881          14 :   n += mData          ? mData         ->SizeOfIncludingThis(aMallocSizeOf) : 0;
    1882          14 :   n += mImportantData ? mImportantData->SizeOfIncludingThis(aMallocSizeOf) : 0;
    1883          14 :   if (mVariables) {
    1884           0 :     n += mVariables->SizeOfIncludingThis(aMallocSizeOf);
    1885             :   }
    1886          14 :   if (mImportantVariables) {
    1887           0 :     n += mImportantVariables->SizeOfIncludingThis(aMallocSizeOf);
    1888             :   }
    1889          14 :   return n;
    1890             : }
    1891             : 
    1892             : void
    1893           0 : Declaration::GetVariableValue(const nsAString& aName, nsAString& aValue) const
    1894             : {
    1895           0 :   aValue.Truncate();
    1896             : 
    1897             :   CSSVariableDeclarations::Type type;
    1898           0 :   nsString value;
    1899             : 
    1900           0 :   if ((mImportantVariables && mImportantVariables->Get(aName, type, value)) ||
    1901           0 :       (mVariables && mVariables->Get(aName, type, value))) {
    1902           0 :     switch (type) {
    1903             :       case CSSVariableDeclarations::eTokenStream:
    1904           0 :         aValue.Append(value);
    1905           0 :         break;
    1906             : 
    1907             :       case CSSVariableDeclarations::eInitial:
    1908           0 :         aValue.AppendLiteral("initial");
    1909           0 :         break;
    1910             : 
    1911             :       case CSSVariableDeclarations::eInherit:
    1912           0 :         aValue.AppendLiteral("inherit");
    1913           0 :         break;
    1914             : 
    1915             :       case CSSVariableDeclarations::eUnset:
    1916           0 :         aValue.AppendLiteral("unset");
    1917           0 :         break;
    1918             : 
    1919             :       default:
    1920           0 :         MOZ_ASSERT(false, "unexpected variable value type");
    1921             :     }
    1922             :   }
    1923           0 : }
    1924             : 
    1925             : void
    1926          74 : Declaration::AddVariable(const nsAString& aName,
    1927             :                          CSSVariableDeclarations::Type aType,
    1928             :                          const nsString& aValue,
    1929             :                          bool aIsImportant,
    1930             :                          bool aOverrideImportant)
    1931             : {
    1932          74 :   MOZ_ASSERT(IsMutable());
    1933             : 
    1934          74 :   nsTArray<nsString>::index_type index = mVariableOrder.IndexOf(aName);
    1935          74 :   if (index == nsTArray<nsString>::NoIndex) {
    1936          74 :     index = mVariableOrder.Length();
    1937          74 :     mVariableOrder.AppendElement(aName);
    1938             :   }
    1939             : 
    1940         296 :   if (!aIsImportant && !aOverrideImportant &&
    1941         148 :       mImportantVariables && mImportantVariables->Has(aName)) {
    1942           0 :     return;
    1943             :   }
    1944             : 
    1945             :   CSSVariableDeclarations* variables;
    1946          74 :   if (aIsImportant) {
    1947           0 :     if (mVariables) {
    1948           0 :       mVariables->Remove(aName);
    1949             :     }
    1950           0 :     if (!mImportantVariables) {
    1951           0 :       mImportantVariables = new CSSVariableDeclarations;
    1952             :     }
    1953           0 :     variables = mImportantVariables;
    1954             :   } else {
    1955          74 :     if (mImportantVariables) {
    1956           0 :       mImportantVariables->Remove(aName);
    1957             :     }
    1958          74 :     if (!mVariables) {
    1959          31 :       mVariables = new CSSVariableDeclarations;
    1960             :     }
    1961          74 :     variables = mVariables;
    1962             :   }
    1963             : 
    1964          74 :   switch (aType) {
    1965             :     case CSSVariableDeclarations::eTokenStream:
    1966          74 :       variables->PutTokenStream(aName, aValue);
    1967          74 :       break;
    1968             : 
    1969             :     case CSSVariableDeclarations::eInitial:
    1970           0 :       MOZ_ASSERT(aValue.IsEmpty());
    1971           0 :       variables->PutInitial(aName);
    1972           0 :       break;
    1973             : 
    1974             :     case CSSVariableDeclarations::eInherit:
    1975           0 :       MOZ_ASSERT(aValue.IsEmpty());
    1976           0 :       variables->PutInherit(aName);
    1977           0 :       break;
    1978             : 
    1979             :     case CSSVariableDeclarations::eUnset:
    1980           0 :       MOZ_ASSERT(aValue.IsEmpty());
    1981           0 :       variables->PutUnset(aName);
    1982           0 :       break;
    1983             : 
    1984             :     default:
    1985           0 :       MOZ_ASSERT(false, "unexpected aType value");
    1986             :   }
    1987             : 
    1988          74 :   uint32_t propertyIndex = index + eCSSProperty_COUNT;
    1989          74 :   mOrder.RemoveElement(propertyIndex);
    1990          74 :   mOrder.AppendElement(propertyIndex);
    1991             : }
    1992             : 
    1993             : void
    1994           0 : Declaration::RemoveVariable(const nsAString& aName)
    1995             : {
    1996           0 :   if (mVariables) {
    1997           0 :     mVariables->Remove(aName);
    1998             :   }
    1999           0 :   if (mImportantVariables) {
    2000           0 :     mImportantVariables->Remove(aName);
    2001             :   }
    2002           0 :   nsTArray<nsString>::index_type index = mVariableOrder.IndexOf(aName);
    2003           0 :   if (index != nsTArray<nsString>::NoIndex) {
    2004           0 :     mOrder.RemoveElement(index + eCSSProperty_COUNT);
    2005             :   }
    2006           0 : }
    2007             : 
    2008             : bool
    2009           0 : Declaration::GetVariableIsImportant(const nsAString& aName) const
    2010             : {
    2011           0 :   return mImportantVariables && mImportantVariables->Has(aName);
    2012             : }
    2013             : 
    2014             : } // namespace css
    2015             : } // namespace mozilla

Generated by: LCOV version 1.13