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