• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
41 using namespace std;
42 
43 namespace WebCore {
44 
sizeForImmutableStylePropertySetWithPropertyCount(unsigned count)45 static size_t sizeForImmutableStylePropertySetWithPropertyCount(unsigned count)
46 {
47     return sizeof(ImmutableStylePropertySet) - sizeof(void*) + sizeof(CSSValue*) * count + sizeof(StylePropertyMetadata) * count;
48 }
49 
create(const CSSProperty * properties,unsigned count,CSSParserMode cssParserMode)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 
immutableCopyIfNeeded() const57 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 
MutableStylePropertySet(CSSParserMode cssParserMode)65 MutableStylePropertySet::MutableStylePropertySet(CSSParserMode cssParserMode)
66     : StylePropertySet(cssParserMode)
67 {
68 }
69 
MutableStylePropertySet(const CSSProperty * properties,unsigned length)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 
ImmutableStylePropertySet(const CSSProperty * properties,unsigned length,CSSParserMode cssParserMode)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 
~ImmutableStylePropertySet()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 
MutableStylePropertySet(const StylePropertySet & other)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 
getPropertyValue(CSSPropertyID propertyID) const109 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 
getPropertyCSSValue(CSSPropertyID propertyID) const118 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 
variableCount() const126 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 
variableValue(const AtomicString & name) const137 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 
removeShorthandProperty(CSSPropertyID propertyID)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 
removeProperty(CSSPropertyID propertyID,String * returnText)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 
removePrefixedOrUnprefixedProperty(CSSPropertyID propertyID)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 
propertyIsImportant(CSSPropertyID propertyID) const198 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 
getPropertyShorthand(CSSPropertyID propertyID) const215 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 
isPropertyImplicit(CSSPropertyID propertyID) const223 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 
setProperty(CSSPropertyID propertyID,const String & value,bool important,StyleSheetContents * contextStyleSheet)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 
setProperty(CSSPropertyID propertyID,PassRefPtr<CSSValue> prpValue,bool important)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 
setProperty(const CSSProperty & property,CSSProperty * slot)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 
getIndexInShorthandVectorForPrefixingVariant(const CSSProperty & property,CSSPropertyID prefixingVariant)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 
setVariableValue(const AtomicString & name,const String & value,bool important)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 
appendPrefixingVariantProperty(const CSSProperty & property)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 
setPrefixingVariantProperty(const CSSProperty & property)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 
setProperty(CSSPropertyID propertyID,CSSValueID identifier,bool important)322 bool MutableStylePropertySet::setProperty(CSSPropertyID propertyID, CSSValueID identifier, bool important)
323 {
324     setProperty(CSSProperty(propertyID, cssValuePool().createIdentifierValue(identifier), important));
325     return true;
326 }
327 
setProperty(CSSPropertyID propertyID,CSSPropertyID identifier,bool important)328 bool MutableStylePropertySet::setProperty(CSSPropertyID propertyID, CSSPropertyID identifier, bool important)
329 {
330     setProperty(CSSProperty(propertyID, cssValuePool().createIdentifierValue(identifier), important));
331     return true;
332 }
333 
parseDeclaration(const String & styleDeclaration,StyleSheetContents * contextStyleSheet)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 
addParsedProperties(const Vector<CSSProperty,256> & properties)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 
addParsedProperty(const CSSProperty & property)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 
asText() const362 String StylePropertySet::asText() const
363 {
364     return StylePropertySerializer(*this).asText();
365 }
366 
hasCSSOMWrapper() const367 bool StylePropertySet::hasCSSOMWrapper() const
368 {
369     return m_isMutable && toMutableStylePropertySet(this)->m_cssomWrapper;
370 }
371 
mergeAndOverrideOnConflict(const StylePropertySet * other)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 
addSubresourceStyleURLs(ListHashSet<KURL> & urls,StyleSheetContents * contextStyleSheet) const385 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 
hasFailedOrCanceledSubresources() const392 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 
blockProperties()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 
clear()438 void MutableStylePropertySet::clear()
439 {
440     m_propertyVector.clear();
441 }
442 
copyBlockProperties() const443 PassRefPtr<MutableStylePropertySet> StylePropertySet::copyBlockProperties() const
444 {
445     return copyPropertiesInSet(blockProperties());
446 }
447 
removeBlockProperties()448 void MutableStylePropertySet::removeBlockProperties()
449 {
450     removePropertiesInSet(blockProperties().data(), blockProperties().size());
451 }
452 
removePropertiesInSet(const CSSPropertyID * set,unsigned length)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 
findPropertyIndex(CSSPropertyID propertyID) const482 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 
findVariableIndex(const AtomicString & name) const497 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 
findCSSPropertyWithID(CSSPropertyID propertyID)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 
propertyMatches(CSSPropertyID propertyID,const CSSValue * propertyValue) const516 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 
removeEquivalentProperties(const StylePropertySet * style)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 
removeEquivalentProperties(const CSSStyleDeclaration * style)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 
removeVariable(const AtomicString & name)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 
clearVariables()562 bool MutableStylePropertySet::clearVariables()
563 {
564     ASSERT(RuntimeEnabledFeatures::cssVariablesEnabled());
565     CSSPropertyID variablesId = CSSPropertyVariable;
566     return removePropertiesInSet(&variablesId, 1);
567 }
568 
create(MutableStylePropertySet * propertySet)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 
addedVariable(const AtomicString & name)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 
removedVariable(const AtomicString & name)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 
clearedVariables()605 void MutableStylePropertySet::VariablesIterator::clearedVariables()
606 {
607     m_remainingNames.clear();
608     m_newNames.clear();
609 }
610 
advance()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 
mutableCopy() const621 PassRefPtr<MutableStylePropertySet> StylePropertySet::mutableCopy() const
622 {
623     return adoptRef(new MutableStylePropertySet(*this));
624 }
625 
copyPropertiesInSet(const Vector<CSSPropertyID> & properties) const626 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 
cssStyleDeclaration()638 PropertySetCSSStyleDeclaration* MutableStylePropertySet::cssStyleDeclaration()
639 {
640     return m_cssomWrapper.get();
641 }
642 
ensureCSSStyleDeclaration()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 
ensureInlineCSSStyleDeclaration(Element * parentElement)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 
averageSizeInBytes()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
showStyle()677 void StylePropertySet::showStyle()
678 {
679     fprintf(stderr, "%s\n", asText().ascii().data());
680 }
681 #endif
682 
create(CSSParserMode cssParserMode)683 PassRefPtr<MutableStylePropertySet> MutableStylePropertySet::create(CSSParserMode cssParserMode)
684 {
685     return adoptRef(new MutableStylePropertySet(cssParserMode));
686 }
687 
create(const CSSProperty * properties,unsigned count)688 PassRefPtr<MutableStylePropertySet> MutableStylePropertySet::create(const CSSProperty* properties, unsigned count)
689 {
690     return adoptRef(new MutableStylePropertySet(properties, count));
691 }
692 
cssName() const693 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 
cssText() const703 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