1 /* 2 * (C) 1999-2003 Lars Knoll (knoll (at) 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 45 static size_t sizeForImmutableStylePropertySetWithPropertyCount(unsigned count) 46 { 47 return sizeof(ImmutableStylePropertySet) - sizeof(void*) + sizeof(CSSValue*) * count + sizeof(StylePropertyMetadata) * count; 48 } 49 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 57 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 65 MutableStylePropertySet::MutableStylePropertySet(CSSParserMode cssParserMode) 66 : StylePropertySet(cssParserMode) 67 { 68 } 69 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 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 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 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 109 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 118 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 126 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 137 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 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 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 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 198 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 215 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 223 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 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 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 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 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 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 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 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 322 bool MutableStylePropertySet::setProperty(CSSPropertyID propertyID, CSSValueID identifier, bool important) 323 { 324 setProperty(CSSProperty(propertyID, cssValuePool().createIdentifierValue(identifier), important)); 325 return true; 326 } 327 328 bool MutableStylePropertySet::setProperty(CSSPropertyID propertyID, CSSPropertyID identifier, bool important) 329 { 330 setProperty(CSSProperty(propertyID, cssValuePool().createIdentifierValue(identifier), important)); 331 return true; 332 } 333 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 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 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 362 String StylePropertySet::asText() const 363 { 364 return StylePropertySerializer(*this).asText(); 365 } 366 367 bool StylePropertySet::hasCSSOMWrapper() const 368 { 369 return m_isMutable && toMutableStylePropertySet(this)->m_cssomWrapper; 370 } 371 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 385 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 392 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 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 438 void MutableStylePropertySet::clear() 439 { 440 m_propertyVector.clear(); 441 } 442 443 PassRefPtr<MutableStylePropertySet> StylePropertySet::copyBlockProperties() const 444 { 445 return copyPropertiesInSet(blockProperties()); 446 } 447 448 void MutableStylePropertySet::removeBlockProperties() 449 { 450 removePropertiesInSet(blockProperties().data(), blockProperties().size()); 451 } 452 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 482 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 497 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 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 516 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 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 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 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 562 bool MutableStylePropertySet::clearVariables() 563 { 564 ASSERT(RuntimeEnabledFeatures::cssVariablesEnabled()); 565 CSSPropertyID variablesId = CSSPropertyVariable; 566 return removePropertiesInSet(&variablesId, 1); 567 } 568 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 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 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 605 void MutableStylePropertySet::VariablesIterator::clearedVariables() 606 { 607 m_remainingNames.clear(); 608 m_newNames.clear(); 609 } 610 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 621 PassRefPtr<MutableStylePropertySet> StylePropertySet::mutableCopy() const 622 { 623 return adoptRef(new MutableStylePropertySet(*this)); 624 } 625 626 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 638 PropertySetCSSStyleDeclaration* MutableStylePropertySet::cssStyleDeclaration() 639 { 640 return m_cssomWrapper.get(); 641 } 642 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 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 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 677 void StylePropertySet::showStyle() 678 { 679 fprintf(stderr, "%s\n", asText().ascii().data()); 680 } 681 #endif 682 683 PassRefPtr<MutableStylePropertySet> MutableStylePropertySet::create(CSSParserMode cssParserMode) 684 { 685 return adoptRef(new MutableStylePropertySet(cssParserMode)); 686 } 687 688 PassRefPtr<MutableStylePropertySet> MutableStylePropertySet::create(const CSSProperty* properties, unsigned count) 689 { 690 return adoptRef(new MutableStylePropertySet(properties, count)); 691 } 692 693 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 703 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