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/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
42using namespace std;
43
44namespace WebCore {
45
46static size_t sizeForImmutableStylePropertySetWithPropertyCount(unsigned count)
47{
48    return sizeof(ImmutableStylePropertySet) - sizeof(void*) + sizeof(CSSValue*) * count + sizeof(StylePropertyMetadata) * count;
49}
50
51PassRefPtr<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
57PassRefPtr<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
65MutableStylePropertySet::MutableStylePropertySet(CSSParserMode cssParserMode)
66    : StylePropertySet(cssParserMode)
67{
68}
69
70MutableStylePropertySet::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
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 < length; ++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 = 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
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 == notFound)
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    return indexOfShorthandForLonghand(prefixedShorthand, matchingShorthandsForLonghand(prefixingVariant));
278}
279
280bool 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
301void 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
311void 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
319bool MutableStylePropertySet::setProperty(CSSPropertyID propertyID, CSSValueID identifier, bool important)
320{
321    setProperty(CSSProperty(propertyID, cssValuePool().createIdentifierValue(identifier), important));
322    return true;
323}
324
325bool MutableStylePropertySet::setProperty(CSSPropertyID propertyID, CSSPropertyID identifier, bool important)
326{
327    setProperty(CSSProperty(propertyID, cssValuePool().createIdentifierValue(identifier), important));
328    return true;
329}
330
331void 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
345void 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
352void 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
359String StylePropertySet::asText() const
360{
361    return StylePropertySerializer(*this).asText();
362}
363
364bool StylePropertySet::hasCSSOMWrapper() const
365{
366    return m_isMutable && static_cast<const MutableStylePropertySet*>(this)->m_cssomWrapper;
367}
368
369void 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
382void 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
389bool 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.
401static 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
426static 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
434void MutableStylePropertySet::clear()
435{
436    m_propertyVector.clear();
437}
438
439PassRefPtr<MutableStylePropertySet> StylePropertySet::copyBlockProperties() const
440{
441    return copyPropertiesInSet(blockProperties());
442}
443
444void MutableStylePropertySet::removeBlockProperties()
445{
446    removePropertiesInSet(blockProperties().data(), blockProperties().size());
447}
448
449bool 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
478int 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
493size_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
504CSSProperty* 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
512bool 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
520void 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
534void 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
548bool 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
558bool MutableStylePropertySet::clearVariables()
559{
560    ASSERT(RuntimeEnabledFeatures::cssVariablesEnabled());
561    CSSPropertyID variablesId = CSSPropertyVariable;
562    return removePropertiesInSet(&variablesId, 1);
563}
564
565PassRefPtr<MutableStylePropertySet> StylePropertySet::mutableCopy() const
566{
567    return adoptRef(new MutableStylePropertySet(*this));
568}
569
570PassRefPtr<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
582PropertySetCSSStyleDeclaration* MutableStylePropertySet::cssStyleDeclaration()
583{
584    return m_cssomWrapper.get();
585}
586
587CSSStyleDeclaration* 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
598CSSStyleDeclaration* 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
608unsigned 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.
615struct SameSizeAsStylePropertySet : public RefCounted<SameSizeAsStylePropertySet> {
616    unsigned bitfield;
617};
618COMPILE_ASSERT(sizeof(StylePropertySet) == sizeof(SameSizeAsStylePropertySet), style_property_set_should_stay_small);
619
620#ifndef NDEBUG
621void StylePropertySet::showStyle()
622{
623    fprintf(stderr, "%s\n", asText().ascii().data());
624}
625#endif
626
627PassRefPtr<MutableStylePropertySet> MutableStylePropertySet::create(CSSParserMode cssParserMode)
628{
629    return adoptRef(new MutableStylePropertySet(cssParserMode));
630}
631
632PassRefPtr<MutableStylePropertySet> MutableStylePropertySet::create(const CSSProperty* properties, unsigned count)
633{
634    return adoptRef(new MutableStylePropertySet(properties, count));
635}
636
637String 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
647String 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