• 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 "core/StylePropertyShorthand.h"
27 #include "core/css/CSSPropertyMetadata.h"
28 #include "core/css/CSSValuePool.h"
29 #include "core/css/StylePropertySerializer.h"
30 #include "core/css/StyleSheetContents.h"
31 #include "core/css/parser/CSSParser.h"
32 #include "core/frame/UseCounter.h"
33 #include "platform/RuntimeEnabledFeatures.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 namespace blink {
42 
sizeForImmutableStylePropertySetWithPropertyCount(unsigned count)43 static size_t sizeForImmutableStylePropertySetWithPropertyCount(unsigned count)
44 {
45     return sizeof(ImmutableStylePropertySet) - sizeof(void*) + sizeof(CSSValue*) * count + sizeof(StylePropertyMetadata) * count;
46 }
47 
create(const CSSProperty * properties,unsigned count,CSSParserMode cssParserMode)48 PassRefPtrWillBeRawPtr<ImmutableStylePropertySet> ImmutableStylePropertySet::create(const CSSProperty* properties, unsigned count, CSSParserMode cssParserMode)
49 {
50     ASSERT(count <= MaxArraySize);
51 #if ENABLE(OILPAN)
52     void* slot = Heap::allocate<StylePropertySet>(sizeForImmutableStylePropertySetWithPropertyCount(count));
53 #else
54     void* slot = WTF::fastMalloc(sizeForImmutableStylePropertySetWithPropertyCount(count));
55 #endif // ENABLE(OILPAN)
56     return adoptRefWillBeNoop(new (slot) ImmutableStylePropertySet(properties, count, cssParserMode));
57 }
58 
immutableCopyIfNeeded() const59 PassRefPtrWillBeRawPtr<ImmutableStylePropertySet> StylePropertySet::immutableCopyIfNeeded() const
60 {
61     if (!isMutable())
62         return toImmutableStylePropertySet(const_cast<StylePropertySet*>(this));
63     const MutableStylePropertySet* mutableThis = toMutableStylePropertySet(this);
64     return ImmutableStylePropertySet::create(mutableThis->m_propertyVector.data(), mutableThis->m_propertyVector.size(), cssParserMode());
65 }
66 
MutableStylePropertySet(CSSParserMode cssParserMode)67 MutableStylePropertySet::MutableStylePropertySet(CSSParserMode cssParserMode)
68     : StylePropertySet(cssParserMode)
69 {
70 }
71 
MutableStylePropertySet(const CSSProperty * properties,unsigned length)72 MutableStylePropertySet::MutableStylePropertySet(const CSSProperty* properties, unsigned length)
73     : StylePropertySet(HTMLStandardMode)
74 {
75     m_propertyVector.reserveInitialCapacity(length);
76     for (unsigned i = 0; i < length; ++i)
77         m_propertyVector.uncheckedAppend(properties[i]);
78 }
79 
ImmutableStylePropertySet(const CSSProperty * properties,unsigned length,CSSParserMode cssParserMode)80 ImmutableStylePropertySet::ImmutableStylePropertySet(const CSSProperty* properties, unsigned length, CSSParserMode cssParserMode)
81     : StylePropertySet(cssParserMode, length)
82 {
83     StylePropertyMetadata* metadataArray = const_cast<StylePropertyMetadata*>(this->metadataArray());
84     RawPtrWillBeMember<CSSValue>* valueArray = const_cast<RawPtrWillBeMember<CSSValue>*>(this->valueArray());
85     for (unsigned i = 0; i < m_arraySize; ++i) {
86         metadataArray[i] = properties[i].metadata();
87         valueArray[i] = properties[i].value();
88 #if !ENABLE(OILPAN)
89         valueArray[i]->ref();
90 #endif
91     }
92 }
93 
~ImmutableStylePropertySet()94 ImmutableStylePropertySet::~ImmutableStylePropertySet()
95 {
96 #if !ENABLE(OILPAN)
97     RawPtrWillBeMember<CSSValue>* valueArray = const_cast<RawPtrWillBeMember<CSSValue>*>(this->valueArray());
98     for (unsigned i = 0; i < m_arraySize; ++i)
99         valueArray[i]->deref();
100 #endif
101 }
102 
findPropertyIndex(CSSPropertyID propertyID) const103 int ImmutableStylePropertySet::findPropertyIndex(CSSPropertyID propertyID) const
104 {
105     // Convert here propertyID into an uint16_t to compare it with the metadata's m_propertyID to avoid
106     // the compiler converting it to an int multiple times in the loop.
107     uint16_t id = static_cast<uint16_t>(propertyID);
108     for (int n = m_arraySize - 1 ; n >= 0; --n) {
109         if (metadataArray()[n].m_propertyID == id) {
110             // Only enabled or internal properties should be part of the style.
111             ASSERT(CSSPropertyMetadata::isEnabledProperty(propertyID) || isInternalProperty(propertyID));
112             return n;
113         }
114     }
115 
116     return -1;
117 }
118 
traceAfterDispatch(Visitor * visitor)119 void ImmutableStylePropertySet::traceAfterDispatch(Visitor* visitor)
120 {
121     const RawPtrWillBeMember<CSSValue>* values = valueArray();
122     for (unsigned i = 0; i < m_arraySize; i++)
123         visitor->trace(values[i]);
124     StylePropertySet::traceAfterDispatch(visitor);
125 }
126 
MutableStylePropertySet(const StylePropertySet & other)127 MutableStylePropertySet::MutableStylePropertySet(const StylePropertySet& other)
128     : StylePropertySet(other.cssParserMode())
129 {
130     if (other.isMutable()) {
131         m_propertyVector = toMutableStylePropertySet(other).m_propertyVector;
132     } else {
133         m_propertyVector.reserveInitialCapacity(other.propertyCount());
134         for (unsigned i = 0; i < other.propertyCount(); ++i)
135             m_propertyVector.uncheckedAppend(other.propertyAt(i).toCSSProperty());
136     }
137 }
138 
getPropertyValue(CSSPropertyID propertyID) const139 String StylePropertySet::getPropertyValue(CSSPropertyID propertyID) const
140 {
141     RefPtrWillBeRawPtr<CSSValue> value = getPropertyCSSValue(propertyID);
142     if (value)
143         return value->cssText();
144 
145     return StylePropertySerializer(*this).getPropertyValue(propertyID);
146 }
147 
getPropertyCSSValue(CSSPropertyID propertyID) const148 PassRefPtrWillBeRawPtr<CSSValue> StylePropertySet::getPropertyCSSValue(CSSPropertyID propertyID) const
149 {
150     int foundPropertyIndex = findPropertyIndex(propertyID);
151     if (foundPropertyIndex == -1)
152         return nullptr;
153     return propertyAt(foundPropertyIndex).value();
154 }
155 
trace(Visitor * visitor)156 void StylePropertySet::trace(Visitor* visitor)
157 {
158     if (m_isMutable)
159         toMutableStylePropertySet(this)->traceAfterDispatch(visitor);
160     else
161         toImmutableStylePropertySet(this)->traceAfterDispatch(visitor);
162 }
163 
164 #if ENABLE(OILPAN)
finalizeGarbageCollectedObject()165 void StylePropertySet::finalizeGarbageCollectedObject()
166 {
167     if (m_isMutable)
168         toMutableStylePropertySet(this)->~MutableStylePropertySet();
169     else
170         toImmutableStylePropertySet(this)->~ImmutableStylePropertySet();
171 }
172 #endif
173 
removeShorthandProperty(CSSPropertyID propertyID)174 bool MutableStylePropertySet::removeShorthandProperty(CSSPropertyID propertyID)
175 {
176     StylePropertyShorthand shorthand = shorthandForProperty(propertyID);
177     if (!shorthand.length())
178         return false;
179 
180     bool ret = removePropertiesInSet(shorthand.properties(), shorthand.length());
181 
182     CSSPropertyID prefixingVariant = prefixingVariantForPropertyId(propertyID);
183     if (prefixingVariant == propertyID)
184         return ret;
185 
186     StylePropertyShorthand shorthandPrefixingVariant = shorthandForProperty(prefixingVariant);
187     return removePropertiesInSet(shorthandPrefixingVariant.properties(), shorthandPrefixingVariant.length());
188 }
189 
removeProperty(CSSPropertyID propertyID,String * returnText)190 bool MutableStylePropertySet::removeProperty(CSSPropertyID propertyID, String* returnText)
191 {
192     if (removeShorthandProperty(propertyID)) {
193         // FIXME: Return an equivalent shorthand when possible.
194         if (returnText)
195             *returnText = "";
196         return true;
197     }
198 
199     int foundPropertyIndex = findPropertyIndex(propertyID);
200     if (foundPropertyIndex == -1) {
201         if (returnText)
202             *returnText = "";
203         return false;
204     }
205 
206     if (returnText)
207         *returnText = propertyAt(foundPropertyIndex).value()->cssText();
208 
209     // A more efficient removal strategy would involve marking entries as empty
210     // and sweeping them when the vector grows too big.
211     m_propertyVector.remove(foundPropertyIndex);
212 
213     removePrefixedOrUnprefixedProperty(propertyID);
214 
215     return true;
216 }
217 
removePrefixedOrUnprefixedProperty(CSSPropertyID propertyID)218 void MutableStylePropertySet::removePrefixedOrUnprefixedProperty(CSSPropertyID propertyID)
219 {
220     int foundPropertyIndex = findPropertyIndex(prefixingVariantForPropertyId(propertyID));
221     if (foundPropertyIndex == -1)
222         return;
223     m_propertyVector.remove(foundPropertyIndex);
224 }
225 
propertyIsImportant(CSSPropertyID propertyID) const226 bool StylePropertySet::propertyIsImportant(CSSPropertyID propertyID) const
227 {
228     int foundPropertyIndex = findPropertyIndex(propertyID);
229     if (foundPropertyIndex != -1)
230         return propertyAt(foundPropertyIndex).isImportant();
231 
232     StylePropertyShorthand shorthand = shorthandForProperty(propertyID);
233     if (!shorthand.length())
234         return false;
235 
236     for (unsigned i = 0; i < shorthand.length(); ++i) {
237         if (!propertyIsImportant(shorthand.properties()[i]))
238             return false;
239     }
240     return true;
241 }
242 
getPropertyShorthand(CSSPropertyID propertyID) const243 CSSPropertyID StylePropertySet::getPropertyShorthand(CSSPropertyID propertyID) const
244 {
245     int foundPropertyIndex = findPropertyIndex(propertyID);
246     if (foundPropertyIndex == -1)
247         return CSSPropertyInvalid;
248     return propertyAt(foundPropertyIndex).shorthandID();
249 }
250 
isPropertyImplicit(CSSPropertyID propertyID) const251 bool StylePropertySet::isPropertyImplicit(CSSPropertyID propertyID) const
252 {
253     int foundPropertyIndex = findPropertyIndex(propertyID);
254     if (foundPropertyIndex == -1)
255         return false;
256     return propertyAt(foundPropertyIndex).isImplicit();
257 }
258 
setProperty(CSSPropertyID propertyID,const String & value,bool important,StyleSheetContents * contextStyleSheet)259 bool MutableStylePropertySet::setProperty(CSSPropertyID propertyID, const String& value, bool important, StyleSheetContents* contextStyleSheet)
260 {
261     // Setting the value to an empty string just removes the property in both IE and Gecko.
262     // Setting it to null seems to produce less consistent results, but we treat it just the same.
263     if (value.isEmpty())
264         return removeProperty(propertyID);
265 
266     // When replacing an existing property value, this moves the property to the end of the list.
267     // Firefox preserves the position, and MSIE moves the property to the beginning.
268     return CSSParser::parseValue(this, propertyID, value, important, cssParserMode(), contextStyleSheet);
269 }
270 
setProperty(CSSPropertyID propertyID,PassRefPtrWillBeRawPtr<CSSValue> prpValue,bool important)271 void MutableStylePropertySet::setProperty(CSSPropertyID propertyID, PassRefPtrWillBeRawPtr<CSSValue> prpValue, bool important)
272 {
273     StylePropertyShorthand shorthand = shorthandForProperty(propertyID);
274     if (!shorthand.length()) {
275         setProperty(CSSProperty(propertyID, prpValue, important));
276         return;
277     }
278 
279     removePropertiesInSet(shorthand.properties(), shorthand.length());
280 
281     RefPtrWillBeRawPtr<CSSValue> value = prpValue;
282     for (unsigned i = 0; i < shorthand.length(); ++i)
283         m_propertyVector.append(CSSProperty(shorthand.properties()[i], value, important));
284 }
285 
setProperty(const CSSProperty & property,CSSProperty * slot)286 void MutableStylePropertySet::setProperty(const CSSProperty& property, CSSProperty* slot)
287 {
288     if (!removeShorthandProperty(property.id())) {
289         CSSProperty* toReplace = slot ? slot : findCSSPropertyWithID(property.id());
290         if (toReplace) {
291             *toReplace = property;
292             setPrefixingVariantProperty(property);
293             return;
294         }
295     }
296     appendPrefixingVariantProperty(property);
297 }
298 
getIndexInShorthandVectorForPrefixingVariant(const CSSProperty & property,CSSPropertyID prefixingVariant)299 unsigned getIndexInShorthandVectorForPrefixingVariant(const CSSProperty& property, CSSPropertyID prefixingVariant)
300 {
301     if (!property.isSetFromShorthand())
302         return 0;
303 
304     CSSPropertyID prefixedShorthand = prefixingVariantForPropertyId(property.shorthandID());
305     Vector<StylePropertyShorthand, 4> shorthands;
306     getMatchingShorthandsForLonghand(prefixingVariant, &shorthands);
307     return indexOfShorthandForLonghand(prefixedShorthand, shorthands);
308 }
309 
appendPrefixingVariantProperty(const CSSProperty & property)310 void MutableStylePropertySet::appendPrefixingVariantProperty(const CSSProperty& property)
311 {
312     m_propertyVector.append(property);
313     CSSPropertyID prefixingVariant = prefixingVariantForPropertyId(property.id());
314     if (prefixingVariant == property.id())
315         return;
316 
317     m_propertyVector.append(CSSProperty(prefixingVariant, property.value(), property.isImportant(), property.isSetFromShorthand(), getIndexInShorthandVectorForPrefixingVariant(property, prefixingVariant), property.metadata().m_implicit));
318 }
319 
setPrefixingVariantProperty(const CSSProperty & property)320 void MutableStylePropertySet::setPrefixingVariantProperty(const CSSProperty& property)
321 {
322     CSSPropertyID prefixingVariant = prefixingVariantForPropertyId(property.id());
323     CSSProperty* toReplace = findCSSPropertyWithID(prefixingVariant);
324     if (toReplace && prefixingVariant != property.id())
325         *toReplace = CSSProperty(prefixingVariant, property.value(), property.isImportant(), property.isSetFromShorthand(), getIndexInShorthandVectorForPrefixingVariant(property, prefixingVariant), property.metadata().m_implicit);
326 }
327 
setProperty(CSSPropertyID propertyID,CSSValueID identifier,bool important)328 bool MutableStylePropertySet::setProperty(CSSPropertyID propertyID, CSSValueID 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(), UseCounter::getFrom(contextStyleSheet));
339     if (contextStyleSheet) {
340         context = contextStyleSheet->parserContext();
341         context.setMode(cssParserMode());
342     }
343 
344     CSSParser parser(context);
345     parser.parseDeclaration(this, styleDeclaration, 0, contextStyleSheet);
346 }
347 
addParsedProperties(const WillBeHeapVector<CSSProperty,256> & properties)348 void MutableStylePropertySet::addParsedProperties(const WillBeHeapVector<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 
mergeAndOverrideOnConflict(const StylePropertySet * other)367 void MutableStylePropertySet::mergeAndOverrideOnConflict(const StylePropertySet* other)
368 {
369     unsigned size = other->propertyCount();
370     for (unsigned n = 0; n < size; ++n) {
371         PropertyReference toMerge = other->propertyAt(n);
372         CSSProperty* old = findCSSPropertyWithID(toMerge.id());
373         if (old)
374             setProperty(toMerge.toCSSProperty(), old);
375         else
376             appendPrefixingVariantProperty(toMerge.toCSSProperty());
377     }
378 }
379 
hasFailedOrCanceledSubresources() const380 bool StylePropertySet::hasFailedOrCanceledSubresources() const
381 {
382     unsigned size = propertyCount();
383     for (unsigned i = 0; i < size; ++i) {
384         if (propertyAt(i).value()->hasFailedOrCanceledSubresources())
385             return true;
386     }
387     return false;
388 }
389 
390 // This is the list of properties we want to copy in the copyBlockProperties() function.
391 // It is the list of CSS properties that apply specially to block-level elements.
392 static const CSSPropertyID staticBlockProperties[] = {
393     CSSPropertyOrphans,
394     CSSPropertyOverflow, // This can be also be applied to replaced elements
395     CSSPropertyWebkitAspectRatio,
396     CSSPropertyWebkitColumnCount,
397     CSSPropertyWebkitColumnGap,
398     CSSPropertyWebkitColumnRuleColor,
399     CSSPropertyWebkitColumnRuleStyle,
400     CSSPropertyWebkitColumnRuleWidth,
401     CSSPropertyWebkitColumnBreakBefore,
402     CSSPropertyWebkitColumnBreakAfter,
403     CSSPropertyWebkitColumnBreakInside,
404     CSSPropertyWebkitColumnWidth,
405     CSSPropertyPageBreakAfter,
406     CSSPropertyPageBreakBefore,
407     CSSPropertyPageBreakInside,
408     CSSPropertyTextAlign,
409     CSSPropertyTextAlignLast,
410     CSSPropertyTextIndent,
411     CSSPropertyTextJustify,
412     CSSPropertyWidows
413 };
414 
blockProperties()415 static const Vector<CSSPropertyID>& blockProperties()
416 {
417     DEFINE_STATIC_LOCAL(Vector<CSSPropertyID>, properties, ());
418     if (properties.isEmpty())
419         CSSPropertyMetadata::filterEnabledCSSPropertiesIntoVector(staticBlockProperties, WTF_ARRAY_LENGTH(staticBlockProperties), properties);
420     return properties;
421 }
422 
clear()423 void MutableStylePropertySet::clear()
424 {
425     m_propertyVector.clear();
426 }
427 
copyBlockProperties() const428 PassRefPtrWillBeRawPtr<MutableStylePropertySet> StylePropertySet::copyBlockProperties() const
429 {
430     return copyPropertiesInSet(blockProperties());
431 }
432 
removeBlockProperties()433 void MutableStylePropertySet::removeBlockProperties()
434 {
435     removePropertiesInSet(blockProperties().data(), blockProperties().size());
436 }
437 
containsId(const CSSPropertyID * set,unsigned length,CSSPropertyID id)438 inline bool containsId(const CSSPropertyID* set, unsigned length, CSSPropertyID id)
439 {
440     for (unsigned i = 0; i < length; ++i) {
441         if (set[i] == id)
442             return true;
443     }
444     return false;
445 }
446 
removePropertiesInSet(const CSSPropertyID * set,unsigned length)447 bool MutableStylePropertySet::removePropertiesInSet(const CSSPropertyID* set, unsigned length)
448 {
449     if (m_propertyVector.isEmpty())
450         return false;
451 
452     WillBeHeapVector<CSSProperty> newProperties;
453     newProperties.reserveInitialCapacity(m_propertyVector.size());
454 
455     unsigned initialSize = m_propertyVector.size();
456     const CSSProperty* properties = m_propertyVector.data();
457     for (unsigned n = 0; n < initialSize; ++n) {
458         const CSSProperty& property = properties[n];
459         // Not quite sure if the isImportant test is needed but it matches the existing behavior.
460         if (!property.isImportant() && containsId(set, length, property.id()))
461             continue;
462         newProperties.append(property);
463     }
464 
465     m_propertyVector = newProperties;
466     return initialSize != m_propertyVector.size();
467 }
468 
findCSSPropertyWithID(CSSPropertyID propertyID)469 CSSProperty* MutableStylePropertySet::findCSSPropertyWithID(CSSPropertyID propertyID)
470 {
471     int foundPropertyIndex = findPropertyIndex(propertyID);
472     if (foundPropertyIndex == -1)
473         return 0;
474     return &m_propertyVector.at(foundPropertyIndex);
475 }
476 
propertyMatches(CSSPropertyID propertyID,const CSSValue * propertyValue) const477 bool StylePropertySet::propertyMatches(CSSPropertyID propertyID, const CSSValue* propertyValue) const
478 {
479     int foundPropertyIndex = findPropertyIndex(propertyID);
480     if (foundPropertyIndex == -1)
481         return false;
482     return propertyAt(foundPropertyIndex).value()->equals(*propertyValue);
483 }
484 
removeEquivalentProperties(const StylePropertySet * style)485 void MutableStylePropertySet::removeEquivalentProperties(const StylePropertySet* style)
486 {
487     Vector<CSSPropertyID> propertiesToRemove;
488     unsigned size = m_propertyVector.size();
489     for (unsigned i = 0; i < size; ++i) {
490         PropertyReference property = propertyAt(i);
491         if (style->propertyMatches(property.id(), property.value()))
492             propertiesToRemove.append(property.id());
493     }
494     // FIXME: This should use mass removal.
495     for (unsigned i = 0; i < propertiesToRemove.size(); ++i)
496         removeProperty(propertiesToRemove[i]);
497 }
498 
removeEquivalentProperties(const CSSStyleDeclaration * style)499 void MutableStylePropertySet::removeEquivalentProperties(const CSSStyleDeclaration* style)
500 {
501     Vector<CSSPropertyID> propertiesToRemove;
502     unsigned size = m_propertyVector.size();
503     for (unsigned i = 0; i < size; ++i) {
504         PropertyReference property = propertyAt(i);
505         if (style->cssPropertyMatches(property.id(), property.value()))
506             propertiesToRemove.append(property.id());
507     }
508     // FIXME: This should use mass removal.
509     for (unsigned i = 0; i < propertiesToRemove.size(); ++i)
510         removeProperty(propertiesToRemove[i]);
511 }
512 
mutableCopy() const513 PassRefPtrWillBeRawPtr<MutableStylePropertySet> StylePropertySet::mutableCopy() const
514 {
515     return adoptRefWillBeNoop(new MutableStylePropertySet(*this));
516 }
517 
copyPropertiesInSet(const Vector<CSSPropertyID> & properties) const518 PassRefPtrWillBeRawPtr<MutableStylePropertySet> StylePropertySet::copyPropertiesInSet(const Vector<CSSPropertyID>& properties) const
519 {
520     WillBeHeapVector<CSSProperty, 256> list;
521     list.reserveInitialCapacity(properties.size());
522     for (unsigned i = 0; i < properties.size(); ++i) {
523         RefPtrWillBeRawPtr<CSSValue> value = getPropertyCSSValue(properties[i]);
524         if (value)
525             list.append(CSSProperty(properties[i], value.release(), false));
526     }
527     return MutableStylePropertySet::create(list.data(), list.size());
528 }
529 
ensureCSSStyleDeclaration()530 CSSStyleDeclaration* MutableStylePropertySet::ensureCSSStyleDeclaration()
531 {
532     // FIXME: get rid of this weirdness of a CSSStyleDeclaration inside of a
533     // style property set.
534     if (m_cssomWrapper) {
535         ASSERT(!static_cast<CSSStyleDeclaration*>(m_cssomWrapper.get())->parentRule());
536         ASSERT(!m_cssomWrapper->parentElement());
537         return m_cssomWrapper.get();
538     }
539     m_cssomWrapper = adoptPtrWillBeNoop(new PropertySetCSSStyleDeclaration(*this));
540     return m_cssomWrapper.get();
541 }
542 
findPropertyIndex(CSSPropertyID propertyID) const543 int MutableStylePropertySet::findPropertyIndex(CSSPropertyID propertyID) const
544 {
545     // Convert here propertyID into an uint16_t to compare it with the metadata's m_propertyID to avoid
546     // the compiler converting it to an int multiple times in the loop.
547     uint16_t id = static_cast<uint16_t>(propertyID);
548     const CSSProperty* properties = m_propertyVector.data();
549     for (int n = m_propertyVector.size() - 1 ; n >= 0; --n) {
550         if (properties[n].metadata().m_propertyID == id) {
551             // Only enabled or internal properties should be part of the style.
552             ASSERT(CSSPropertyMetadata::isEnabledProperty(propertyID) || isInternalProperty(propertyID));
553             return n;
554         }
555     }
556 
557     return -1;
558 }
559 
traceAfterDispatch(Visitor * visitor)560 void MutableStylePropertySet::traceAfterDispatch(Visitor* visitor)
561 {
562     visitor->trace(m_cssomWrapper);
563     visitor->trace(m_propertyVector);
564     StylePropertySet::traceAfterDispatch(visitor);
565 }
566 
averageSizeInBytes()567 unsigned StylePropertySet::averageSizeInBytes()
568 {
569     // Please update this if the storage scheme changes so that this longer reflects the actual size.
570     return sizeForImmutableStylePropertySetWithPropertyCount(4);
571 }
572 
573 // See the function above if you need to update this.
574 struct SameSizeAsStylePropertySet : public RefCountedWillBeGarbageCollectedFinalized<SameSizeAsStylePropertySet> {
575     unsigned bitfield;
576 };
577 COMPILE_ASSERT(sizeof(StylePropertySet) == sizeof(SameSizeAsStylePropertySet), style_property_set_should_stay_small);
578 
579 #ifndef NDEBUG
showStyle()580 void StylePropertySet::showStyle()
581 {
582     fprintf(stderr, "%s\n", asText().ascii().data());
583 }
584 #endif
585 
create(CSSParserMode cssParserMode)586 PassRefPtrWillBeRawPtr<MutableStylePropertySet> MutableStylePropertySet::create(CSSParserMode cssParserMode)
587 {
588     return adoptRefWillBeNoop(new MutableStylePropertySet(cssParserMode));
589 }
590 
create(const CSSProperty * properties,unsigned count)591 PassRefPtrWillBeRawPtr<MutableStylePropertySet> MutableStylePropertySet::create(const CSSProperty* properties, unsigned count)
592 {
593     return adoptRefWillBeNoop(new MutableStylePropertySet(properties, count));
594 }
595 
cssName() const596 String StylePropertySet::PropertyReference::cssName() const
597 {
598     return getPropertyNameString(id());
599 }
600 
cssText() const601 String StylePropertySet::PropertyReference::cssText() const
602 {
603     StringBuilder result;
604     result.append(cssName());
605     result.appendLiteral(": ");
606     result.append(propertyValue()->cssText());
607     if (isImportant())
608         result.appendLiteral(" !important");
609     result.append(';');
610     return result.toString();
611 }
612 
613 
614 } // namespace blink
615