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/parser/BisonCSSParser.h"
28 #include "core/css/CSSValuePool.h"
29 #include "core/css/RuntimeCSSEnabled.h"
30 #include "core/css/StylePropertySerializer.h"
31 #include "core/css/StyleSheetContents.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 WebCore {
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 PassRefPtr<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 adoptRefWillBeRefCountedGarbageCollected(new (slot) ImmutableStylePropertySet(properties, count, cssParserMode));
57 }
58
immutableCopyIfNeeded() const59 PassRefPtr<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(RuntimeCSSEnabled::isCSSPropertyEnabled(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 BisonCSSParser::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
setProperty(CSSPropertyID propertyID,CSSPropertyID identifier,bool important)334 bool MutableStylePropertySet::setProperty(CSSPropertyID propertyID, CSSPropertyID identifier, bool important)
335 {
336 setProperty(CSSProperty(propertyID, cssValuePool().createIdentifierValue(identifier), important));
337 return true;
338 }
339
parseDeclaration(const String & styleDeclaration,StyleSheetContents * contextStyleSheet)340 void MutableStylePropertySet::parseDeclaration(const String& styleDeclaration, StyleSheetContents* contextStyleSheet)
341 {
342 m_propertyVector.clear();
343
344 CSSParserContext context(cssParserMode(), UseCounter::getFrom(contextStyleSheet));
345 if (contextStyleSheet) {
346 context = contextStyleSheet->parserContext();
347 context.setMode(cssParserMode());
348 }
349
350 BisonCSSParser parser(context);
351 parser.parseDeclaration(this, styleDeclaration, 0, contextStyleSheet);
352 }
353
addParsedProperties(const WillBeHeapVector<CSSProperty,256> & properties)354 void MutableStylePropertySet::addParsedProperties(const WillBeHeapVector<CSSProperty, 256>& properties)
355 {
356 m_propertyVector.reserveCapacity(m_propertyVector.size() + properties.size());
357 for (unsigned i = 0; i < properties.size(); ++i)
358 addParsedProperty(properties[i]);
359 }
360
addParsedProperty(const CSSProperty & property)361 void MutableStylePropertySet::addParsedProperty(const CSSProperty& property)
362 {
363 // Only add properties that have no !important counterpart present
364 if (!propertyIsImportant(property.id()) || property.isImportant())
365 setProperty(property);
366 }
367
asText() const368 String StylePropertySet::asText() const
369 {
370 return StylePropertySerializer(*this).asText();
371 }
372
mergeAndOverrideOnConflict(const StylePropertySet * other)373 void MutableStylePropertySet::mergeAndOverrideOnConflict(const StylePropertySet* other)
374 {
375 unsigned size = other->propertyCount();
376 for (unsigned n = 0; n < size; ++n) {
377 PropertyReference toMerge = other->propertyAt(n);
378 CSSProperty* old = findCSSPropertyWithID(toMerge.id());
379 if (old)
380 setProperty(toMerge.toCSSProperty(), old);
381 else
382 appendPrefixingVariantProperty(toMerge.toCSSProperty());
383 }
384 }
385
hasFailedOrCanceledSubresources() const386 bool StylePropertySet::hasFailedOrCanceledSubresources() const
387 {
388 unsigned size = propertyCount();
389 for (unsigned i = 0; i < size; ++i) {
390 if (propertyAt(i).value()->hasFailedOrCanceledSubresources())
391 return true;
392 }
393 return false;
394 }
395
396 // This is the list of properties we want to copy in the copyBlockProperties() function.
397 // It is the list of CSS properties that apply specially to block-level elements.
398 static const CSSPropertyID staticBlockProperties[] = {
399 CSSPropertyOrphans,
400 CSSPropertyOverflow, // This can be also be applied to replaced elements
401 CSSPropertyWebkitAspectRatio,
402 CSSPropertyWebkitColumnCount,
403 CSSPropertyWebkitColumnGap,
404 CSSPropertyWebkitColumnRuleColor,
405 CSSPropertyWebkitColumnRuleStyle,
406 CSSPropertyWebkitColumnRuleWidth,
407 CSSPropertyWebkitColumnBreakBefore,
408 CSSPropertyWebkitColumnBreakAfter,
409 CSSPropertyWebkitColumnBreakInside,
410 CSSPropertyWebkitColumnWidth,
411 CSSPropertyPageBreakAfter,
412 CSSPropertyPageBreakBefore,
413 CSSPropertyPageBreakInside,
414 CSSPropertyTextAlign,
415 CSSPropertyTextAlignLast,
416 CSSPropertyTextIndent,
417 CSSPropertyTextJustify,
418 CSSPropertyWidows
419 };
420
blockProperties()421 static const Vector<CSSPropertyID>& blockProperties()
422 {
423 DEFINE_STATIC_LOCAL(Vector<CSSPropertyID>, properties, ());
424 if (properties.isEmpty())
425 RuntimeCSSEnabled::filterEnabledCSSPropertiesIntoVector(staticBlockProperties, WTF_ARRAY_LENGTH(staticBlockProperties), properties);
426 return properties;
427 }
428
clear()429 void MutableStylePropertySet::clear()
430 {
431 m_propertyVector.clear();
432 }
433
copyBlockProperties() const434 PassRefPtrWillBeRawPtr<MutableStylePropertySet> StylePropertySet::copyBlockProperties() const
435 {
436 return copyPropertiesInSet(blockProperties());
437 }
438
removeBlockProperties()439 void MutableStylePropertySet::removeBlockProperties()
440 {
441 removePropertiesInSet(blockProperties().data(), blockProperties().size());
442 }
443
containsId(const CSSPropertyID * set,unsigned length,CSSPropertyID id)444 inline bool containsId(const CSSPropertyID* set, unsigned length, CSSPropertyID id)
445 {
446 for (unsigned i = 0; i < length; ++i) {
447 if (set[i] == id)
448 return true;
449 }
450 return false;
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 WillBeHeapVector<CSSProperty> newProperties;
459 newProperties.reserveInitialCapacity(m_propertyVector.size());
460
461 unsigned initialSize = m_propertyVector.size();
462 const CSSProperty* properties = m_propertyVector.data();
463 for (unsigned n = 0; n < initialSize; ++n) {
464 const CSSProperty& property = properties[n];
465 // Not quite sure if the isImportant test is needed but it matches the existing behavior.
466 if (!property.isImportant() && containsId(set, length, property.id()))
467 continue;
468 newProperties.append(property);
469 }
470
471 m_propertyVector = newProperties;
472 return initialSize != m_propertyVector.size();
473 }
474
findCSSPropertyWithID(CSSPropertyID propertyID)475 CSSProperty* MutableStylePropertySet::findCSSPropertyWithID(CSSPropertyID propertyID)
476 {
477 int foundPropertyIndex = findPropertyIndex(propertyID);
478 if (foundPropertyIndex == -1)
479 return 0;
480 return &m_propertyVector.at(foundPropertyIndex);
481 }
482
propertyMatches(CSSPropertyID propertyID,const CSSValue * propertyValue) const483 bool StylePropertySet::propertyMatches(CSSPropertyID propertyID, const CSSValue* propertyValue) const
484 {
485 int foundPropertyIndex = findPropertyIndex(propertyID);
486 if (foundPropertyIndex == -1)
487 return false;
488 return propertyAt(foundPropertyIndex).value()->equals(*propertyValue);
489 }
490
removeEquivalentProperties(const StylePropertySet * style)491 void MutableStylePropertySet::removeEquivalentProperties(const StylePropertySet* style)
492 {
493 Vector<CSSPropertyID> propertiesToRemove;
494 unsigned size = m_propertyVector.size();
495 for (unsigned i = 0; i < size; ++i) {
496 PropertyReference property = propertyAt(i);
497 if (style->propertyMatches(property.id(), property.value()))
498 propertiesToRemove.append(property.id());
499 }
500 // FIXME: This should use mass removal.
501 for (unsigned i = 0; i < propertiesToRemove.size(); ++i)
502 removeProperty(propertiesToRemove[i]);
503 }
504
removeEquivalentProperties(const CSSStyleDeclaration * style)505 void MutableStylePropertySet::removeEquivalentProperties(const CSSStyleDeclaration* style)
506 {
507 Vector<CSSPropertyID> propertiesToRemove;
508 unsigned size = m_propertyVector.size();
509 for (unsigned i = 0; i < size; ++i) {
510 PropertyReference property = propertyAt(i);
511 if (style->cssPropertyMatches(property.id(), property.value()))
512 propertiesToRemove.append(property.id());
513 }
514 // FIXME: This should use mass removal.
515 for (unsigned i = 0; i < propertiesToRemove.size(); ++i)
516 removeProperty(propertiesToRemove[i]);
517 }
518
mutableCopy() const519 PassRefPtrWillBeRawPtr<MutableStylePropertySet> StylePropertySet::mutableCopy() const
520 {
521 return adoptRefWillBeRefCountedGarbageCollected(new MutableStylePropertySet(*this));
522 }
523
copyPropertiesInSet(const Vector<CSSPropertyID> & properties) const524 PassRefPtrWillBeRawPtr<MutableStylePropertySet> StylePropertySet::copyPropertiesInSet(const Vector<CSSPropertyID>& properties) const
525 {
526 WillBeHeapVector<CSSProperty, 256> list;
527 list.reserveInitialCapacity(properties.size());
528 for (unsigned i = 0; i < properties.size(); ++i) {
529 RefPtrWillBeRawPtr<CSSValue> value = getPropertyCSSValue(properties[i]);
530 if (value)
531 list.append(CSSProperty(properties[i], value.release(), false));
532 }
533 return MutableStylePropertySet::create(list.data(), list.size());
534 }
535
ensureCSSStyleDeclaration()536 CSSStyleDeclaration* MutableStylePropertySet::ensureCSSStyleDeclaration()
537 {
538 // FIXME: get rid of this weirdness of a CSSStyleDeclaration inside of a
539 // style property set.
540 if (m_cssomWrapper) {
541 ASSERT(!static_cast<CSSStyleDeclaration*>(m_cssomWrapper.get())->parentRule());
542 ASSERT(!m_cssomWrapper->parentElement());
543 return m_cssomWrapper.get();
544 }
545 m_cssomWrapper = adoptPtrWillBeNoop(new PropertySetCSSStyleDeclaration(*this));
546 return m_cssomWrapper.get();
547 }
548
findPropertyIndex(CSSPropertyID propertyID) const549 int MutableStylePropertySet::findPropertyIndex(CSSPropertyID propertyID) const
550 {
551 // Convert here propertyID into an uint16_t to compare it with the metadata's m_propertyID to avoid
552 // the compiler converting it to an int multiple times in the loop.
553 uint16_t id = static_cast<uint16_t>(propertyID);
554 const CSSProperty* properties = m_propertyVector.data();
555 for (int n = m_propertyVector.size() - 1 ; n >= 0; --n) {
556 if (properties[n].metadata().m_propertyID == id) {
557 // Only enabled or internal properties should be part of the style.
558 ASSERT(RuntimeCSSEnabled::isCSSPropertyEnabled(propertyID) || isInternalProperty(propertyID));
559 return n;
560 }
561 }
562
563 return -1;
564 }
565
traceAfterDispatch(Visitor * visitor)566 void MutableStylePropertySet::traceAfterDispatch(Visitor* visitor)
567 {
568 visitor->trace(m_cssomWrapper);
569 visitor->trace(m_propertyVector);
570 StylePropertySet::traceAfterDispatch(visitor);
571 }
572
averageSizeInBytes()573 unsigned StylePropertySet::averageSizeInBytes()
574 {
575 // Please update this if the storage scheme changes so that this longer reflects the actual size.
576 return sizeForImmutableStylePropertySetWithPropertyCount(4);
577 }
578
579 // See the function above if you need to update this.
580 struct SameSizeAsStylePropertySet : public RefCountedWillBeRefCountedGarbageCollected<SameSizeAsStylePropertySet> {
581 unsigned bitfield;
582 };
583 COMPILE_ASSERT(sizeof(StylePropertySet) == sizeof(SameSizeAsStylePropertySet), style_property_set_should_stay_small);
584
585 #ifndef NDEBUG
showStyle()586 void StylePropertySet::showStyle()
587 {
588 fprintf(stderr, "%s\n", asText().ascii().data());
589 }
590 #endif
591
create(CSSParserMode cssParserMode)592 PassRefPtrWillBeRawPtr<MutableStylePropertySet> MutableStylePropertySet::create(CSSParserMode cssParserMode)
593 {
594 return adoptRefWillBeRefCountedGarbageCollected(new MutableStylePropertySet(cssParserMode));
595 }
596
create(const CSSProperty * properties,unsigned count)597 PassRefPtrWillBeRawPtr<MutableStylePropertySet> MutableStylePropertySet::create(const CSSProperty* properties, unsigned count)
598 {
599 return adoptRefWillBeRefCountedGarbageCollected(new MutableStylePropertySet(properties, count));
600 }
601
cssName() const602 String StylePropertySet::PropertyReference::cssName() const
603 {
604 return getPropertyNameString(id());
605 }
606
cssText() const607 String StylePropertySet::PropertyReference::cssText() const
608 {
609 StringBuilder result;
610 result.append(cssName());
611 result.appendLiteral(": ");
612 result.append(propertyValue()->cssText());
613 if (isImportant())
614 result.appendLiteral(" !important");
615 result.append(';');
616 return result.toString();
617 }
618
619
620 } // namespace WebCore
621