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