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