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/PropertySetCSSStyleDeclaration.h" 32 #include "core/css/StylePropertySerializer.h" 33 #include "core/css/StyleSheetContents.h" 34 #include "core/page/RuntimeCSSEnabled.h" 35 #include "wtf/text/StringBuilder.h" 36 37 #ifndef NDEBUG 38 #include "wtf/text/CString.h" 39 #include <stdio.h> 40 #endif 41 42 using namespace std; 43 44 namespace WebCore { 45 46 static size_t sizeForImmutableStylePropertySetWithPropertyCount(unsigned count) 47 { 48 return sizeof(ImmutableStylePropertySet) - sizeof(void*) + sizeof(CSSValue*) * count + sizeof(StylePropertyMetadata) * count; 49 } 50 51 PassRefPtr<ImmutableStylePropertySet> ImmutableStylePropertySet::create(const CSSProperty* properties, unsigned count, CSSParserMode cssParserMode) 52 { 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 static_cast<ImmutableStylePropertySet*>(const_cast<StylePropertySet*>(this)); 61 const MutableStylePropertySet* mutableThis = static_cast<const MutableStylePropertySet*>(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(CSSStrictMode) 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 < length; ++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 = static_cast<const MutableStylePropertySet&>(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 == notFound) 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 return indexOfShorthandForLonghand(prefixedShorthand, matchingShorthandsForLonghand(prefixingVariant)); 278 } 279 280 bool MutableStylePropertySet::setVariableValue(const AtomicString& name, const String& value, bool important) 281 { 282 ASSERT(RuntimeEnabledFeatures::cssVariablesEnabled()); 283 if (value.isEmpty()) 284 return removeVariable(name); 285 286 size_t index = findVariableIndex(name); 287 if (index != notFound) { 288 CSSValue* cssValue = m_propertyVector.at(index).value(); 289 if (toCSSVariableValue(cssValue)->value() == value) 290 return false; 291 } 292 293 CSSProperty property(CSSPropertyVariable, CSSVariableValue::create(name, value), important); 294 if (index == notFound) 295 m_propertyVector.append(property); 296 else 297 m_propertyVector.at(index) = property; 298 return true; 299 } 300 301 void MutableStylePropertySet::appendPrefixingVariantProperty(const CSSProperty& property) 302 { 303 m_propertyVector.append(property); 304 CSSPropertyID prefixingVariant = prefixingVariantForPropertyId(property.id()); 305 if (prefixingVariant == property.id()) 306 return; 307 308 m_propertyVector.append(CSSProperty(prefixingVariant, property.value(), property.isImportant(), property.isSetFromShorthand(), getIndexInShorthandVectorForPrefixingVariant(property, prefixingVariant), property.metadata().m_implicit)); 309 } 310 311 void MutableStylePropertySet::setPrefixingVariantProperty(const CSSProperty& property) 312 { 313 CSSPropertyID prefixingVariant = prefixingVariantForPropertyId(property.id()); 314 CSSProperty* toReplace = findCSSPropertyWithID(prefixingVariant); 315 if (toReplace && prefixingVariant != property.id()) 316 *toReplace = CSSProperty(prefixingVariant, property.value(), property.isImportant(), property.isSetFromShorthand(), getIndexInShorthandVectorForPrefixingVariant(property, prefixingVariant), property.metadata().m_implicit); 317 } 318 319 bool MutableStylePropertySet::setProperty(CSSPropertyID propertyID, CSSValueID identifier, bool important) 320 { 321 setProperty(CSSProperty(propertyID, cssValuePool().createIdentifierValue(identifier), important)); 322 return true; 323 } 324 325 bool MutableStylePropertySet::setProperty(CSSPropertyID propertyID, CSSPropertyID identifier, bool important) 326 { 327 setProperty(CSSProperty(propertyID, cssValuePool().createIdentifierValue(identifier), important)); 328 return true; 329 } 330 331 void MutableStylePropertySet::parseDeclaration(const String& styleDeclaration, StyleSheetContents* contextStyleSheet) 332 { 333 m_propertyVector.clear(); 334 335 CSSParserContext context(cssParserMode()); 336 if (contextStyleSheet) { 337 context = contextStyleSheet->parserContext(); 338 context.mode = cssParserMode(); 339 } 340 341 CSSParser parser(context, UseCounter::getFrom(contextStyleSheet)); 342 parser.parseDeclaration(this, styleDeclaration, 0, contextStyleSheet); 343 } 344 345 void MutableStylePropertySet::addParsedProperties(const Vector<CSSProperty>& properties) 346 { 347 m_propertyVector.reserveCapacity(m_propertyVector.size() + properties.size()); 348 for (unsigned i = 0; i < properties.size(); ++i) 349 addParsedProperty(properties[i]); 350 } 351 352 void MutableStylePropertySet::addParsedProperty(const CSSProperty& property) 353 { 354 // Only add properties that have no !important counterpart present 355 if (!propertyIsImportant(property.id()) || property.isImportant()) 356 setProperty(property); 357 } 358 359 String StylePropertySet::asText() const 360 { 361 return StylePropertySerializer(*this).asText(); 362 } 363 364 bool StylePropertySet::hasCSSOMWrapper() const 365 { 366 return m_isMutable && static_cast<const MutableStylePropertySet*>(this)->m_cssomWrapper; 367 } 368 369 void MutableStylePropertySet::mergeAndOverrideOnConflict(const StylePropertySet* other) 370 { 371 unsigned size = other->propertyCount(); 372 for (unsigned n = 0; n < size; ++n) { 373 PropertyReference toMerge = other->propertyAt(n); 374 CSSProperty* old = findCSSPropertyWithID(toMerge.id()); 375 if (old) 376 setProperty(toMerge.toCSSProperty(), old); 377 else 378 appendPrefixingVariantProperty(toMerge.toCSSProperty()); 379 } 380 } 381 382 void StylePropertySet::addSubresourceStyleURLs(ListHashSet<KURL>& urls, StyleSheetContents* contextStyleSheet) const 383 { 384 unsigned size = propertyCount(); 385 for (unsigned i = 0; i < size; ++i) 386 propertyAt(i).value()->addSubresourceStyleURLs(urls, contextStyleSheet); 387 } 388 389 bool StylePropertySet::hasFailedOrCanceledSubresources() const 390 { 391 unsigned size = propertyCount(); 392 for (unsigned i = 0; i < size; ++i) { 393 if (propertyAt(i).value()->hasFailedOrCanceledSubresources()) 394 return true; 395 } 396 return false; 397 } 398 399 // This is the list of properties we want to copy in the copyBlockProperties() function. 400 // It is the list of CSS properties that apply specially to block-level elements. 401 static const CSSPropertyID staticBlockProperties[] = { 402 CSSPropertyOrphans, 403 CSSPropertyOverflow, // This can be also be applied to replaced elements 404 CSSPropertyWebkitAspectRatio, 405 CSSPropertyWebkitColumnCount, 406 CSSPropertyWebkitColumnGap, 407 CSSPropertyWebkitColumnRuleColor, 408 CSSPropertyWebkitColumnRuleStyle, 409 CSSPropertyWebkitColumnRuleWidth, 410 CSSPropertyWebkitColumnBreakBefore, 411 CSSPropertyWebkitColumnBreakAfter, 412 CSSPropertyWebkitColumnBreakInside, 413 CSSPropertyWebkitColumnWidth, 414 CSSPropertyPageBreakAfter, 415 CSSPropertyPageBreakBefore, 416 CSSPropertyPageBreakInside, 417 CSSPropertyWebkitRegionBreakAfter, 418 CSSPropertyWebkitRegionBreakBefore, 419 CSSPropertyWebkitRegionBreakInside, 420 CSSPropertyTextAlign, 421 CSSPropertyTextAlignLast, 422 CSSPropertyTextIndent, 423 CSSPropertyWidows 424 }; 425 426 static const Vector<CSSPropertyID>& blockProperties() 427 { 428 DEFINE_STATIC_LOCAL(Vector<CSSPropertyID>, properties, ()); 429 if (properties.isEmpty()) 430 RuntimeCSSEnabled::filterEnabledCSSPropertiesIntoVector(staticBlockProperties, WTF_ARRAY_LENGTH(staticBlockProperties), properties); 431 return properties; 432 } 433 434 void MutableStylePropertySet::clear() 435 { 436 m_propertyVector.clear(); 437 } 438 439 PassRefPtr<MutableStylePropertySet> StylePropertySet::copyBlockProperties() const 440 { 441 return copyPropertiesInSet(blockProperties()); 442 } 443 444 void MutableStylePropertySet::removeBlockProperties() 445 { 446 removePropertiesInSet(blockProperties().data(), blockProperties().size()); 447 } 448 449 bool MutableStylePropertySet::removePropertiesInSet(const CSSPropertyID* set, unsigned length) 450 { 451 if (m_propertyVector.isEmpty()) 452 return false; 453 454 // FIXME: This is always used with static sets and in that case constructing the hash repeatedly is pretty pointless. 455 HashSet<CSSPropertyID> toRemove; 456 for (unsigned i = 0; i < length; ++i) 457 toRemove.add(set[i]); 458 459 Vector<CSSProperty> newProperties; 460 newProperties.reserveInitialCapacity(m_propertyVector.size()); 461 462 unsigned size = m_propertyVector.size(); 463 for (unsigned n = 0; n < size; ++n) { 464 const CSSProperty& property = m_propertyVector.at(n); 465 // Not quite sure if the isImportant test is needed but it matches the existing behavior. 466 if (!property.isImportant()) { 467 if (toRemove.contains(property.id())) 468 continue; 469 } 470 newProperties.append(property); 471 } 472 473 bool changed = newProperties.size() != m_propertyVector.size(); 474 m_propertyVector = newProperties; 475 return changed; 476 } 477 478 int StylePropertySet::findPropertyIndex(CSSPropertyID propertyID) const 479 { 480 // Convert here propertyID into an uint16_t to compare it with the metadata's m_propertyID to avoid 481 // the compiler converting it to an int multiple times in the loop. 482 uint16_t id = static_cast<uint16_t>(propertyID); 483 for (int n = propertyCount() - 1 ; n >= 0; --n) { 484 if (id == propertyAt(n).propertyMetadata().m_propertyID) { 485 // Only enabled properties should be part of the style. 486 ASSERT(RuntimeCSSEnabled::isCSSPropertyEnabled(propertyID)); 487 return n; 488 } 489 } 490 return -1; 491 } 492 493 size_t StylePropertySet::findVariableIndex(const AtomicString& name) const 494 { 495 ASSERT(RuntimeEnabledFeatures::cssVariablesEnabled()); 496 for (int i = propertyCount() - 1; i >= 0; --i) { 497 const PropertyReference& property = propertyAt(i); 498 if (property.id() == CSSPropertyVariable && toCSSVariableValue(property.value())->name() == name) 499 return i; 500 } 501 return notFound; 502 } 503 504 CSSProperty* MutableStylePropertySet::findCSSPropertyWithID(CSSPropertyID propertyID) 505 { 506 int foundPropertyIndex = findPropertyIndex(propertyID); 507 if (foundPropertyIndex == -1) 508 return 0; 509 return &m_propertyVector.at(foundPropertyIndex); 510 } 511 512 bool StylePropertySet::propertyMatches(CSSPropertyID propertyID, const CSSValue* propertyValue) const 513 { 514 int foundPropertyIndex = findPropertyIndex(propertyID); 515 if (foundPropertyIndex == -1) 516 return false; 517 return propertyAt(foundPropertyIndex).value()->equals(*propertyValue); 518 } 519 520 void MutableStylePropertySet::removeEquivalentProperties(const StylePropertySet* style) 521 { 522 Vector<CSSPropertyID> propertiesToRemove; 523 unsigned size = m_propertyVector.size(); 524 for (unsigned i = 0; i < size; ++i) { 525 PropertyReference property = propertyAt(i); 526 if (style->propertyMatches(property.id(), property.value())) 527 propertiesToRemove.append(property.id()); 528 } 529 // FIXME: This should use mass removal. 530 for (unsigned i = 0; i < propertiesToRemove.size(); ++i) 531 removeProperty(propertiesToRemove[i]); 532 } 533 534 void MutableStylePropertySet::removeEquivalentProperties(const CSSStyleDeclaration* style) 535 { 536 Vector<CSSPropertyID> propertiesToRemove; 537 unsigned size = m_propertyVector.size(); 538 for (unsigned i = 0; i < size; ++i) { 539 PropertyReference property = propertyAt(i); 540 if (style->cssPropertyMatches(property.id(), property.value())) 541 propertiesToRemove.append(property.id()); 542 } 543 // FIXME: This should use mass removal. 544 for (unsigned i = 0; i < propertiesToRemove.size(); ++i) 545 removeProperty(propertiesToRemove[i]); 546 } 547 548 bool MutableStylePropertySet::removeVariable(const AtomicString& name) 549 { 550 ASSERT(RuntimeEnabledFeatures::cssVariablesEnabled()); 551 size_t index = findVariableIndex(name); 552 if (index == notFound) 553 return false; 554 m_propertyVector.remove(index); 555 return true; 556 } 557 558 bool MutableStylePropertySet::clearVariables() 559 { 560 ASSERT(RuntimeEnabledFeatures::cssVariablesEnabled()); 561 CSSPropertyID variablesId = CSSPropertyVariable; 562 return removePropertiesInSet(&variablesId, 1); 563 } 564 565 PassRefPtr<MutableStylePropertySet> StylePropertySet::mutableCopy() const 566 { 567 return adoptRef(new MutableStylePropertySet(*this)); 568 } 569 570 PassRefPtr<MutableStylePropertySet> StylePropertySet::copyPropertiesInSet(const Vector<CSSPropertyID>& properties) const 571 { 572 Vector<CSSProperty, 256> list; 573 list.reserveInitialCapacity(properties.size()); 574 for (unsigned i = 0; i < properties.size(); ++i) { 575 RefPtr<CSSValue> value = getPropertyCSSValue(properties[i]); 576 if (value) 577 list.append(CSSProperty(properties[i], value.release(), false)); 578 } 579 return MutableStylePropertySet::create(list.data(), list.size()); 580 } 581 582 PropertySetCSSStyleDeclaration* MutableStylePropertySet::cssStyleDeclaration() 583 { 584 return m_cssomWrapper.get(); 585 } 586 587 CSSStyleDeclaration* MutableStylePropertySet::ensureCSSStyleDeclaration() 588 { 589 if (m_cssomWrapper) { 590 ASSERT(!static_cast<CSSStyleDeclaration*>(m_cssomWrapper.get())->parentRule()); 591 ASSERT(!m_cssomWrapper->parentElement()); 592 return m_cssomWrapper.get(); 593 } 594 m_cssomWrapper = adoptPtr(new PropertySetCSSStyleDeclaration(this)); 595 return m_cssomWrapper.get(); 596 } 597 598 CSSStyleDeclaration* MutableStylePropertySet::ensureInlineCSSStyleDeclaration(Element* parentElement) 599 { 600 if (m_cssomWrapper) { 601 ASSERT(m_cssomWrapper->parentElement() == parentElement); 602 return m_cssomWrapper.get(); 603 } 604 m_cssomWrapper = adoptPtr(new InlineCSSStyleDeclaration(this, parentElement)); 605 return m_cssomWrapper.get(); 606 } 607 608 unsigned StylePropertySet::averageSizeInBytes() 609 { 610 // Please update this if the storage scheme changes so that this longer reflects the actual size. 611 return sizeForImmutableStylePropertySetWithPropertyCount(4); 612 } 613 614 // See the function above if you need to update this. 615 struct SameSizeAsStylePropertySet : public RefCounted<SameSizeAsStylePropertySet> { 616 unsigned bitfield; 617 }; 618 COMPILE_ASSERT(sizeof(StylePropertySet) == sizeof(SameSizeAsStylePropertySet), style_property_set_should_stay_small); 619 620 #ifndef NDEBUG 621 void StylePropertySet::showStyle() 622 { 623 fprintf(stderr, "%s\n", asText().ascii().data()); 624 } 625 #endif 626 627 PassRefPtr<MutableStylePropertySet> MutableStylePropertySet::create(CSSParserMode cssParserMode) 628 { 629 return adoptRef(new MutableStylePropertySet(cssParserMode)); 630 } 631 632 PassRefPtr<MutableStylePropertySet> MutableStylePropertySet::create(const CSSProperty* properties, unsigned count) 633 { 634 return adoptRef(new MutableStylePropertySet(properties, count)); 635 } 636 637 String StylePropertySet::PropertyReference::cssName() const 638 { 639 if (id() == CSSPropertyVariable) { 640 if (!propertyValue()->isVariableValue()) 641 return emptyString(); // Should not happen, but if it does, avoid a bad cast. 642 return "var-" + toCSSVariableValue(propertyValue())->name(); 643 } 644 return getPropertyNameString(id()); 645 } 646 647 String StylePropertySet::PropertyReference::cssText() const 648 { 649 StringBuilder result; 650 result.append(cssName()); 651 result.appendLiteral(": "); 652 result.append(propertyValue()->cssText()); 653 if (isImportant()) 654 result.appendLiteral(" !important"); 655 result.append(';'); 656 return result.toString(); 657 } 658 659 660 } // namespace WebCore 661