|
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/ArrayUtils.h" |
|
12 #include "mozilla/MemoryReporting.h" |
|
13 |
|
14 #include "mozilla/css/Declaration.h" |
|
15 #include "nsPrintfCString.h" |
|
16 #include "gfxFontConstants.h" |
|
17 #include "nsStyleUtil.h" |
|
18 |
|
19 namespace mozilla { |
|
20 namespace css { |
|
21 |
|
22 Declaration::Declaration() |
|
23 : mImmutable(false) |
|
24 { |
|
25 MOZ_COUNT_CTOR(mozilla::css::Declaration); |
|
26 } |
|
27 |
|
28 Declaration::Declaration(const Declaration& aCopy) |
|
29 : mOrder(aCopy.mOrder), |
|
30 mVariableOrder(aCopy.mVariableOrder), |
|
31 mData(aCopy.mData ? aCopy.mData->Clone() : nullptr), |
|
32 mImportantData(aCopy.mImportantData ? |
|
33 aCopy.mImportantData->Clone() : nullptr), |
|
34 mVariables(aCopy.mVariables ? |
|
35 new CSSVariableDeclarations(*aCopy.mVariables) : |
|
36 nullptr), |
|
37 mImportantVariables(aCopy.mImportantVariables ? |
|
38 new CSSVariableDeclarations(*aCopy.mImportantVariables) : |
|
39 nullptr), |
|
40 mImmutable(false) |
|
41 { |
|
42 MOZ_COUNT_CTOR(mozilla::css::Declaration); |
|
43 } |
|
44 |
|
45 Declaration::~Declaration() |
|
46 { |
|
47 MOZ_COUNT_DTOR(mozilla::css::Declaration); |
|
48 } |
|
49 |
|
50 void |
|
51 Declaration::ValueAppended(nsCSSProperty aProperty) |
|
52 { |
|
53 NS_ABORT_IF_FALSE(!mData && !mImportantData, |
|
54 "should only be called while expanded"); |
|
55 NS_ABORT_IF_FALSE(!nsCSSProps::IsShorthand(aProperty), |
|
56 "shorthands forbidden"); |
|
57 // order IS important for CSS, so remove and add to the end |
|
58 mOrder.RemoveElement(static_cast<uint32_t>(aProperty)); |
|
59 mOrder.AppendElement(static_cast<uint32_t>(aProperty)); |
|
60 } |
|
61 |
|
62 void |
|
63 Declaration::RemoveProperty(nsCSSProperty aProperty) |
|
64 { |
|
65 MOZ_ASSERT(0 <= aProperty && aProperty < eCSSProperty_COUNT); |
|
66 |
|
67 nsCSSExpandedDataBlock data; |
|
68 ExpandTo(&data); |
|
69 NS_ABORT_IF_FALSE(!mData && !mImportantData, "Expand didn't null things out"); |
|
70 |
|
71 if (nsCSSProps::IsShorthand(aProperty)) { |
|
72 CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p, aProperty) { |
|
73 data.ClearLonghandProperty(*p); |
|
74 mOrder.RemoveElement(static_cast<uint32_t>(*p)); |
|
75 } |
|
76 } else { |
|
77 data.ClearLonghandProperty(aProperty); |
|
78 mOrder.RemoveElement(static_cast<uint32_t>(aProperty)); |
|
79 } |
|
80 |
|
81 CompressFrom(&data); |
|
82 } |
|
83 |
|
84 bool |
|
85 Declaration::HasProperty(nsCSSProperty aProperty) const |
|
86 { |
|
87 NS_ABORT_IF_FALSE(0 <= aProperty && |
|
88 aProperty < eCSSProperty_COUNT_no_shorthands, |
|
89 "property ID out of range"); |
|
90 |
|
91 nsCSSCompressedDataBlock *data = GetValueIsImportant(aProperty) |
|
92 ? mImportantData : mData; |
|
93 const nsCSSValue *val = data->ValueFor(aProperty); |
|
94 return !!val; |
|
95 } |
|
96 |
|
97 bool |
|
98 Declaration::AppendValueToString(nsCSSProperty aProperty, |
|
99 nsAString& aResult, |
|
100 nsCSSValue::Serialization aSerialization) const |
|
101 { |
|
102 NS_ABORT_IF_FALSE(0 <= aProperty && |
|
103 aProperty < eCSSProperty_COUNT_no_shorthands, |
|
104 "property ID out of range"); |
|
105 |
|
106 nsCSSCompressedDataBlock *data = GetValueIsImportant(aProperty) |
|
107 ? mImportantData : mData; |
|
108 const nsCSSValue *val = data->ValueFor(aProperty); |
|
109 if (!val) { |
|
110 return false; |
|
111 } |
|
112 |
|
113 val->AppendToString(aProperty, aResult, aSerialization); |
|
114 return true; |
|
115 } |
|
116 |
|
117 // Helper to append |aString| with the shorthand sides notation used in e.g. |
|
118 // 'padding'. |aProperties| and |aValues| are expected to have 4 elements. |
|
119 static void |
|
120 AppendSidesShorthandToString(const nsCSSProperty aProperties[], |
|
121 const nsCSSValue* aValues[], |
|
122 nsAString& aString, |
|
123 nsCSSValue::Serialization aSerialization) |
|
124 { |
|
125 const nsCSSValue& value1 = *aValues[0]; |
|
126 const nsCSSValue& value2 = *aValues[1]; |
|
127 const nsCSSValue& value3 = *aValues[2]; |
|
128 const nsCSSValue& value4 = *aValues[3]; |
|
129 |
|
130 NS_ABORT_IF_FALSE(value1.GetUnit() != eCSSUnit_Null, "null value 1"); |
|
131 value1.AppendToString(aProperties[0], aString, aSerialization); |
|
132 if (value1 != value2 || value1 != value3 || value1 != value4) { |
|
133 aString.Append(char16_t(' ')); |
|
134 NS_ABORT_IF_FALSE(value2.GetUnit() != eCSSUnit_Null, "null value 2"); |
|
135 value2.AppendToString(aProperties[1], aString, aSerialization); |
|
136 if (value1 != value3 || value2 != value4) { |
|
137 aString.Append(char16_t(' ')); |
|
138 NS_ABORT_IF_FALSE(value3.GetUnit() != eCSSUnit_Null, "null value 3"); |
|
139 value3.AppendToString(aProperties[2], aString, aSerialization); |
|
140 if (value2 != value4) { |
|
141 aString.Append(char16_t(' ')); |
|
142 NS_ABORT_IF_FALSE(value4.GetUnit() != eCSSUnit_Null, "null value 4"); |
|
143 value4.AppendToString(aProperties[3], aString, aSerialization); |
|
144 } |
|
145 } |
|
146 } |
|
147 } |
|
148 |
|
149 void |
|
150 Declaration::GetValue(nsCSSProperty aProperty, nsAString& aValue) const |
|
151 { |
|
152 GetValue(aProperty, aValue, nsCSSValue::eNormalized); |
|
153 } |
|
154 |
|
155 void |
|
156 Declaration::GetAuthoredValue(nsCSSProperty aProperty, nsAString& aValue) const |
|
157 { |
|
158 GetValue(aProperty, aValue, nsCSSValue::eAuthorSpecified); |
|
159 } |
|
160 |
|
161 void |
|
162 Declaration::GetValue(nsCSSProperty aProperty, nsAString& aValue, |
|
163 nsCSSValue::Serialization aSerialization) const |
|
164 { |
|
165 aValue.Truncate(0); |
|
166 |
|
167 // simple properties are easy. |
|
168 if (!nsCSSProps::IsShorthand(aProperty)) { |
|
169 AppendValueToString(aProperty, aValue, aSerialization); |
|
170 return; |
|
171 } |
|
172 |
|
173 // DOM Level 2 Style says (when describing CSS2Properties, although |
|
174 // not CSSStyleDeclaration.getPropertyValue): |
|
175 // However, if there is no shorthand declaration that could be added |
|
176 // to the ruleset without changing in any way the rules already |
|
177 // declared in the ruleset (i.e., by adding longhand rules that were |
|
178 // previously not declared in the ruleset), then the empty string |
|
179 // should be returned for the shorthand property. |
|
180 // This means we need to check a number of cases: |
|
181 // (1) Since a shorthand sets all sub-properties, if some of its |
|
182 // subproperties were not specified, we must return the empty |
|
183 // string. |
|
184 // (2) Since 'inherit', 'initial' and 'unset' can only be specified |
|
185 // as the values for entire properties, we need to return the |
|
186 // empty string if some but not all of the subproperties have one |
|
187 // of those values. |
|
188 // (3) Since a single value only makes sense with or without |
|
189 // !important, we return the empty string if some values are |
|
190 // !important and some are not. |
|
191 // Since we're doing this check for 'inherit' and 'initial' up front, |
|
192 // we can also simplify the property serialization code by serializing |
|
193 // those values up front as well. |
|
194 // |
|
195 // Additionally, if a shorthand property was set using a value with a |
|
196 // variable reference and none of its component longhand properties were |
|
197 // then overridden on the declaration, we return the token stream |
|
198 // assigned to the shorthand. |
|
199 const nsCSSValue* tokenStream = nullptr; |
|
200 uint32_t totalCount = 0, importantCount = 0, |
|
201 initialCount = 0, inheritCount = 0, unsetCount = 0, |
|
202 matchingTokenStreamCount = 0; |
|
203 CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p, aProperty) { |
|
204 if (*p == eCSSProperty__x_system_font || |
|
205 nsCSSProps::PropHasFlags(*p, CSS_PROPERTY_DIRECTIONAL_SOURCE)) { |
|
206 // The system-font subproperty and the *-source properties don't count. |
|
207 continue; |
|
208 } |
|
209 ++totalCount; |
|
210 const nsCSSValue *val = mData->ValueFor(*p); |
|
211 NS_ABORT_IF_FALSE(!val || !mImportantData || !mImportantData->ValueFor(*p), |
|
212 "can't be in both blocks"); |
|
213 if (!val && mImportantData) { |
|
214 ++importantCount; |
|
215 val = mImportantData->ValueFor(*p); |
|
216 } |
|
217 if (!val) { |
|
218 // Case (1) above: some subproperties not specified. |
|
219 return; |
|
220 } |
|
221 if (val->GetUnit() == eCSSUnit_Inherit) { |
|
222 ++inheritCount; |
|
223 } else if (val->GetUnit() == eCSSUnit_Initial) { |
|
224 ++initialCount; |
|
225 } else if (val->GetUnit() == eCSSUnit_Unset) { |
|
226 ++unsetCount; |
|
227 } else if (val->GetUnit() == eCSSUnit_TokenStream && |
|
228 val->GetTokenStreamValue()->mShorthandPropertyID == aProperty) { |
|
229 tokenStream = val; |
|
230 ++matchingTokenStreamCount; |
|
231 } |
|
232 } |
|
233 if (importantCount != 0 && importantCount != totalCount) { |
|
234 // Case (3), no consistent importance. |
|
235 return; |
|
236 } |
|
237 if (initialCount == totalCount) { |
|
238 // Simplify serialization below by serializing initial up-front. |
|
239 nsCSSValue(eCSSUnit_Initial).AppendToString(eCSSProperty_UNKNOWN, aValue, |
|
240 nsCSSValue::eNormalized); |
|
241 return; |
|
242 } |
|
243 if (inheritCount == totalCount) { |
|
244 // Simplify serialization below by serializing inherit up-front. |
|
245 nsCSSValue(eCSSUnit_Inherit).AppendToString(eCSSProperty_UNKNOWN, aValue, |
|
246 nsCSSValue::eNormalized); |
|
247 return; |
|
248 } |
|
249 if (unsetCount == totalCount) { |
|
250 // Simplify serialization below by serializing unset up-front. |
|
251 nsCSSValue(eCSSUnit_Unset).AppendToString(eCSSProperty_UNKNOWN, aValue, |
|
252 nsCSSValue::eNormalized); |
|
253 return; |
|
254 } |
|
255 if (initialCount != 0 || inheritCount != 0 || unsetCount != 0) { |
|
256 // Case (2): partially initial, inherit or unset. |
|
257 return; |
|
258 } |
|
259 if (tokenStream) { |
|
260 if (matchingTokenStreamCount == totalCount) { |
|
261 // Shorthand was specified using variable references and all of its |
|
262 // longhand components were set by the shorthand. |
|
263 aValue.Append(tokenStream->GetTokenStreamValue()->mTokenStream); |
|
264 } else { |
|
265 // In all other cases, serialize to the empty string. |
|
266 } |
|
267 return; |
|
268 } |
|
269 |
|
270 nsCSSCompressedDataBlock *data = importantCount ? mImportantData : mData; |
|
271 switch (aProperty) { |
|
272 case eCSSProperty_margin: |
|
273 case eCSSProperty_padding: |
|
274 case eCSSProperty_border_color: |
|
275 case eCSSProperty_border_style: |
|
276 case eCSSProperty_border_width: { |
|
277 const nsCSSProperty* subprops = |
|
278 nsCSSProps::SubpropertyEntryFor(aProperty); |
|
279 NS_ABORT_IF_FALSE(nsCSSProps::GetStringValue(subprops[0]).Find("-top") != |
|
280 kNotFound, "first subprop must be top"); |
|
281 NS_ABORT_IF_FALSE(nsCSSProps::GetStringValue(subprops[1]).Find("-right") != |
|
282 kNotFound, "second subprop must be right"); |
|
283 NS_ABORT_IF_FALSE(nsCSSProps::GetStringValue(subprops[2]).Find("-bottom") != |
|
284 kNotFound, "third subprop must be bottom"); |
|
285 NS_ABORT_IF_FALSE(nsCSSProps::GetStringValue(subprops[3]).Find("-left") != |
|
286 kNotFound, "fourth subprop must be left"); |
|
287 const nsCSSValue* vals[4] = { |
|
288 data->ValueFor(subprops[0]), |
|
289 data->ValueFor(subprops[1]), |
|
290 data->ValueFor(subprops[2]), |
|
291 data->ValueFor(subprops[3]) |
|
292 }; |
|
293 AppendSidesShorthandToString(subprops, vals, aValue, aSerialization); |
|
294 break; |
|
295 } |
|
296 case eCSSProperty_border_radius: |
|
297 case eCSSProperty__moz_outline_radius: { |
|
298 const nsCSSProperty* subprops = |
|
299 nsCSSProps::SubpropertyEntryFor(aProperty); |
|
300 const nsCSSValue* vals[4] = { |
|
301 data->ValueFor(subprops[0]), |
|
302 data->ValueFor(subprops[1]), |
|
303 data->ValueFor(subprops[2]), |
|
304 data->ValueFor(subprops[3]) |
|
305 }; |
|
306 |
|
307 // For compatibility, only write a slash and the y-values |
|
308 // if they're not identical to the x-values. |
|
309 bool needY = false; |
|
310 const nsCSSValue* xVals[4]; |
|
311 const nsCSSValue* yVals[4]; |
|
312 for (int i = 0; i < 4; i++) { |
|
313 if (vals[i]->GetUnit() == eCSSUnit_Pair) { |
|
314 needY = true; |
|
315 xVals[i] = &vals[i]->GetPairValue().mXValue; |
|
316 yVals[i] = &vals[i]->GetPairValue().mYValue; |
|
317 } else { |
|
318 xVals[i] = yVals[i] = vals[i]; |
|
319 } |
|
320 } |
|
321 |
|
322 AppendSidesShorthandToString(subprops, xVals, aValue, aSerialization); |
|
323 if (needY) { |
|
324 aValue.AppendLiteral(" / "); |
|
325 AppendSidesShorthandToString(subprops, yVals, aValue, aSerialization); |
|
326 } |
|
327 break; |
|
328 } |
|
329 case eCSSProperty_border_image: { |
|
330 // Even though there are some cases where we could omit |
|
331 // 'border-image-source' (when it's none), it's probably not a |
|
332 // good idea since it's likely to be confusing. It would also |
|
333 // require adding the extra check that we serialize *something*. |
|
334 AppendValueToString(eCSSProperty_border_image_source, aValue, |
|
335 aSerialization); |
|
336 |
|
337 bool sliceDefault = data->HasDefaultBorderImageSlice(); |
|
338 bool widthDefault = data->HasDefaultBorderImageWidth(); |
|
339 bool outsetDefault = data->HasDefaultBorderImageOutset(); |
|
340 |
|
341 if (!sliceDefault || !widthDefault || !outsetDefault) { |
|
342 aValue.Append(char16_t(' ')); |
|
343 AppendValueToString(eCSSProperty_border_image_slice, aValue, |
|
344 aSerialization); |
|
345 if (!widthDefault || !outsetDefault) { |
|
346 aValue.Append(NS_LITERAL_STRING(" /")); |
|
347 if (!widthDefault) { |
|
348 aValue.Append(char16_t(' ')); |
|
349 AppendValueToString(eCSSProperty_border_image_width, aValue, |
|
350 aSerialization); |
|
351 } |
|
352 if (!outsetDefault) { |
|
353 aValue.Append(NS_LITERAL_STRING(" / ")); |
|
354 AppendValueToString(eCSSProperty_border_image_outset, aValue, |
|
355 aSerialization); |
|
356 } |
|
357 } |
|
358 } |
|
359 |
|
360 bool repeatDefault = data->HasDefaultBorderImageRepeat(); |
|
361 if (!repeatDefault) { |
|
362 aValue.Append(char16_t(' ')); |
|
363 AppendValueToString(eCSSProperty_border_image_repeat, aValue, |
|
364 aSerialization); |
|
365 } |
|
366 break; |
|
367 } |
|
368 case eCSSProperty_border: { |
|
369 // If we have a non-default value for any of the properties that |
|
370 // this shorthand sets but cannot specify, we have to return the |
|
371 // empty string. |
|
372 if (data->ValueFor(eCSSProperty_border_image_source)->GetUnit() != |
|
373 eCSSUnit_None || |
|
374 !data->HasDefaultBorderImageSlice() || |
|
375 !data->HasDefaultBorderImageWidth() || |
|
376 !data->HasDefaultBorderImageOutset() || |
|
377 !data->HasDefaultBorderImageRepeat() || |
|
378 data->ValueFor(eCSSProperty_border_top_colors)->GetUnit() != |
|
379 eCSSUnit_None || |
|
380 data->ValueFor(eCSSProperty_border_right_colors)->GetUnit() != |
|
381 eCSSUnit_None || |
|
382 data->ValueFor(eCSSProperty_border_bottom_colors)->GetUnit() != |
|
383 eCSSUnit_None || |
|
384 data->ValueFor(eCSSProperty_border_left_colors)->GetUnit() != |
|
385 eCSSUnit_None) { |
|
386 break; |
|
387 } |
|
388 |
|
389 const nsCSSProperty* subproptables[3] = { |
|
390 nsCSSProps::SubpropertyEntryFor(eCSSProperty_border_color), |
|
391 nsCSSProps::SubpropertyEntryFor(eCSSProperty_border_style), |
|
392 nsCSSProps::SubpropertyEntryFor(eCSSProperty_border_width) |
|
393 }; |
|
394 bool match = true; |
|
395 for (const nsCSSProperty** subprops = subproptables, |
|
396 **subprops_end = ArrayEnd(subproptables); |
|
397 subprops < subprops_end; ++subprops) { |
|
398 // Check only the first four subprops in each table, since the |
|
399 // others are extras for dimensional box properties. |
|
400 const nsCSSValue *firstSide = data->ValueFor((*subprops)[0]); |
|
401 for (int32_t side = 1; side < 4; ++side) { |
|
402 const nsCSSValue *otherSide = |
|
403 data->ValueFor((*subprops)[side]); |
|
404 if (*firstSide != *otherSide) |
|
405 match = false; |
|
406 } |
|
407 } |
|
408 if (!match) { |
|
409 // We can't express what we have in the border shorthand |
|
410 break; |
|
411 } |
|
412 // tweak aProperty and fall through |
|
413 aProperty = eCSSProperty_border_top; |
|
414 } |
|
415 case eCSSProperty_border_top: |
|
416 case eCSSProperty_border_right: |
|
417 case eCSSProperty_border_bottom: |
|
418 case eCSSProperty_border_left: |
|
419 case eCSSProperty_border_start: |
|
420 case eCSSProperty_border_end: |
|
421 case eCSSProperty__moz_column_rule: |
|
422 case eCSSProperty_outline: { |
|
423 const nsCSSProperty* subprops = |
|
424 nsCSSProps::SubpropertyEntryFor(aProperty); |
|
425 NS_ABORT_IF_FALSE(StringEndsWith(nsCSSProps::GetStringValue(subprops[2]), |
|
426 NS_LITERAL_CSTRING("-color")) || |
|
427 StringEndsWith(nsCSSProps::GetStringValue(subprops[2]), |
|
428 NS_LITERAL_CSTRING("-color-value")), |
|
429 "third subprop must be the color property"); |
|
430 const nsCSSValue *colorValue = data->ValueFor(subprops[2]); |
|
431 bool isMozUseTextColor = |
|
432 colorValue->GetUnit() == eCSSUnit_Enumerated && |
|
433 colorValue->GetIntValue() == NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR; |
|
434 if (!AppendValueToString(subprops[0], aValue, aSerialization) || |
|
435 !(aValue.Append(char16_t(' ')), |
|
436 AppendValueToString(subprops[1], aValue, aSerialization)) || |
|
437 // Don't output a third value when it's -moz-use-text-color. |
|
438 !(isMozUseTextColor || |
|
439 (aValue.Append(char16_t(' ')), |
|
440 AppendValueToString(subprops[2], aValue, aSerialization)))) { |
|
441 aValue.Truncate(); |
|
442 } |
|
443 break; |
|
444 } |
|
445 case eCSSProperty_margin_left: |
|
446 case eCSSProperty_margin_right: |
|
447 case eCSSProperty_margin_start: |
|
448 case eCSSProperty_margin_end: |
|
449 case eCSSProperty_padding_left: |
|
450 case eCSSProperty_padding_right: |
|
451 case eCSSProperty_padding_start: |
|
452 case eCSSProperty_padding_end: |
|
453 case eCSSProperty_border_left_color: |
|
454 case eCSSProperty_border_left_style: |
|
455 case eCSSProperty_border_left_width: |
|
456 case eCSSProperty_border_right_color: |
|
457 case eCSSProperty_border_right_style: |
|
458 case eCSSProperty_border_right_width: |
|
459 case eCSSProperty_border_start_color: |
|
460 case eCSSProperty_border_start_style: |
|
461 case eCSSProperty_border_start_width: |
|
462 case eCSSProperty_border_end_color: |
|
463 case eCSSProperty_border_end_style: |
|
464 case eCSSProperty_border_end_width: { |
|
465 const nsCSSProperty* subprops = |
|
466 nsCSSProps::SubpropertyEntryFor(aProperty); |
|
467 NS_ABORT_IF_FALSE(subprops[3] == eCSSProperty_UNKNOWN, |
|
468 "not box property with physical vs. logical cascading"); |
|
469 AppendValueToString(subprops[0], aValue, aSerialization); |
|
470 break; |
|
471 } |
|
472 case eCSSProperty_background: { |
|
473 // We know from above that all subproperties were specified. |
|
474 // However, we still can't represent that in the shorthand unless |
|
475 // they're all lists of the same length. So if they're different |
|
476 // lengths, we need to bail out. |
|
477 // We also need to bail out if an item has background-clip and |
|
478 // background-origin that are different and not the default |
|
479 // values. (We omit them if they're both default.) |
|
480 const nsCSSValueList *image = |
|
481 data->ValueFor(eCSSProperty_background_image)-> |
|
482 GetListValue(); |
|
483 const nsCSSValuePairList *repeat = |
|
484 data->ValueFor(eCSSProperty_background_repeat)-> |
|
485 GetPairListValue(); |
|
486 const nsCSSValueList *attachment = |
|
487 data->ValueFor(eCSSProperty_background_attachment)-> |
|
488 GetListValue(); |
|
489 const nsCSSValueList *position = |
|
490 data->ValueFor(eCSSProperty_background_position)-> |
|
491 GetListValue(); |
|
492 const nsCSSValueList *clip = |
|
493 data->ValueFor(eCSSProperty_background_clip)-> |
|
494 GetListValue(); |
|
495 const nsCSSValueList *origin = |
|
496 data->ValueFor(eCSSProperty_background_origin)-> |
|
497 GetListValue(); |
|
498 const nsCSSValuePairList *size = |
|
499 data->ValueFor(eCSSProperty_background_size)-> |
|
500 GetPairListValue(); |
|
501 for (;;) { |
|
502 image->mValue.AppendToString(eCSSProperty_background_image, aValue, |
|
503 aSerialization); |
|
504 aValue.Append(char16_t(' ')); |
|
505 repeat->mXValue.AppendToString(eCSSProperty_background_repeat, aValue, |
|
506 aSerialization); |
|
507 if (repeat->mYValue.GetUnit() != eCSSUnit_Null) { |
|
508 repeat->mYValue.AppendToString(eCSSProperty_background_repeat, aValue, |
|
509 aSerialization); |
|
510 } |
|
511 aValue.Append(char16_t(' ')); |
|
512 attachment->mValue.AppendToString(eCSSProperty_background_attachment, |
|
513 aValue, aSerialization); |
|
514 aValue.Append(char16_t(' ')); |
|
515 position->mValue.AppendToString(eCSSProperty_background_position, |
|
516 aValue, aSerialization); |
|
517 |
|
518 if (size->mXValue.GetUnit() != eCSSUnit_Auto || |
|
519 size->mYValue.GetUnit() != eCSSUnit_Auto) { |
|
520 aValue.Append(char16_t(' ')); |
|
521 aValue.Append(char16_t('/')); |
|
522 aValue.Append(char16_t(' ')); |
|
523 size->mXValue.AppendToString(eCSSProperty_background_size, aValue, |
|
524 aSerialization); |
|
525 aValue.Append(char16_t(' ')); |
|
526 size->mYValue.AppendToString(eCSSProperty_background_size, aValue, |
|
527 aSerialization); |
|
528 } |
|
529 |
|
530 NS_ABORT_IF_FALSE(clip->mValue.GetUnit() == eCSSUnit_Enumerated && |
|
531 origin->mValue.GetUnit() == eCSSUnit_Enumerated, |
|
532 "should not have inherit/initial within list"); |
|
533 |
|
534 if (clip->mValue.GetIntValue() != NS_STYLE_BG_CLIP_BORDER || |
|
535 origin->mValue.GetIntValue() != NS_STYLE_BG_ORIGIN_PADDING) { |
|
536 MOZ_ASSERT(nsCSSProps::kKeywordTableTable[ |
|
537 eCSSProperty_background_origin] == |
|
538 nsCSSProps::kBackgroundOriginKTable); |
|
539 MOZ_ASSERT(nsCSSProps::kKeywordTableTable[ |
|
540 eCSSProperty_background_clip] == |
|
541 nsCSSProps::kBackgroundOriginKTable); |
|
542 static_assert(NS_STYLE_BG_CLIP_BORDER == |
|
543 NS_STYLE_BG_ORIGIN_BORDER && |
|
544 NS_STYLE_BG_CLIP_PADDING == |
|
545 NS_STYLE_BG_ORIGIN_PADDING && |
|
546 NS_STYLE_BG_CLIP_CONTENT == |
|
547 NS_STYLE_BG_ORIGIN_CONTENT, |
|
548 "bg-clip and bg-origin style constants must agree"); |
|
549 aValue.Append(char16_t(' ')); |
|
550 origin->mValue.AppendToString(eCSSProperty_background_origin, aValue, |
|
551 aSerialization); |
|
552 |
|
553 if (clip->mValue != origin->mValue) { |
|
554 aValue.Append(char16_t(' ')); |
|
555 clip->mValue.AppendToString(eCSSProperty_background_clip, aValue, |
|
556 aSerialization); |
|
557 } |
|
558 } |
|
559 |
|
560 image = image->mNext; |
|
561 repeat = repeat->mNext; |
|
562 attachment = attachment->mNext; |
|
563 position = position->mNext; |
|
564 clip = clip->mNext; |
|
565 origin = origin->mNext; |
|
566 size = size->mNext; |
|
567 |
|
568 if (!image) { |
|
569 if (repeat || attachment || position || clip || origin || size) { |
|
570 // Uneven length lists, so can't be serialized as shorthand. |
|
571 aValue.Truncate(); |
|
572 return; |
|
573 } |
|
574 break; |
|
575 } |
|
576 if (!repeat || !attachment || !position || !clip || !origin || !size) { |
|
577 // Uneven length lists, so can't be serialized as shorthand. |
|
578 aValue.Truncate(); |
|
579 return; |
|
580 } |
|
581 aValue.Append(char16_t(',')); |
|
582 aValue.Append(char16_t(' ')); |
|
583 } |
|
584 |
|
585 aValue.Append(char16_t(' ')); |
|
586 AppendValueToString(eCSSProperty_background_color, aValue, |
|
587 aSerialization); |
|
588 break; |
|
589 } |
|
590 case eCSSProperty_font: { |
|
591 // systemFont might not be present; other values are guaranteed to be |
|
592 // available based on the shorthand check at the beginning of the |
|
593 // function, as long as the prop is enabled |
|
594 const nsCSSValue *systemFont = |
|
595 data->ValueFor(eCSSProperty__x_system_font); |
|
596 const nsCSSValue *style = |
|
597 data->ValueFor(eCSSProperty_font_style); |
|
598 const nsCSSValue *variant = |
|
599 data->ValueFor(eCSSProperty_font_variant); |
|
600 const nsCSSValue *weight = |
|
601 data->ValueFor(eCSSProperty_font_weight); |
|
602 const nsCSSValue *size = |
|
603 data->ValueFor(eCSSProperty_font_size); |
|
604 const nsCSSValue *lh = |
|
605 data->ValueFor(eCSSProperty_line_height); |
|
606 const nsCSSValue *family = |
|
607 data->ValueFor(eCSSProperty_font_family); |
|
608 const nsCSSValue *stretch = |
|
609 data->ValueFor(eCSSProperty_font_stretch); |
|
610 const nsCSSValue *sizeAdjust = |
|
611 data->ValueFor(eCSSProperty_font_size_adjust); |
|
612 const nsCSSValue *featureSettings = |
|
613 data->ValueFor(eCSSProperty_font_feature_settings); |
|
614 const nsCSSValue *languageOverride = |
|
615 data->ValueFor(eCSSProperty_font_language_override); |
|
616 const nsCSSValue *fontKerning = |
|
617 data->ValueFor(eCSSProperty_font_kerning); |
|
618 const nsCSSValue *fontSynthesis = |
|
619 data->ValueFor(eCSSProperty_font_synthesis); |
|
620 const nsCSSValue *fontVariantAlternates = |
|
621 data->ValueFor(eCSSProperty_font_variant_alternates); |
|
622 const nsCSSValue *fontVariantCaps = |
|
623 data->ValueFor(eCSSProperty_font_variant_caps); |
|
624 const nsCSSValue *fontVariantEastAsian = |
|
625 data->ValueFor(eCSSProperty_font_variant_east_asian); |
|
626 const nsCSSValue *fontVariantLigatures = |
|
627 data->ValueFor(eCSSProperty_font_variant_ligatures); |
|
628 const nsCSSValue *fontVariantNumeric = |
|
629 data->ValueFor(eCSSProperty_font_variant_numeric); |
|
630 const nsCSSValue *fontVariantPosition = |
|
631 data->ValueFor(eCSSProperty_font_variant_position); |
|
632 |
|
633 // if font features are not enabled, pointers for fontVariant |
|
634 // values above may be null since the shorthand check ignores them |
|
635 // font-variant-alternates enabled ==> layout.css.font-features.enabled is true |
|
636 bool fontFeaturesEnabled = |
|
637 nsCSSProps::IsEnabled(eCSSProperty_font_variant_alternates); |
|
638 |
|
639 if (systemFont && |
|
640 systemFont->GetUnit() != eCSSUnit_None && |
|
641 systemFont->GetUnit() != eCSSUnit_Null) { |
|
642 if (style->GetUnit() != eCSSUnit_System_Font || |
|
643 variant->GetUnit() != eCSSUnit_System_Font || |
|
644 weight->GetUnit() != eCSSUnit_System_Font || |
|
645 size->GetUnit() != eCSSUnit_System_Font || |
|
646 lh->GetUnit() != eCSSUnit_System_Font || |
|
647 family->GetUnit() != eCSSUnit_System_Font || |
|
648 stretch->GetUnit() != eCSSUnit_System_Font || |
|
649 sizeAdjust->GetUnit() != eCSSUnit_System_Font || |
|
650 featureSettings->GetUnit() != eCSSUnit_System_Font || |
|
651 languageOverride->GetUnit() != eCSSUnit_System_Font || |
|
652 (fontFeaturesEnabled && |
|
653 (fontKerning->GetUnit() != eCSSUnit_System_Font || |
|
654 fontSynthesis->GetUnit() != eCSSUnit_System_Font || |
|
655 fontVariantAlternates->GetUnit() != eCSSUnit_System_Font || |
|
656 fontVariantCaps->GetUnit() != eCSSUnit_System_Font || |
|
657 fontVariantEastAsian->GetUnit() != eCSSUnit_System_Font || |
|
658 fontVariantLigatures->GetUnit() != eCSSUnit_System_Font || |
|
659 fontVariantNumeric->GetUnit() != eCSSUnit_System_Font || |
|
660 fontVariantPosition->GetUnit() != eCSSUnit_System_Font))) { |
|
661 // This can't be represented as a shorthand. |
|
662 return; |
|
663 } |
|
664 systemFont->AppendToString(eCSSProperty__x_system_font, aValue, |
|
665 aSerialization); |
|
666 } else { |
|
667 // properties reset by this shorthand property to their |
|
668 // initial values but not represented in its syntax |
|
669 if (stretch->GetUnit() != eCSSUnit_Enumerated || |
|
670 stretch->GetIntValue() != NS_STYLE_FONT_STRETCH_NORMAL || |
|
671 sizeAdjust->GetUnit() != eCSSUnit_None || |
|
672 featureSettings->GetUnit() != eCSSUnit_Normal || |
|
673 languageOverride->GetUnit() != eCSSUnit_Normal || |
|
674 (fontFeaturesEnabled && |
|
675 (fontKerning->GetIntValue() != NS_FONT_KERNING_AUTO || |
|
676 fontSynthesis->GetUnit() != eCSSUnit_Enumerated || |
|
677 fontSynthesis->GetIntValue() != |
|
678 (NS_FONT_SYNTHESIS_WEIGHT | NS_FONT_SYNTHESIS_STYLE) || |
|
679 fontVariantAlternates->GetUnit() != eCSSUnit_Normal || |
|
680 fontVariantCaps->GetUnit() != eCSSUnit_Normal || |
|
681 fontVariantEastAsian->GetUnit() != eCSSUnit_Normal || |
|
682 fontVariantLigatures->GetUnit() != eCSSUnit_Normal || |
|
683 fontVariantNumeric->GetUnit() != eCSSUnit_Normal || |
|
684 fontVariantPosition->GetUnit() != eCSSUnit_Normal))) { |
|
685 return; |
|
686 } |
|
687 |
|
688 if (style->GetUnit() != eCSSUnit_Enumerated || |
|
689 style->GetIntValue() != NS_FONT_STYLE_NORMAL) { |
|
690 style->AppendToString(eCSSProperty_font_style, aValue, |
|
691 aSerialization); |
|
692 aValue.Append(char16_t(' ')); |
|
693 } |
|
694 if (variant->GetUnit() != eCSSUnit_Enumerated || |
|
695 variant->GetIntValue() != NS_FONT_VARIANT_NORMAL) { |
|
696 variant->AppendToString(eCSSProperty_font_variant, aValue, |
|
697 aSerialization); |
|
698 aValue.Append(char16_t(' ')); |
|
699 } |
|
700 if (weight->GetUnit() != eCSSUnit_Enumerated || |
|
701 weight->GetIntValue() != NS_FONT_WEIGHT_NORMAL) { |
|
702 weight->AppendToString(eCSSProperty_font_weight, aValue, |
|
703 aSerialization); |
|
704 aValue.Append(char16_t(' ')); |
|
705 } |
|
706 size->AppendToString(eCSSProperty_font_size, aValue, aSerialization); |
|
707 if (lh->GetUnit() != eCSSUnit_Normal) { |
|
708 aValue.Append(char16_t('/')); |
|
709 lh->AppendToString(eCSSProperty_line_height, aValue, aSerialization); |
|
710 } |
|
711 aValue.Append(char16_t(' ')); |
|
712 family->AppendToString(eCSSProperty_font_family, aValue, |
|
713 aSerialization); |
|
714 } |
|
715 break; |
|
716 } |
|
717 case eCSSProperty_list_style: |
|
718 if (AppendValueToString(eCSSProperty_list_style_type, aValue, |
|
719 aSerialization)) { |
|
720 aValue.Append(char16_t(' ')); |
|
721 } |
|
722 if (AppendValueToString(eCSSProperty_list_style_position, aValue, |
|
723 aSerialization)) { |
|
724 aValue.Append(char16_t(' ')); |
|
725 } |
|
726 AppendValueToString(eCSSProperty_list_style_image, aValue, |
|
727 aSerialization); |
|
728 break; |
|
729 case eCSSProperty_overflow: { |
|
730 const nsCSSValue &xValue = |
|
731 *data->ValueFor(eCSSProperty_overflow_x); |
|
732 const nsCSSValue &yValue = |
|
733 *data->ValueFor(eCSSProperty_overflow_y); |
|
734 if (xValue == yValue) |
|
735 xValue.AppendToString(eCSSProperty_overflow_x, aValue, aSerialization); |
|
736 break; |
|
737 } |
|
738 case eCSSProperty_text_decoration: { |
|
739 // If text-decoration-color or text-decoration-style isn't initial value, |
|
740 // we cannot serialize the text-decoration shorthand value. |
|
741 const nsCSSValue *decorationColor = |
|
742 data->ValueFor(eCSSProperty_text_decoration_color); |
|
743 const nsCSSValue *decorationStyle = |
|
744 data->ValueFor(eCSSProperty_text_decoration_style); |
|
745 |
|
746 NS_ABORT_IF_FALSE(decorationStyle->GetUnit() == eCSSUnit_Enumerated, |
|
747 nsPrintfCString("bad text-decoration-style unit %d", |
|
748 decorationStyle->GetUnit()).get()); |
|
749 |
|
750 if (decorationColor->GetUnit() != eCSSUnit_Enumerated || |
|
751 decorationColor->GetIntValue() != NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR || |
|
752 decorationStyle->GetIntValue() != |
|
753 NS_STYLE_TEXT_DECORATION_STYLE_SOLID) { |
|
754 return; |
|
755 } |
|
756 |
|
757 AppendValueToString(eCSSProperty_text_decoration_line, aValue, |
|
758 aSerialization); |
|
759 break; |
|
760 } |
|
761 case eCSSProperty_transition: { |
|
762 const nsCSSValue *transProp = |
|
763 data->ValueFor(eCSSProperty_transition_property); |
|
764 const nsCSSValue *transDuration = |
|
765 data->ValueFor(eCSSProperty_transition_duration); |
|
766 const nsCSSValue *transTiming = |
|
767 data->ValueFor(eCSSProperty_transition_timing_function); |
|
768 const nsCSSValue *transDelay = |
|
769 data->ValueFor(eCSSProperty_transition_delay); |
|
770 |
|
771 NS_ABORT_IF_FALSE(transDuration->GetUnit() == eCSSUnit_List || |
|
772 transDuration->GetUnit() == eCSSUnit_ListDep, |
|
773 nsPrintfCString("bad t-duration unit %d", |
|
774 transDuration->GetUnit()).get()); |
|
775 NS_ABORT_IF_FALSE(transTiming->GetUnit() == eCSSUnit_List || |
|
776 transTiming->GetUnit() == eCSSUnit_ListDep, |
|
777 nsPrintfCString("bad t-timing unit %d", |
|
778 transTiming->GetUnit()).get()); |
|
779 NS_ABORT_IF_FALSE(transDelay->GetUnit() == eCSSUnit_List || |
|
780 transDelay->GetUnit() == eCSSUnit_ListDep, |
|
781 nsPrintfCString("bad t-delay unit %d", |
|
782 transDelay->GetUnit()).get()); |
|
783 |
|
784 const nsCSSValueList* dur = transDuration->GetListValue(); |
|
785 const nsCSSValueList* tim = transTiming->GetListValue(); |
|
786 const nsCSSValueList* del = transDelay->GetListValue(); |
|
787 |
|
788 if (transProp->GetUnit() == eCSSUnit_None || |
|
789 transProp->GetUnit() == eCSSUnit_All) { |
|
790 // If any of the other three lists has more than one element, |
|
791 // we can't use the shorthand. |
|
792 if (!dur->mNext && !tim->mNext && !del->mNext) { |
|
793 transProp->AppendToString(eCSSProperty_transition_property, aValue, |
|
794 aSerialization); |
|
795 aValue.Append(char16_t(' ')); |
|
796 dur->mValue.AppendToString(eCSSProperty_transition_duration,aValue, |
|
797 aSerialization); |
|
798 aValue.Append(char16_t(' ')); |
|
799 tim->mValue.AppendToString(eCSSProperty_transition_timing_function, |
|
800 aValue, aSerialization); |
|
801 aValue.Append(char16_t(' ')); |
|
802 del->mValue.AppendToString(eCSSProperty_transition_delay, aValue, |
|
803 aSerialization); |
|
804 aValue.Append(char16_t(' ')); |
|
805 } else { |
|
806 aValue.Truncate(); |
|
807 } |
|
808 } else { |
|
809 NS_ABORT_IF_FALSE(transProp->GetUnit() == eCSSUnit_List || |
|
810 transProp->GetUnit() == eCSSUnit_ListDep, |
|
811 nsPrintfCString("bad t-prop unit %d", |
|
812 transProp->GetUnit()).get()); |
|
813 const nsCSSValueList* pro = transProp->GetListValue(); |
|
814 for (;;) { |
|
815 pro->mValue.AppendToString(eCSSProperty_transition_property, |
|
816 aValue, aSerialization); |
|
817 aValue.Append(char16_t(' ')); |
|
818 dur->mValue.AppendToString(eCSSProperty_transition_duration, |
|
819 aValue, aSerialization); |
|
820 aValue.Append(char16_t(' ')); |
|
821 tim->mValue.AppendToString(eCSSProperty_transition_timing_function, |
|
822 aValue, aSerialization); |
|
823 aValue.Append(char16_t(' ')); |
|
824 del->mValue.AppendToString(eCSSProperty_transition_delay, |
|
825 aValue, aSerialization); |
|
826 pro = pro->mNext; |
|
827 dur = dur->mNext; |
|
828 tim = tim->mNext; |
|
829 del = del->mNext; |
|
830 if (!pro || !dur || !tim || !del) { |
|
831 break; |
|
832 } |
|
833 aValue.AppendLiteral(", "); |
|
834 } |
|
835 if (pro || dur || tim || del) { |
|
836 // Lists not all the same length, can't use shorthand. |
|
837 aValue.Truncate(); |
|
838 } |
|
839 } |
|
840 break; |
|
841 } |
|
842 case eCSSProperty_animation: { |
|
843 const nsCSSProperty* subprops = |
|
844 nsCSSProps::SubpropertyEntryFor(eCSSProperty_animation); |
|
845 static const size_t numProps = 7; |
|
846 NS_ABORT_IF_FALSE(subprops[numProps] == eCSSProperty_UNKNOWN, |
|
847 "unexpected number of subproperties"); |
|
848 const nsCSSValue* values[numProps]; |
|
849 const nsCSSValueList* lists[numProps]; |
|
850 |
|
851 for (uint32_t i = 0; i < numProps; ++i) { |
|
852 values[i] = data->ValueFor(subprops[i]); |
|
853 NS_ABORT_IF_FALSE(values[i]->GetUnit() == eCSSUnit_List || |
|
854 values[i]->GetUnit() == eCSSUnit_ListDep, |
|
855 nsPrintfCString("bad a-duration unit %d", |
|
856 values[i]->GetUnit()).get()); |
|
857 lists[i] = values[i]->GetListValue(); |
|
858 } |
|
859 |
|
860 for (;;) { |
|
861 // We must serialize 'animation-name' last in case it has |
|
862 // a value that conflicts with one of the other keyword properties. |
|
863 NS_ABORT_IF_FALSE(subprops[numProps - 1] == |
|
864 eCSSProperty_animation_name, |
|
865 "animation-name must be last"); |
|
866 bool done = false; |
|
867 for (uint32_t i = 0;;) { |
|
868 lists[i]->mValue.AppendToString(subprops[i], aValue, aSerialization); |
|
869 lists[i] = lists[i]->mNext; |
|
870 if (!lists[i]) { |
|
871 done = true; |
|
872 } |
|
873 if (++i == numProps) { |
|
874 break; |
|
875 } |
|
876 aValue.Append(char16_t(' ')); |
|
877 } |
|
878 if (done) { |
|
879 break; |
|
880 } |
|
881 aValue.AppendLiteral(", "); |
|
882 } |
|
883 for (uint32_t i = 0; i < numProps; ++i) { |
|
884 if (lists[i]) { |
|
885 // Lists not all the same length, can't use shorthand. |
|
886 aValue.Truncate(); |
|
887 break; |
|
888 } |
|
889 } |
|
890 break; |
|
891 } |
|
892 case eCSSProperty_marker: { |
|
893 const nsCSSValue &endValue = |
|
894 *data->ValueFor(eCSSProperty_marker_end); |
|
895 const nsCSSValue &midValue = |
|
896 *data->ValueFor(eCSSProperty_marker_mid); |
|
897 const nsCSSValue &startValue = |
|
898 *data->ValueFor(eCSSProperty_marker_start); |
|
899 if (endValue == midValue && midValue == startValue) |
|
900 AppendValueToString(eCSSProperty_marker_end, aValue, aSerialization); |
|
901 break; |
|
902 } |
|
903 case eCSSProperty__moz_columns: { |
|
904 // Two values, column-count and column-width, separated by a space. |
|
905 const nsCSSProperty* subprops = |
|
906 nsCSSProps::SubpropertyEntryFor(aProperty); |
|
907 AppendValueToString(subprops[0], aValue, aSerialization); |
|
908 aValue.Append(char16_t(' ')); |
|
909 AppendValueToString(subprops[1], aValue, aSerialization); |
|
910 break; |
|
911 } |
|
912 case eCSSProperty_flex: { |
|
913 // flex-grow, flex-shrink, flex-basis, separated by single space |
|
914 const nsCSSProperty* subprops = |
|
915 nsCSSProps::SubpropertyEntryFor(aProperty); |
|
916 |
|
917 AppendValueToString(subprops[0], aValue, aSerialization); |
|
918 aValue.Append(char16_t(' ')); |
|
919 AppendValueToString(subprops[1], aValue, aSerialization); |
|
920 aValue.Append(char16_t(' ')); |
|
921 AppendValueToString(subprops[2], aValue, aSerialization); |
|
922 break; |
|
923 } |
|
924 case eCSSProperty_flex_flow: { |
|
925 // flex-direction, flex-wrap, separated by single space |
|
926 const nsCSSProperty* subprops = |
|
927 nsCSSProps::SubpropertyEntryFor(aProperty); |
|
928 NS_ABORT_IF_FALSE(subprops[2] == eCSSProperty_UNKNOWN, |
|
929 "must have exactly two subproperties"); |
|
930 |
|
931 AppendValueToString(subprops[0], aValue, aSerialization); |
|
932 aValue.Append(char16_t(' ')); |
|
933 AppendValueToString(subprops[1], aValue, aSerialization); |
|
934 break; |
|
935 } |
|
936 case eCSSProperty_grid_row: |
|
937 case eCSSProperty_grid_column: { |
|
938 // grid-{row,column}-start, grid-{row,column}-end, separated by a slash |
|
939 const nsCSSProperty* subprops = |
|
940 nsCSSProps::SubpropertyEntryFor(aProperty); |
|
941 NS_ABORT_IF_FALSE(subprops[2] == eCSSProperty_UNKNOWN, |
|
942 "must have exactly two subproperties"); |
|
943 |
|
944 // TODO: should we simplify when possible? |
|
945 AppendValueToString(subprops[0], aValue, aSerialization); |
|
946 aValue.AppendLiteral(" / "); |
|
947 AppendValueToString(subprops[1], aValue, aSerialization); |
|
948 break; |
|
949 } |
|
950 case eCSSProperty_grid_area: { |
|
951 const nsCSSProperty* subprops = |
|
952 nsCSSProps::SubpropertyEntryFor(aProperty); |
|
953 NS_ABORT_IF_FALSE(subprops[4] == eCSSProperty_UNKNOWN, |
|
954 "must have exactly four subproperties"); |
|
955 |
|
956 // TODO: should we simplify when possible? |
|
957 AppendValueToString(subprops[0], aValue, aSerialization); |
|
958 aValue.AppendLiteral(" / "); |
|
959 AppendValueToString(subprops[1], aValue, aSerialization); |
|
960 aValue.AppendLiteral(" / "); |
|
961 AppendValueToString(subprops[2], aValue, aSerialization); |
|
962 aValue.AppendLiteral(" / "); |
|
963 AppendValueToString(subprops[3], aValue, aSerialization); |
|
964 break; |
|
965 } |
|
966 |
|
967 // This can express either grid-template-{areas,columns,rows} |
|
968 // or grid-auto-{flow,columns,rows}, but not both. |
|
969 case eCSSProperty_grid: { |
|
970 const nsCSSValue& areasValue = |
|
971 *data->ValueFor(eCSSProperty_grid_template_areas); |
|
972 const nsCSSValue& columnsValue = |
|
973 *data->ValueFor(eCSSProperty_grid_template_columns); |
|
974 const nsCSSValue& rowsValue = |
|
975 *data->ValueFor(eCSSProperty_grid_template_rows); |
|
976 |
|
977 const nsCSSValue& autoFlowValue = |
|
978 *data->ValueFor(eCSSProperty_grid_auto_flow); |
|
979 const nsCSSValue& autoColumnsValue = |
|
980 *data->ValueFor(eCSSProperty_grid_auto_columns); |
|
981 const nsCSSValue& autoRowsValue = |
|
982 *data->ValueFor(eCSSProperty_grid_auto_rows); |
|
983 |
|
984 if (areasValue.GetUnit() == eCSSUnit_None && |
|
985 columnsValue.GetUnit() == eCSSUnit_None && |
|
986 rowsValue.GetUnit() == eCSSUnit_None) { |
|
987 AppendValueToString(eCSSProperty_grid_auto_flow, |
|
988 aValue, aSerialization); |
|
989 aValue.Append(char16_t(' ')); |
|
990 AppendValueToString(eCSSProperty_grid_auto_columns, |
|
991 aValue, aSerialization); |
|
992 aValue.AppendLiteral(" / "); |
|
993 AppendValueToString(eCSSProperty_grid_auto_rows, |
|
994 aValue, aSerialization); |
|
995 break; |
|
996 } else if (!(autoFlowValue.GetUnit() == eCSSUnit_Enumerated && |
|
997 autoFlowValue.GetIntValue() == NS_STYLE_GRID_AUTO_FLOW_NONE && |
|
998 autoColumnsValue.GetUnit() == eCSSUnit_Auto && |
|
999 autoRowsValue.GetUnit() == eCSSUnit_Auto)) { |
|
1000 // Not serializable, bail. |
|
1001 return; |
|
1002 } |
|
1003 // Fall through to eCSSProperty_grid_template |
|
1004 } |
|
1005 case eCSSProperty_grid_template: { |
|
1006 const nsCSSValue& areasValue = |
|
1007 *data->ValueFor(eCSSProperty_grid_template_areas); |
|
1008 const nsCSSValue& columnsValue = |
|
1009 *data->ValueFor(eCSSProperty_grid_template_columns); |
|
1010 const nsCSSValue& rowsValue = |
|
1011 *data->ValueFor(eCSSProperty_grid_template_rows); |
|
1012 if (areasValue.GetUnit() == eCSSUnit_None) { |
|
1013 AppendValueToString(eCSSProperty_grid_template_columns, |
|
1014 aValue, aSerialization); |
|
1015 aValue.AppendLiteral(" / "); |
|
1016 AppendValueToString(eCSSProperty_grid_template_rows, |
|
1017 aValue, aSerialization); |
|
1018 break; |
|
1019 } |
|
1020 if (columnsValue.GetUnit() == eCSSUnit_List || |
|
1021 columnsValue.GetUnit() == eCSSUnit_ListDep) { |
|
1022 const nsCSSValueList* columnsItem = columnsValue.GetListValue(); |
|
1023 if (columnsItem->mValue.GetUnit() == eCSSUnit_Enumerated && |
|
1024 columnsItem->mValue.GetIntValue() == NS_STYLE_GRID_TEMPLATE_SUBGRID) { |
|
1025 // We have "grid-template-areas:[something]; grid-template-columns:subgrid" |
|
1026 // which isn't a value that the shorthand can express. Bail. |
|
1027 return; |
|
1028 } |
|
1029 } |
|
1030 if (rowsValue.GetUnit() != eCSSUnit_List && |
|
1031 rowsValue.GetUnit() != eCSSUnit_ListDep) { |
|
1032 // We have "grid-template-areas:[something]; grid-template-rows:none" |
|
1033 // which isn't a value that the shorthand can express. Bail. |
|
1034 return; |
|
1035 } |
|
1036 const nsCSSValueList* rowsItem = rowsValue.GetListValue(); |
|
1037 if (rowsItem->mValue.GetUnit() == eCSSUnit_Enumerated && |
|
1038 rowsItem->mValue.GetIntValue() == NS_STYLE_GRID_TEMPLATE_SUBGRID) { |
|
1039 // We have "grid-template-areas:[something]; grid-template-rows:subgrid" |
|
1040 // which isn't a value that the shorthand can express. Bail. |
|
1041 return; |
|
1042 } |
|
1043 const GridTemplateAreasValue* areas = areasValue.GetGridTemplateAreas(); |
|
1044 uint32_t nRowItems = 0; |
|
1045 while (rowsItem) { |
|
1046 nRowItems++; |
|
1047 rowsItem = rowsItem->mNext; |
|
1048 } |
|
1049 MOZ_ASSERT(nRowItems % 2 == 1, "expected an odd number of items"); |
|
1050 if ((nRowItems - 1) / 2 != areas->NRows()) { |
|
1051 // Not serializable, bail. |
|
1052 return; |
|
1053 } |
|
1054 if (columnsValue.GetUnit() != eCSSUnit_None) { |
|
1055 AppendValueToString(eCSSProperty_grid_template_columns, |
|
1056 aValue, aSerialization); |
|
1057 aValue.AppendLiteral(" / "); |
|
1058 } |
|
1059 rowsItem = rowsValue.GetListValue(); |
|
1060 uint32_t row = 0; |
|
1061 for (;;) { |
|
1062 bool addSpaceSeparator = true; |
|
1063 nsCSSUnit unit = rowsItem->mValue.GetUnit(); |
|
1064 |
|
1065 if (unit == eCSSUnit_Null) { |
|
1066 // Empty or omitted <line-names>. Serializes to nothing. |
|
1067 addSpaceSeparator = false; // Avoid a double space. |
|
1068 |
|
1069 } else if (unit == eCSSUnit_List || unit == eCSSUnit_ListDep) { |
|
1070 // Non-empty <line-names> |
|
1071 aValue.AppendLiteral("("); |
|
1072 rowsItem->mValue.AppendToString(eCSSProperty_grid_template_rows, |
|
1073 aValue, aSerialization); |
|
1074 aValue.AppendLiteral(")"); |
|
1075 |
|
1076 } else { |
|
1077 nsStyleUtil::AppendEscapedCSSString(areas->mTemplates[row++], aValue); |
|
1078 aValue.Append(char16_t(' ')); |
|
1079 |
|
1080 // <track-size> |
|
1081 rowsItem->mValue.AppendToString(eCSSProperty_grid_template_rows, |
|
1082 aValue, aSerialization); |
|
1083 if (rowsItem->mNext && |
|
1084 rowsItem->mNext->mValue.GetUnit() == eCSSUnit_Null && |
|
1085 !rowsItem->mNext->mNext) { |
|
1086 // Break out of the loop early to avoid a trailing space. |
|
1087 break; |
|
1088 } |
|
1089 } |
|
1090 |
|
1091 rowsItem = rowsItem->mNext; |
|
1092 if (!rowsItem) { |
|
1093 break; |
|
1094 } |
|
1095 |
|
1096 if (addSpaceSeparator) { |
|
1097 aValue.Append(char16_t(' ')); |
|
1098 } |
|
1099 } |
|
1100 break; |
|
1101 } |
|
1102 case eCSSProperty__moz_transform: { |
|
1103 // shorthands that are just aliases with different parsing rules |
|
1104 const nsCSSProperty* subprops = |
|
1105 nsCSSProps::SubpropertyEntryFor(aProperty); |
|
1106 NS_ABORT_IF_FALSE(subprops[1] == eCSSProperty_UNKNOWN, |
|
1107 "must have exactly one subproperty"); |
|
1108 AppendValueToString(subprops[0], aValue, aSerialization); |
|
1109 break; |
|
1110 } |
|
1111 case eCSSProperty_all: |
|
1112 // If we got here, then we didn't have all "inherit" or "initial" or |
|
1113 // "unset" values for all of the longhand property components of 'all'. |
|
1114 // There is no other possible value that is valid for all properties, |
|
1115 // so serialize as the empty string. |
|
1116 break; |
|
1117 default: |
|
1118 NS_ABORT_IF_FALSE(false, "no other shorthands"); |
|
1119 break; |
|
1120 } |
|
1121 } |
|
1122 |
|
1123 bool |
|
1124 Declaration::GetValueIsImportant(const nsAString& aProperty) const |
|
1125 { |
|
1126 nsCSSProperty propID = |
|
1127 nsCSSProps::LookupProperty(aProperty, nsCSSProps::eIgnoreEnabledState); |
|
1128 if (propID == eCSSProperty_UNKNOWN) { |
|
1129 return false; |
|
1130 } |
|
1131 if (propID == eCSSPropertyExtra_variable) { |
|
1132 const nsSubstring& variableName = |
|
1133 Substring(aProperty, CSS_CUSTOM_NAME_PREFIX_LENGTH); |
|
1134 return GetVariableValueIsImportant(variableName); |
|
1135 } |
|
1136 return GetValueIsImportant(propID); |
|
1137 } |
|
1138 |
|
1139 bool |
|
1140 Declaration::GetValueIsImportant(nsCSSProperty aProperty) const |
|
1141 { |
|
1142 if (!mImportantData) |
|
1143 return false; |
|
1144 |
|
1145 // Calling ValueFor is inefficient, but we can assume '!important' is rare. |
|
1146 |
|
1147 if (!nsCSSProps::IsShorthand(aProperty)) { |
|
1148 return mImportantData->ValueFor(aProperty) != nullptr; |
|
1149 } |
|
1150 |
|
1151 CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p, aProperty) { |
|
1152 if (*p == eCSSProperty__x_system_font) { |
|
1153 // The system_font subproperty doesn't count. |
|
1154 continue; |
|
1155 } |
|
1156 if (!mImportantData->ValueFor(*p)) { |
|
1157 return false; |
|
1158 } |
|
1159 } |
|
1160 return true; |
|
1161 } |
|
1162 |
|
1163 void |
|
1164 Declaration::AppendPropertyAndValueToString(nsCSSProperty aProperty, |
|
1165 nsAutoString& aValue, |
|
1166 nsAString& aResult) const |
|
1167 { |
|
1168 NS_ABORT_IF_FALSE(0 <= aProperty && aProperty < eCSSProperty_COUNT, |
|
1169 "property enum out of range"); |
|
1170 NS_ABORT_IF_FALSE((aProperty < eCSSProperty_COUNT_no_shorthands) == |
|
1171 aValue.IsEmpty(), |
|
1172 "aValue should be given for shorthands but not longhands"); |
|
1173 AppendASCIItoUTF16(nsCSSProps::GetStringValue(aProperty), aResult); |
|
1174 aResult.AppendLiteral(": "); |
|
1175 if (aValue.IsEmpty()) |
|
1176 AppendValueToString(aProperty, aResult, nsCSSValue::eNormalized); |
|
1177 else |
|
1178 aResult.Append(aValue); |
|
1179 if (GetValueIsImportant(aProperty)) { |
|
1180 aResult.AppendLiteral(" ! important"); |
|
1181 } |
|
1182 aResult.AppendLiteral("; "); |
|
1183 } |
|
1184 |
|
1185 void |
|
1186 Declaration::AppendVariableAndValueToString(const nsAString& aName, |
|
1187 nsAString& aResult) const |
|
1188 { |
|
1189 aResult.AppendLiteral("--"); |
|
1190 aResult.Append(aName); |
|
1191 CSSVariableDeclarations::Type type; |
|
1192 nsString value; |
|
1193 bool important; |
|
1194 |
|
1195 if (mImportantVariables && mImportantVariables->Get(aName, type, value)) { |
|
1196 important = true; |
|
1197 } else { |
|
1198 MOZ_ASSERT(mVariables); |
|
1199 MOZ_ASSERT(mVariables->Has(aName)); |
|
1200 mVariables->Get(aName, type, value); |
|
1201 important = false; |
|
1202 } |
|
1203 |
|
1204 switch (type) { |
|
1205 case CSSVariableDeclarations::eTokenStream: |
|
1206 if (value.IsEmpty()) { |
|
1207 aResult.Append(':'); |
|
1208 } else { |
|
1209 aResult.AppendLiteral(": "); |
|
1210 aResult.Append(value); |
|
1211 } |
|
1212 break; |
|
1213 |
|
1214 case CSSVariableDeclarations::eInitial: |
|
1215 aResult.AppendLiteral("initial"); |
|
1216 break; |
|
1217 |
|
1218 case CSSVariableDeclarations::eInherit: |
|
1219 aResult.AppendLiteral("inherit"); |
|
1220 break; |
|
1221 |
|
1222 case CSSVariableDeclarations::eUnset: |
|
1223 aResult.AppendLiteral("unset"); |
|
1224 break; |
|
1225 |
|
1226 default: |
|
1227 MOZ_ASSERT(false, "unexpected variable value type"); |
|
1228 } |
|
1229 |
|
1230 if (important) { |
|
1231 aResult.AppendLiteral("! important"); |
|
1232 } |
|
1233 aResult.AppendLiteral("; "); |
|
1234 } |
|
1235 |
|
1236 void |
|
1237 Declaration::ToString(nsAString& aString) const |
|
1238 { |
|
1239 // Someone cares about this declaration's contents, so don't let it |
|
1240 // change from under them. See e.g. bug 338679. |
|
1241 SetImmutable(); |
|
1242 |
|
1243 nsCSSCompressedDataBlock *systemFontData = |
|
1244 GetValueIsImportant(eCSSProperty__x_system_font) ? mImportantData : mData; |
|
1245 const nsCSSValue *systemFont = |
|
1246 systemFontData->ValueFor(eCSSProperty__x_system_font); |
|
1247 const bool haveSystemFont = systemFont && |
|
1248 systemFont->GetUnit() != eCSSUnit_None && |
|
1249 systemFont->GetUnit() != eCSSUnit_Null; |
|
1250 bool didSystemFont = false; |
|
1251 |
|
1252 int32_t count = mOrder.Length(); |
|
1253 int32_t index; |
|
1254 nsAutoTArray<nsCSSProperty, 16> shorthandsUsed; |
|
1255 for (index = 0; index < count; index++) { |
|
1256 nsCSSProperty property = GetPropertyAt(index); |
|
1257 |
|
1258 if (property == eCSSPropertyExtra_variable) { |
|
1259 uint32_t variableIndex = mOrder[index] - eCSSProperty_COUNT; |
|
1260 AppendVariableAndValueToString(mVariableOrder[variableIndex], aString); |
|
1261 continue; |
|
1262 } |
|
1263 |
|
1264 if (!nsCSSProps::IsEnabled(property)) { |
|
1265 continue; |
|
1266 } |
|
1267 bool doneProperty = false; |
|
1268 |
|
1269 // If we already used this property in a shorthand, skip it. |
|
1270 if (shorthandsUsed.Length() > 0) { |
|
1271 for (const nsCSSProperty *shorthands = |
|
1272 nsCSSProps::ShorthandsContaining(property); |
|
1273 *shorthands != eCSSProperty_UNKNOWN; ++shorthands) { |
|
1274 if (shorthandsUsed.Contains(*shorthands)) { |
|
1275 doneProperty = true; |
|
1276 break; |
|
1277 } |
|
1278 } |
|
1279 if (doneProperty) |
|
1280 continue; |
|
1281 } |
|
1282 |
|
1283 // Try to use this property in a shorthand. |
|
1284 nsAutoString value; |
|
1285 for (const nsCSSProperty *shorthands = |
|
1286 nsCSSProps::ShorthandsContaining(property); |
|
1287 *shorthands != eCSSProperty_UNKNOWN; ++shorthands) { |
|
1288 // ShorthandsContaining returns the shorthands in order from those |
|
1289 // that contain the most subproperties to those that contain the |
|
1290 // least, which is exactly the order we want to test them. |
|
1291 nsCSSProperty shorthand = *shorthands; |
|
1292 |
|
1293 // If GetValue gives us a non-empty string back, we can use that |
|
1294 // value; otherwise it's not possible to use this shorthand. |
|
1295 GetValue(shorthand, value); |
|
1296 if (!value.IsEmpty()) { |
|
1297 AppendPropertyAndValueToString(shorthand, value, aString); |
|
1298 shorthandsUsed.AppendElement(shorthand); |
|
1299 doneProperty = true; |
|
1300 break; |
|
1301 } |
|
1302 |
|
1303 NS_ABORT_IF_FALSE(shorthand != eCSSProperty_font || |
|
1304 *(shorthands + 1) == eCSSProperty_UNKNOWN, |
|
1305 "font should always be the only containing shorthand"); |
|
1306 if (shorthand == eCSSProperty_font) { |
|
1307 if (haveSystemFont && !didSystemFont) { |
|
1308 // Output the shorthand font declaration that we will |
|
1309 // partially override later. But don't add it to |
|
1310 // |shorthandsUsed|, since we will have to override it. |
|
1311 systemFont->AppendToString(eCSSProperty__x_system_font, value, |
|
1312 nsCSSValue::eNormalized); |
|
1313 AppendPropertyAndValueToString(eCSSProperty_font, value, aString); |
|
1314 value.Truncate(); |
|
1315 didSystemFont = true; |
|
1316 } |
|
1317 |
|
1318 // That we output the system font is enough for this property if: |
|
1319 // (1) it's the hidden system font subproperty (which either |
|
1320 // means we output it or we don't have it), or |
|
1321 // (2) its value is the hidden system font value and it matches |
|
1322 // the hidden system font subproperty in importance, and |
|
1323 // we output the system font subproperty. |
|
1324 const nsCSSValue *val = systemFontData->ValueFor(property); |
|
1325 if (property == eCSSProperty__x_system_font || |
|
1326 (haveSystemFont && val && val->GetUnit() == eCSSUnit_System_Font)) { |
|
1327 doneProperty = true; |
|
1328 } |
|
1329 } |
|
1330 } |
|
1331 if (doneProperty) |
|
1332 continue; |
|
1333 |
|
1334 NS_ABORT_IF_FALSE(value.IsEmpty(), "value should be empty now"); |
|
1335 AppendPropertyAndValueToString(property, value, aString); |
|
1336 } |
|
1337 if (! aString.IsEmpty()) { |
|
1338 // if the string is not empty, we have trailing whitespace we |
|
1339 // should remove |
|
1340 aString.Truncate(aString.Length() - 1); |
|
1341 } |
|
1342 } |
|
1343 |
|
1344 #ifdef DEBUG |
|
1345 void |
|
1346 Declaration::List(FILE* out, int32_t aIndent) const |
|
1347 { |
|
1348 for (int32_t index = aIndent; --index >= 0; ) fputs(" ", out); |
|
1349 |
|
1350 fputs("{ ", out); |
|
1351 nsAutoString s; |
|
1352 ToString(s); |
|
1353 fputs(NS_ConvertUTF16toUTF8(s).get(), out); |
|
1354 fputs("}", out); |
|
1355 } |
|
1356 #endif |
|
1357 |
|
1358 bool |
|
1359 Declaration::GetNthProperty(uint32_t aIndex, nsAString& aReturn) const |
|
1360 { |
|
1361 aReturn.Truncate(); |
|
1362 if (aIndex < mOrder.Length()) { |
|
1363 nsCSSProperty property = GetPropertyAt(aIndex); |
|
1364 if (property == eCSSPropertyExtra_variable) { |
|
1365 GetCustomPropertyNameAt(aIndex, aReturn); |
|
1366 return true; |
|
1367 } |
|
1368 if (0 <= property) { |
|
1369 AppendASCIItoUTF16(nsCSSProps::GetStringValue(property), aReturn); |
|
1370 return true; |
|
1371 } |
|
1372 } |
|
1373 return false; |
|
1374 } |
|
1375 |
|
1376 void |
|
1377 Declaration::InitializeEmpty() |
|
1378 { |
|
1379 NS_ABORT_IF_FALSE(!mData && !mImportantData, "already initialized"); |
|
1380 mData = nsCSSCompressedDataBlock::CreateEmptyBlock(); |
|
1381 } |
|
1382 |
|
1383 Declaration* |
|
1384 Declaration::EnsureMutable() |
|
1385 { |
|
1386 NS_ABORT_IF_FALSE(mData, "should only be called when not expanded"); |
|
1387 if (!IsMutable()) { |
|
1388 return new Declaration(*this); |
|
1389 } else { |
|
1390 return this; |
|
1391 } |
|
1392 } |
|
1393 |
|
1394 size_t |
|
1395 Declaration::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const |
|
1396 { |
|
1397 size_t n = aMallocSizeOf(this); |
|
1398 n += mOrder.SizeOfExcludingThis(aMallocSizeOf); |
|
1399 n += mData ? mData ->SizeOfIncludingThis(aMallocSizeOf) : 0; |
|
1400 n += mImportantData ? mImportantData->SizeOfIncludingThis(aMallocSizeOf) : 0; |
|
1401 if (mVariables) { |
|
1402 n += mVariables->SizeOfIncludingThis(aMallocSizeOf); |
|
1403 } |
|
1404 if (mImportantVariables) { |
|
1405 n += mImportantVariables->SizeOfIncludingThis(aMallocSizeOf); |
|
1406 } |
|
1407 return n; |
|
1408 } |
|
1409 |
|
1410 bool |
|
1411 Declaration::HasVariableDeclaration(const nsAString& aName) const |
|
1412 { |
|
1413 return (mVariables && mVariables->Has(aName)) || |
|
1414 (mImportantVariables && mImportantVariables->Has(aName)); |
|
1415 } |
|
1416 |
|
1417 void |
|
1418 Declaration::GetVariableDeclaration(const nsAString& aName, |
|
1419 nsAString& aValue) const |
|
1420 { |
|
1421 aValue.Truncate(); |
|
1422 |
|
1423 CSSVariableDeclarations::Type type; |
|
1424 nsString value; |
|
1425 |
|
1426 if ((mImportantVariables && mImportantVariables->Get(aName, type, value)) || |
|
1427 (mVariables && mVariables->Get(aName, type, value))) { |
|
1428 switch (type) { |
|
1429 case CSSVariableDeclarations::eTokenStream: |
|
1430 aValue.Append(value); |
|
1431 break; |
|
1432 |
|
1433 case CSSVariableDeclarations::eInitial: |
|
1434 aValue.AppendLiteral("initial"); |
|
1435 break; |
|
1436 |
|
1437 case CSSVariableDeclarations::eInherit: |
|
1438 aValue.AppendLiteral("inherit"); |
|
1439 break; |
|
1440 |
|
1441 case CSSVariableDeclarations::eUnset: |
|
1442 aValue.AppendLiteral("unset"); |
|
1443 break; |
|
1444 |
|
1445 default: |
|
1446 MOZ_ASSERT(false, "unexpected variable value type"); |
|
1447 } |
|
1448 } |
|
1449 } |
|
1450 |
|
1451 void |
|
1452 Declaration::AddVariableDeclaration(const nsAString& aName, |
|
1453 CSSVariableDeclarations::Type aType, |
|
1454 const nsString& aValue, |
|
1455 bool aIsImportant, |
|
1456 bool aOverrideImportant) |
|
1457 { |
|
1458 MOZ_ASSERT(IsMutable()); |
|
1459 |
|
1460 nsTArray<nsString>::index_type index = mVariableOrder.IndexOf(aName); |
|
1461 if (index == nsTArray<nsString>::NoIndex) { |
|
1462 index = mVariableOrder.Length(); |
|
1463 mVariableOrder.AppendElement(aName); |
|
1464 } |
|
1465 |
|
1466 if (!aIsImportant && !aOverrideImportant && |
|
1467 mImportantVariables && mImportantVariables->Has(aName)) { |
|
1468 return; |
|
1469 } |
|
1470 |
|
1471 CSSVariableDeclarations* variables; |
|
1472 if (aIsImportant) { |
|
1473 if (mVariables) { |
|
1474 mVariables->Remove(aName); |
|
1475 } |
|
1476 if (!mImportantVariables) { |
|
1477 mImportantVariables = new CSSVariableDeclarations; |
|
1478 } |
|
1479 variables = mImportantVariables; |
|
1480 } else { |
|
1481 if (mImportantVariables) { |
|
1482 mImportantVariables->Remove(aName); |
|
1483 } |
|
1484 if (!mVariables) { |
|
1485 mVariables = new CSSVariableDeclarations; |
|
1486 } |
|
1487 variables = mVariables; |
|
1488 } |
|
1489 |
|
1490 switch (aType) { |
|
1491 case CSSVariableDeclarations::eTokenStream: |
|
1492 variables->PutTokenStream(aName, aValue); |
|
1493 break; |
|
1494 |
|
1495 case CSSVariableDeclarations::eInitial: |
|
1496 MOZ_ASSERT(aValue.IsEmpty()); |
|
1497 variables->PutInitial(aName); |
|
1498 break; |
|
1499 |
|
1500 case CSSVariableDeclarations::eInherit: |
|
1501 MOZ_ASSERT(aValue.IsEmpty()); |
|
1502 variables->PutInherit(aName); |
|
1503 break; |
|
1504 |
|
1505 case CSSVariableDeclarations::eUnset: |
|
1506 MOZ_ASSERT(aValue.IsEmpty()); |
|
1507 variables->PutUnset(aName); |
|
1508 break; |
|
1509 |
|
1510 default: |
|
1511 MOZ_ASSERT(false, "unexpected aType value"); |
|
1512 } |
|
1513 |
|
1514 uint32_t propertyIndex = index + eCSSProperty_COUNT; |
|
1515 mOrder.RemoveElement(propertyIndex); |
|
1516 mOrder.AppendElement(propertyIndex); |
|
1517 } |
|
1518 |
|
1519 void |
|
1520 Declaration::RemoveVariableDeclaration(const nsAString& aName) |
|
1521 { |
|
1522 if (mVariables) { |
|
1523 mVariables->Remove(aName); |
|
1524 } |
|
1525 if (mImportantVariables) { |
|
1526 mImportantVariables->Remove(aName); |
|
1527 } |
|
1528 nsTArray<nsString>::index_type index = mVariableOrder.IndexOf(aName); |
|
1529 if (index != nsTArray<nsString>::NoIndex) { |
|
1530 mOrder.RemoveElement(index + eCSSProperty_COUNT); |
|
1531 } |
|
1532 } |
|
1533 |
|
1534 bool |
|
1535 Declaration::GetVariableValueIsImportant(const nsAString& aName) const |
|
1536 { |
|
1537 return mImportantVariables && mImportantVariables->Has(aName); |
|
1538 } |
|
1539 |
|
1540 } // namespace mozilla::css |
|
1541 } // namespace mozilla |