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 "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
41using namespace std;
42
43namespace WebCore {
44
45static size_t sizeForImmutableStylePropertySetWithPropertyCount(unsigned count)
46{
47    return sizeof(ImmutableStylePropertySet) - sizeof(void*) + sizeof(CSSValue*) * count + sizeof(StylePropertyMetadata) * count;
48}
49
50PassRefPtr<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
57PassRefPtr<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
65MutableStylePropertySet::MutableStylePropertySet(CSSParserMode cssParserMode)
66    : StylePropertySet(cssParserMode)
67{
68}
69
70MutableStylePropertySet::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
78ImmutableStylePropertySet::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
90ImmutableStylePropertySet::~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
97MutableStylePropertySet::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
109String 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
118PassRefPtr<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
126unsigned 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
137String 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
146bool 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
162bool 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
190void MutableStylePropertySet::removePrefixedOrUnprefixedProperty(CSSPropertyID propertyID)
191{
192    int foundPropertyIndex = findPropertyIndex(prefixingVariantForPropertyId(propertyID));
193    if (foundPropertyIndex == -1)
194        return;
195    m_propertyVector.remove(foundPropertyIndex);
196}
197
198bool 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
215CSSPropertyID 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
223bool 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
231bool 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
243void 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
258void 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
271unsigned 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
282bool 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
304void 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
314void 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
322bool MutableStylePropertySet::setProperty(CSSPropertyID propertyID, CSSValueID identifier, bool important)
323{
324    setProperty(CSSProperty(propertyID, cssValuePool().createIdentifierValue(identifier), important));
325    return true;
326}
327
328bool MutableStylePropertySet::setProperty(CSSPropertyID propertyID, CSSPropertyID identifier, bool important)
329{
330    setProperty(CSSProperty(propertyID, cssValuePool().createIdentifierValue(identifier), important));
331    return true;
332}
333
334void 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
348void 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
355void 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
362String StylePropertySet::asText() const
363{
364    return StylePropertySerializer(*this).asText();
365}
366
367bool StylePropertySet::hasCSSOMWrapper() const
368{
369    return m_isMutable && toMutableStylePropertySet(this)->m_cssomWrapper;
370}
371
372void 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
385void 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
392bool 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.
404static 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
430static 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
438void MutableStylePropertySet::clear()
439{
440    m_propertyVector.clear();
441}
442
443PassRefPtr<MutableStylePropertySet> StylePropertySet::copyBlockProperties() const
444{
445    return copyPropertiesInSet(blockProperties());
446}
447
448void MutableStylePropertySet::removeBlockProperties()
449{
450    removePropertiesInSet(blockProperties().data(), blockProperties().size());
451}
452
453bool 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
482int 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
497size_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
508CSSProperty* 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
516bool 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
524void 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
538void 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
552bool 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
562bool MutableStylePropertySet::clearVariables()
563{
564    ASSERT(RuntimeEnabledFeatures::cssVariablesEnabled());
565    CSSPropertyID variablesId = CSSPropertyVariable;
566    return removePropertiesInSet(&variablesId, 1);
567}
568
569PassRefPtr<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
588void 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
595void 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
605void MutableStylePropertySet::VariablesIterator::clearedVariables()
606{
607    m_remainingNames.clear();
608    m_newNames.clear();
609}
610
611void 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
621PassRefPtr<MutableStylePropertySet> StylePropertySet::mutableCopy() const
622{
623    return adoptRef(new MutableStylePropertySet(*this));
624}
625
626PassRefPtr<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
638PropertySetCSSStyleDeclaration* MutableStylePropertySet::cssStyleDeclaration()
639{
640    return m_cssomWrapper.get();
641}
642
643CSSStyleDeclaration* 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
654CSSStyleDeclaration* 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
664unsigned 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.
671struct SameSizeAsStylePropertySet : public RefCounted<SameSizeAsStylePropertySet> {
672    unsigned bitfield;
673};
674COMPILE_ASSERT(sizeof(StylePropertySet) == sizeof(SameSizeAsStylePropertySet), style_property_set_should_stay_small);
675
676#ifndef NDEBUG
677void StylePropertySet::showStyle()
678{
679    fprintf(stderr, "%s\n", asText().ascii().data());
680}
681#endif
682
683PassRefPtr<MutableStylePropertySet> MutableStylePropertySet::create(CSSParserMode cssParserMode)
684{
685    return adoptRef(new MutableStylePropertySet(cssParserMode));
686}
687
688PassRefPtr<MutableStylePropertySet> MutableStylePropertySet::create(const CSSProperty* properties, unsigned count)
689{
690    return adoptRef(new MutableStylePropertySet(properties, count));
691}
692
693String 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
703String 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