Use "= default" to denote default constructor or destructor
[WebKit-https.git] / Source / WebCore / css / StyleProperties.cpp
1 /*
2  * (C) 1999-2003 Lars Knoll (knoll@kde.org)
3  * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012, 2013 Apple Inc. All rights reserved.
4  * Copyright (C) 2011 Research In Motion Limited. All rights reserved.
5  * Copyright (C) 2013 Intel Corporation. All rights reserved.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public License
18  * along with this library; see the file COPYING.LIB.  If not, write to
19  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  */
22
23 #include "config.h"
24 #include "StyleProperties.h"
25
26 #include "CSSComputedStyleDeclaration.h"
27 #include "CSSCustomPropertyValue.h"
28 #include "CSSDeferredParser.h"
29 #include "CSSParser.h"
30 #include "CSSPendingSubstitutionValue.h"
31 #include "CSSValueKeywords.h"
32 #include "CSSValueList.h"
33 #include "CSSValuePool.h"
34 #include "Color.h"
35 #include "Document.h"
36 #include "PropertySetCSSStyleDeclaration.h"
37 #include "StylePropertyShorthand.h"
38 #include "StylePropertyShorthandFunctions.h"
39 #include "StyleSheetContents.h"
40 #include <bitset>
41 #include <wtf/text/StringBuilder.h>
42
43 #ifndef NDEBUG
44 #include <stdio.h>
45 #include <wtf/text/CString.h>
46 #endif
47
48 namespace WebCore {
49
50 static size_t sizeForImmutableStylePropertiesWithPropertyCount(unsigned count)
51 {
52     return sizeof(ImmutableStyleProperties) - sizeof(void*) + sizeof(CSSValue*) * count + sizeof(StylePropertyMetadata) * count;
53 }
54
55 static bool isInitialOrInherit(const String& value)
56 {
57     return value.length() == 7 && (value == "initial" || value == "inherit");
58 }
59
60 Ref<ImmutableStyleProperties> ImmutableStyleProperties::create(const CSSProperty* properties, unsigned count, CSSParserMode cssParserMode)
61 {
62     void* slot = WTF::fastMalloc(sizeForImmutableStylePropertiesWithPropertyCount(count));
63     return adoptRef(*new (NotNull, slot) ImmutableStyleProperties(properties, count, cssParserMode));
64 }
65
66 Ref<ImmutableStyleProperties> StyleProperties::immutableCopyIfNeeded() const
67 {
68     if (is<ImmutableStyleProperties>(*this))
69         return downcast<ImmutableStyleProperties>(const_cast<StyleProperties&>(*this));
70     const MutableStyleProperties& mutableThis = downcast<MutableStyleProperties>(*this);
71     return ImmutableStyleProperties::create(mutableThis.m_propertyVector.data(), mutableThis.m_propertyVector.size(), cssParserMode());
72 }
73
74 MutableStyleProperties::MutableStyleProperties(CSSParserMode cssParserMode)
75     : StyleProperties(cssParserMode, MutablePropertiesType)
76 {
77 }
78
79 MutableStyleProperties::MutableStyleProperties(const CSSProperty* properties, unsigned length)
80     : StyleProperties(HTMLStandardMode, MutablePropertiesType)
81 {
82     m_propertyVector.reserveInitialCapacity(length);
83     for (unsigned i = 0; i < length; ++i)
84         m_propertyVector.uncheckedAppend(properties[i]);
85 }
86
87 MutableStyleProperties::~MutableStyleProperties() = default;
88
89 ImmutableStyleProperties::ImmutableStyleProperties(const CSSProperty* properties, unsigned length, CSSParserMode cssParserMode)
90     : StyleProperties(cssParserMode, length)
91 {
92     StylePropertyMetadata* metadataArray = const_cast<StylePropertyMetadata*>(this->metadataArray());
93     CSSValue** valueArray = const_cast<CSSValue**>(this->valueArray());
94     for (unsigned i = 0; i < length; ++i) {
95         metadataArray[i] = properties[i].metadata();
96         valueArray[i] = properties[i].value();
97         valueArray[i]->ref();
98     }
99 }
100
101 ImmutableStyleProperties::~ImmutableStyleProperties()
102 {
103     CSSValue** valueArray = const_cast<CSSValue**>(this->valueArray());
104     for (unsigned i = 0; i < m_arraySize; ++i)
105         valueArray[i]->deref();
106 }
107
108 MutableStyleProperties::MutableStyleProperties(const StyleProperties& other)
109     : StyleProperties(other.cssParserMode(), MutablePropertiesType)
110 {
111     ASSERT(other.type() != DeferredPropertiesType);
112     if (is<MutableStyleProperties>(other))
113         m_propertyVector = downcast<MutableStyleProperties>(other).m_propertyVector;
114     else {
115         const auto& immutableOther = downcast<ImmutableStyleProperties>(other);
116         unsigned propertyCount = immutableOther.propertyCount();
117         m_propertyVector.reserveInitialCapacity(propertyCount);
118         for (unsigned i = 0; i < propertyCount; ++i)
119             m_propertyVector.uncheckedAppend(immutableOther.propertyAt(i).toCSSProperty());
120     }
121 }
122
123 String StyleProperties::getPropertyValue(CSSPropertyID propertyID) const
124 {
125     RefPtr<CSSValue> value = getPropertyCSSValue(propertyID);
126     if (value)
127         return value->cssText();
128
129     const StylePropertyShorthand& shorthand = shorthandForProperty(propertyID);
130     if (shorthand.length()) {
131         RefPtr<CSSValue> value = getPropertyCSSValueInternal(shorthand.properties()[0]);
132         if (!value || value->isPendingSubstitutionValue())
133             return String();
134     }
135
136     // Shorthand and 4-values properties
137     switch (propertyID) {
138     case CSSPropertyAll:
139         return getCommonValue(allShorthand());
140     case CSSPropertyAnimation:
141         return getLayeredShorthandValue(animationShorthand());
142     case CSSPropertyBorderSpacing:
143         return borderSpacingValue(borderSpacingShorthand());
144     case CSSPropertyBackgroundPosition:
145         return getLayeredShorthandValue(backgroundPositionShorthand());
146     case CSSPropertyBackgroundRepeat:
147         return getLayeredShorthandValue(backgroundRepeatShorthand());
148     case CSSPropertyBackground:
149         return getLayeredShorthandValue(backgroundShorthand());
150     case CSSPropertyBorder:
151         return borderPropertyValue(OmitUncommonValues);
152     case CSSPropertyBorderTop:
153         return getShorthandValue(borderTopShorthand());
154     case CSSPropertyBorderRight:
155         return getShorthandValue(borderRightShorthand());
156     case CSSPropertyBorderBottom:
157         return getShorthandValue(borderBottomShorthand());
158     case CSSPropertyBorderLeft:
159         return getShorthandValue(borderLeftShorthand());
160     case CSSPropertyOutline:
161         return getShorthandValue(outlineShorthand());
162     case CSSPropertyBorderColor:
163         return get4Values(borderColorShorthand());
164     case CSSPropertyBorderWidth:
165         return get4Values(borderWidthShorthand());
166     case CSSPropertyBorderStyle:
167         return get4Values(borderStyleShorthand());
168     case CSSPropertyColumnRule:
169         return getShorthandValue(columnRuleShorthand());
170     case CSSPropertyColumns:
171         return getShorthandValue(columnsShorthand());
172     case CSSPropertyFlex:
173         return getShorthandValue(flexShorthand());
174     case CSSPropertyFlexFlow:
175         return getShorthandValue(flexFlowShorthand());
176     case CSSPropertyGridArea:
177         return getShorthandValue(gridAreaShorthand());
178     case CSSPropertyGridTemplate:
179         return getShorthandValue(gridTemplateShorthand());
180     case CSSPropertyGrid:
181         return getShorthandValue(gridShorthand());
182     case CSSPropertyGridColumn:
183         return getShorthandValue(gridColumnShorthand());
184     case CSSPropertyGridRow:
185         return getShorthandValue(gridRowShorthand());
186     case CSSPropertyPlaceContent:
187         return getAlignmentShorthandValue(placeContentShorthand());
188     case CSSPropertyPlaceItems:
189         return getAlignmentShorthandValue(placeItemsShorthand());
190     case CSSPropertyPlaceSelf:
191         return getAlignmentShorthandValue(placeSelfShorthand());
192     case CSSPropertyFont:
193         return fontValue();
194     case CSSPropertyMargin:
195         return get4Values(marginShorthand());
196     case CSSPropertyWebkitMarginCollapse:
197         return getShorthandValue(webkitMarginCollapseShorthand());
198     case CSSPropertyOverflow:
199         return getCommonValue(overflowShorthand());
200     case CSSPropertyPadding:
201         return get4Values(paddingShorthand());
202     case CSSPropertyTransition:
203         return getLayeredShorthandValue(transitionShorthand());
204     case CSSPropertyListStyle:
205         return getShorthandValue(listStyleShorthand());
206     case CSSPropertyWebkitMarquee:
207         return getShorthandValue(webkitMarqueeShorthand());
208     case CSSPropertyWebkitMaskPosition:
209         return getLayeredShorthandValue(webkitMaskPositionShorthand());
210     case CSSPropertyWebkitMaskRepeat:
211         return getLayeredShorthandValue(webkitMaskRepeatShorthand());
212     case CSSPropertyWebkitMask:
213         return getLayeredShorthandValue(webkitMaskShorthand());
214     case CSSPropertyWebkitTextEmphasis:
215         return getShorthandValue(webkitTextEmphasisShorthand());
216     case CSSPropertyWebkitTextStroke:
217         return getShorthandValue(webkitTextStrokeShorthand());
218     case CSSPropertyPerspectiveOrigin:
219         return getShorthandValue(perspectiveOriginShorthand());
220     case CSSPropertyTransformOrigin:
221         return getShorthandValue(transformOriginShorthand());
222     case CSSPropertyMarker: {
223         RefPtr<CSSValue> value = getPropertyCSSValueInternal(CSSPropertyMarkerStart);
224         if (value)
225             return value->cssText();
226         return String();
227     }
228     case CSSPropertyBorderRadius:
229         return get4Values(borderRadiusShorthand());
230 #if ENABLE(CSS_SCROLL_SNAP)
231     case CSSPropertyScrollSnapMargin:
232         return get4Values(scrollSnapMarginShorthand());
233     case CSSPropertyScrollPadding:
234         return get4Values(scrollPaddingShorthand());
235 #endif
236     default:
237         return String();
238     }
239 }
240
241 std::optional<Color> StyleProperties::propertyAsColor(CSSPropertyID property) const
242 {
243     auto colorValue = getPropertyCSSValue(property);
244     if (!is<CSSPrimitiveValue>(colorValue.get()))
245         return std::nullopt;
246
247     auto& primitiveColor = downcast<CSSPrimitiveValue>(*colorValue);
248     return primitiveColor.isRGBColor() ? primitiveColor.color() : CSSParser::parseColor(colorValue->cssText());
249 }
250
251 CSSValueID StyleProperties::propertyAsValueID(CSSPropertyID property) const
252 {
253     auto cssValue = getPropertyCSSValue(property);
254     return is<CSSPrimitiveValue>(cssValue.get()) ? downcast<CSSPrimitiveValue>(*cssValue).valueID() : CSSValueInvalid;
255 }
256
257 String StyleProperties::getCustomPropertyValue(const String& propertyName) const
258 {
259     RefPtr<CSSValue> value = getCustomPropertyCSSValue(propertyName);
260     if (value)
261         return value->cssText();
262     return String();
263 }
264
265 String StyleProperties::borderSpacingValue(const StylePropertyShorthand& shorthand) const
266 {
267     RefPtr<CSSValue> horizontalValue = getPropertyCSSValueInternal(shorthand.properties()[0]);
268     RefPtr<CSSValue> verticalValue = getPropertyCSSValueInternal(shorthand.properties()[1]);
269
270     // While standard border-spacing property does not allow specifying border-spacing-vertical without
271     // specifying border-spacing-horizontal <http://www.w3.org/TR/CSS21/tables.html#separated-borders>,
272     // -webkit-border-spacing-vertical can be set without -webkit-border-spacing-horizontal.
273     if (!horizontalValue || !verticalValue)
274         return String();
275
276     String horizontalValueCSSText = horizontalValue->cssText();
277     String verticalValueCSSText = verticalValue->cssText();
278     if (horizontalValueCSSText == verticalValueCSSText)
279         return horizontalValueCSSText;
280     return horizontalValueCSSText + ' ' + verticalValueCSSText;
281 }
282
283 void StyleProperties::appendFontLonghandValueIfExplicit(CSSPropertyID propertyID, StringBuilder& result, String& commonValue) const
284 {
285     int foundPropertyIndex = findPropertyIndex(propertyID);
286     if (foundPropertyIndex == -1)
287         return; // All longhands must have at least implicit values if "font" is specified.
288
289     if (propertyAt(foundPropertyIndex).isImplicit()) {
290         commonValue = String();
291         return;
292     }
293
294     char prefix = '\0';
295     switch (propertyID) {
296     case CSSPropertyFontStyle:
297         break; // No prefix.
298     case CSSPropertyFontFamily:
299     case CSSPropertyFontVariantCaps:
300     case CSSPropertyFontWeight:
301     case CSSPropertyFontStretch:
302         prefix = ' ';
303         break;
304     case CSSPropertyLineHeight:
305         prefix = '/';
306         break;
307     default:
308         ASSERT_NOT_REACHED();
309     }
310
311     if (prefix && !result.isEmpty())
312         result.append(prefix);
313     String value = propertyAt(foundPropertyIndex).value()->cssText();
314     result.append(value);
315     if (!commonValue.isNull() && commonValue != value)
316         commonValue = String();
317 }
318
319 String StyleProperties::fontValue() const
320 {
321     int fontSizePropertyIndex = findPropertyIndex(CSSPropertyFontSize);
322     int fontFamilyPropertyIndex = findPropertyIndex(CSSPropertyFontFamily);
323     if (fontSizePropertyIndex == -1 || fontFamilyPropertyIndex == -1)
324         return emptyString();
325
326     PropertyReference fontSizeProperty = propertyAt(fontSizePropertyIndex);
327     PropertyReference fontFamilyProperty = propertyAt(fontFamilyPropertyIndex);
328     if (fontSizeProperty.isImplicit() || fontFamilyProperty.isImplicit())
329         return emptyString();
330
331     String commonValue = fontSizeProperty.value()->cssText();
332     StringBuilder result;
333     appendFontLonghandValueIfExplicit(CSSPropertyFontStyle, result, commonValue);
334     appendFontLonghandValueIfExplicit(CSSPropertyFontVariantCaps, result, commonValue);
335     appendFontLonghandValueIfExplicit(CSSPropertyFontWeight, result, commonValue);
336     appendFontLonghandValueIfExplicit(CSSPropertyFontStretch, result, commonValue);
337     if (!result.isEmpty())
338         result.append(' ');
339     result.append(fontSizeProperty.value()->cssText());
340     appendFontLonghandValueIfExplicit(CSSPropertyLineHeight, result, commonValue);
341     if (!result.isEmpty())
342         result.append(' ');
343     result.append(fontFamilyProperty.value()->cssText());
344     if (isInitialOrInherit(commonValue))
345         return commonValue;
346     return result.toString();
347 }
348
349 String StyleProperties::get4Values(const StylePropertyShorthand& shorthand) const
350 {
351     // Assume the properties are in the usual order top, right, bottom, left.
352     int topValueIndex = findPropertyIndex(shorthand.properties()[0]);
353     int rightValueIndex = findPropertyIndex(shorthand.properties()[1]);
354     int bottomValueIndex = findPropertyIndex(shorthand.properties()[2]);
355     int leftValueIndex = findPropertyIndex(shorthand.properties()[3]);
356
357     if (topValueIndex == -1 || rightValueIndex == -1 || bottomValueIndex == -1 || leftValueIndex == -1)
358         return String();
359
360     PropertyReference top = propertyAt(topValueIndex);
361     PropertyReference right = propertyAt(rightValueIndex);
362     PropertyReference bottom = propertyAt(bottomValueIndex);
363     PropertyReference left = propertyAt(leftValueIndex);
364
365     // All 4 properties must be specified.
366     if (!top.value() || !right.value() || !bottom.value() || !left.value())
367         return String();
368
369     if (top.isInherited() && right.isInherited() && bottom.isInherited() && left.isInherited())
370         return getValueName(CSSValueInherit);
371
372     if (top.value()->isInitialValue() || right.value()->isInitialValue() || bottom.value()->isInitialValue() || left.value()->isInitialValue()) {
373         if (top.value()->isInitialValue() && right.value()->isInitialValue() && bottom.value()->isInitialValue() && left.value()->isInitialValue() && !top.isImplicit()) {
374             // All components are "initial" and "top" is not implicit.
375             return getValueName(CSSValueInitial);
376         }
377         return String();
378     }
379     if (top.isImportant() != right.isImportant() || right.isImportant() != bottom.isImportant() || bottom.isImportant() != left.isImportant())
380         return String();
381
382     bool showLeft = !right.value()->equals(*left.value());
383     bool showBottom = !top.value()->equals(*bottom.value()) || showLeft;
384     bool showRight = !top.value()->equals(*right.value()) || showBottom;
385
386     StringBuilder result;
387     result.append(top.value()->cssText());
388     if (showRight) {
389         result.append(' ');
390         result.append(right.value()->cssText());
391     }
392     if (showBottom) {
393         result.append(' ');
394         result.append(bottom.value()->cssText());
395     }
396     if (showLeft) {
397         result.append(' ');
398         result.append(left.value()->cssText());
399     }
400     return result.toString();
401 }
402
403 String StyleProperties::getLayeredShorthandValue(const StylePropertyShorthand& shorthand) const
404 {
405     StringBuilder result;
406
407     const unsigned size = shorthand.length();
408     // Begin by collecting the properties into an array.
409     Vector< RefPtr<CSSValue>> values(size);
410     size_t numLayers = 0;
411
412     for (unsigned i = 0; i < size; ++i) {
413         values[i] = getPropertyCSSValueInternal(shorthand.properties()[i]);
414         if (!values[i]) {
415             // We don't have all longhand properties defined as required for the shorthand
416             // property and thus should not serialize to a shorthand value. See spec at
417             // http://www.w3.org/TR/cssom-1/#serialize-a-css-declaration-block.
418             return String();
419         }
420         if (values[i]->isBaseValueList())
421             numLayers = std::max(downcast<CSSValueList>(*values[i]).length(), numLayers);
422         else
423             numLayers = std::max<size_t>(1U, numLayers);
424     }
425
426     String commonValue;
427     bool commonValueInitialized = false;
428
429     // Now stitch the properties together. Implicit initial values are flagged as such and
430     // can safely be omitted.
431     for (size_t i = 0; i < numLayers; i++) {
432         StringBuilder layerResult;
433         bool useRepeatXShorthand = false;
434         bool useRepeatYShorthand = false;
435         bool useSingleWordShorthand = false;
436         bool foundPositionYCSSProperty = false;
437         for (unsigned j = 0; j < size; j++) {
438             RefPtr<CSSValue> value;
439             if (values[j]) {
440                 if (values[j]->isBaseValueList())
441                     value = downcast<CSSValueList>(*values[j]).item(i);
442                 else {
443                     value = values[j];
444
445                     // Color only belongs in the last layer.
446                     if (shorthand.properties()[j] == CSSPropertyBackgroundColor) {
447                         if (i != numLayers - 1)
448                             value = nullptr;
449                     } else if (i) // Other singletons only belong in the first layer.
450                         value = nullptr;
451                 }
452             }
453
454             // We need to report background-repeat as it was written in the CSS. If the property is implicit,
455             // then it was written with only one value. Here we figure out which value that was so we can
456             // report back correctly.
457             if ((shorthand.properties()[j] == CSSPropertyBackgroundRepeatX && isPropertyImplicit(shorthand.properties()[j]))
458                 || (shorthand.properties()[j] == CSSPropertyWebkitMaskRepeatX && isPropertyImplicit(shorthand.properties()[j]))) {
459
460                 // BUG 49055: make sure the value was not reset in the layer check just above.
461                 if ((j < size - 1 && shorthand.properties()[j + 1] == CSSPropertyBackgroundRepeatY && value)
462                     || (j < size - 1 && shorthand.properties()[j + 1] == CSSPropertyWebkitMaskRepeatY && value)) {
463                     RefPtr<CSSValue> yValue;
464                     RefPtr<CSSValue> nextValue = values[j + 1];
465                     if (nextValue) {
466                         if (is<CSSValueList>(*nextValue))
467                             yValue = downcast<CSSValueList>(*nextValue).itemWithoutBoundsCheck(i);
468                         else
469                             yValue = nextValue;
470
471                         if (!is<CSSPrimitiveValue>(*value) || !is<CSSPrimitiveValue>(*yValue))
472                             continue;
473
474                         CSSValueID xId = downcast<CSSPrimitiveValue>(*value).valueID();
475                         CSSValueID yId = downcast<CSSPrimitiveValue>(*yValue).valueID();
476                         if (xId != yId) {
477                             if (xId == CSSValueRepeat && yId == CSSValueNoRepeat) {
478                                 useRepeatXShorthand = true;
479                                 ++j;
480                             } else if (xId == CSSValueNoRepeat && yId == CSSValueRepeat) {
481                                 useRepeatYShorthand = true;
482                                 continue;
483                             }
484                         } else {
485                             useSingleWordShorthand = true;
486                             ++j;
487                         }
488                     }
489                 }
490             }
491
492             String valueText;
493             if (value && !value->isImplicitInitialValue()) {
494                 if (!layerResult.isEmpty())
495                     layerResult.append(' ');
496                 if (foundPositionYCSSProperty
497                     && (shorthand.properties()[j] == CSSPropertyBackgroundSize || shorthand.properties()[j] == CSSPropertyWebkitMaskSize))
498                     layerResult.appendLiteral("/ ");
499                 if (!foundPositionYCSSProperty
500                     && (shorthand.properties()[j] == CSSPropertyBackgroundSize || shorthand.properties()[j] == CSSPropertyWebkitMaskSize))
501                     continue;
502
503                 if (useRepeatXShorthand) {
504                     useRepeatXShorthand = false;
505                     layerResult.append(getValueName(CSSValueRepeatX));
506                 } else if (useRepeatYShorthand) {
507                     useRepeatYShorthand = false;
508                     layerResult.append(getValueName(CSSValueRepeatY));
509                 } else {
510                     if (useSingleWordShorthand)
511                         useSingleWordShorthand = false;
512                     valueText = value->cssText();
513                     layerResult.append(valueText);
514                 }
515
516                 if (shorthand.properties()[j] == CSSPropertyBackgroundPositionY
517                     || shorthand.properties()[j] == CSSPropertyWebkitMaskPositionY) {
518                     foundPositionYCSSProperty = true;
519
520                     // background-position is a special case: if only the first offset is specified,
521                     // the second one defaults to "center", not the same value.
522                     if (commonValueInitialized && commonValue != "initial" && commonValue != "inherit")
523                         commonValue = String();
524                 }
525             }
526
527             if (!commonValueInitialized) {
528                 commonValue = valueText;
529                 commonValueInitialized = true;
530             } else if (!commonValue.isNull() && commonValue != valueText)
531                 commonValue = String();
532         }
533
534         if (!layerResult.isEmpty()) {
535             if (!result.isEmpty())
536                 result.appendLiteral(", ");
537             result.append(layerResult);
538         }
539     }
540
541     if (isInitialOrInherit(commonValue))
542         return commonValue;
543
544     if (result.isEmpty())
545         return String();
546     return result.toString();
547 }
548
549 String StyleProperties::getShorthandValue(const StylePropertyShorthand& shorthand) const
550 {
551     String commonValue;
552     StringBuilder result;
553     for (unsigned i = 0; i < shorthand.length(); ++i) {
554         if (!isPropertyImplicit(shorthand.properties()[i])) {
555             RefPtr<CSSValue> value = getPropertyCSSValueInternal(shorthand.properties()[i]);
556             if (!value)
557                 return String();
558             String valueText = value->cssText();
559             if (!i)
560                 commonValue = valueText;
561             else if (!commonValue.isNull() && commonValue != valueText)
562                 commonValue = String();
563             if (value->isInitialValue())
564                 continue;
565             if (!result.isEmpty())
566                 result.append(' ');
567             result.append(valueText);
568         } else
569             commonValue = String();
570     }
571     if (isInitialOrInherit(commonValue))
572         return commonValue;
573     if (result.isEmpty())
574         return String();
575     return result.toString();
576 }
577
578 // only returns a non-null value if all properties have the same, non-null value
579 String StyleProperties::getCommonValue(const StylePropertyShorthand& shorthand) const
580 {
581     String res;
582     bool lastPropertyWasImportant = false;
583     for (unsigned i = 0; i < shorthand.length(); ++i) {
584         RefPtr<CSSValue> value = getPropertyCSSValueInternal(shorthand.properties()[i]);
585         if (!value)
586             return String();
587         // FIXME: CSSInitialValue::cssText should generate the right value.
588         String text = value->cssText();
589         if (text.isNull())
590             return String();
591         if (res.isNull())
592             res = text;
593         else if (res != text)
594             return String();
595
596         bool currentPropertyIsImportant = propertyIsImportant(shorthand.properties()[i]);
597         if (i && lastPropertyWasImportant != currentPropertyIsImportant)
598             return String();
599         lastPropertyWasImportant = currentPropertyIsImportant;
600     }
601     return res;
602 }
603
604 String StyleProperties::getAlignmentShorthandValue(const StylePropertyShorthand& shorthand) const
605 {
606     String value = getCommonValue(shorthand);
607     if (value.isNull() || value.isEmpty())
608         return getShorthandValue(shorthand);
609     return value;
610 }
611
612 String StyleProperties::borderPropertyValue(CommonValueMode valueMode) const
613 {
614     const StylePropertyShorthand properties[3] = { borderWidthShorthand(), borderStyleShorthand(), borderColorShorthand() };
615     String commonValue;
616     StringBuilder result;
617     for (size_t i = 0; i < WTF_ARRAY_LENGTH(properties); ++i) {
618         String value = getCommonValue(properties[i]);
619         if (value.isNull()) {
620             if (valueMode == ReturnNullOnUncommonValues)
621                 return String();
622             ASSERT(valueMode == OmitUncommonValues);
623             continue;
624         }
625         if (!i)
626             commonValue = value;
627         else if (!commonValue.isNull() && commonValue != value)
628             commonValue = String();
629         if (value == "initial")
630             continue;
631         if (!result.isEmpty())
632             result.append(' ');
633         result.append(value);
634     }
635     if (isInitialOrInherit(commonValue))
636         return commonValue;
637     return result.isEmpty() ? String() : result.toString();
638 }
639
640 RefPtr<CSSValue> StyleProperties::getPropertyCSSValue(CSSPropertyID propertyID) const
641 {
642     return getPropertyCSSValueInternal(propertyID);
643 }
644
645 RefPtr<CSSValue> StyleProperties::getPropertyCSSValueInternal(CSSPropertyID propertyID) const
646 {
647     int foundPropertyIndex = findPropertyIndex(propertyID);
648     if (foundPropertyIndex == -1)
649         return nullptr;
650     return propertyAt(foundPropertyIndex).value();
651 }
652
653 RefPtr<CSSValue> StyleProperties::getCustomPropertyCSSValue(const String& propertyName) const
654 {
655     int foundPropertyIndex = findCustomPropertyIndex(propertyName);
656     if (foundPropertyIndex == -1)
657         return nullptr;
658     return propertyAt(foundPropertyIndex).value();
659 }
660
661 bool MutableStyleProperties::removeShorthandProperty(CSSPropertyID propertyID)
662 {
663     StylePropertyShorthand shorthand = shorthandForProperty(propertyID);
664     if (!shorthand.length())
665         return false;
666
667     return removePropertiesInSet(shorthand.properties(), shorthand.length());
668 }
669
670 bool MutableStyleProperties::removeProperty(CSSPropertyID propertyID, String* returnText)
671 {
672     if (removeShorthandProperty(propertyID)) {
673         // FIXME: Return an equivalent shorthand when possible.
674         if (returnText)
675             *returnText = emptyString();
676         return true;
677     }
678
679     int foundPropertyIndex = findPropertyIndex(propertyID);
680     if (foundPropertyIndex == -1) {
681         if (returnText)
682             *returnText = emptyString();
683         return false;
684     }
685
686     if (returnText)
687         *returnText = propertyAt(foundPropertyIndex).value()->cssText();
688
689     // A more efficient removal strategy would involve marking entries as empty
690     // and sweeping them when the vector grows too big.
691     m_propertyVector.remove(foundPropertyIndex);
692
693     return true;
694 }
695
696 bool MutableStyleProperties::removeCustomProperty(const String& propertyName, String* returnText)
697 {
698     int foundPropertyIndex = findCustomPropertyIndex(propertyName);
699     if (foundPropertyIndex == -1) {
700         if (returnText)
701             *returnText = emptyString();
702         return false;
703     }
704
705     if (returnText)
706         *returnText = propertyAt(foundPropertyIndex).value()->cssText();
707
708     // A more efficient removal strategy would involve marking entries as empty
709     // and sweeping them when the vector grows too big.
710     m_propertyVector.remove(foundPropertyIndex);
711
712     return true;
713 }
714
715 bool StyleProperties::propertyIsImportant(CSSPropertyID propertyID) const
716 {
717     int foundPropertyIndex = findPropertyIndex(propertyID);
718     if (foundPropertyIndex != -1)
719         return propertyAt(foundPropertyIndex).isImportant();
720
721     StylePropertyShorthand shorthand = shorthandForProperty(propertyID);
722     if (!shorthand.length())
723         return false;
724
725     for (unsigned i = 0; i < shorthand.length(); ++i) {
726         if (!propertyIsImportant(shorthand.properties()[i]))
727             return false;
728     }
729     return true;
730 }
731
732 bool StyleProperties::customPropertyIsImportant(const String& propertyName) const
733 {
734     int foundPropertyIndex = findCustomPropertyIndex(propertyName);
735     if (foundPropertyIndex != -1)
736         return propertyAt(foundPropertyIndex).isImportant();
737     return false;
738 }
739
740 String StyleProperties::getPropertyShorthand(CSSPropertyID propertyID) const
741 {
742     int foundPropertyIndex = findPropertyIndex(propertyID);
743     if (foundPropertyIndex == -1)
744         return String();
745     return getPropertyNameString(propertyAt(foundPropertyIndex).shorthandID());
746 }
747
748 bool StyleProperties::isPropertyImplicit(CSSPropertyID propertyID) const
749 {
750     int foundPropertyIndex = findPropertyIndex(propertyID);
751     if (foundPropertyIndex == -1)
752         return false;
753     return propertyAt(foundPropertyIndex).isImplicit();
754 }
755
756 bool MutableStyleProperties::setProperty(CSSPropertyID propertyID, const String& value, bool important, CSSParserContext parserContext)
757 {
758     // Setting the value to an empty string just removes the property in both IE and Gecko.
759     // Setting it to null seems to produce less consistent results, but we treat it just the same.
760     if (value.isEmpty())
761         return removeProperty(propertyID);
762
763     parserContext.mode = cssParserMode();
764
765     // When replacing an existing property value, this moves the property to the end of the list.
766     // Firefox preserves the position, and MSIE moves the property to the beginning.
767     return CSSParser::parseValue(*this, propertyID, value, important, parserContext) == CSSParser::ParseResult::Changed;
768 }
769
770 bool MutableStyleProperties::setProperty(CSSPropertyID propertyID, const String& value, bool important)
771 {
772     CSSParserContext parserContext(cssParserMode());
773     return setProperty(propertyID, value, important, parserContext);
774 }
775
776 bool MutableStyleProperties::setCustomProperty(const String& propertyName, const String& value, bool important, CSSParserContext parserContext)
777 {
778     // Setting the value to an empty string just removes the property in both IE and Gecko.
779     // Setting it to null seems to produce less consistent results, but we treat it just the same.
780     if (value.isEmpty())
781         return removeCustomProperty(propertyName);
782
783     parserContext.mode = cssParserMode();
784     // When replacing an existing property value, this moves the property to the end of the list.
785     // Firefox preserves the position, and MSIE moves the property to the beginning.
786     return CSSParser::parseCustomPropertyValue(*this, propertyName, value, important, parserContext) == CSSParser::ParseResult::Changed;
787 }
788
789 void MutableStyleProperties::setProperty(CSSPropertyID propertyID, RefPtr<CSSValue>&& value, bool important)
790 {
791     StylePropertyShorthand shorthand = shorthandForProperty(propertyID);
792     if (!shorthand.length()) {
793         setProperty(CSSProperty(propertyID, WTFMove(value), important));
794         return;
795     }
796
797     removePropertiesInSet(shorthand.properties(), shorthand.length());
798
799     for (unsigned i = 0; i < shorthand.length(); ++i)
800         m_propertyVector.append(CSSProperty(shorthand.properties()[i], value.copyRef(), important));
801 }
802
803 bool MutableStyleProperties::setProperty(const CSSProperty& property, CSSProperty* slot)
804 {
805     if (!removeShorthandProperty(property.id())) {
806         CSSProperty* toReplace = slot;
807         if (!slot) {
808             if (property.id() == CSSPropertyCustom) {
809                 if (property.value())
810                     toReplace = findCustomCSSPropertyWithName(downcast<CSSCustomPropertyValue>(*property.value()).name());
811             } else
812                 toReplace = findCSSPropertyWithID(property.id());
813         }
814         
815         if (toReplace) {
816             if (*toReplace == property)
817                 return false;
818
819             *toReplace = property;
820             return true;
821         }
822     }
823
824     m_propertyVector.append(property);
825     return true;
826 }
827
828 bool MutableStyleProperties::setProperty(CSSPropertyID propertyID, CSSValueID identifier, bool important)
829 {
830     return setProperty(CSSProperty(propertyID, CSSValuePool::singleton().createIdentifierValue(identifier), important));
831 }
832
833 bool MutableStyleProperties::setProperty(CSSPropertyID propertyID, CSSPropertyID identifier, bool important)
834 {
835     return setProperty(CSSProperty(propertyID, CSSValuePool::singleton().createIdentifierValue(identifier), important));
836 }
837
838 bool MutableStyleProperties::parseDeclaration(const String& styleDeclaration, CSSParserContext context)
839 {
840     auto oldProperties = WTFMove(m_propertyVector);
841     m_propertyVector.clear();
842
843     context.mode = cssParserMode();
844
845     CSSParser parser(context);
846     parser.parseDeclaration(*this, styleDeclaration);
847
848     // We could do better. Just changing property order does not require style invalidation.
849     return oldProperties != m_propertyVector;
850 }
851
852 bool MutableStyleProperties::addParsedProperties(const ParsedPropertyVector& properties)
853 {
854     bool anyChanged = false;
855     m_propertyVector.reserveCapacity(m_propertyVector.size() + properties.size());
856     for (const auto& property : properties) {
857         if (addParsedProperty(property))
858             anyChanged = true;
859     }
860
861     return anyChanged;
862 }
863
864 bool MutableStyleProperties::addParsedProperty(const CSSProperty& property)
865 {
866     if (property.id() == CSSPropertyCustom) {
867         if ((property.value() && !customPropertyIsImportant(downcast<CSSCustomPropertyValue>(*property.value()).name())) || property.isImportant())
868             return setProperty(property);
869         return false;
870     }
871     return setProperty(property);
872 }
873
874 String StyleProperties::asText() const
875 {
876     StringBuilder result;
877
878     int positionXPropertyIndex = -1;
879     int positionYPropertyIndex = -1;
880     int repeatXPropertyIndex = -1;
881     int repeatYPropertyIndex = -1;
882
883     std::bitset<numCSSProperties> shorthandPropertyUsed;
884     std::bitset<numCSSProperties> shorthandPropertyAppeared;
885
886     unsigned size = propertyCount();
887     unsigned numDecls = 0;
888     for (unsigned n = 0; n < size; ++n) {
889         PropertyReference property = propertyAt(n);
890         CSSPropertyID propertyID = property.id();
891         CSSPropertyID shorthandPropertyID = CSSPropertyInvalid;
892         CSSPropertyID borderFallbackShorthandProperty = CSSPropertyInvalid;
893         String value;
894         
895         if (property.value() && property.value()->isPendingSubstitutionValue()) {
896             auto& substitutionValue = downcast<CSSPendingSubstitutionValue>(*property.value());
897             shorthandPropertyID = substitutionValue.shorthandPropertyId();
898             value = substitutionValue.shorthandValue()->cssText();
899         } else {
900             switch (propertyID) {
901             case CSSPropertyAnimationName:
902             case CSSPropertyAnimationDuration:
903             case CSSPropertyAnimationTimingFunction:
904             case CSSPropertyAnimationDelay:
905             case CSSPropertyAnimationIterationCount:
906             case CSSPropertyAnimationDirection:
907             case CSSPropertyAnimationFillMode:
908             case CSSPropertyAnimationPlayState:
909                 shorthandPropertyID = CSSPropertyAnimation;
910                 break;
911             case CSSPropertyBackgroundPositionX:
912                 positionXPropertyIndex = n;
913                 continue;
914             case CSSPropertyBackgroundPositionY:
915                 positionYPropertyIndex = n;
916                 continue;
917             case CSSPropertyBackgroundRepeatX:
918                 repeatXPropertyIndex = n;
919                 continue;
920             case CSSPropertyBackgroundRepeatY:
921                 repeatYPropertyIndex = n;
922                 continue;
923             case CSSPropertyBorderTopWidth:
924             case CSSPropertyBorderRightWidth:
925             case CSSPropertyBorderBottomWidth:
926             case CSSPropertyBorderLeftWidth:
927                 if (!borderFallbackShorthandProperty)
928                     borderFallbackShorthandProperty = CSSPropertyBorderWidth;
929                 FALLTHROUGH;
930             case CSSPropertyBorderTopStyle:
931             case CSSPropertyBorderRightStyle:
932             case CSSPropertyBorderBottomStyle:
933             case CSSPropertyBorderLeftStyle:
934                 if (!borderFallbackShorthandProperty)
935                     borderFallbackShorthandProperty = CSSPropertyBorderStyle;
936                 FALLTHROUGH;
937             case CSSPropertyBorderTopColor:
938             case CSSPropertyBorderRightColor:
939             case CSSPropertyBorderBottomColor:
940             case CSSPropertyBorderLeftColor:
941                 if (!borderFallbackShorthandProperty)
942                     borderFallbackShorthandProperty = CSSPropertyBorderColor;
943
944                 // FIXME: Deal with cases where only some of border-(top|right|bottom|left) are specified.
945                 ASSERT(CSSPropertyBorder - firstCSSProperty < shorthandPropertyAppeared.size());
946                 if (!shorthandPropertyAppeared[CSSPropertyBorder - firstCSSProperty]) {
947                     value = borderPropertyValue(ReturnNullOnUncommonValues);
948                     if (value.isNull())
949                         shorthandPropertyAppeared.set(CSSPropertyBorder - firstCSSProperty);
950                     else
951                         shorthandPropertyID = CSSPropertyBorder;
952                 } else if (shorthandPropertyUsed[CSSPropertyBorder - firstCSSProperty])
953                     shorthandPropertyID = CSSPropertyBorder;
954                 if (!shorthandPropertyID)
955                     shorthandPropertyID = borderFallbackShorthandProperty;
956                 break;
957             case CSSPropertyWebkitBorderHorizontalSpacing:
958             case CSSPropertyWebkitBorderVerticalSpacing:
959                 shorthandPropertyID = CSSPropertyBorderSpacing;
960                 break;
961             case CSSPropertyFontFamily:
962             case CSSPropertyLineHeight:
963             case CSSPropertyFontSize:
964             case CSSPropertyFontStyle:
965             case CSSPropertyFontVariantCaps:
966             case CSSPropertyFontWeight:
967                 // Don't use CSSPropertyFont because old UAs can't recognize them but are important for editing.
968                 break;
969             case CSSPropertyListStyleType:
970             case CSSPropertyListStylePosition:
971             case CSSPropertyListStyleImage:
972                 shorthandPropertyID = CSSPropertyListStyle;
973                 break;
974             case CSSPropertyMarginTop:
975             case CSSPropertyMarginRight:
976             case CSSPropertyMarginBottom:
977             case CSSPropertyMarginLeft:
978                 shorthandPropertyID = CSSPropertyMargin;
979                 break;
980             case CSSPropertyOutlineWidth:
981             case CSSPropertyOutlineStyle:
982             case CSSPropertyOutlineColor:
983                 shorthandPropertyID = CSSPropertyOutline;
984                 break;
985             case CSSPropertyOverflowX:
986             case CSSPropertyOverflowY:
987                 shorthandPropertyID = CSSPropertyOverflow;
988                 break;
989             case CSSPropertyPaddingTop:
990             case CSSPropertyPaddingRight:
991             case CSSPropertyPaddingBottom:
992             case CSSPropertyPaddingLeft:
993                 shorthandPropertyID = CSSPropertyPadding;
994                 break;
995 #if ENABLE(CSS_SCROLL_SNAP)
996             case CSSPropertyScrollPaddingTop:
997             case CSSPropertyScrollPaddingRight:
998             case CSSPropertyScrollPaddingBottom:
999             case CSSPropertyScrollPaddingLeft:
1000                 shorthandPropertyID = CSSPropertyScrollPadding;
1001                 break;
1002             case CSSPropertyScrollSnapMarginTop:
1003             case CSSPropertyScrollSnapMarginRight:
1004             case CSSPropertyScrollSnapMarginBottom:
1005             case CSSPropertyScrollSnapMarginLeft:
1006                 shorthandPropertyID = CSSPropertyScrollSnapMargin;
1007                 break;
1008 #endif
1009             case CSSPropertyTransitionProperty:
1010             case CSSPropertyTransitionDuration:
1011             case CSSPropertyTransitionTimingFunction:
1012             case CSSPropertyTransitionDelay:
1013                 shorthandPropertyID = CSSPropertyTransition;
1014                 break;
1015             case CSSPropertyFlexDirection:
1016             case CSSPropertyFlexWrap:
1017                 shorthandPropertyID = CSSPropertyFlexFlow;
1018                 break;
1019             case CSSPropertyFlexBasis:
1020             case CSSPropertyFlexGrow:
1021             case CSSPropertyFlexShrink:
1022                 shorthandPropertyID = CSSPropertyFlex;
1023                 break;
1024             case CSSPropertyWebkitMaskPositionX:
1025             case CSSPropertyWebkitMaskPositionY:
1026             case CSSPropertyWebkitMaskRepeatX:
1027             case CSSPropertyWebkitMaskRepeatY:
1028             case CSSPropertyWebkitMaskImage:
1029             case CSSPropertyWebkitMaskRepeat:
1030             case CSSPropertyWebkitMaskPosition:
1031             case CSSPropertyWebkitMaskClip:
1032             case CSSPropertyWebkitMaskOrigin:
1033                 shorthandPropertyID = CSSPropertyWebkitMask;
1034                 break;
1035             case CSSPropertyPerspectiveOriginX:
1036             case CSSPropertyPerspectiveOriginY:
1037                 shorthandPropertyID = CSSPropertyPerspectiveOrigin;
1038                 break;
1039             case CSSPropertyTransformOriginX:
1040             case CSSPropertyTransformOriginY:
1041             case CSSPropertyTransformOriginZ:
1042                 shorthandPropertyID = CSSPropertyTransformOrigin;
1043                 break;
1044             default:
1045                 break;
1046             }
1047         }
1048
1049         unsigned shortPropertyIndex = shorthandPropertyID - firstCSSProperty;
1050         if (shorthandPropertyID) {
1051             ASSERT(shortPropertyIndex < shorthandPropertyUsed.size());
1052             if (shorthandPropertyUsed[shortPropertyIndex])
1053                 continue;
1054             if (!shorthandPropertyAppeared[shortPropertyIndex] && value.isNull())
1055                 value = getPropertyValue(shorthandPropertyID);
1056             shorthandPropertyAppeared.set(shortPropertyIndex);
1057         }
1058
1059         if (!value.isNull()) {
1060             propertyID = shorthandPropertyID;
1061             shorthandPropertyUsed.set(shortPropertyIndex);
1062         } else
1063             value = property.value()->cssText();
1064
1065         if (propertyID != CSSPropertyCustom && value == "initial" && !CSSProperty::isInheritedProperty(propertyID))
1066             continue;
1067
1068         if (numDecls++)
1069             result.append(' ');
1070
1071         if (propertyID == CSSPropertyCustom)
1072             result.append(downcast<CSSCustomPropertyValue>(*property.value()).name());
1073         else
1074             result.append(getPropertyName(propertyID));
1075
1076         result.appendLiteral(": ");
1077         result.append(value);
1078         if (property.isImportant())
1079             result.appendLiteral(" !important");
1080         result.append(';');
1081     }
1082
1083     // FIXME: This is a not-so-nice way to turn x/y positions into single background-position in output.
1084     // It is required because background-position-x/y are non-standard properties and WebKit generated output
1085     // would not work in Firefox (<rdar://problem/5143183>)
1086     // It would be a better solution if background-position was CSS_PAIR.
1087     if (positionXPropertyIndex != -1 && positionYPropertyIndex != -1 && propertyAt(positionXPropertyIndex).isImportant() == propertyAt(positionYPropertyIndex).isImportant()) {
1088         PropertyReference positionXProperty = propertyAt(positionXPropertyIndex);
1089         PropertyReference positionYProperty = propertyAt(positionYPropertyIndex);
1090
1091         if (numDecls++)
1092             result.append(' ');
1093         result.appendLiteral("background-position: ");
1094         if (positionXProperty.value()->isValueList() || positionYProperty.value()->isValueList())
1095             result.append(getLayeredShorthandValue(backgroundPositionShorthand()));
1096         else {
1097             result.append(positionXProperty.value()->cssText());
1098             result.append(' ');
1099             result.append(positionYProperty.value()->cssText());
1100         }
1101         if (positionXProperty.isImportant())
1102             result.appendLiteral(" !important");
1103         result.append(';');
1104     } else {
1105         if (positionXPropertyIndex != -1) {
1106             if (numDecls++)
1107                 result.append(' ');
1108             result.append(propertyAt(positionXPropertyIndex).cssText());
1109         }
1110         if (positionYPropertyIndex != -1) {
1111             if (numDecls++)
1112                 result.append(' ');
1113             result.append(propertyAt(positionYPropertyIndex).cssText());
1114         }
1115     }
1116
1117     // FIXME: We need to do the same for background-repeat.
1118     if (repeatXPropertyIndex != -1 && repeatYPropertyIndex != -1 && propertyAt(repeatXPropertyIndex).isImportant() == propertyAt(repeatYPropertyIndex).isImportant()) {
1119         PropertyReference repeatXProperty = propertyAt(repeatXPropertyIndex);
1120         PropertyReference repeatYProperty = propertyAt(repeatYPropertyIndex);
1121
1122         if (numDecls++)
1123             result.append(' ');
1124         result.appendLiteral("background-repeat: ");
1125         if (repeatXProperty.value()->isValueList() || repeatYProperty.value()->isValueList())
1126             result.append(getLayeredShorthandValue(backgroundRepeatShorthand()));
1127         else {
1128             result.append(repeatXProperty.value()->cssText());
1129             result.append(' ');
1130             result.append(repeatYProperty.value()->cssText());
1131         }
1132         if (repeatXProperty.isImportant())
1133             result.appendLiteral(" !important");
1134         result.append(';');
1135     } else {
1136         if (repeatXPropertyIndex != -1) {
1137             if (numDecls++)
1138                 result.append(' ');
1139             result.append(propertyAt(repeatXPropertyIndex).cssText());
1140         }
1141         if (repeatYPropertyIndex != -1) {
1142             if (numDecls++)
1143                 result.append(' ');
1144             result.append(propertyAt(repeatYPropertyIndex).cssText());
1145         }
1146     }
1147
1148     ASSERT(!numDecls ^ !result.isEmpty());
1149     return result.toString();
1150 }
1151
1152 bool StyleProperties::hasCSSOMWrapper() const
1153 {
1154     return is<MutableStyleProperties>(*this) && downcast<MutableStyleProperties>(*this).m_cssomWrapper;
1155 }
1156
1157 void MutableStyleProperties::mergeAndOverrideOnConflict(const StyleProperties& other)
1158 {
1159     unsigned size = other.propertyCount();
1160     for (unsigned i = 0; i < size; ++i)
1161         addParsedProperty(other.propertyAt(i).toCSSProperty());
1162 }
1163
1164 bool StyleProperties::traverseSubresources(const WTF::Function<bool (const CachedResource&)>& handler) const
1165 {
1166     unsigned size = propertyCount();
1167     for (unsigned i = 0; i < size; ++i) {
1168         if (propertyAt(i).value()->traverseSubresources(handler))
1169             return true;
1170     }
1171     return false;
1172 }
1173
1174 // This is the list of properties we want to copy in the copyBlockProperties() function.
1175 // It is the list of CSS properties that apply specially to block-level elements.
1176 static const CSSPropertyID blockProperties[] = {
1177     CSSPropertyOrphans,
1178     CSSPropertyOverflow, // This can be also be applied to replaced elements
1179     CSSPropertyWebkitAspectRatio,
1180     CSSPropertyColumnCount,
1181     CSSPropertyColumnGap,
1182     CSSPropertyColumnRuleColor,
1183     CSSPropertyColumnRuleStyle,
1184     CSSPropertyColumnRuleWidth,
1185     CSSPropertyWebkitColumnBreakBefore,
1186     CSSPropertyWebkitColumnBreakAfter,
1187     CSSPropertyWebkitColumnBreakInside,
1188     CSSPropertyColumnWidth,
1189     CSSPropertyPageBreakAfter,
1190     CSSPropertyPageBreakBefore,
1191     CSSPropertyPageBreakInside,
1192     CSSPropertyTextAlign,
1193 #if ENABLE(CSS3_TEXT)
1194     CSSPropertyWebkitTextAlignLast,
1195     CSSPropertyWebkitTextJustify,
1196 #endif // CSS3_TEXT
1197     CSSPropertyTextIndent,
1198     CSSPropertyWidows
1199 };
1200
1201 void MutableStyleProperties::clear()
1202 {
1203     m_propertyVector.clear();
1204 }
1205
1206 const unsigned numBlockProperties = WTF_ARRAY_LENGTH(blockProperties);
1207
1208 Ref<MutableStyleProperties> StyleProperties::copyBlockProperties() const
1209 {
1210     return copyPropertiesInSet(blockProperties, numBlockProperties);
1211 }
1212
1213 void MutableStyleProperties::removeBlockProperties()
1214 {
1215     removePropertiesInSet(blockProperties, numBlockProperties);
1216 }
1217
1218 bool MutableStyleProperties::removePropertiesInSet(const CSSPropertyID* set, unsigned length)
1219 {
1220     if (m_propertyVector.isEmpty())
1221         return false;
1222
1223     // FIXME: This is always used with static sets and in that case constructing the hash repeatedly is pretty pointless.
1224     HashSet<CSSPropertyID> toRemove;
1225     for (unsigned i = 0; i < length; ++i)
1226         toRemove.add(set[i]);
1227
1228     return m_propertyVector.removeAllMatching([&toRemove] (const CSSProperty& property) {
1229         // Not quite sure if the isImportant test is needed but it matches the existing behavior.
1230         return !property.isImportant() && toRemove.contains(property.id());
1231     }) > 0;
1232 }
1233
1234 int ImmutableStyleProperties::findPropertyIndex(CSSPropertyID propertyID) const
1235 {
1236     // Convert here propertyID into an uint16_t to compare it with the metadata's m_propertyID to avoid
1237     // the compiler converting it to an int multiple times in the loop.
1238     uint16_t id = static_cast<uint16_t>(propertyID);
1239     for (int n = m_arraySize - 1 ; n >= 0; --n) {
1240         if (metadataArray()[n].m_propertyID == id)
1241             return n;
1242     }
1243
1244     return -1;
1245 }
1246
1247 int MutableStyleProperties::findPropertyIndex(CSSPropertyID propertyID) const
1248 {
1249     // Convert here propertyID into an uint16_t to compare it with the metadata's m_propertyID to avoid
1250     // the compiler converting it to an int multiple times in the loop.
1251     uint16_t id = static_cast<uint16_t>(propertyID);
1252     for (int n = m_propertyVector.size() - 1 ; n >= 0; --n) {
1253         if (m_propertyVector.at(n).metadata().m_propertyID == id)
1254             return n;
1255     }
1256
1257     return -1;
1258 }
1259
1260 int ImmutableStyleProperties::findCustomPropertyIndex(const String& propertyName) const
1261 {
1262     // Convert the propertyID into an uint16_t to compare it with the metadata's m_propertyID to avoid
1263     // the compiler converting it to an int multiple times in the loop.
1264     for (int n = m_arraySize - 1 ; n >= 0; --n) {
1265         if (metadataArray()[n].m_propertyID == CSSPropertyCustom) {
1266             // We found a custom property. See if the name matches.
1267             if (!valueArray()[n])
1268                 continue;
1269             if (downcast<CSSCustomPropertyValue>(*valueArray()[n]).name() == propertyName)
1270                 return n;
1271         }
1272     }
1273
1274     return -1;
1275 }
1276
1277 int MutableStyleProperties::findCustomPropertyIndex(const String& propertyName) const
1278 {
1279     // Convert the propertyID into an uint16_t to compare it with the metadata's m_propertyID to avoid
1280     // the compiler converting it to an int multiple times in the loop.
1281     for (int n = m_propertyVector.size() - 1 ; n >= 0; --n) {
1282         if (m_propertyVector.at(n).metadata().m_propertyID == CSSPropertyCustom) {
1283             // We found a custom property. See if the name matches.
1284             if (!m_propertyVector.at(n).value())
1285                 continue;
1286             if (downcast<CSSCustomPropertyValue>(*m_propertyVector.at(n).value()).name() == propertyName)
1287                 return n;
1288         }
1289     }
1290
1291     return -1;
1292 }
1293
1294 CSSProperty* MutableStyleProperties::findCSSPropertyWithID(CSSPropertyID propertyID)
1295 {
1296     int foundPropertyIndex = findPropertyIndex(propertyID);
1297     if (foundPropertyIndex == -1)
1298         return 0;
1299     return &m_propertyVector.at(foundPropertyIndex);
1300 }
1301
1302 CSSProperty* MutableStyleProperties::findCustomCSSPropertyWithName(const String& propertyName)
1303 {
1304     int foundPropertyIndex = findCustomPropertyIndex(propertyName);
1305     if (foundPropertyIndex == -1)
1306         return 0;
1307     return &m_propertyVector.at(foundPropertyIndex);
1308 }
1309
1310 bool StyleProperties::propertyMatches(CSSPropertyID propertyID, const CSSValue* propertyValue) const
1311 {
1312     int foundPropertyIndex = findPropertyIndex(propertyID);
1313     if (foundPropertyIndex == -1)
1314         return false;
1315     return propertyAt(foundPropertyIndex).value()->equals(*propertyValue);
1316 }
1317
1318 Ref<MutableStyleProperties> StyleProperties::mutableCopy() const
1319 {
1320     return adoptRef(*new MutableStyleProperties(*this));
1321 }
1322
1323 Ref<MutableStyleProperties> StyleProperties::copyPropertiesInSet(const CSSPropertyID* set, unsigned length) const
1324 {
1325     Vector<CSSProperty, 256> list;
1326     list.reserveInitialCapacity(length);
1327     for (unsigned i = 0; i < length; ++i) {
1328         if (auto value = getPropertyCSSValueInternal(set[i]))
1329             list.uncheckedAppend(CSSProperty(set[i], WTFMove(value), false));
1330     }
1331     return MutableStyleProperties::create(list.data(), list.size());
1332 }
1333
1334 PropertySetCSSStyleDeclaration* MutableStyleProperties::cssStyleDeclaration()
1335 {
1336     return m_cssomWrapper.get();
1337 }
1338
1339 CSSStyleDeclaration& MutableStyleProperties::ensureCSSStyleDeclaration()
1340 {
1341     if (m_cssomWrapper) {
1342         ASSERT(!static_cast<CSSStyleDeclaration*>(m_cssomWrapper.get())->parentRule());
1343         ASSERT(!m_cssomWrapper->parentElement());
1344         return *m_cssomWrapper;
1345     }
1346     m_cssomWrapper = std::make_unique<PropertySetCSSStyleDeclaration>(*this);
1347     return *m_cssomWrapper;
1348 }
1349
1350 CSSStyleDeclaration& MutableStyleProperties::ensureInlineCSSStyleDeclaration(StyledElement& parentElement)
1351 {
1352     if (m_cssomWrapper) {
1353         ASSERT(m_cssomWrapper->parentElement() == &parentElement);
1354         return *m_cssomWrapper;
1355     }
1356     m_cssomWrapper = std::make_unique<InlineCSSStyleDeclaration>(*this, parentElement);
1357     return *m_cssomWrapper;
1358 }
1359
1360 unsigned StyleProperties::averageSizeInBytes()
1361 {
1362     // Please update this if the storage scheme changes so that this longer reflects the actual size.
1363     return sizeForImmutableStylePropertiesWithPropertyCount(4);
1364 }
1365
1366 // See the function above if you need to update this.
1367 struct SameSizeAsStyleProperties : public RefCounted<SameSizeAsStyleProperties> {
1368     unsigned bitfield;
1369 };
1370 COMPILE_ASSERT(sizeof(StyleProperties) == sizeof(SameSizeAsStyleProperties), style_property_set_should_stay_small);
1371
1372 #ifndef NDEBUG
1373 void StyleProperties::showStyle()
1374 {
1375     fprintf(stderr, "%s\n", asText().ascii().data());
1376 }
1377 #endif
1378
1379 Ref<MutableStyleProperties> MutableStyleProperties::create(CSSParserMode cssParserMode)
1380 {
1381     return adoptRef(*new MutableStyleProperties(cssParserMode));
1382 }
1383
1384 Ref<MutableStyleProperties> MutableStyleProperties::create(const CSSProperty* properties, unsigned count)
1385 {
1386     return adoptRef(*new MutableStyleProperties(properties, count));
1387 }
1388
1389 String StyleProperties::PropertyReference::cssName() const
1390 {
1391     if (id() == CSSPropertyCustom)
1392         return downcast<CSSCustomPropertyValue>(*value()).name();
1393     return getPropertyNameString(id());
1394 }
1395
1396 String StyleProperties::PropertyReference::cssText() const
1397 {
1398     StringBuilder result;
1399     result.append(cssName());
1400     result.appendLiteral(": ");
1401     result.append(m_value->cssText());
1402     if (isImportant())
1403         result.appendLiteral(" !important");
1404     result.append(';');
1405     return result.toString();
1406 }
1407     
1408 Ref<DeferredStyleProperties> DeferredStyleProperties::create(const CSSParserTokenRange& tokenRange, CSSDeferredParser& parser)
1409 {
1410     return adoptRef(*new DeferredStyleProperties(tokenRange, parser));
1411 }
1412
1413 DeferredStyleProperties::DeferredStyleProperties(const CSSParserTokenRange& range, CSSDeferredParser& parser)
1414     : StylePropertiesBase(parser.mode(), DeferredPropertiesType)
1415     , m_parser(parser)
1416 {
1417     size_t length = range.end() - range.begin();
1418     m_tokens.reserveCapacity(length);
1419     m_tokens.append(range.begin(), length);
1420 }
1421     
1422 DeferredStyleProperties::~DeferredStyleProperties() = default;
1423
1424 Ref<ImmutableStyleProperties> DeferredStyleProperties::parseDeferredProperties()
1425 {
1426     return m_parser->parseDeclaration(m_tokens);
1427 }
1428
1429 } // namespace WebCore