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