1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/style/Declaration.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1541 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +/* 1.10 + * representation of a declaration block (or style attribute) in a CSS 1.11 + * stylesheet 1.12 + */ 1.13 + 1.14 +#include "mozilla/ArrayUtils.h" 1.15 +#include "mozilla/MemoryReporting.h" 1.16 + 1.17 +#include "mozilla/css/Declaration.h" 1.18 +#include "nsPrintfCString.h" 1.19 +#include "gfxFontConstants.h" 1.20 +#include "nsStyleUtil.h" 1.21 + 1.22 +namespace mozilla { 1.23 +namespace css { 1.24 + 1.25 +Declaration::Declaration() 1.26 + : mImmutable(false) 1.27 +{ 1.28 + MOZ_COUNT_CTOR(mozilla::css::Declaration); 1.29 +} 1.30 + 1.31 +Declaration::Declaration(const Declaration& aCopy) 1.32 + : mOrder(aCopy.mOrder), 1.33 + mVariableOrder(aCopy.mVariableOrder), 1.34 + mData(aCopy.mData ? aCopy.mData->Clone() : nullptr), 1.35 + mImportantData(aCopy.mImportantData ? 1.36 + aCopy.mImportantData->Clone() : nullptr), 1.37 + mVariables(aCopy.mVariables ? 1.38 + new CSSVariableDeclarations(*aCopy.mVariables) : 1.39 + nullptr), 1.40 + mImportantVariables(aCopy.mImportantVariables ? 1.41 + new CSSVariableDeclarations(*aCopy.mImportantVariables) : 1.42 + nullptr), 1.43 + mImmutable(false) 1.44 +{ 1.45 + MOZ_COUNT_CTOR(mozilla::css::Declaration); 1.46 +} 1.47 + 1.48 +Declaration::~Declaration() 1.49 +{ 1.50 + MOZ_COUNT_DTOR(mozilla::css::Declaration); 1.51 +} 1.52 + 1.53 +void 1.54 +Declaration::ValueAppended(nsCSSProperty aProperty) 1.55 +{ 1.56 + NS_ABORT_IF_FALSE(!mData && !mImportantData, 1.57 + "should only be called while expanded"); 1.58 + NS_ABORT_IF_FALSE(!nsCSSProps::IsShorthand(aProperty), 1.59 + "shorthands forbidden"); 1.60 + // order IS important for CSS, so remove and add to the end 1.61 + mOrder.RemoveElement(static_cast<uint32_t>(aProperty)); 1.62 + mOrder.AppendElement(static_cast<uint32_t>(aProperty)); 1.63 +} 1.64 + 1.65 +void 1.66 +Declaration::RemoveProperty(nsCSSProperty aProperty) 1.67 +{ 1.68 + MOZ_ASSERT(0 <= aProperty && aProperty < eCSSProperty_COUNT); 1.69 + 1.70 + nsCSSExpandedDataBlock data; 1.71 + ExpandTo(&data); 1.72 + NS_ABORT_IF_FALSE(!mData && !mImportantData, "Expand didn't null things out"); 1.73 + 1.74 + if (nsCSSProps::IsShorthand(aProperty)) { 1.75 + CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p, aProperty) { 1.76 + data.ClearLonghandProperty(*p); 1.77 + mOrder.RemoveElement(static_cast<uint32_t>(*p)); 1.78 + } 1.79 + } else { 1.80 + data.ClearLonghandProperty(aProperty); 1.81 + mOrder.RemoveElement(static_cast<uint32_t>(aProperty)); 1.82 + } 1.83 + 1.84 + CompressFrom(&data); 1.85 +} 1.86 + 1.87 +bool 1.88 +Declaration::HasProperty(nsCSSProperty aProperty) const 1.89 +{ 1.90 + NS_ABORT_IF_FALSE(0 <= aProperty && 1.91 + aProperty < eCSSProperty_COUNT_no_shorthands, 1.92 + "property ID out of range"); 1.93 + 1.94 + nsCSSCompressedDataBlock *data = GetValueIsImportant(aProperty) 1.95 + ? mImportantData : mData; 1.96 + const nsCSSValue *val = data->ValueFor(aProperty); 1.97 + return !!val; 1.98 +} 1.99 + 1.100 +bool 1.101 +Declaration::AppendValueToString(nsCSSProperty aProperty, 1.102 + nsAString& aResult, 1.103 + nsCSSValue::Serialization aSerialization) const 1.104 +{ 1.105 + NS_ABORT_IF_FALSE(0 <= aProperty && 1.106 + aProperty < eCSSProperty_COUNT_no_shorthands, 1.107 + "property ID out of range"); 1.108 + 1.109 + nsCSSCompressedDataBlock *data = GetValueIsImportant(aProperty) 1.110 + ? mImportantData : mData; 1.111 + const nsCSSValue *val = data->ValueFor(aProperty); 1.112 + if (!val) { 1.113 + return false; 1.114 + } 1.115 + 1.116 + val->AppendToString(aProperty, aResult, aSerialization); 1.117 + return true; 1.118 +} 1.119 + 1.120 +// Helper to append |aString| with the shorthand sides notation used in e.g. 1.121 +// 'padding'. |aProperties| and |aValues| are expected to have 4 elements. 1.122 +static void 1.123 +AppendSidesShorthandToString(const nsCSSProperty aProperties[], 1.124 + const nsCSSValue* aValues[], 1.125 + nsAString& aString, 1.126 + nsCSSValue::Serialization aSerialization) 1.127 +{ 1.128 + const nsCSSValue& value1 = *aValues[0]; 1.129 + const nsCSSValue& value2 = *aValues[1]; 1.130 + const nsCSSValue& value3 = *aValues[2]; 1.131 + const nsCSSValue& value4 = *aValues[3]; 1.132 + 1.133 + NS_ABORT_IF_FALSE(value1.GetUnit() != eCSSUnit_Null, "null value 1"); 1.134 + value1.AppendToString(aProperties[0], aString, aSerialization); 1.135 + if (value1 != value2 || value1 != value3 || value1 != value4) { 1.136 + aString.Append(char16_t(' ')); 1.137 + NS_ABORT_IF_FALSE(value2.GetUnit() != eCSSUnit_Null, "null value 2"); 1.138 + value2.AppendToString(aProperties[1], aString, aSerialization); 1.139 + if (value1 != value3 || value2 != value4) { 1.140 + aString.Append(char16_t(' ')); 1.141 + NS_ABORT_IF_FALSE(value3.GetUnit() != eCSSUnit_Null, "null value 3"); 1.142 + value3.AppendToString(aProperties[2], aString, aSerialization); 1.143 + if (value2 != value4) { 1.144 + aString.Append(char16_t(' ')); 1.145 + NS_ABORT_IF_FALSE(value4.GetUnit() != eCSSUnit_Null, "null value 4"); 1.146 + value4.AppendToString(aProperties[3], aString, aSerialization); 1.147 + } 1.148 + } 1.149 + } 1.150 +} 1.151 + 1.152 +void 1.153 +Declaration::GetValue(nsCSSProperty aProperty, nsAString& aValue) const 1.154 +{ 1.155 + GetValue(aProperty, aValue, nsCSSValue::eNormalized); 1.156 +} 1.157 + 1.158 +void 1.159 +Declaration::GetAuthoredValue(nsCSSProperty aProperty, nsAString& aValue) const 1.160 +{ 1.161 + GetValue(aProperty, aValue, nsCSSValue::eAuthorSpecified); 1.162 +} 1.163 + 1.164 +void 1.165 +Declaration::GetValue(nsCSSProperty aProperty, nsAString& aValue, 1.166 + nsCSSValue::Serialization aSerialization) const 1.167 +{ 1.168 + aValue.Truncate(0); 1.169 + 1.170 + // simple properties are easy. 1.171 + if (!nsCSSProps::IsShorthand(aProperty)) { 1.172 + AppendValueToString(aProperty, aValue, aSerialization); 1.173 + return; 1.174 + } 1.175 + 1.176 + // DOM Level 2 Style says (when describing CSS2Properties, although 1.177 + // not CSSStyleDeclaration.getPropertyValue): 1.178 + // However, if there is no shorthand declaration that could be added 1.179 + // to the ruleset without changing in any way the rules already 1.180 + // declared in the ruleset (i.e., by adding longhand rules that were 1.181 + // previously not declared in the ruleset), then the empty string 1.182 + // should be returned for the shorthand property. 1.183 + // This means we need to check a number of cases: 1.184 + // (1) Since a shorthand sets all sub-properties, if some of its 1.185 + // subproperties were not specified, we must return the empty 1.186 + // string. 1.187 + // (2) Since 'inherit', 'initial' and 'unset' can only be specified 1.188 + // as the values for entire properties, we need to return the 1.189 + // empty string if some but not all of the subproperties have one 1.190 + // of those values. 1.191 + // (3) Since a single value only makes sense with or without 1.192 + // !important, we return the empty string if some values are 1.193 + // !important and some are not. 1.194 + // Since we're doing this check for 'inherit' and 'initial' up front, 1.195 + // we can also simplify the property serialization code by serializing 1.196 + // those values up front as well. 1.197 + // 1.198 + // Additionally, if a shorthand property was set using a value with a 1.199 + // variable reference and none of its component longhand properties were 1.200 + // then overridden on the declaration, we return the token stream 1.201 + // assigned to the shorthand. 1.202 + const nsCSSValue* tokenStream = nullptr; 1.203 + uint32_t totalCount = 0, importantCount = 0, 1.204 + initialCount = 0, inheritCount = 0, unsetCount = 0, 1.205 + matchingTokenStreamCount = 0; 1.206 + CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p, aProperty) { 1.207 + if (*p == eCSSProperty__x_system_font || 1.208 + nsCSSProps::PropHasFlags(*p, CSS_PROPERTY_DIRECTIONAL_SOURCE)) { 1.209 + // The system-font subproperty and the *-source properties don't count. 1.210 + continue; 1.211 + } 1.212 + ++totalCount; 1.213 + const nsCSSValue *val = mData->ValueFor(*p); 1.214 + NS_ABORT_IF_FALSE(!val || !mImportantData || !mImportantData->ValueFor(*p), 1.215 + "can't be in both blocks"); 1.216 + if (!val && mImportantData) { 1.217 + ++importantCount; 1.218 + val = mImportantData->ValueFor(*p); 1.219 + } 1.220 + if (!val) { 1.221 + // Case (1) above: some subproperties not specified. 1.222 + return; 1.223 + } 1.224 + if (val->GetUnit() == eCSSUnit_Inherit) { 1.225 + ++inheritCount; 1.226 + } else if (val->GetUnit() == eCSSUnit_Initial) { 1.227 + ++initialCount; 1.228 + } else if (val->GetUnit() == eCSSUnit_Unset) { 1.229 + ++unsetCount; 1.230 + } else if (val->GetUnit() == eCSSUnit_TokenStream && 1.231 + val->GetTokenStreamValue()->mShorthandPropertyID == aProperty) { 1.232 + tokenStream = val; 1.233 + ++matchingTokenStreamCount; 1.234 + } 1.235 + } 1.236 + if (importantCount != 0 && importantCount != totalCount) { 1.237 + // Case (3), no consistent importance. 1.238 + return; 1.239 + } 1.240 + if (initialCount == totalCount) { 1.241 + // Simplify serialization below by serializing initial up-front. 1.242 + nsCSSValue(eCSSUnit_Initial).AppendToString(eCSSProperty_UNKNOWN, aValue, 1.243 + nsCSSValue::eNormalized); 1.244 + return; 1.245 + } 1.246 + if (inheritCount == totalCount) { 1.247 + // Simplify serialization below by serializing inherit up-front. 1.248 + nsCSSValue(eCSSUnit_Inherit).AppendToString(eCSSProperty_UNKNOWN, aValue, 1.249 + nsCSSValue::eNormalized); 1.250 + return; 1.251 + } 1.252 + if (unsetCount == totalCount) { 1.253 + // Simplify serialization below by serializing unset up-front. 1.254 + nsCSSValue(eCSSUnit_Unset).AppendToString(eCSSProperty_UNKNOWN, aValue, 1.255 + nsCSSValue::eNormalized); 1.256 + return; 1.257 + } 1.258 + if (initialCount != 0 || inheritCount != 0 || unsetCount != 0) { 1.259 + // Case (2): partially initial, inherit or unset. 1.260 + return; 1.261 + } 1.262 + if (tokenStream) { 1.263 + if (matchingTokenStreamCount == totalCount) { 1.264 + // Shorthand was specified using variable references and all of its 1.265 + // longhand components were set by the shorthand. 1.266 + aValue.Append(tokenStream->GetTokenStreamValue()->mTokenStream); 1.267 + } else { 1.268 + // In all other cases, serialize to the empty string. 1.269 + } 1.270 + return; 1.271 + } 1.272 + 1.273 + nsCSSCompressedDataBlock *data = importantCount ? mImportantData : mData; 1.274 + switch (aProperty) { 1.275 + case eCSSProperty_margin: 1.276 + case eCSSProperty_padding: 1.277 + case eCSSProperty_border_color: 1.278 + case eCSSProperty_border_style: 1.279 + case eCSSProperty_border_width: { 1.280 + const nsCSSProperty* subprops = 1.281 + nsCSSProps::SubpropertyEntryFor(aProperty); 1.282 + NS_ABORT_IF_FALSE(nsCSSProps::GetStringValue(subprops[0]).Find("-top") != 1.283 + kNotFound, "first subprop must be top"); 1.284 + NS_ABORT_IF_FALSE(nsCSSProps::GetStringValue(subprops[1]).Find("-right") != 1.285 + kNotFound, "second subprop must be right"); 1.286 + NS_ABORT_IF_FALSE(nsCSSProps::GetStringValue(subprops[2]).Find("-bottom") != 1.287 + kNotFound, "third subprop must be bottom"); 1.288 + NS_ABORT_IF_FALSE(nsCSSProps::GetStringValue(subprops[3]).Find("-left") != 1.289 + kNotFound, "fourth subprop must be left"); 1.290 + const nsCSSValue* vals[4] = { 1.291 + data->ValueFor(subprops[0]), 1.292 + data->ValueFor(subprops[1]), 1.293 + data->ValueFor(subprops[2]), 1.294 + data->ValueFor(subprops[3]) 1.295 + }; 1.296 + AppendSidesShorthandToString(subprops, vals, aValue, aSerialization); 1.297 + break; 1.298 + } 1.299 + case eCSSProperty_border_radius: 1.300 + case eCSSProperty__moz_outline_radius: { 1.301 + const nsCSSProperty* subprops = 1.302 + nsCSSProps::SubpropertyEntryFor(aProperty); 1.303 + const nsCSSValue* vals[4] = { 1.304 + data->ValueFor(subprops[0]), 1.305 + data->ValueFor(subprops[1]), 1.306 + data->ValueFor(subprops[2]), 1.307 + data->ValueFor(subprops[3]) 1.308 + }; 1.309 + 1.310 + // For compatibility, only write a slash and the y-values 1.311 + // if they're not identical to the x-values. 1.312 + bool needY = false; 1.313 + const nsCSSValue* xVals[4]; 1.314 + const nsCSSValue* yVals[4]; 1.315 + for (int i = 0; i < 4; i++) { 1.316 + if (vals[i]->GetUnit() == eCSSUnit_Pair) { 1.317 + needY = true; 1.318 + xVals[i] = &vals[i]->GetPairValue().mXValue; 1.319 + yVals[i] = &vals[i]->GetPairValue().mYValue; 1.320 + } else { 1.321 + xVals[i] = yVals[i] = vals[i]; 1.322 + } 1.323 + } 1.324 + 1.325 + AppendSidesShorthandToString(subprops, xVals, aValue, aSerialization); 1.326 + if (needY) { 1.327 + aValue.AppendLiteral(" / "); 1.328 + AppendSidesShorthandToString(subprops, yVals, aValue, aSerialization); 1.329 + } 1.330 + break; 1.331 + } 1.332 + case eCSSProperty_border_image: { 1.333 + // Even though there are some cases where we could omit 1.334 + // 'border-image-source' (when it's none), it's probably not a 1.335 + // good idea since it's likely to be confusing. It would also 1.336 + // require adding the extra check that we serialize *something*. 1.337 + AppendValueToString(eCSSProperty_border_image_source, aValue, 1.338 + aSerialization); 1.339 + 1.340 + bool sliceDefault = data->HasDefaultBorderImageSlice(); 1.341 + bool widthDefault = data->HasDefaultBorderImageWidth(); 1.342 + bool outsetDefault = data->HasDefaultBorderImageOutset(); 1.343 + 1.344 + if (!sliceDefault || !widthDefault || !outsetDefault) { 1.345 + aValue.Append(char16_t(' ')); 1.346 + AppendValueToString(eCSSProperty_border_image_slice, aValue, 1.347 + aSerialization); 1.348 + if (!widthDefault || !outsetDefault) { 1.349 + aValue.Append(NS_LITERAL_STRING(" /")); 1.350 + if (!widthDefault) { 1.351 + aValue.Append(char16_t(' ')); 1.352 + AppendValueToString(eCSSProperty_border_image_width, aValue, 1.353 + aSerialization); 1.354 + } 1.355 + if (!outsetDefault) { 1.356 + aValue.Append(NS_LITERAL_STRING(" / ")); 1.357 + AppendValueToString(eCSSProperty_border_image_outset, aValue, 1.358 + aSerialization); 1.359 + } 1.360 + } 1.361 + } 1.362 + 1.363 + bool repeatDefault = data->HasDefaultBorderImageRepeat(); 1.364 + if (!repeatDefault) { 1.365 + aValue.Append(char16_t(' ')); 1.366 + AppendValueToString(eCSSProperty_border_image_repeat, aValue, 1.367 + aSerialization); 1.368 + } 1.369 + break; 1.370 + } 1.371 + case eCSSProperty_border: { 1.372 + // If we have a non-default value for any of the properties that 1.373 + // this shorthand sets but cannot specify, we have to return the 1.374 + // empty string. 1.375 + if (data->ValueFor(eCSSProperty_border_image_source)->GetUnit() != 1.376 + eCSSUnit_None || 1.377 + !data->HasDefaultBorderImageSlice() || 1.378 + !data->HasDefaultBorderImageWidth() || 1.379 + !data->HasDefaultBorderImageOutset() || 1.380 + !data->HasDefaultBorderImageRepeat() || 1.381 + data->ValueFor(eCSSProperty_border_top_colors)->GetUnit() != 1.382 + eCSSUnit_None || 1.383 + data->ValueFor(eCSSProperty_border_right_colors)->GetUnit() != 1.384 + eCSSUnit_None || 1.385 + data->ValueFor(eCSSProperty_border_bottom_colors)->GetUnit() != 1.386 + eCSSUnit_None || 1.387 + data->ValueFor(eCSSProperty_border_left_colors)->GetUnit() != 1.388 + eCSSUnit_None) { 1.389 + break; 1.390 + } 1.391 + 1.392 + const nsCSSProperty* subproptables[3] = { 1.393 + nsCSSProps::SubpropertyEntryFor(eCSSProperty_border_color), 1.394 + nsCSSProps::SubpropertyEntryFor(eCSSProperty_border_style), 1.395 + nsCSSProps::SubpropertyEntryFor(eCSSProperty_border_width) 1.396 + }; 1.397 + bool match = true; 1.398 + for (const nsCSSProperty** subprops = subproptables, 1.399 + **subprops_end = ArrayEnd(subproptables); 1.400 + subprops < subprops_end; ++subprops) { 1.401 + // Check only the first four subprops in each table, since the 1.402 + // others are extras for dimensional box properties. 1.403 + const nsCSSValue *firstSide = data->ValueFor((*subprops)[0]); 1.404 + for (int32_t side = 1; side < 4; ++side) { 1.405 + const nsCSSValue *otherSide = 1.406 + data->ValueFor((*subprops)[side]); 1.407 + if (*firstSide != *otherSide) 1.408 + match = false; 1.409 + } 1.410 + } 1.411 + if (!match) { 1.412 + // We can't express what we have in the border shorthand 1.413 + break; 1.414 + } 1.415 + // tweak aProperty and fall through 1.416 + aProperty = eCSSProperty_border_top; 1.417 + } 1.418 + case eCSSProperty_border_top: 1.419 + case eCSSProperty_border_right: 1.420 + case eCSSProperty_border_bottom: 1.421 + case eCSSProperty_border_left: 1.422 + case eCSSProperty_border_start: 1.423 + case eCSSProperty_border_end: 1.424 + case eCSSProperty__moz_column_rule: 1.425 + case eCSSProperty_outline: { 1.426 + const nsCSSProperty* subprops = 1.427 + nsCSSProps::SubpropertyEntryFor(aProperty); 1.428 + NS_ABORT_IF_FALSE(StringEndsWith(nsCSSProps::GetStringValue(subprops[2]), 1.429 + NS_LITERAL_CSTRING("-color")) || 1.430 + StringEndsWith(nsCSSProps::GetStringValue(subprops[2]), 1.431 + NS_LITERAL_CSTRING("-color-value")), 1.432 + "third subprop must be the color property"); 1.433 + const nsCSSValue *colorValue = data->ValueFor(subprops[2]); 1.434 + bool isMozUseTextColor = 1.435 + colorValue->GetUnit() == eCSSUnit_Enumerated && 1.436 + colorValue->GetIntValue() == NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR; 1.437 + if (!AppendValueToString(subprops[0], aValue, aSerialization) || 1.438 + !(aValue.Append(char16_t(' ')), 1.439 + AppendValueToString(subprops[1], aValue, aSerialization)) || 1.440 + // Don't output a third value when it's -moz-use-text-color. 1.441 + !(isMozUseTextColor || 1.442 + (aValue.Append(char16_t(' ')), 1.443 + AppendValueToString(subprops[2], aValue, aSerialization)))) { 1.444 + aValue.Truncate(); 1.445 + } 1.446 + break; 1.447 + } 1.448 + case eCSSProperty_margin_left: 1.449 + case eCSSProperty_margin_right: 1.450 + case eCSSProperty_margin_start: 1.451 + case eCSSProperty_margin_end: 1.452 + case eCSSProperty_padding_left: 1.453 + case eCSSProperty_padding_right: 1.454 + case eCSSProperty_padding_start: 1.455 + case eCSSProperty_padding_end: 1.456 + case eCSSProperty_border_left_color: 1.457 + case eCSSProperty_border_left_style: 1.458 + case eCSSProperty_border_left_width: 1.459 + case eCSSProperty_border_right_color: 1.460 + case eCSSProperty_border_right_style: 1.461 + case eCSSProperty_border_right_width: 1.462 + case eCSSProperty_border_start_color: 1.463 + case eCSSProperty_border_start_style: 1.464 + case eCSSProperty_border_start_width: 1.465 + case eCSSProperty_border_end_color: 1.466 + case eCSSProperty_border_end_style: 1.467 + case eCSSProperty_border_end_width: { 1.468 + const nsCSSProperty* subprops = 1.469 + nsCSSProps::SubpropertyEntryFor(aProperty); 1.470 + NS_ABORT_IF_FALSE(subprops[3] == eCSSProperty_UNKNOWN, 1.471 + "not box property with physical vs. logical cascading"); 1.472 + AppendValueToString(subprops[0], aValue, aSerialization); 1.473 + break; 1.474 + } 1.475 + case eCSSProperty_background: { 1.476 + // We know from above that all subproperties were specified. 1.477 + // However, we still can't represent that in the shorthand unless 1.478 + // they're all lists of the same length. So if they're different 1.479 + // lengths, we need to bail out. 1.480 + // We also need to bail out if an item has background-clip and 1.481 + // background-origin that are different and not the default 1.482 + // values. (We omit them if they're both default.) 1.483 + const nsCSSValueList *image = 1.484 + data->ValueFor(eCSSProperty_background_image)-> 1.485 + GetListValue(); 1.486 + const nsCSSValuePairList *repeat = 1.487 + data->ValueFor(eCSSProperty_background_repeat)-> 1.488 + GetPairListValue(); 1.489 + const nsCSSValueList *attachment = 1.490 + data->ValueFor(eCSSProperty_background_attachment)-> 1.491 + GetListValue(); 1.492 + const nsCSSValueList *position = 1.493 + data->ValueFor(eCSSProperty_background_position)-> 1.494 + GetListValue(); 1.495 + const nsCSSValueList *clip = 1.496 + data->ValueFor(eCSSProperty_background_clip)-> 1.497 + GetListValue(); 1.498 + const nsCSSValueList *origin = 1.499 + data->ValueFor(eCSSProperty_background_origin)-> 1.500 + GetListValue(); 1.501 + const nsCSSValuePairList *size = 1.502 + data->ValueFor(eCSSProperty_background_size)-> 1.503 + GetPairListValue(); 1.504 + for (;;) { 1.505 + image->mValue.AppendToString(eCSSProperty_background_image, aValue, 1.506 + aSerialization); 1.507 + aValue.Append(char16_t(' ')); 1.508 + repeat->mXValue.AppendToString(eCSSProperty_background_repeat, aValue, 1.509 + aSerialization); 1.510 + if (repeat->mYValue.GetUnit() != eCSSUnit_Null) { 1.511 + repeat->mYValue.AppendToString(eCSSProperty_background_repeat, aValue, 1.512 + aSerialization); 1.513 + } 1.514 + aValue.Append(char16_t(' ')); 1.515 + attachment->mValue.AppendToString(eCSSProperty_background_attachment, 1.516 + aValue, aSerialization); 1.517 + aValue.Append(char16_t(' ')); 1.518 + position->mValue.AppendToString(eCSSProperty_background_position, 1.519 + aValue, aSerialization); 1.520 + 1.521 + if (size->mXValue.GetUnit() != eCSSUnit_Auto || 1.522 + size->mYValue.GetUnit() != eCSSUnit_Auto) { 1.523 + aValue.Append(char16_t(' ')); 1.524 + aValue.Append(char16_t('/')); 1.525 + aValue.Append(char16_t(' ')); 1.526 + size->mXValue.AppendToString(eCSSProperty_background_size, aValue, 1.527 + aSerialization); 1.528 + aValue.Append(char16_t(' ')); 1.529 + size->mYValue.AppendToString(eCSSProperty_background_size, aValue, 1.530 + aSerialization); 1.531 + } 1.532 + 1.533 + NS_ABORT_IF_FALSE(clip->mValue.GetUnit() == eCSSUnit_Enumerated && 1.534 + origin->mValue.GetUnit() == eCSSUnit_Enumerated, 1.535 + "should not have inherit/initial within list"); 1.536 + 1.537 + if (clip->mValue.GetIntValue() != NS_STYLE_BG_CLIP_BORDER || 1.538 + origin->mValue.GetIntValue() != NS_STYLE_BG_ORIGIN_PADDING) { 1.539 + MOZ_ASSERT(nsCSSProps::kKeywordTableTable[ 1.540 + eCSSProperty_background_origin] == 1.541 + nsCSSProps::kBackgroundOriginKTable); 1.542 + MOZ_ASSERT(nsCSSProps::kKeywordTableTable[ 1.543 + eCSSProperty_background_clip] == 1.544 + nsCSSProps::kBackgroundOriginKTable); 1.545 + static_assert(NS_STYLE_BG_CLIP_BORDER == 1.546 + NS_STYLE_BG_ORIGIN_BORDER && 1.547 + NS_STYLE_BG_CLIP_PADDING == 1.548 + NS_STYLE_BG_ORIGIN_PADDING && 1.549 + NS_STYLE_BG_CLIP_CONTENT == 1.550 + NS_STYLE_BG_ORIGIN_CONTENT, 1.551 + "bg-clip and bg-origin style constants must agree"); 1.552 + aValue.Append(char16_t(' ')); 1.553 + origin->mValue.AppendToString(eCSSProperty_background_origin, aValue, 1.554 + aSerialization); 1.555 + 1.556 + if (clip->mValue != origin->mValue) { 1.557 + aValue.Append(char16_t(' ')); 1.558 + clip->mValue.AppendToString(eCSSProperty_background_clip, aValue, 1.559 + aSerialization); 1.560 + } 1.561 + } 1.562 + 1.563 + image = image->mNext; 1.564 + repeat = repeat->mNext; 1.565 + attachment = attachment->mNext; 1.566 + position = position->mNext; 1.567 + clip = clip->mNext; 1.568 + origin = origin->mNext; 1.569 + size = size->mNext; 1.570 + 1.571 + if (!image) { 1.572 + if (repeat || attachment || position || clip || origin || size) { 1.573 + // Uneven length lists, so can't be serialized as shorthand. 1.574 + aValue.Truncate(); 1.575 + return; 1.576 + } 1.577 + break; 1.578 + } 1.579 + if (!repeat || !attachment || !position || !clip || !origin || !size) { 1.580 + // Uneven length lists, so can't be serialized as shorthand. 1.581 + aValue.Truncate(); 1.582 + return; 1.583 + } 1.584 + aValue.Append(char16_t(',')); 1.585 + aValue.Append(char16_t(' ')); 1.586 + } 1.587 + 1.588 + aValue.Append(char16_t(' ')); 1.589 + AppendValueToString(eCSSProperty_background_color, aValue, 1.590 + aSerialization); 1.591 + break; 1.592 + } 1.593 + case eCSSProperty_font: { 1.594 + // systemFont might not be present; other values are guaranteed to be 1.595 + // available based on the shorthand check at the beginning of the 1.596 + // function, as long as the prop is enabled 1.597 + const nsCSSValue *systemFont = 1.598 + data->ValueFor(eCSSProperty__x_system_font); 1.599 + const nsCSSValue *style = 1.600 + data->ValueFor(eCSSProperty_font_style); 1.601 + const nsCSSValue *variant = 1.602 + data->ValueFor(eCSSProperty_font_variant); 1.603 + const nsCSSValue *weight = 1.604 + data->ValueFor(eCSSProperty_font_weight); 1.605 + const nsCSSValue *size = 1.606 + data->ValueFor(eCSSProperty_font_size); 1.607 + const nsCSSValue *lh = 1.608 + data->ValueFor(eCSSProperty_line_height); 1.609 + const nsCSSValue *family = 1.610 + data->ValueFor(eCSSProperty_font_family); 1.611 + const nsCSSValue *stretch = 1.612 + data->ValueFor(eCSSProperty_font_stretch); 1.613 + const nsCSSValue *sizeAdjust = 1.614 + data->ValueFor(eCSSProperty_font_size_adjust); 1.615 + const nsCSSValue *featureSettings = 1.616 + data->ValueFor(eCSSProperty_font_feature_settings); 1.617 + const nsCSSValue *languageOverride = 1.618 + data->ValueFor(eCSSProperty_font_language_override); 1.619 + const nsCSSValue *fontKerning = 1.620 + data->ValueFor(eCSSProperty_font_kerning); 1.621 + const nsCSSValue *fontSynthesis = 1.622 + data->ValueFor(eCSSProperty_font_synthesis); 1.623 + const nsCSSValue *fontVariantAlternates = 1.624 + data->ValueFor(eCSSProperty_font_variant_alternates); 1.625 + const nsCSSValue *fontVariantCaps = 1.626 + data->ValueFor(eCSSProperty_font_variant_caps); 1.627 + const nsCSSValue *fontVariantEastAsian = 1.628 + data->ValueFor(eCSSProperty_font_variant_east_asian); 1.629 + const nsCSSValue *fontVariantLigatures = 1.630 + data->ValueFor(eCSSProperty_font_variant_ligatures); 1.631 + const nsCSSValue *fontVariantNumeric = 1.632 + data->ValueFor(eCSSProperty_font_variant_numeric); 1.633 + const nsCSSValue *fontVariantPosition = 1.634 + data->ValueFor(eCSSProperty_font_variant_position); 1.635 + 1.636 + // if font features are not enabled, pointers for fontVariant 1.637 + // values above may be null since the shorthand check ignores them 1.638 + // font-variant-alternates enabled ==> layout.css.font-features.enabled is true 1.639 + bool fontFeaturesEnabled = 1.640 + nsCSSProps::IsEnabled(eCSSProperty_font_variant_alternates); 1.641 + 1.642 + if (systemFont && 1.643 + systemFont->GetUnit() != eCSSUnit_None && 1.644 + systemFont->GetUnit() != eCSSUnit_Null) { 1.645 + if (style->GetUnit() != eCSSUnit_System_Font || 1.646 + variant->GetUnit() != eCSSUnit_System_Font || 1.647 + weight->GetUnit() != eCSSUnit_System_Font || 1.648 + size->GetUnit() != eCSSUnit_System_Font || 1.649 + lh->GetUnit() != eCSSUnit_System_Font || 1.650 + family->GetUnit() != eCSSUnit_System_Font || 1.651 + stretch->GetUnit() != eCSSUnit_System_Font || 1.652 + sizeAdjust->GetUnit() != eCSSUnit_System_Font || 1.653 + featureSettings->GetUnit() != eCSSUnit_System_Font || 1.654 + languageOverride->GetUnit() != eCSSUnit_System_Font || 1.655 + (fontFeaturesEnabled && 1.656 + (fontKerning->GetUnit() != eCSSUnit_System_Font || 1.657 + fontSynthesis->GetUnit() != eCSSUnit_System_Font || 1.658 + fontVariantAlternates->GetUnit() != eCSSUnit_System_Font || 1.659 + fontVariantCaps->GetUnit() != eCSSUnit_System_Font || 1.660 + fontVariantEastAsian->GetUnit() != eCSSUnit_System_Font || 1.661 + fontVariantLigatures->GetUnit() != eCSSUnit_System_Font || 1.662 + fontVariantNumeric->GetUnit() != eCSSUnit_System_Font || 1.663 + fontVariantPosition->GetUnit() != eCSSUnit_System_Font))) { 1.664 + // This can't be represented as a shorthand. 1.665 + return; 1.666 + } 1.667 + systemFont->AppendToString(eCSSProperty__x_system_font, aValue, 1.668 + aSerialization); 1.669 + } else { 1.670 + // properties reset by this shorthand property to their 1.671 + // initial values but not represented in its syntax 1.672 + if (stretch->GetUnit() != eCSSUnit_Enumerated || 1.673 + stretch->GetIntValue() != NS_STYLE_FONT_STRETCH_NORMAL || 1.674 + sizeAdjust->GetUnit() != eCSSUnit_None || 1.675 + featureSettings->GetUnit() != eCSSUnit_Normal || 1.676 + languageOverride->GetUnit() != eCSSUnit_Normal || 1.677 + (fontFeaturesEnabled && 1.678 + (fontKerning->GetIntValue() != NS_FONT_KERNING_AUTO || 1.679 + fontSynthesis->GetUnit() != eCSSUnit_Enumerated || 1.680 + fontSynthesis->GetIntValue() != 1.681 + (NS_FONT_SYNTHESIS_WEIGHT | NS_FONT_SYNTHESIS_STYLE) || 1.682 + fontVariantAlternates->GetUnit() != eCSSUnit_Normal || 1.683 + fontVariantCaps->GetUnit() != eCSSUnit_Normal || 1.684 + fontVariantEastAsian->GetUnit() != eCSSUnit_Normal || 1.685 + fontVariantLigatures->GetUnit() != eCSSUnit_Normal || 1.686 + fontVariantNumeric->GetUnit() != eCSSUnit_Normal || 1.687 + fontVariantPosition->GetUnit() != eCSSUnit_Normal))) { 1.688 + return; 1.689 + } 1.690 + 1.691 + if (style->GetUnit() != eCSSUnit_Enumerated || 1.692 + style->GetIntValue() != NS_FONT_STYLE_NORMAL) { 1.693 + style->AppendToString(eCSSProperty_font_style, aValue, 1.694 + aSerialization); 1.695 + aValue.Append(char16_t(' ')); 1.696 + } 1.697 + if (variant->GetUnit() != eCSSUnit_Enumerated || 1.698 + variant->GetIntValue() != NS_FONT_VARIANT_NORMAL) { 1.699 + variant->AppendToString(eCSSProperty_font_variant, aValue, 1.700 + aSerialization); 1.701 + aValue.Append(char16_t(' ')); 1.702 + } 1.703 + if (weight->GetUnit() != eCSSUnit_Enumerated || 1.704 + weight->GetIntValue() != NS_FONT_WEIGHT_NORMAL) { 1.705 + weight->AppendToString(eCSSProperty_font_weight, aValue, 1.706 + aSerialization); 1.707 + aValue.Append(char16_t(' ')); 1.708 + } 1.709 + size->AppendToString(eCSSProperty_font_size, aValue, aSerialization); 1.710 + if (lh->GetUnit() != eCSSUnit_Normal) { 1.711 + aValue.Append(char16_t('/')); 1.712 + lh->AppendToString(eCSSProperty_line_height, aValue, aSerialization); 1.713 + } 1.714 + aValue.Append(char16_t(' ')); 1.715 + family->AppendToString(eCSSProperty_font_family, aValue, 1.716 + aSerialization); 1.717 + } 1.718 + break; 1.719 + } 1.720 + case eCSSProperty_list_style: 1.721 + if (AppendValueToString(eCSSProperty_list_style_type, aValue, 1.722 + aSerialization)) { 1.723 + aValue.Append(char16_t(' ')); 1.724 + } 1.725 + if (AppendValueToString(eCSSProperty_list_style_position, aValue, 1.726 + aSerialization)) { 1.727 + aValue.Append(char16_t(' ')); 1.728 + } 1.729 + AppendValueToString(eCSSProperty_list_style_image, aValue, 1.730 + aSerialization); 1.731 + break; 1.732 + case eCSSProperty_overflow: { 1.733 + const nsCSSValue &xValue = 1.734 + *data->ValueFor(eCSSProperty_overflow_x); 1.735 + const nsCSSValue &yValue = 1.736 + *data->ValueFor(eCSSProperty_overflow_y); 1.737 + if (xValue == yValue) 1.738 + xValue.AppendToString(eCSSProperty_overflow_x, aValue, aSerialization); 1.739 + break; 1.740 + } 1.741 + case eCSSProperty_text_decoration: { 1.742 + // If text-decoration-color or text-decoration-style isn't initial value, 1.743 + // we cannot serialize the text-decoration shorthand value. 1.744 + const nsCSSValue *decorationColor = 1.745 + data->ValueFor(eCSSProperty_text_decoration_color); 1.746 + const nsCSSValue *decorationStyle = 1.747 + data->ValueFor(eCSSProperty_text_decoration_style); 1.748 + 1.749 + NS_ABORT_IF_FALSE(decorationStyle->GetUnit() == eCSSUnit_Enumerated, 1.750 + nsPrintfCString("bad text-decoration-style unit %d", 1.751 + decorationStyle->GetUnit()).get()); 1.752 + 1.753 + if (decorationColor->GetUnit() != eCSSUnit_Enumerated || 1.754 + decorationColor->GetIntValue() != NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR || 1.755 + decorationStyle->GetIntValue() != 1.756 + NS_STYLE_TEXT_DECORATION_STYLE_SOLID) { 1.757 + return; 1.758 + } 1.759 + 1.760 + AppendValueToString(eCSSProperty_text_decoration_line, aValue, 1.761 + aSerialization); 1.762 + break; 1.763 + } 1.764 + case eCSSProperty_transition: { 1.765 + const nsCSSValue *transProp = 1.766 + data->ValueFor(eCSSProperty_transition_property); 1.767 + const nsCSSValue *transDuration = 1.768 + data->ValueFor(eCSSProperty_transition_duration); 1.769 + const nsCSSValue *transTiming = 1.770 + data->ValueFor(eCSSProperty_transition_timing_function); 1.771 + const nsCSSValue *transDelay = 1.772 + data->ValueFor(eCSSProperty_transition_delay); 1.773 + 1.774 + NS_ABORT_IF_FALSE(transDuration->GetUnit() == eCSSUnit_List || 1.775 + transDuration->GetUnit() == eCSSUnit_ListDep, 1.776 + nsPrintfCString("bad t-duration unit %d", 1.777 + transDuration->GetUnit()).get()); 1.778 + NS_ABORT_IF_FALSE(transTiming->GetUnit() == eCSSUnit_List || 1.779 + transTiming->GetUnit() == eCSSUnit_ListDep, 1.780 + nsPrintfCString("bad t-timing unit %d", 1.781 + transTiming->GetUnit()).get()); 1.782 + NS_ABORT_IF_FALSE(transDelay->GetUnit() == eCSSUnit_List || 1.783 + transDelay->GetUnit() == eCSSUnit_ListDep, 1.784 + nsPrintfCString("bad t-delay unit %d", 1.785 + transDelay->GetUnit()).get()); 1.786 + 1.787 + const nsCSSValueList* dur = transDuration->GetListValue(); 1.788 + const nsCSSValueList* tim = transTiming->GetListValue(); 1.789 + const nsCSSValueList* del = transDelay->GetListValue(); 1.790 + 1.791 + if (transProp->GetUnit() == eCSSUnit_None || 1.792 + transProp->GetUnit() == eCSSUnit_All) { 1.793 + // If any of the other three lists has more than one element, 1.794 + // we can't use the shorthand. 1.795 + if (!dur->mNext && !tim->mNext && !del->mNext) { 1.796 + transProp->AppendToString(eCSSProperty_transition_property, aValue, 1.797 + aSerialization); 1.798 + aValue.Append(char16_t(' ')); 1.799 + dur->mValue.AppendToString(eCSSProperty_transition_duration,aValue, 1.800 + aSerialization); 1.801 + aValue.Append(char16_t(' ')); 1.802 + tim->mValue.AppendToString(eCSSProperty_transition_timing_function, 1.803 + aValue, aSerialization); 1.804 + aValue.Append(char16_t(' ')); 1.805 + del->mValue.AppendToString(eCSSProperty_transition_delay, aValue, 1.806 + aSerialization); 1.807 + aValue.Append(char16_t(' ')); 1.808 + } else { 1.809 + aValue.Truncate(); 1.810 + } 1.811 + } else { 1.812 + NS_ABORT_IF_FALSE(transProp->GetUnit() == eCSSUnit_List || 1.813 + transProp->GetUnit() == eCSSUnit_ListDep, 1.814 + nsPrintfCString("bad t-prop unit %d", 1.815 + transProp->GetUnit()).get()); 1.816 + const nsCSSValueList* pro = transProp->GetListValue(); 1.817 + for (;;) { 1.818 + pro->mValue.AppendToString(eCSSProperty_transition_property, 1.819 + aValue, aSerialization); 1.820 + aValue.Append(char16_t(' ')); 1.821 + dur->mValue.AppendToString(eCSSProperty_transition_duration, 1.822 + aValue, aSerialization); 1.823 + aValue.Append(char16_t(' ')); 1.824 + tim->mValue.AppendToString(eCSSProperty_transition_timing_function, 1.825 + aValue, aSerialization); 1.826 + aValue.Append(char16_t(' ')); 1.827 + del->mValue.AppendToString(eCSSProperty_transition_delay, 1.828 + aValue, aSerialization); 1.829 + pro = pro->mNext; 1.830 + dur = dur->mNext; 1.831 + tim = tim->mNext; 1.832 + del = del->mNext; 1.833 + if (!pro || !dur || !tim || !del) { 1.834 + break; 1.835 + } 1.836 + aValue.AppendLiteral(", "); 1.837 + } 1.838 + if (pro || dur || tim || del) { 1.839 + // Lists not all the same length, can't use shorthand. 1.840 + aValue.Truncate(); 1.841 + } 1.842 + } 1.843 + break; 1.844 + } 1.845 + case eCSSProperty_animation: { 1.846 + const nsCSSProperty* subprops = 1.847 + nsCSSProps::SubpropertyEntryFor(eCSSProperty_animation); 1.848 + static const size_t numProps = 7; 1.849 + NS_ABORT_IF_FALSE(subprops[numProps] == eCSSProperty_UNKNOWN, 1.850 + "unexpected number of subproperties"); 1.851 + const nsCSSValue* values[numProps]; 1.852 + const nsCSSValueList* lists[numProps]; 1.853 + 1.854 + for (uint32_t i = 0; i < numProps; ++i) { 1.855 + values[i] = data->ValueFor(subprops[i]); 1.856 + NS_ABORT_IF_FALSE(values[i]->GetUnit() == eCSSUnit_List || 1.857 + values[i]->GetUnit() == eCSSUnit_ListDep, 1.858 + nsPrintfCString("bad a-duration unit %d", 1.859 + values[i]->GetUnit()).get()); 1.860 + lists[i] = values[i]->GetListValue(); 1.861 + } 1.862 + 1.863 + for (;;) { 1.864 + // We must serialize 'animation-name' last in case it has 1.865 + // a value that conflicts with one of the other keyword properties. 1.866 + NS_ABORT_IF_FALSE(subprops[numProps - 1] == 1.867 + eCSSProperty_animation_name, 1.868 + "animation-name must be last"); 1.869 + bool done = false; 1.870 + for (uint32_t i = 0;;) { 1.871 + lists[i]->mValue.AppendToString(subprops[i], aValue, aSerialization); 1.872 + lists[i] = lists[i]->mNext; 1.873 + if (!lists[i]) { 1.874 + done = true; 1.875 + } 1.876 + if (++i == numProps) { 1.877 + break; 1.878 + } 1.879 + aValue.Append(char16_t(' ')); 1.880 + } 1.881 + if (done) { 1.882 + break; 1.883 + } 1.884 + aValue.AppendLiteral(", "); 1.885 + } 1.886 + for (uint32_t i = 0; i < numProps; ++i) { 1.887 + if (lists[i]) { 1.888 + // Lists not all the same length, can't use shorthand. 1.889 + aValue.Truncate(); 1.890 + break; 1.891 + } 1.892 + } 1.893 + break; 1.894 + } 1.895 + case eCSSProperty_marker: { 1.896 + const nsCSSValue &endValue = 1.897 + *data->ValueFor(eCSSProperty_marker_end); 1.898 + const nsCSSValue &midValue = 1.899 + *data->ValueFor(eCSSProperty_marker_mid); 1.900 + const nsCSSValue &startValue = 1.901 + *data->ValueFor(eCSSProperty_marker_start); 1.902 + if (endValue == midValue && midValue == startValue) 1.903 + AppendValueToString(eCSSProperty_marker_end, aValue, aSerialization); 1.904 + break; 1.905 + } 1.906 + case eCSSProperty__moz_columns: { 1.907 + // Two values, column-count and column-width, separated by a space. 1.908 + const nsCSSProperty* subprops = 1.909 + nsCSSProps::SubpropertyEntryFor(aProperty); 1.910 + AppendValueToString(subprops[0], aValue, aSerialization); 1.911 + aValue.Append(char16_t(' ')); 1.912 + AppendValueToString(subprops[1], aValue, aSerialization); 1.913 + break; 1.914 + } 1.915 + case eCSSProperty_flex: { 1.916 + // flex-grow, flex-shrink, flex-basis, separated by single space 1.917 + const nsCSSProperty* subprops = 1.918 + nsCSSProps::SubpropertyEntryFor(aProperty); 1.919 + 1.920 + AppendValueToString(subprops[0], aValue, aSerialization); 1.921 + aValue.Append(char16_t(' ')); 1.922 + AppendValueToString(subprops[1], aValue, aSerialization); 1.923 + aValue.Append(char16_t(' ')); 1.924 + AppendValueToString(subprops[2], aValue, aSerialization); 1.925 + break; 1.926 + } 1.927 + case eCSSProperty_flex_flow: { 1.928 + // flex-direction, flex-wrap, separated by single space 1.929 + const nsCSSProperty* subprops = 1.930 + nsCSSProps::SubpropertyEntryFor(aProperty); 1.931 + NS_ABORT_IF_FALSE(subprops[2] == eCSSProperty_UNKNOWN, 1.932 + "must have exactly two subproperties"); 1.933 + 1.934 + AppendValueToString(subprops[0], aValue, aSerialization); 1.935 + aValue.Append(char16_t(' ')); 1.936 + AppendValueToString(subprops[1], aValue, aSerialization); 1.937 + break; 1.938 + } 1.939 + case eCSSProperty_grid_row: 1.940 + case eCSSProperty_grid_column: { 1.941 + // grid-{row,column}-start, grid-{row,column}-end, separated by a slash 1.942 + const nsCSSProperty* subprops = 1.943 + nsCSSProps::SubpropertyEntryFor(aProperty); 1.944 + NS_ABORT_IF_FALSE(subprops[2] == eCSSProperty_UNKNOWN, 1.945 + "must have exactly two subproperties"); 1.946 + 1.947 + // TODO: should we simplify when possible? 1.948 + AppendValueToString(subprops[0], aValue, aSerialization); 1.949 + aValue.AppendLiteral(" / "); 1.950 + AppendValueToString(subprops[1], aValue, aSerialization); 1.951 + break; 1.952 + } 1.953 + case eCSSProperty_grid_area: { 1.954 + const nsCSSProperty* subprops = 1.955 + nsCSSProps::SubpropertyEntryFor(aProperty); 1.956 + NS_ABORT_IF_FALSE(subprops[4] == eCSSProperty_UNKNOWN, 1.957 + "must have exactly four subproperties"); 1.958 + 1.959 + // TODO: should we simplify when possible? 1.960 + AppendValueToString(subprops[0], aValue, aSerialization); 1.961 + aValue.AppendLiteral(" / "); 1.962 + AppendValueToString(subprops[1], aValue, aSerialization); 1.963 + aValue.AppendLiteral(" / "); 1.964 + AppendValueToString(subprops[2], aValue, aSerialization); 1.965 + aValue.AppendLiteral(" / "); 1.966 + AppendValueToString(subprops[3], aValue, aSerialization); 1.967 + break; 1.968 + } 1.969 + 1.970 + // This can express either grid-template-{areas,columns,rows} 1.971 + // or grid-auto-{flow,columns,rows}, but not both. 1.972 + case eCSSProperty_grid: { 1.973 + const nsCSSValue& areasValue = 1.974 + *data->ValueFor(eCSSProperty_grid_template_areas); 1.975 + const nsCSSValue& columnsValue = 1.976 + *data->ValueFor(eCSSProperty_grid_template_columns); 1.977 + const nsCSSValue& rowsValue = 1.978 + *data->ValueFor(eCSSProperty_grid_template_rows); 1.979 + 1.980 + const nsCSSValue& autoFlowValue = 1.981 + *data->ValueFor(eCSSProperty_grid_auto_flow); 1.982 + const nsCSSValue& autoColumnsValue = 1.983 + *data->ValueFor(eCSSProperty_grid_auto_columns); 1.984 + const nsCSSValue& autoRowsValue = 1.985 + *data->ValueFor(eCSSProperty_grid_auto_rows); 1.986 + 1.987 + if (areasValue.GetUnit() == eCSSUnit_None && 1.988 + columnsValue.GetUnit() == eCSSUnit_None && 1.989 + rowsValue.GetUnit() == eCSSUnit_None) { 1.990 + AppendValueToString(eCSSProperty_grid_auto_flow, 1.991 + aValue, aSerialization); 1.992 + aValue.Append(char16_t(' ')); 1.993 + AppendValueToString(eCSSProperty_grid_auto_columns, 1.994 + aValue, aSerialization); 1.995 + aValue.AppendLiteral(" / "); 1.996 + AppendValueToString(eCSSProperty_grid_auto_rows, 1.997 + aValue, aSerialization); 1.998 + break; 1.999 + } else if (!(autoFlowValue.GetUnit() == eCSSUnit_Enumerated && 1.1000 + autoFlowValue.GetIntValue() == NS_STYLE_GRID_AUTO_FLOW_NONE && 1.1001 + autoColumnsValue.GetUnit() == eCSSUnit_Auto && 1.1002 + autoRowsValue.GetUnit() == eCSSUnit_Auto)) { 1.1003 + // Not serializable, bail. 1.1004 + return; 1.1005 + } 1.1006 + // Fall through to eCSSProperty_grid_template 1.1007 + } 1.1008 + case eCSSProperty_grid_template: { 1.1009 + const nsCSSValue& areasValue = 1.1010 + *data->ValueFor(eCSSProperty_grid_template_areas); 1.1011 + const nsCSSValue& columnsValue = 1.1012 + *data->ValueFor(eCSSProperty_grid_template_columns); 1.1013 + const nsCSSValue& rowsValue = 1.1014 + *data->ValueFor(eCSSProperty_grid_template_rows); 1.1015 + if (areasValue.GetUnit() == eCSSUnit_None) { 1.1016 + AppendValueToString(eCSSProperty_grid_template_columns, 1.1017 + aValue, aSerialization); 1.1018 + aValue.AppendLiteral(" / "); 1.1019 + AppendValueToString(eCSSProperty_grid_template_rows, 1.1020 + aValue, aSerialization); 1.1021 + break; 1.1022 + } 1.1023 + if (columnsValue.GetUnit() == eCSSUnit_List || 1.1024 + columnsValue.GetUnit() == eCSSUnit_ListDep) { 1.1025 + const nsCSSValueList* columnsItem = columnsValue.GetListValue(); 1.1026 + if (columnsItem->mValue.GetUnit() == eCSSUnit_Enumerated && 1.1027 + columnsItem->mValue.GetIntValue() == NS_STYLE_GRID_TEMPLATE_SUBGRID) { 1.1028 + // We have "grid-template-areas:[something]; grid-template-columns:subgrid" 1.1029 + // which isn't a value that the shorthand can express. Bail. 1.1030 + return; 1.1031 + } 1.1032 + } 1.1033 + if (rowsValue.GetUnit() != eCSSUnit_List && 1.1034 + rowsValue.GetUnit() != eCSSUnit_ListDep) { 1.1035 + // We have "grid-template-areas:[something]; grid-template-rows:none" 1.1036 + // which isn't a value that the shorthand can express. Bail. 1.1037 + return; 1.1038 + } 1.1039 + const nsCSSValueList* rowsItem = rowsValue.GetListValue(); 1.1040 + if (rowsItem->mValue.GetUnit() == eCSSUnit_Enumerated && 1.1041 + rowsItem->mValue.GetIntValue() == NS_STYLE_GRID_TEMPLATE_SUBGRID) { 1.1042 + // We have "grid-template-areas:[something]; grid-template-rows:subgrid" 1.1043 + // which isn't a value that the shorthand can express. Bail. 1.1044 + return; 1.1045 + } 1.1046 + const GridTemplateAreasValue* areas = areasValue.GetGridTemplateAreas(); 1.1047 + uint32_t nRowItems = 0; 1.1048 + while (rowsItem) { 1.1049 + nRowItems++; 1.1050 + rowsItem = rowsItem->mNext; 1.1051 + } 1.1052 + MOZ_ASSERT(nRowItems % 2 == 1, "expected an odd number of items"); 1.1053 + if ((nRowItems - 1) / 2 != areas->NRows()) { 1.1054 + // Not serializable, bail. 1.1055 + return; 1.1056 + } 1.1057 + if (columnsValue.GetUnit() != eCSSUnit_None) { 1.1058 + AppendValueToString(eCSSProperty_grid_template_columns, 1.1059 + aValue, aSerialization); 1.1060 + aValue.AppendLiteral(" / "); 1.1061 + } 1.1062 + rowsItem = rowsValue.GetListValue(); 1.1063 + uint32_t row = 0; 1.1064 + for (;;) { 1.1065 + bool addSpaceSeparator = true; 1.1066 + nsCSSUnit unit = rowsItem->mValue.GetUnit(); 1.1067 + 1.1068 + if (unit == eCSSUnit_Null) { 1.1069 + // Empty or omitted <line-names>. Serializes to nothing. 1.1070 + addSpaceSeparator = false; // Avoid a double space. 1.1071 + 1.1072 + } else if (unit == eCSSUnit_List || unit == eCSSUnit_ListDep) { 1.1073 + // Non-empty <line-names> 1.1074 + aValue.AppendLiteral("("); 1.1075 + rowsItem->mValue.AppendToString(eCSSProperty_grid_template_rows, 1.1076 + aValue, aSerialization); 1.1077 + aValue.AppendLiteral(")"); 1.1078 + 1.1079 + } else { 1.1080 + nsStyleUtil::AppendEscapedCSSString(areas->mTemplates[row++], aValue); 1.1081 + aValue.Append(char16_t(' ')); 1.1082 + 1.1083 + // <track-size> 1.1084 + rowsItem->mValue.AppendToString(eCSSProperty_grid_template_rows, 1.1085 + aValue, aSerialization); 1.1086 + if (rowsItem->mNext && 1.1087 + rowsItem->mNext->mValue.GetUnit() == eCSSUnit_Null && 1.1088 + !rowsItem->mNext->mNext) { 1.1089 + // Break out of the loop early to avoid a trailing space. 1.1090 + break; 1.1091 + } 1.1092 + } 1.1093 + 1.1094 + rowsItem = rowsItem->mNext; 1.1095 + if (!rowsItem) { 1.1096 + break; 1.1097 + } 1.1098 + 1.1099 + if (addSpaceSeparator) { 1.1100 + aValue.Append(char16_t(' ')); 1.1101 + } 1.1102 + } 1.1103 + break; 1.1104 + } 1.1105 + case eCSSProperty__moz_transform: { 1.1106 + // shorthands that are just aliases with different parsing rules 1.1107 + const nsCSSProperty* subprops = 1.1108 + nsCSSProps::SubpropertyEntryFor(aProperty); 1.1109 + NS_ABORT_IF_FALSE(subprops[1] == eCSSProperty_UNKNOWN, 1.1110 + "must have exactly one subproperty"); 1.1111 + AppendValueToString(subprops[0], aValue, aSerialization); 1.1112 + break; 1.1113 + } 1.1114 + case eCSSProperty_all: 1.1115 + // If we got here, then we didn't have all "inherit" or "initial" or 1.1116 + // "unset" values for all of the longhand property components of 'all'. 1.1117 + // There is no other possible value that is valid for all properties, 1.1118 + // so serialize as the empty string. 1.1119 + break; 1.1120 + default: 1.1121 + NS_ABORT_IF_FALSE(false, "no other shorthands"); 1.1122 + break; 1.1123 + } 1.1124 +} 1.1125 + 1.1126 +bool 1.1127 +Declaration::GetValueIsImportant(const nsAString& aProperty) const 1.1128 +{ 1.1129 + nsCSSProperty propID = 1.1130 + nsCSSProps::LookupProperty(aProperty, nsCSSProps::eIgnoreEnabledState); 1.1131 + if (propID == eCSSProperty_UNKNOWN) { 1.1132 + return false; 1.1133 + } 1.1134 + if (propID == eCSSPropertyExtra_variable) { 1.1135 + const nsSubstring& variableName = 1.1136 + Substring(aProperty, CSS_CUSTOM_NAME_PREFIX_LENGTH); 1.1137 + return GetVariableValueIsImportant(variableName); 1.1138 + } 1.1139 + return GetValueIsImportant(propID); 1.1140 +} 1.1141 + 1.1142 +bool 1.1143 +Declaration::GetValueIsImportant(nsCSSProperty aProperty) const 1.1144 +{ 1.1145 + if (!mImportantData) 1.1146 + return false; 1.1147 + 1.1148 + // Calling ValueFor is inefficient, but we can assume '!important' is rare. 1.1149 + 1.1150 + if (!nsCSSProps::IsShorthand(aProperty)) { 1.1151 + return mImportantData->ValueFor(aProperty) != nullptr; 1.1152 + } 1.1153 + 1.1154 + CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p, aProperty) { 1.1155 + if (*p == eCSSProperty__x_system_font) { 1.1156 + // The system_font subproperty doesn't count. 1.1157 + continue; 1.1158 + } 1.1159 + if (!mImportantData->ValueFor(*p)) { 1.1160 + return false; 1.1161 + } 1.1162 + } 1.1163 + return true; 1.1164 +} 1.1165 + 1.1166 +void 1.1167 +Declaration::AppendPropertyAndValueToString(nsCSSProperty aProperty, 1.1168 + nsAutoString& aValue, 1.1169 + nsAString& aResult) const 1.1170 +{ 1.1171 + NS_ABORT_IF_FALSE(0 <= aProperty && aProperty < eCSSProperty_COUNT, 1.1172 + "property enum out of range"); 1.1173 + NS_ABORT_IF_FALSE((aProperty < eCSSProperty_COUNT_no_shorthands) == 1.1174 + aValue.IsEmpty(), 1.1175 + "aValue should be given for shorthands but not longhands"); 1.1176 + AppendASCIItoUTF16(nsCSSProps::GetStringValue(aProperty), aResult); 1.1177 + aResult.AppendLiteral(": "); 1.1178 + if (aValue.IsEmpty()) 1.1179 + AppendValueToString(aProperty, aResult, nsCSSValue::eNormalized); 1.1180 + else 1.1181 + aResult.Append(aValue); 1.1182 + if (GetValueIsImportant(aProperty)) { 1.1183 + aResult.AppendLiteral(" ! important"); 1.1184 + } 1.1185 + aResult.AppendLiteral("; "); 1.1186 +} 1.1187 + 1.1188 +void 1.1189 +Declaration::AppendVariableAndValueToString(const nsAString& aName, 1.1190 + nsAString& aResult) const 1.1191 +{ 1.1192 + aResult.AppendLiteral("--"); 1.1193 + aResult.Append(aName); 1.1194 + CSSVariableDeclarations::Type type; 1.1195 + nsString value; 1.1196 + bool important; 1.1197 + 1.1198 + if (mImportantVariables && mImportantVariables->Get(aName, type, value)) { 1.1199 + important = true; 1.1200 + } else { 1.1201 + MOZ_ASSERT(mVariables); 1.1202 + MOZ_ASSERT(mVariables->Has(aName)); 1.1203 + mVariables->Get(aName, type, value); 1.1204 + important = false; 1.1205 + } 1.1206 + 1.1207 + switch (type) { 1.1208 + case CSSVariableDeclarations::eTokenStream: 1.1209 + if (value.IsEmpty()) { 1.1210 + aResult.Append(':'); 1.1211 + } else { 1.1212 + aResult.AppendLiteral(": "); 1.1213 + aResult.Append(value); 1.1214 + } 1.1215 + break; 1.1216 + 1.1217 + case CSSVariableDeclarations::eInitial: 1.1218 + aResult.AppendLiteral("initial"); 1.1219 + break; 1.1220 + 1.1221 + case CSSVariableDeclarations::eInherit: 1.1222 + aResult.AppendLiteral("inherit"); 1.1223 + break; 1.1224 + 1.1225 + case CSSVariableDeclarations::eUnset: 1.1226 + aResult.AppendLiteral("unset"); 1.1227 + break; 1.1228 + 1.1229 + default: 1.1230 + MOZ_ASSERT(false, "unexpected variable value type"); 1.1231 + } 1.1232 + 1.1233 + if (important) { 1.1234 + aResult.AppendLiteral("! important"); 1.1235 + } 1.1236 + aResult.AppendLiteral("; "); 1.1237 +} 1.1238 + 1.1239 +void 1.1240 +Declaration::ToString(nsAString& aString) const 1.1241 +{ 1.1242 + // Someone cares about this declaration's contents, so don't let it 1.1243 + // change from under them. See e.g. bug 338679. 1.1244 + SetImmutable(); 1.1245 + 1.1246 + nsCSSCompressedDataBlock *systemFontData = 1.1247 + GetValueIsImportant(eCSSProperty__x_system_font) ? mImportantData : mData; 1.1248 + const nsCSSValue *systemFont = 1.1249 + systemFontData->ValueFor(eCSSProperty__x_system_font); 1.1250 + const bool haveSystemFont = systemFont && 1.1251 + systemFont->GetUnit() != eCSSUnit_None && 1.1252 + systemFont->GetUnit() != eCSSUnit_Null; 1.1253 + bool didSystemFont = false; 1.1254 + 1.1255 + int32_t count = mOrder.Length(); 1.1256 + int32_t index; 1.1257 + nsAutoTArray<nsCSSProperty, 16> shorthandsUsed; 1.1258 + for (index = 0; index < count; index++) { 1.1259 + nsCSSProperty property = GetPropertyAt(index); 1.1260 + 1.1261 + if (property == eCSSPropertyExtra_variable) { 1.1262 + uint32_t variableIndex = mOrder[index] - eCSSProperty_COUNT; 1.1263 + AppendVariableAndValueToString(mVariableOrder[variableIndex], aString); 1.1264 + continue; 1.1265 + } 1.1266 + 1.1267 + if (!nsCSSProps::IsEnabled(property)) { 1.1268 + continue; 1.1269 + } 1.1270 + bool doneProperty = false; 1.1271 + 1.1272 + // If we already used this property in a shorthand, skip it. 1.1273 + if (shorthandsUsed.Length() > 0) { 1.1274 + for (const nsCSSProperty *shorthands = 1.1275 + nsCSSProps::ShorthandsContaining(property); 1.1276 + *shorthands != eCSSProperty_UNKNOWN; ++shorthands) { 1.1277 + if (shorthandsUsed.Contains(*shorthands)) { 1.1278 + doneProperty = true; 1.1279 + break; 1.1280 + } 1.1281 + } 1.1282 + if (doneProperty) 1.1283 + continue; 1.1284 + } 1.1285 + 1.1286 + // Try to use this property in a shorthand. 1.1287 + nsAutoString value; 1.1288 + for (const nsCSSProperty *shorthands = 1.1289 + nsCSSProps::ShorthandsContaining(property); 1.1290 + *shorthands != eCSSProperty_UNKNOWN; ++shorthands) { 1.1291 + // ShorthandsContaining returns the shorthands in order from those 1.1292 + // that contain the most subproperties to those that contain the 1.1293 + // least, which is exactly the order we want to test them. 1.1294 + nsCSSProperty shorthand = *shorthands; 1.1295 + 1.1296 + // If GetValue gives us a non-empty string back, we can use that 1.1297 + // value; otherwise it's not possible to use this shorthand. 1.1298 + GetValue(shorthand, value); 1.1299 + if (!value.IsEmpty()) { 1.1300 + AppendPropertyAndValueToString(shorthand, value, aString); 1.1301 + shorthandsUsed.AppendElement(shorthand); 1.1302 + doneProperty = true; 1.1303 + break; 1.1304 + } 1.1305 + 1.1306 + NS_ABORT_IF_FALSE(shorthand != eCSSProperty_font || 1.1307 + *(shorthands + 1) == eCSSProperty_UNKNOWN, 1.1308 + "font should always be the only containing shorthand"); 1.1309 + if (shorthand == eCSSProperty_font) { 1.1310 + if (haveSystemFont && !didSystemFont) { 1.1311 + // Output the shorthand font declaration that we will 1.1312 + // partially override later. But don't add it to 1.1313 + // |shorthandsUsed|, since we will have to override it. 1.1314 + systemFont->AppendToString(eCSSProperty__x_system_font, value, 1.1315 + nsCSSValue::eNormalized); 1.1316 + AppendPropertyAndValueToString(eCSSProperty_font, value, aString); 1.1317 + value.Truncate(); 1.1318 + didSystemFont = true; 1.1319 + } 1.1320 + 1.1321 + // That we output the system font is enough for this property if: 1.1322 + // (1) it's the hidden system font subproperty (which either 1.1323 + // means we output it or we don't have it), or 1.1324 + // (2) its value is the hidden system font value and it matches 1.1325 + // the hidden system font subproperty in importance, and 1.1326 + // we output the system font subproperty. 1.1327 + const nsCSSValue *val = systemFontData->ValueFor(property); 1.1328 + if (property == eCSSProperty__x_system_font || 1.1329 + (haveSystemFont && val && val->GetUnit() == eCSSUnit_System_Font)) { 1.1330 + doneProperty = true; 1.1331 + } 1.1332 + } 1.1333 + } 1.1334 + if (doneProperty) 1.1335 + continue; 1.1336 + 1.1337 + NS_ABORT_IF_FALSE(value.IsEmpty(), "value should be empty now"); 1.1338 + AppendPropertyAndValueToString(property, value, aString); 1.1339 + } 1.1340 + if (! aString.IsEmpty()) { 1.1341 + // if the string is not empty, we have trailing whitespace we 1.1342 + // should remove 1.1343 + aString.Truncate(aString.Length() - 1); 1.1344 + } 1.1345 +} 1.1346 + 1.1347 +#ifdef DEBUG 1.1348 +void 1.1349 +Declaration::List(FILE* out, int32_t aIndent) const 1.1350 +{ 1.1351 + for (int32_t index = aIndent; --index >= 0; ) fputs(" ", out); 1.1352 + 1.1353 + fputs("{ ", out); 1.1354 + nsAutoString s; 1.1355 + ToString(s); 1.1356 + fputs(NS_ConvertUTF16toUTF8(s).get(), out); 1.1357 + fputs("}", out); 1.1358 +} 1.1359 +#endif 1.1360 + 1.1361 +bool 1.1362 +Declaration::GetNthProperty(uint32_t aIndex, nsAString& aReturn) const 1.1363 +{ 1.1364 + aReturn.Truncate(); 1.1365 + if (aIndex < mOrder.Length()) { 1.1366 + nsCSSProperty property = GetPropertyAt(aIndex); 1.1367 + if (property == eCSSPropertyExtra_variable) { 1.1368 + GetCustomPropertyNameAt(aIndex, aReturn); 1.1369 + return true; 1.1370 + } 1.1371 + if (0 <= property) { 1.1372 + AppendASCIItoUTF16(nsCSSProps::GetStringValue(property), aReturn); 1.1373 + return true; 1.1374 + } 1.1375 + } 1.1376 + return false; 1.1377 +} 1.1378 + 1.1379 +void 1.1380 +Declaration::InitializeEmpty() 1.1381 +{ 1.1382 + NS_ABORT_IF_FALSE(!mData && !mImportantData, "already initialized"); 1.1383 + mData = nsCSSCompressedDataBlock::CreateEmptyBlock(); 1.1384 +} 1.1385 + 1.1386 +Declaration* 1.1387 +Declaration::EnsureMutable() 1.1388 +{ 1.1389 + NS_ABORT_IF_FALSE(mData, "should only be called when not expanded"); 1.1390 + if (!IsMutable()) { 1.1391 + return new Declaration(*this); 1.1392 + } else { 1.1393 + return this; 1.1394 + } 1.1395 +} 1.1396 + 1.1397 +size_t 1.1398 +Declaration::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const 1.1399 +{ 1.1400 + size_t n = aMallocSizeOf(this); 1.1401 + n += mOrder.SizeOfExcludingThis(aMallocSizeOf); 1.1402 + n += mData ? mData ->SizeOfIncludingThis(aMallocSizeOf) : 0; 1.1403 + n += mImportantData ? mImportantData->SizeOfIncludingThis(aMallocSizeOf) : 0; 1.1404 + if (mVariables) { 1.1405 + n += mVariables->SizeOfIncludingThis(aMallocSizeOf); 1.1406 + } 1.1407 + if (mImportantVariables) { 1.1408 + n += mImportantVariables->SizeOfIncludingThis(aMallocSizeOf); 1.1409 + } 1.1410 + return n; 1.1411 +} 1.1412 + 1.1413 +bool 1.1414 +Declaration::HasVariableDeclaration(const nsAString& aName) const 1.1415 +{ 1.1416 + return (mVariables && mVariables->Has(aName)) || 1.1417 + (mImportantVariables && mImportantVariables->Has(aName)); 1.1418 +} 1.1419 + 1.1420 +void 1.1421 +Declaration::GetVariableDeclaration(const nsAString& aName, 1.1422 + nsAString& aValue) const 1.1423 +{ 1.1424 + aValue.Truncate(); 1.1425 + 1.1426 + CSSVariableDeclarations::Type type; 1.1427 + nsString value; 1.1428 + 1.1429 + if ((mImportantVariables && mImportantVariables->Get(aName, type, value)) || 1.1430 + (mVariables && mVariables->Get(aName, type, value))) { 1.1431 + switch (type) { 1.1432 + case CSSVariableDeclarations::eTokenStream: 1.1433 + aValue.Append(value); 1.1434 + break; 1.1435 + 1.1436 + case CSSVariableDeclarations::eInitial: 1.1437 + aValue.AppendLiteral("initial"); 1.1438 + break; 1.1439 + 1.1440 + case CSSVariableDeclarations::eInherit: 1.1441 + aValue.AppendLiteral("inherit"); 1.1442 + break; 1.1443 + 1.1444 + case CSSVariableDeclarations::eUnset: 1.1445 + aValue.AppendLiteral("unset"); 1.1446 + break; 1.1447 + 1.1448 + default: 1.1449 + MOZ_ASSERT(false, "unexpected variable value type"); 1.1450 + } 1.1451 + } 1.1452 +} 1.1453 + 1.1454 +void 1.1455 +Declaration::AddVariableDeclaration(const nsAString& aName, 1.1456 + CSSVariableDeclarations::Type aType, 1.1457 + const nsString& aValue, 1.1458 + bool aIsImportant, 1.1459 + bool aOverrideImportant) 1.1460 +{ 1.1461 + MOZ_ASSERT(IsMutable()); 1.1462 + 1.1463 + nsTArray<nsString>::index_type index = mVariableOrder.IndexOf(aName); 1.1464 + if (index == nsTArray<nsString>::NoIndex) { 1.1465 + index = mVariableOrder.Length(); 1.1466 + mVariableOrder.AppendElement(aName); 1.1467 + } 1.1468 + 1.1469 + if (!aIsImportant && !aOverrideImportant && 1.1470 + mImportantVariables && mImportantVariables->Has(aName)) { 1.1471 + return; 1.1472 + } 1.1473 + 1.1474 + CSSVariableDeclarations* variables; 1.1475 + if (aIsImportant) { 1.1476 + if (mVariables) { 1.1477 + mVariables->Remove(aName); 1.1478 + } 1.1479 + if (!mImportantVariables) { 1.1480 + mImportantVariables = new CSSVariableDeclarations; 1.1481 + } 1.1482 + variables = mImportantVariables; 1.1483 + } else { 1.1484 + if (mImportantVariables) { 1.1485 + mImportantVariables->Remove(aName); 1.1486 + } 1.1487 + if (!mVariables) { 1.1488 + mVariables = new CSSVariableDeclarations; 1.1489 + } 1.1490 + variables = mVariables; 1.1491 + } 1.1492 + 1.1493 + switch (aType) { 1.1494 + case CSSVariableDeclarations::eTokenStream: 1.1495 + variables->PutTokenStream(aName, aValue); 1.1496 + break; 1.1497 + 1.1498 + case CSSVariableDeclarations::eInitial: 1.1499 + MOZ_ASSERT(aValue.IsEmpty()); 1.1500 + variables->PutInitial(aName); 1.1501 + break; 1.1502 + 1.1503 + case CSSVariableDeclarations::eInherit: 1.1504 + MOZ_ASSERT(aValue.IsEmpty()); 1.1505 + variables->PutInherit(aName); 1.1506 + break; 1.1507 + 1.1508 + case CSSVariableDeclarations::eUnset: 1.1509 + MOZ_ASSERT(aValue.IsEmpty()); 1.1510 + variables->PutUnset(aName); 1.1511 + break; 1.1512 + 1.1513 + default: 1.1514 + MOZ_ASSERT(false, "unexpected aType value"); 1.1515 + } 1.1516 + 1.1517 + uint32_t propertyIndex = index + eCSSProperty_COUNT; 1.1518 + mOrder.RemoveElement(propertyIndex); 1.1519 + mOrder.AppendElement(propertyIndex); 1.1520 +} 1.1521 + 1.1522 +void 1.1523 +Declaration::RemoveVariableDeclaration(const nsAString& aName) 1.1524 +{ 1.1525 + if (mVariables) { 1.1526 + mVariables->Remove(aName); 1.1527 + } 1.1528 + if (mImportantVariables) { 1.1529 + mImportantVariables->Remove(aName); 1.1530 + } 1.1531 + nsTArray<nsString>::index_type index = mVariableOrder.IndexOf(aName); 1.1532 + if (index != nsTArray<nsString>::NoIndex) { 1.1533 + mOrder.RemoveElement(index + eCSSProperty_COUNT); 1.1534 + } 1.1535 +} 1.1536 + 1.1537 +bool 1.1538 +Declaration::GetVariableValueIsImportant(const nsAString& aName) const 1.1539 +{ 1.1540 + return mImportantVariables && mImportantVariables->Has(aName); 1.1541 +} 1.1542 + 1.1543 +} // namespace mozilla::css 1.1544 +} // namespace mozilla