Home | History | Annotate | Download | only in css
      1 /*
      2  * (C) 1999-2003 Lars Knoll (knoll (at) 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 "core/css/StylePropertySet.h"
     25 
     26 #include "RuntimeEnabledFeatures.h"
     27 #include "StylePropertyShorthand.h"
     28 #include "core/css/CSSParser.h"
     29 #include "core/css/CSSValuePool.h"
     30 #include "core/css/CSSVariableValue.h"
     31 #include "core/css/PropertySetCSSStyleDeclaration.h"
     32 #include "core/css/StylePropertySerializer.h"
     33 #include "core/css/StyleSheetContents.h"
     34 #include "core/page/RuntimeCSSEnabled.h"
     35 #include "wtf/text/StringBuilder.h"
     36 
     37 #ifndef NDEBUG
     38 #include "wtf/text/CString.h"
     39 #include <stdio.h>
     40 #endif
     41 
     42 using namespace std;
     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 PassRefPtr<ImmutableStylePropertySet> ImmutableStylePropertySet::create(const CSSProperty* properties, unsigned count, CSSParserMode cssParserMode)
     52 {
     53     void* slot = WTF::fastMalloc(sizeForImmutableStylePropertySetWithPropertyCount(count));
     54     return adoptRef(new (slot) ImmutableStylePropertySet(properties, count, cssParserMode));
     55 }
     56 
     57 PassRefPtr<ImmutableStylePropertySet> StylePropertySet::immutableCopyIfNeeded() const
     58 {
     59     if (!isMutable())
     60         return static_cast<ImmutableStylePropertySet*>(const_cast<StylePropertySet*>(this));
     61     const MutableStylePropertySet* mutableThis = static_cast<const MutableStylePropertySet*>(this);
     62     return ImmutableStylePropertySet::create(mutableThis->m_propertyVector.data(), mutableThis->m_propertyVector.size(), cssParserMode());
     63 }
     64 
     65 MutableStylePropertySet::MutableStylePropertySet(CSSParserMode cssParserMode)
     66     : StylePropertySet(cssParserMode)
     67 {
     68 }
     69 
     70 MutableStylePropertySet::MutableStylePropertySet(const CSSProperty* properties, unsigned length)
     71     : StylePropertySet(CSSStrictMode)
     72 {
     73     m_propertyVector.reserveInitialCapacity(length);
     74     for (unsigned i = 0; i < length; ++i)
     75         m_propertyVector.uncheckedAppend(properties[i]);
     76 }
     77 
     78 ImmutableStylePropertySet::ImmutableStylePropertySet(const CSSProperty* properties, unsigned length, CSSParserMode cssParserMode)
     79     : StylePropertySet(cssParserMode, length)
     80 {
     81     StylePropertyMetadata* metadataArray = const_cast<StylePropertyMetadata*>(this->metadataArray());
     82     CSSValue** valueArray = const_cast<CSSValue**>(this->valueArray());
     83     for (unsigned i = 0; i < length; ++i) {
     84         metadataArray[i] = properties[i].metadata();
     85         valueArray[i] = properties[i].value();
     86         valueArray[i]->ref();
     87     }
     88 }
     89 
     90 ImmutableStylePropertySet::~ImmutableStylePropertySet()
     91 {
     92     CSSValue** valueArray = const_cast<CSSValue**>(this->valueArray());
     93     for (unsigned i = 0; i < m_arraySize; ++i)
     94         valueArray[i]->deref();
     95 }
     96 
     97 MutableStylePropertySet::MutableStylePropertySet(const StylePropertySet& other)
     98     : StylePropertySet(other.cssParserMode())
     99 {
    100     if (other.isMutable())
    101         m_propertyVector = static_cast<const MutableStylePropertySet&>(other).m_propertyVector;
    102     else {
    103         m_propertyVector.reserveInitialCapacity(other.propertyCount());
    104         for (unsigned i = 0; i < other.propertyCount(); ++i)
    105             m_propertyVector.uncheckedAppend(other.propertyAt(i).toCSSProperty());
    106     }
    107 }
    108 
    109 String StylePropertySet::getPropertyValue(CSSPropertyID propertyID) const
    110 {
    111     RefPtr<CSSValue> value = getPropertyCSSValue(propertyID);
    112     if (value)
    113         return value->cssText();
    114 
    115     return StylePropertySerializer(*this).getPropertyValue(propertyID);
    116 }
    117 
    118 PassRefPtr<CSSValue> StylePropertySet::getPropertyCSSValue(CSSPropertyID propertyID) const
    119 {
    120     int foundPropertyIndex = findPropertyIndex(propertyID);
    121     if (foundPropertyIndex == -1)
    122         return 0;
    123     return propertyAt(foundPropertyIndex).value();
    124 }
    125 
    126 unsigned StylePropertySet::variableCount() const
    127 {
    128     ASSERT(RuntimeEnabledFeatures::cssVariablesEnabled());
    129     unsigned count = 0;
    130     for (unsigned i = 0; i < propertyCount(); ++i) {
    131         if (propertyAt(i).id() == CSSPropertyVariable)
    132             count++;
    133     }
    134     return count;
    135 }
    136 
    137 String StylePropertySet::variableValue(const AtomicString& name) const
    138 {
    139     ASSERT(RuntimeEnabledFeatures::cssVariablesEnabled());
    140     size_t index = findVariableIndex(name);
    141     if (index == notFound)
    142         return String();
    143     return toCSSVariableValue(propertyAt(index).value())->value();
    144 }
    145 
    146 bool MutableStylePropertySet::removeShorthandProperty(CSSPropertyID propertyID)
    147 {
    148     StylePropertyShorthand shorthand = shorthandForProperty(propertyID);
    149     if (!shorthand.length())
    150         return false;
    151 
    152     bool ret = removePropertiesInSet(shorthand.properties(), shorthand.length());
    153 
    154     CSSPropertyID prefixingVariant = prefixingVariantForPropertyId(propertyID);
    155     if (prefixingVariant == propertyID)
    156         return ret;
    157 
    158     StylePropertyShorthand shorthandPrefixingVariant = shorthandForProperty(prefixingVariant);
    159     return removePropertiesInSet(shorthandPrefixingVariant.properties(), shorthandPrefixingVariant.length());
    160 }
    161 
    162 bool MutableStylePropertySet::removeProperty(CSSPropertyID propertyID, String* returnText)
    163 {
    164     if (removeShorthandProperty(propertyID)) {
    165         // FIXME: Return an equivalent shorthand when possible.
    166         if (returnText)
    167             *returnText = "";
    168         return true;
    169     }
    170 
    171     int foundPropertyIndex = findPropertyIndex(propertyID);
    172     if (foundPropertyIndex == -1) {
    173         if (returnText)
    174             *returnText = "";
    175         return false;
    176     }
    177 
    178     if (returnText)
    179         *returnText = propertyAt(foundPropertyIndex).value()->cssText();
    180 
    181     // A more efficient removal strategy would involve marking entries as empty
    182     // and sweeping them when the vector grows too big.
    183     m_propertyVector.remove(foundPropertyIndex);
    184 
    185     removePrefixedOrUnprefixedProperty(propertyID);
    186 
    187     return true;
    188 }
    189 
    190 void MutableStylePropertySet::removePrefixedOrUnprefixedProperty(CSSPropertyID propertyID)
    191 {
    192     int foundPropertyIndex = findPropertyIndex(prefixingVariantForPropertyId(propertyID));
    193     if (foundPropertyIndex == -1)
    194         return;
    195     m_propertyVector.remove(foundPropertyIndex);
    196 }
    197 
    198 bool StylePropertySet::propertyIsImportant(CSSPropertyID propertyID) const
    199 {
    200     int foundPropertyIndex = findPropertyIndex(propertyID);
    201     if (foundPropertyIndex != -1)
    202         return propertyAt(foundPropertyIndex).isImportant();
    203 
    204     StylePropertyShorthand shorthand = shorthandForProperty(propertyID);
    205     if (!shorthand.length())
    206         return false;
    207 
    208     for (unsigned i = 0; i < shorthand.length(); ++i) {
    209         if (!propertyIsImportant(shorthand.properties()[i]))
    210             return false;
    211     }
    212     return true;
    213 }
    214 
    215 CSSPropertyID StylePropertySet::getPropertyShorthand(CSSPropertyID propertyID) const
    216 {
    217     int foundPropertyIndex = findPropertyIndex(propertyID);
    218     if (foundPropertyIndex == -1)
    219         return CSSPropertyInvalid;
    220     return propertyAt(foundPropertyIndex).shorthandID();
    221 }
    222 
    223 bool StylePropertySet::isPropertyImplicit(CSSPropertyID propertyID) const
    224 {
    225     int foundPropertyIndex = findPropertyIndex(propertyID);
    226     if (foundPropertyIndex == -1)
    227         return false;
    228     return propertyAt(foundPropertyIndex).isImplicit();
    229 }
    230 
    231 bool MutableStylePropertySet::setProperty(CSSPropertyID propertyID, const String& value, bool important, StyleSheetContents* contextStyleSheet)
    232 {
    233     // Setting the value to an empty string just removes the property in both IE and Gecko.
    234     // Setting it to null seems to produce less consistent results, but we treat it just the same.
    235     if (value.isEmpty())
    236         return removeProperty(propertyID);
    237 
    238     // When replacing an existing property value, this moves the property to the end of the list.
    239     // Firefox preserves the position, and MSIE moves the property to the beginning.
    240     return CSSParser::parseValue(this, propertyID, value, important, cssParserMode(), contextStyleSheet);
    241 }
    242 
    243 void MutableStylePropertySet::setProperty(CSSPropertyID propertyID, PassRefPtr<CSSValue> prpValue, bool important)
    244 {
    245     StylePropertyShorthand shorthand = shorthandForProperty(propertyID);
    246     if (!shorthand.length()) {
    247         setProperty(CSSProperty(propertyID, prpValue, important));
    248         return;
    249     }
    250 
    251     removePropertiesInSet(shorthand.properties(), shorthand.length());
    252 
    253     RefPtr<CSSValue> value = prpValue;
    254     for (unsigned i = 0; i < shorthand.length(); ++i)
    255         m_propertyVector.append(CSSProperty(shorthand.properties()[i], value, important));
    256 }
    257 
    258 void MutableStylePropertySet::setProperty(const CSSProperty& property, CSSProperty* slot)
    259 {
    260     if (!removeShorthandProperty(property.id())) {
    261         CSSProperty* toReplace = slot ? slot : findCSSPropertyWithID(property.id());
    262         if (toReplace) {
    263             *toReplace = property;
    264             setPrefixingVariantProperty(property);
    265             return;
    266         }
    267     }
    268     appendPrefixingVariantProperty(property);
    269 }
    270 
    271 unsigned getIndexInShorthandVectorForPrefixingVariant(const CSSProperty& property, CSSPropertyID prefixingVariant)
    272 {
    273     if (!property.isSetFromShorthand())
    274         return 0;
    275 
    276     CSSPropertyID prefixedShorthand = prefixingVariantForPropertyId(property.shorthandID());
    277     return indexOfShorthandForLonghand(prefixedShorthand, matchingShorthandsForLonghand(prefixingVariant));
    278 }
    279 
    280 bool MutableStylePropertySet::setVariableValue(const AtomicString& name, const String& value, bool important)
    281 {
    282     ASSERT(RuntimeEnabledFeatures::cssVariablesEnabled());
    283     if (value.isEmpty())
    284         return removeVariable(name);
    285 
    286     size_t index = findVariableIndex(name);
    287     if (index != notFound) {
    288         CSSValue* cssValue = m_propertyVector.at(index).value();
    289         if (toCSSVariableValue(cssValue)->value() == value)
    290             return false;
    291     }
    292 
    293     CSSProperty property(CSSPropertyVariable, CSSVariableValue::create(name, value), important);
    294     if (index == notFound)
    295         m_propertyVector.append(property);
    296     else
    297         m_propertyVector.at(index) = property;
    298     return true;
    299 }
    300 
    301 void MutableStylePropertySet::appendPrefixingVariantProperty(const CSSProperty& property)
    302 {
    303     m_propertyVector.append(property);
    304     CSSPropertyID prefixingVariant = prefixingVariantForPropertyId(property.id());
    305     if (prefixingVariant == property.id())
    306         return;
    307 
    308     m_propertyVector.append(CSSProperty(prefixingVariant, property.value(), property.isImportant(), property.isSetFromShorthand(), getIndexInShorthandVectorForPrefixingVariant(property, prefixingVariant), property.metadata().m_implicit));
    309 }
    310 
    311 void MutableStylePropertySet::setPrefixingVariantProperty(const CSSProperty& property)
    312 {
    313     CSSPropertyID prefixingVariant = prefixingVariantForPropertyId(property.id());
    314     CSSProperty* toReplace = findCSSPropertyWithID(prefixingVariant);
    315     if (toReplace && prefixingVariant != property.id())
    316         *toReplace = CSSProperty(prefixingVariant, property.value(), property.isImportant(), property.isSetFromShorthand(), getIndexInShorthandVectorForPrefixingVariant(property, prefixingVariant), property.metadata().m_implicit);
    317 }
    318 
    319 bool MutableStylePropertySet::setProperty(CSSPropertyID propertyID, CSSValueID identifier, bool important)
    320 {
    321     setProperty(CSSProperty(propertyID, cssValuePool().createIdentifierValue(identifier), important));
    322     return true;
    323 }
    324 
    325 bool MutableStylePropertySet::setProperty(CSSPropertyID propertyID, CSSPropertyID identifier, bool important)
    326 {
    327     setProperty(CSSProperty(propertyID, cssValuePool().createIdentifierValue(identifier), important));
    328     return true;
    329 }
    330 
    331 void MutableStylePropertySet::parseDeclaration(const String& styleDeclaration, StyleSheetContents* contextStyleSheet)
    332 {
    333     m_propertyVector.clear();
    334 
    335     CSSParserContext context(cssParserMode());
    336     if (contextStyleSheet) {
    337         context = contextStyleSheet->parserContext();
    338         context.mode = cssParserMode();
    339     }
    340 
    341     CSSParser parser(context, UseCounter::getFrom(contextStyleSheet));
    342     parser.parseDeclaration(this, styleDeclaration, 0, contextStyleSheet);
    343 }
    344 
    345 void MutableStylePropertySet::addParsedProperties(const Vector<CSSProperty>& properties)
    346 {
    347     m_propertyVector.reserveCapacity(m_propertyVector.size() + properties.size());
    348     for (unsigned i = 0; i < properties.size(); ++i)
    349         addParsedProperty(properties[i]);
    350 }
    351 
    352 void MutableStylePropertySet::addParsedProperty(const CSSProperty& property)
    353 {
    354     // Only add properties that have no !important counterpart present
    355     if (!propertyIsImportant(property.id()) || property.isImportant())
    356         setProperty(property);
    357 }
    358 
    359 String StylePropertySet::asText() const
    360 {
    361     return StylePropertySerializer(*this).asText();
    362 }
    363 
    364 bool StylePropertySet::hasCSSOMWrapper() const
    365 {
    366     return m_isMutable && static_cast<const MutableStylePropertySet*>(this)->m_cssomWrapper;
    367 }
    368 
    369 void MutableStylePropertySet::mergeAndOverrideOnConflict(const StylePropertySet* other)
    370 {
    371     unsigned size = other->propertyCount();
    372     for (unsigned n = 0; n < size; ++n) {
    373         PropertyReference toMerge = other->propertyAt(n);
    374         CSSProperty* old = findCSSPropertyWithID(toMerge.id());
    375         if (old)
    376             setProperty(toMerge.toCSSProperty(), old);
    377         else
    378             appendPrefixingVariantProperty(toMerge.toCSSProperty());
    379     }
    380 }
    381 
    382 void StylePropertySet::addSubresourceStyleURLs(ListHashSet<KURL>& urls, StyleSheetContents* contextStyleSheet) const
    383 {
    384     unsigned size = propertyCount();
    385     for (unsigned i = 0; i < size; ++i)
    386         propertyAt(i).value()->addSubresourceStyleURLs(urls, contextStyleSheet);
    387 }
    388 
    389 bool StylePropertySet::hasFailedOrCanceledSubresources() const
    390 {
    391     unsigned size = propertyCount();
    392     for (unsigned i = 0; i < size; ++i) {
    393         if (propertyAt(i).value()->hasFailedOrCanceledSubresources())
    394             return true;
    395     }
    396     return false;
    397 }
    398 
    399 // This is the list of properties we want to copy in the copyBlockProperties() function.
    400 // It is the list of CSS properties that apply specially to block-level elements.
    401 static const CSSPropertyID staticBlockProperties[] = {
    402     CSSPropertyOrphans,
    403     CSSPropertyOverflow, // This can be also be applied to replaced elements
    404     CSSPropertyWebkitAspectRatio,
    405     CSSPropertyWebkitColumnCount,
    406     CSSPropertyWebkitColumnGap,
    407     CSSPropertyWebkitColumnRuleColor,
    408     CSSPropertyWebkitColumnRuleStyle,
    409     CSSPropertyWebkitColumnRuleWidth,
    410     CSSPropertyWebkitColumnBreakBefore,
    411     CSSPropertyWebkitColumnBreakAfter,
    412     CSSPropertyWebkitColumnBreakInside,
    413     CSSPropertyWebkitColumnWidth,
    414     CSSPropertyPageBreakAfter,
    415     CSSPropertyPageBreakBefore,
    416     CSSPropertyPageBreakInside,
    417     CSSPropertyWebkitRegionBreakAfter,
    418     CSSPropertyWebkitRegionBreakBefore,
    419     CSSPropertyWebkitRegionBreakInside,
    420     CSSPropertyTextAlign,
    421     CSSPropertyTextAlignLast,
    422     CSSPropertyTextIndent,
    423     CSSPropertyWidows
    424 };
    425 
    426 static const Vector<CSSPropertyID>& blockProperties()
    427 {
    428     DEFINE_STATIC_LOCAL(Vector<CSSPropertyID>, properties, ());
    429     if (properties.isEmpty())
    430         RuntimeCSSEnabled::filterEnabledCSSPropertiesIntoVector(staticBlockProperties, WTF_ARRAY_LENGTH(staticBlockProperties), properties);
    431     return properties;
    432 }
    433 
    434 void MutableStylePropertySet::clear()
    435 {
    436     m_propertyVector.clear();
    437 }
    438 
    439 PassRefPtr<MutableStylePropertySet> StylePropertySet::copyBlockProperties() const
    440 {
    441     return copyPropertiesInSet(blockProperties());
    442 }
    443 
    444 void MutableStylePropertySet::removeBlockProperties()
    445 {
    446     removePropertiesInSet(blockProperties().data(), blockProperties().size());
    447 }
    448 
    449 bool MutableStylePropertySet::removePropertiesInSet(const CSSPropertyID* set, unsigned length)
    450 {
    451     if (m_propertyVector.isEmpty())
    452         return false;
    453 
    454     // FIXME: This is always used with static sets and in that case constructing the hash repeatedly is pretty pointless.
    455     HashSet<CSSPropertyID> toRemove;
    456     for (unsigned i = 0; i < length; ++i)
    457         toRemove.add(set[i]);
    458 
    459     Vector<CSSProperty> newProperties;
    460     newProperties.reserveInitialCapacity(m_propertyVector.size());
    461 
    462     unsigned size = m_propertyVector.size();
    463     for (unsigned n = 0; n < size; ++n) {
    464         const CSSProperty& property = m_propertyVector.at(n);
    465         // Not quite sure if the isImportant test is needed but it matches the existing behavior.
    466         if (!property.isImportant()) {
    467             if (toRemove.contains(property.id()))
    468                 continue;
    469         }
    470         newProperties.append(property);
    471     }
    472 
    473     bool changed = newProperties.size() != m_propertyVector.size();
    474     m_propertyVector = newProperties;
    475     return changed;
    476 }
    477 
    478 int StylePropertySet::findPropertyIndex(CSSPropertyID propertyID) const
    479 {
    480     // Convert here propertyID into an uint16_t to compare it with the metadata's m_propertyID to avoid
    481     // the compiler converting it to an int multiple times in the loop.
    482     uint16_t id = static_cast<uint16_t>(propertyID);
    483     for (int n = propertyCount() - 1 ; n >= 0; --n) {
    484         if (id == propertyAt(n).propertyMetadata().m_propertyID) {
    485             // Only enabled properties should be part of the style.
    486             ASSERT(RuntimeCSSEnabled::isCSSPropertyEnabled(propertyID));
    487             return n;
    488         }
    489     }
    490     return -1;
    491 }
    492 
    493 size_t StylePropertySet::findVariableIndex(const AtomicString& name) const
    494 {
    495     ASSERT(RuntimeEnabledFeatures::cssVariablesEnabled());
    496     for (int i = propertyCount() - 1; i >= 0; --i) {
    497         const PropertyReference& property = propertyAt(i);
    498         if (property.id() == CSSPropertyVariable && toCSSVariableValue(property.value())->name() == name)
    499             return i;
    500     }
    501     return notFound;
    502 }
    503 
    504 CSSProperty* MutableStylePropertySet::findCSSPropertyWithID(CSSPropertyID propertyID)
    505 {
    506     int foundPropertyIndex = findPropertyIndex(propertyID);
    507     if (foundPropertyIndex == -1)
    508         return 0;
    509     return &m_propertyVector.at(foundPropertyIndex);
    510 }
    511 
    512 bool StylePropertySet::propertyMatches(CSSPropertyID propertyID, const CSSValue* propertyValue) const
    513 {
    514     int foundPropertyIndex = findPropertyIndex(propertyID);
    515     if (foundPropertyIndex == -1)
    516         return false;
    517     return propertyAt(foundPropertyIndex).value()->equals(*propertyValue);
    518 }
    519 
    520 void MutableStylePropertySet::removeEquivalentProperties(const StylePropertySet* style)
    521 {
    522     Vector<CSSPropertyID> propertiesToRemove;
    523     unsigned size = m_propertyVector.size();
    524     for (unsigned i = 0; i < size; ++i) {
    525         PropertyReference property = propertyAt(i);
    526         if (style->propertyMatches(property.id(), property.value()))
    527             propertiesToRemove.append(property.id());
    528     }
    529     // FIXME: This should use mass removal.
    530     for (unsigned i = 0; i < propertiesToRemove.size(); ++i)
    531         removeProperty(propertiesToRemove[i]);
    532 }
    533 
    534 void MutableStylePropertySet::removeEquivalentProperties(const CSSStyleDeclaration* style)
    535 {
    536     Vector<CSSPropertyID> propertiesToRemove;
    537     unsigned size = m_propertyVector.size();
    538     for (unsigned i = 0; i < size; ++i) {
    539         PropertyReference property = propertyAt(i);
    540         if (style->cssPropertyMatches(property.id(), property.value()))
    541             propertiesToRemove.append(property.id());
    542     }
    543     // FIXME: This should use mass removal.
    544     for (unsigned i = 0; i < propertiesToRemove.size(); ++i)
    545         removeProperty(propertiesToRemove[i]);
    546 }
    547 
    548 bool MutableStylePropertySet::removeVariable(const AtomicString& name)
    549 {
    550     ASSERT(RuntimeEnabledFeatures::cssVariablesEnabled());
    551     size_t index = findVariableIndex(name);
    552     if (index == notFound)
    553         return false;
    554     m_propertyVector.remove(index);
    555     return true;
    556 }
    557 
    558 bool MutableStylePropertySet::clearVariables()
    559 {
    560     ASSERT(RuntimeEnabledFeatures::cssVariablesEnabled());
    561     CSSPropertyID variablesId = CSSPropertyVariable;
    562     return removePropertiesInSet(&variablesId, 1);
    563 }
    564 
    565 PassRefPtr<MutableStylePropertySet> StylePropertySet::mutableCopy() const
    566 {
    567     return adoptRef(new MutableStylePropertySet(*this));
    568 }
    569 
    570 PassRefPtr<MutableStylePropertySet> StylePropertySet::copyPropertiesInSet(const Vector<CSSPropertyID>& properties) const
    571 {
    572     Vector<CSSProperty, 256> list;
    573     list.reserveInitialCapacity(properties.size());
    574     for (unsigned i = 0; i < properties.size(); ++i) {
    575         RefPtr<CSSValue> value = getPropertyCSSValue(properties[i]);
    576         if (value)
    577             list.append(CSSProperty(properties[i], value.release(), false));
    578     }
    579     return MutableStylePropertySet::create(list.data(), list.size());
    580 }
    581 
    582 PropertySetCSSStyleDeclaration* MutableStylePropertySet::cssStyleDeclaration()
    583 {
    584     return m_cssomWrapper.get();
    585 }
    586 
    587 CSSStyleDeclaration* MutableStylePropertySet::ensureCSSStyleDeclaration()
    588 {
    589     if (m_cssomWrapper) {
    590         ASSERT(!static_cast<CSSStyleDeclaration*>(m_cssomWrapper.get())->parentRule());
    591         ASSERT(!m_cssomWrapper->parentElement());
    592         return m_cssomWrapper.get();
    593     }
    594     m_cssomWrapper = adoptPtr(new PropertySetCSSStyleDeclaration(this));
    595     return m_cssomWrapper.get();
    596 }
    597 
    598 CSSStyleDeclaration* MutableStylePropertySet::ensureInlineCSSStyleDeclaration(Element* parentElement)
    599 {
    600     if (m_cssomWrapper) {
    601         ASSERT(m_cssomWrapper->parentElement() == parentElement);
    602         return m_cssomWrapper.get();
    603     }
    604     m_cssomWrapper = adoptPtr(new InlineCSSStyleDeclaration(this, parentElement));
    605     return m_cssomWrapper.get();
    606 }
    607 
    608 unsigned StylePropertySet::averageSizeInBytes()
    609 {
    610     // Please update this if the storage scheme changes so that this longer reflects the actual size.
    611     return sizeForImmutableStylePropertySetWithPropertyCount(4);
    612 }
    613 
    614 // See the function above if you need to update this.
    615 struct SameSizeAsStylePropertySet : public RefCounted<SameSizeAsStylePropertySet> {
    616     unsigned bitfield;
    617 };
    618 COMPILE_ASSERT(sizeof(StylePropertySet) == sizeof(SameSizeAsStylePropertySet), style_property_set_should_stay_small);
    619 
    620 #ifndef NDEBUG
    621 void StylePropertySet::showStyle()
    622 {
    623     fprintf(stderr, "%s\n", asText().ascii().data());
    624 }
    625 #endif
    626 
    627 PassRefPtr<MutableStylePropertySet> MutableStylePropertySet::create(CSSParserMode cssParserMode)
    628 {
    629     return adoptRef(new MutableStylePropertySet(cssParserMode));
    630 }
    631 
    632 PassRefPtr<MutableStylePropertySet> MutableStylePropertySet::create(const CSSProperty* properties, unsigned count)
    633 {
    634     return adoptRef(new MutableStylePropertySet(properties, count));
    635 }
    636 
    637 String StylePropertySet::PropertyReference::cssName() const
    638 {
    639     if (id() == CSSPropertyVariable) {
    640         if (!propertyValue()->isVariableValue())
    641             return emptyString(); // Should not happen, but if it does, avoid a bad cast.
    642         return "var-" + toCSSVariableValue(propertyValue())->name();
    643     }
    644     return getPropertyNameString(id());
    645 }
    646 
    647 String StylePropertySet::PropertyReference::cssText() const
    648 {
    649     StringBuilder result;
    650     result.append(cssName());
    651     result.appendLiteral(": ");
    652     result.append(propertyValue()->cssText());
    653     if (isImportant())
    654         result.appendLiteral(" !important");
    655     result.append(';');
    656     return result.toString();
    657 }
    658 
    659 
    660 } // namespace WebCore
    661