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/RuntimeCSSEnabled.h"
     32 #include "core/css/StylePropertySerializer.h"
     33 #include "core/css/StyleSheetContents.h"
     34 #include "wtf/text/StringBuilder.h"
     35 
     36 #ifndef NDEBUG
     37 #include "wtf/text/CString.h"
     38 #include <stdio.h>
     39 #endif
     40 
     41 using namespace std;
     42 
     43 namespace WebCore {
     44 
     45 static size_t sizeForImmutableStylePropertySetWithPropertyCount(unsigned count)
     46 {
     47     return sizeof(ImmutableStylePropertySet) - sizeof(void*) + sizeof(CSSValue*) * count + sizeof(StylePropertyMetadata) * count;
     48 }
     49 
     50 PassRefPtr<ImmutableStylePropertySet> ImmutableStylePropertySet::create(const CSSProperty* properties, unsigned count, CSSParserMode cssParserMode)
     51 {
     52     ASSERT(count <= MaxArraySize);
     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 toImmutableStylePropertySet(const_cast<StylePropertySet*>(this));
     61     const MutableStylePropertySet* mutableThis = toMutableStylePropertySet(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(HTMLStandardMode)
     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 < m_arraySize; ++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 = toMutableStylePropertySet(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 == kNotFound)
    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     Vector<StylePropertyShorthand, 4> shorthands;
    278     getMatchingShorthandsForLonghand(prefixingVariant, &shorthands);
    279     return indexOfShorthandForLonghand(prefixedShorthand, shorthands);
    280 }
    281 
    282 bool MutableStylePropertySet::setVariableValue(const AtomicString& name, const String& value, bool important)
    283 {
    284     ASSERT(RuntimeEnabledFeatures::cssVariablesEnabled());
    285     if (value.isEmpty())
    286         return removeVariable(name);
    287 
    288     size_t index = findVariableIndex(name);
    289     if (index != kNotFound) {
    290         const CSSValue* cssValue = m_propertyVector.at(index).value();
    291         if (toCSSVariableValue(cssValue)->value() == value)
    292             return false;
    293     }
    294 
    295     CSSProperty property(CSSPropertyVariable, CSSVariableValue::create(name, value), important);
    296     if (index == kNotFound) {
    297         m_propertyVector.append(property);
    298         return true;
    299     }
    300     m_propertyVector.at(index) = property;
    301     return false;
    302 }
    303 
    304 void MutableStylePropertySet::appendPrefixingVariantProperty(const CSSProperty& property)
    305 {
    306     m_propertyVector.append(property);
    307     CSSPropertyID prefixingVariant = prefixingVariantForPropertyId(property.id());
    308     if (prefixingVariant == property.id())
    309         return;
    310 
    311     m_propertyVector.append(CSSProperty(prefixingVariant, property.value(), property.isImportant(), property.isSetFromShorthand(), getIndexInShorthandVectorForPrefixingVariant(property, prefixingVariant), property.metadata().m_implicit));
    312 }
    313 
    314 void MutableStylePropertySet::setPrefixingVariantProperty(const CSSProperty& property)
    315 {
    316     CSSPropertyID prefixingVariant = prefixingVariantForPropertyId(property.id());
    317     CSSProperty* toReplace = findCSSPropertyWithID(prefixingVariant);
    318     if (toReplace && prefixingVariant != property.id())
    319         *toReplace = CSSProperty(prefixingVariant, property.value(), property.isImportant(), property.isSetFromShorthand(), getIndexInShorthandVectorForPrefixingVariant(property, prefixingVariant), property.metadata().m_implicit);
    320 }
    321 
    322 bool MutableStylePropertySet::setProperty(CSSPropertyID propertyID, CSSValueID identifier, bool important)
    323 {
    324     setProperty(CSSProperty(propertyID, cssValuePool().createIdentifierValue(identifier), important));
    325     return true;
    326 }
    327 
    328 bool MutableStylePropertySet::setProperty(CSSPropertyID propertyID, CSSPropertyID identifier, bool important)
    329 {
    330     setProperty(CSSProperty(propertyID, cssValuePool().createIdentifierValue(identifier), important));
    331     return true;
    332 }
    333 
    334 void MutableStylePropertySet::parseDeclaration(const String& styleDeclaration, StyleSheetContents* contextStyleSheet)
    335 {
    336     m_propertyVector.clear();
    337 
    338     CSSParserContext context(cssParserMode());
    339     if (contextStyleSheet) {
    340         context = contextStyleSheet->parserContext();
    341         context.setMode(cssParserMode());
    342     }
    343 
    344     CSSParser parser(context, UseCounter::getFrom(contextStyleSheet));
    345     parser.parseDeclaration(this, styleDeclaration, 0, contextStyleSheet);
    346 }
    347 
    348 void MutableStylePropertySet::addParsedProperties(const Vector<CSSProperty, 256>& properties)
    349 {
    350     m_propertyVector.reserveCapacity(m_propertyVector.size() + properties.size());
    351     for (unsigned i = 0; i < properties.size(); ++i)
    352         addParsedProperty(properties[i]);
    353 }
    354 
    355 void MutableStylePropertySet::addParsedProperty(const CSSProperty& property)
    356 {
    357     // Only add properties that have no !important counterpart present
    358     if (!propertyIsImportant(property.id()) || property.isImportant())
    359         setProperty(property);
    360 }
    361 
    362 String StylePropertySet::asText() const
    363 {
    364     return StylePropertySerializer(*this).asText();
    365 }
    366 
    367 bool StylePropertySet::hasCSSOMWrapper() const
    368 {
    369     return m_isMutable && toMutableStylePropertySet(this)->m_cssomWrapper;
    370 }
    371 
    372 void MutableStylePropertySet::mergeAndOverrideOnConflict(const StylePropertySet* other)
    373 {
    374     unsigned size = other->propertyCount();
    375     for (unsigned n = 0; n < size; ++n) {
    376         PropertyReference toMerge = other->propertyAt(n);
    377         CSSProperty* old = findCSSPropertyWithID(toMerge.id());
    378         if (old)
    379             setProperty(toMerge.toCSSProperty(), old);
    380         else
    381             appendPrefixingVariantProperty(toMerge.toCSSProperty());
    382     }
    383 }
    384 
    385 void StylePropertySet::addSubresourceStyleURLs(ListHashSet<KURL>& urls, StyleSheetContents* contextStyleSheet) const
    386 {
    387     unsigned size = propertyCount();
    388     for (unsigned i = 0; i < size; ++i)
    389         propertyAt(i).value()->addSubresourceStyleURLs(urls, contextStyleSheet);
    390 }
    391 
    392 bool StylePropertySet::hasFailedOrCanceledSubresources() const
    393 {
    394     unsigned size = propertyCount();
    395     for (unsigned i = 0; i < size; ++i) {
    396         if (propertyAt(i).value()->hasFailedOrCanceledSubresources())
    397             return true;
    398     }
    399     return false;
    400 }
    401 
    402 // This is the list of properties we want to copy in the copyBlockProperties() function.
    403 // It is the list of CSS properties that apply specially to block-level elements.
    404 static const CSSPropertyID staticBlockProperties[] = {
    405     CSSPropertyOrphans,
    406     CSSPropertyOverflow, // This can be also be applied to replaced elements
    407     CSSPropertyWebkitAspectRatio,
    408     CSSPropertyWebkitColumnCount,
    409     CSSPropertyWebkitColumnGap,
    410     CSSPropertyWebkitColumnRuleColor,
    411     CSSPropertyWebkitColumnRuleStyle,
    412     CSSPropertyWebkitColumnRuleWidth,
    413     CSSPropertyWebkitColumnBreakBefore,
    414     CSSPropertyWebkitColumnBreakAfter,
    415     CSSPropertyWebkitColumnBreakInside,
    416     CSSPropertyWebkitColumnWidth,
    417     CSSPropertyPageBreakAfter,
    418     CSSPropertyPageBreakBefore,
    419     CSSPropertyPageBreakInside,
    420     CSSPropertyWebkitRegionBreakAfter,
    421     CSSPropertyWebkitRegionBreakBefore,
    422     CSSPropertyWebkitRegionBreakInside,
    423     CSSPropertyTextAlign,
    424     CSSPropertyTextAlignLast,
    425     CSSPropertyTextIndent,
    426     CSSPropertyTextJustify,
    427     CSSPropertyWidows
    428 };
    429 
    430 static const Vector<CSSPropertyID>& blockProperties()
    431 {
    432     DEFINE_STATIC_LOCAL(Vector<CSSPropertyID>, properties, ());
    433     if (properties.isEmpty())
    434         RuntimeCSSEnabled::filterEnabledCSSPropertiesIntoVector(staticBlockProperties, WTF_ARRAY_LENGTH(staticBlockProperties), properties);
    435     return properties;
    436 }
    437 
    438 void MutableStylePropertySet::clear()
    439 {
    440     m_propertyVector.clear();
    441 }
    442 
    443 PassRefPtr<MutableStylePropertySet> StylePropertySet::copyBlockProperties() const
    444 {
    445     return copyPropertiesInSet(blockProperties());
    446 }
    447 
    448 void MutableStylePropertySet::removeBlockProperties()
    449 {
    450     removePropertiesInSet(blockProperties().data(), blockProperties().size());
    451 }
    452 
    453 bool MutableStylePropertySet::removePropertiesInSet(const CSSPropertyID* set, unsigned length)
    454 {
    455     if (m_propertyVector.isEmpty())
    456         return false;
    457 
    458     // FIXME: This is always used with static sets and in that case constructing the hash repeatedly is pretty pointless.
    459     HashSet<CSSPropertyID> toRemove;
    460     for (unsigned i = 0; i < length; ++i)
    461         toRemove.add(set[i]);
    462 
    463     Vector<CSSProperty> newProperties;
    464     newProperties.reserveInitialCapacity(m_propertyVector.size());
    465 
    466     unsigned size = m_propertyVector.size();
    467     for (unsigned n = 0; n < size; ++n) {
    468         const CSSProperty& property = m_propertyVector.at(n);
    469         // Not quite sure if the isImportant test is needed but it matches the existing behavior.
    470         if (!property.isImportant()) {
    471             if (toRemove.contains(property.id()))
    472                 continue;
    473         }
    474         newProperties.append(property);
    475     }
    476 
    477     bool changed = newProperties.size() != m_propertyVector.size();
    478     m_propertyVector = newProperties;
    479     return changed;
    480 }
    481 
    482 int StylePropertySet::findPropertyIndex(CSSPropertyID propertyID) const
    483 {
    484     // Convert here propertyID into an uint16_t to compare it with the metadata's m_propertyID to avoid
    485     // the compiler converting it to an int multiple times in the loop.
    486     uint16_t id = static_cast<uint16_t>(propertyID);
    487     for (int n = propertyCount() - 1 ; n >= 0; --n) {
    488         if (id == propertyAt(n).propertyMetadata().m_propertyID) {
    489             // Only enabled or internal properties should be part of the style.
    490             ASSERT(RuntimeCSSEnabled::isCSSPropertyEnabled(propertyID) || isInternalProperty(propertyID));
    491             return n;
    492         }
    493     }
    494     return -1;
    495 }
    496 
    497 size_t StylePropertySet::findVariableIndex(const AtomicString& name) const
    498 {
    499     ASSERT(RuntimeEnabledFeatures::cssVariablesEnabled());
    500     for (int i = propertyCount() - 1; i >= 0; --i) {
    501         const PropertyReference& property = propertyAt(i);
    502         if (property.id() == CSSPropertyVariable && toCSSVariableValue(property.value())->name() == name)
    503             return i;
    504     }
    505     return kNotFound;
    506 }
    507 
    508 CSSProperty* MutableStylePropertySet::findCSSPropertyWithID(CSSPropertyID propertyID)
    509 {
    510     int foundPropertyIndex = findPropertyIndex(propertyID);
    511     if (foundPropertyIndex == -1)
    512         return 0;
    513     return &m_propertyVector.at(foundPropertyIndex);
    514 }
    515 
    516 bool StylePropertySet::propertyMatches(CSSPropertyID propertyID, const CSSValue* propertyValue) const
    517 {
    518     int foundPropertyIndex = findPropertyIndex(propertyID);
    519     if (foundPropertyIndex == -1)
    520         return false;
    521     return propertyAt(foundPropertyIndex).value()->equals(*propertyValue);
    522 }
    523 
    524 void MutableStylePropertySet::removeEquivalentProperties(const StylePropertySet* style)
    525 {
    526     Vector<CSSPropertyID> propertiesToRemove;
    527     unsigned size = m_propertyVector.size();
    528     for (unsigned i = 0; i < size; ++i) {
    529         PropertyReference property = propertyAt(i);
    530         if (style->propertyMatches(property.id(), property.value()))
    531             propertiesToRemove.append(property.id());
    532     }
    533     // FIXME: This should use mass removal.
    534     for (unsigned i = 0; i < propertiesToRemove.size(); ++i)
    535         removeProperty(propertiesToRemove[i]);
    536 }
    537 
    538 void MutableStylePropertySet::removeEquivalentProperties(const CSSStyleDeclaration* style)
    539 {
    540     Vector<CSSPropertyID> propertiesToRemove;
    541     unsigned size = m_propertyVector.size();
    542     for (unsigned i = 0; i < size; ++i) {
    543         PropertyReference property = propertyAt(i);
    544         if (style->cssPropertyMatches(property.id(), property.value()))
    545             propertiesToRemove.append(property.id());
    546     }
    547     // FIXME: This should use mass removal.
    548     for (unsigned i = 0; i < propertiesToRemove.size(); ++i)
    549         removeProperty(propertiesToRemove[i]);
    550 }
    551 
    552 bool MutableStylePropertySet::removeVariable(const AtomicString& name)
    553 {
    554     ASSERT(RuntimeEnabledFeatures::cssVariablesEnabled());
    555     size_t index = findVariableIndex(name);
    556     if (index == kNotFound)
    557         return false;
    558     m_propertyVector.remove(index);
    559     return true;
    560 }
    561 
    562 bool MutableStylePropertySet::clearVariables()
    563 {
    564     ASSERT(RuntimeEnabledFeatures::cssVariablesEnabled());
    565     CSSPropertyID variablesId = CSSPropertyVariable;
    566     return removePropertiesInSet(&variablesId, 1);
    567 }
    568 
    569 PassRefPtr<MutableStylePropertySet::VariablesIterator> MutableStylePropertySet::VariablesIterator::create(MutableStylePropertySet* propertySet)
    570 {
    571     ASSERT(RuntimeEnabledFeatures::cssVariablesEnabled());
    572     const size_t propertyCount = propertySet->propertyCount();
    573     size_t variableCount = 0;
    574     Vector<AtomicString> remainingNames(propertyCount);
    575     for (int i = propertyCount; i--; ) {
    576         const PropertyReference& property = propertySet->propertyAt(i);
    577         if (property.id() == CSSPropertyVariable)
    578             remainingNames[variableCount++] = toCSSVariableValue(property.value())->name();
    579     }
    580     remainingNames.shrink(variableCount);
    581 
    582     RefPtr<VariablesIterator> iterator = adoptRef(new VariablesIterator(propertySet));
    583     // FIXME: Make use of the Vector move constructor when rvalues are supported on all platforms.
    584     iterator->takeRemainingNames(remainingNames);
    585     return iterator.release();
    586 }
    587 
    588 void MutableStylePropertySet::VariablesIterator::addedVariable(const AtomicString& name)
    589 {
    590     ASSERT(!m_remainingNames.contains(name));
    591     ASSERT(!m_newNames.contains(name));
    592     m_newNames.append(name);
    593 }
    594 
    595 void MutableStylePropertySet::VariablesIterator::removedVariable(const AtomicString& name)
    596 {
    597     size_t index = m_remainingNames.find(name);
    598     if (index != kNotFound)
    599         m_remainingNames.remove(index);
    600     index = m_newNames.find(name);
    601     if (index != kNotFound)
    602         m_newNames.remove(index);
    603 }
    604 
    605 void MutableStylePropertySet::VariablesIterator::clearedVariables()
    606 {
    607     m_remainingNames.clear();
    608     m_newNames.clear();
    609 }
    610 
    611 void MutableStylePropertySet::VariablesIterator::advance()
    612 {
    613     if (!atEnd())
    614         m_remainingNames.removeLast();
    615     if (!m_newNames.isEmpty()) {
    616         m_remainingNames.appendVector(m_newNames);
    617         m_newNames.clear();
    618     }
    619 }
    620 
    621 PassRefPtr<MutableStylePropertySet> StylePropertySet::mutableCopy() const
    622 {
    623     return adoptRef(new MutableStylePropertySet(*this));
    624 }
    625 
    626 PassRefPtr<MutableStylePropertySet> StylePropertySet::copyPropertiesInSet(const Vector<CSSPropertyID>& properties) const
    627 {
    628     Vector<CSSProperty, 256> list;
    629     list.reserveInitialCapacity(properties.size());
    630     for (unsigned i = 0; i < properties.size(); ++i) {
    631         RefPtr<CSSValue> value = getPropertyCSSValue(properties[i]);
    632         if (value)
    633             list.append(CSSProperty(properties[i], value.release(), false));
    634     }
    635     return MutableStylePropertySet::create(list.data(), list.size());
    636 }
    637 
    638 PropertySetCSSStyleDeclaration* MutableStylePropertySet::cssStyleDeclaration()
    639 {
    640     return m_cssomWrapper.get();
    641 }
    642 
    643 CSSStyleDeclaration* MutableStylePropertySet::ensureCSSStyleDeclaration()
    644 {
    645     if (m_cssomWrapper) {
    646         ASSERT(!static_cast<CSSStyleDeclaration*>(m_cssomWrapper.get())->parentRule());
    647         ASSERT(!m_cssomWrapper->parentElement());
    648         return m_cssomWrapper.get();
    649     }
    650     m_cssomWrapper = adoptPtr(new PropertySetCSSStyleDeclaration(this));
    651     return m_cssomWrapper.get();
    652 }
    653 
    654 CSSStyleDeclaration* MutableStylePropertySet::ensureInlineCSSStyleDeclaration(Element* parentElement)
    655 {
    656     if (m_cssomWrapper) {
    657         ASSERT(m_cssomWrapper->parentElement() == parentElement);
    658         return m_cssomWrapper.get();
    659     }
    660     m_cssomWrapper = adoptPtr(new InlineCSSStyleDeclaration(this, parentElement));
    661     return m_cssomWrapper.get();
    662 }
    663 
    664 unsigned StylePropertySet::averageSizeInBytes()
    665 {
    666     // Please update this if the storage scheme changes so that this longer reflects the actual size.
    667     return sizeForImmutableStylePropertySetWithPropertyCount(4);
    668 }
    669 
    670 // See the function above if you need to update this.
    671 struct SameSizeAsStylePropertySet : public RefCounted<SameSizeAsStylePropertySet> {
    672     unsigned bitfield;
    673 };
    674 COMPILE_ASSERT(sizeof(StylePropertySet) == sizeof(SameSizeAsStylePropertySet), style_property_set_should_stay_small);
    675 
    676 #ifndef NDEBUG
    677 void StylePropertySet::showStyle()
    678 {
    679     fprintf(stderr, "%s\n", asText().ascii().data());
    680 }
    681 #endif
    682 
    683 PassRefPtr<MutableStylePropertySet> MutableStylePropertySet::create(CSSParserMode cssParserMode)
    684 {
    685     return adoptRef(new MutableStylePropertySet(cssParserMode));
    686 }
    687 
    688 PassRefPtr<MutableStylePropertySet> MutableStylePropertySet::create(const CSSProperty* properties, unsigned count)
    689 {
    690     return adoptRef(new MutableStylePropertySet(properties, count));
    691 }
    692 
    693 String StylePropertySet::PropertyReference::cssName() const
    694 {
    695     if (id() == CSSPropertyVariable) {
    696         if (!propertyValue()->isVariableValue())
    697             return emptyString(); // Should not happen, but if it does, avoid a bad cast.
    698         return "var-" + toCSSVariableValue(propertyValue())->name();
    699     }
    700     return getPropertyNameString(id());
    701 }
    702 
    703 String StylePropertySet::PropertyReference::cssText() const
    704 {
    705     StringBuilder result;
    706     result.append(cssName());
    707     result.appendLiteral(": ");
    708     result.append(propertyValue()->cssText());
    709     if (isImportant())
    710         result.appendLiteral(" !important");
    711     result.append(';');
    712     return result.toString();
    713 }
    714 
    715 
    716 } // namespace WebCore
    717