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 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Library General Public 8 * License as published by the Free Software Foundation; either 9 * version 2 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Library General Public License for more details. 15 * 16 * You should have received a copy of the GNU Library General Public License 17 * along with this library; see the file COPYING.LIB. If not, write to 18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 * Boston, MA 02110-1301, USA. 20 */ 21 22#include "config.h" 23#include "StylePropertySet.h" 24 25#include "CSSComputedStyleDeclaration.h" 26#include "CSSParser.h" 27#include "CSSValueKeywords.h" 28#include "CSSValueList.h" 29#include "CSSValuePool.h" 30#include "Document.h" 31#include "PropertySetCSSStyleDeclaration.h" 32#include "StylePropertyShorthand.h" 33#include "StyleSheetContents.h" 34#include <wtf/BitArray.h> 35#include <wtf/text/StringBuilder.h> 36 37#if ENABLE(CSS_VARIABLES) 38#include "CSSVariableValue.h" 39#endif 40 41#ifndef NDEBUG 42#include <stdio.h> 43#include <wtf/ASCIICType.h> 44#include <wtf/text/CString.h> 45#endif 46 47using namespace std; 48 49namespace WebCore { 50 51typedef HashMap<MutableStylePropertySet*, OwnPtr<PropertySetCSSStyleDeclaration> > PropertySetCSSOMWrapperMap; 52static PropertySetCSSOMWrapperMap& propertySetCSSOMWrapperMap() 53{ 54 DEFINE_STATIC_LOCAL(PropertySetCSSOMWrapperMap, propertySetCSSOMWrapperMapInstance, ()); 55 return propertySetCSSOMWrapperMapInstance; 56} 57 58static size_t sizeForImmutableStylePropertySetWithPropertyCount(unsigned count) 59{ 60 return sizeof(ImmutableStylePropertySet) - sizeof(void*) + sizeof(CSSValue*) * count + sizeof(StylePropertyMetadata) * count; 61} 62 63static bool isInitialOrInherit(const String& value) 64{ 65 DEFINE_STATIC_LOCAL(String, initial, ("initial")); 66 DEFINE_STATIC_LOCAL(String, inherit, ("inherit")); 67 return value.length() == 7 && (value == initial || value == inherit); 68} 69 70PassRefPtr<ImmutableStylePropertySet> ImmutableStylePropertySet::create(const CSSProperty* properties, unsigned count, CSSParserMode cssParserMode) 71{ 72 void* slot = WTF::fastMalloc(sizeForImmutableStylePropertySetWithPropertyCount(count)); 73 return adoptRef(new (NotNull, slot) ImmutableStylePropertySet(properties, count, cssParserMode)); 74} 75 76PassRefPtr<ImmutableStylePropertySet> StylePropertySet::immutableCopyIfNeeded() const 77{ 78 if (!isMutable()) 79 return static_cast<ImmutableStylePropertySet*>(const_cast<StylePropertySet*>(this)); 80 const MutableStylePropertySet* mutableThis = static_cast<const MutableStylePropertySet*>(this); 81 return ImmutableStylePropertySet::create(mutableThis->m_propertyVector.data(), mutableThis->m_propertyVector.size(), cssParserMode()); 82} 83 84MutableStylePropertySet::MutableStylePropertySet(const CSSProperty* properties, unsigned length) 85 : StylePropertySet(CSSStrictMode) 86{ 87 m_propertyVector.reserveInitialCapacity(length); 88 for (unsigned i = 0; i < length; ++i) 89 m_propertyVector.uncheckedAppend(properties[i]); 90} 91 92ImmutableStylePropertySet::ImmutableStylePropertySet(const CSSProperty* properties, unsigned length, CSSParserMode cssParserMode) 93 : StylePropertySet(cssParserMode, length) 94{ 95 StylePropertyMetadata* metadataArray = const_cast<StylePropertyMetadata*>(this->metadataArray()); 96 CSSValue** valueArray = const_cast<CSSValue**>(this->valueArray()); 97 for (unsigned i = 0; i < length; ++i) { 98 metadataArray[i] = properties[i].metadata(); 99 valueArray[i] = properties[i].value(); 100 valueArray[i]->ref(); 101 } 102} 103 104ImmutableStylePropertySet::~ImmutableStylePropertySet() 105{ 106 CSSValue** valueArray = const_cast<CSSValue**>(this->valueArray()); 107 for (unsigned i = 0; i < m_arraySize; ++i) 108 valueArray[i]->deref(); 109} 110 111MutableStylePropertySet::MutableStylePropertySet(const StylePropertySet& other) 112 : StylePropertySet(other.cssParserMode()) 113{ 114 if (other.isMutable()) 115 m_propertyVector = static_cast<const MutableStylePropertySet&>(other).m_propertyVector; 116 else { 117 m_propertyVector.reserveInitialCapacity(other.propertyCount()); 118 for (unsigned i = 0; i < other.propertyCount(); ++i) 119 m_propertyVector.uncheckedAppend(other.propertyAt(i).toCSSProperty()); 120 } 121} 122 123MutableStylePropertySet::~MutableStylePropertySet() 124{ 125 ASSERT(!m_ownsCSSOMWrapper || propertySetCSSOMWrapperMap().contains(this)); 126 if (m_ownsCSSOMWrapper) 127 propertySetCSSOMWrapperMap().remove(this); 128} 129 130String StylePropertySet::getPropertyValue(CSSPropertyID propertyID) const 131{ 132 RefPtr<CSSValue> value = getPropertyCSSValue(propertyID); 133 if (value) 134 return value->cssText(); 135 136 // Shorthand and 4-values properties 137 switch (propertyID) { 138 case CSSPropertyBorderSpacing: 139 return borderSpacingValue(borderSpacingShorthand()); 140 case CSSPropertyBackgroundPosition: 141 return getLayeredShorthandValue(backgroundPositionShorthand()); 142 case CSSPropertyBackgroundRepeat: 143 return getLayeredShorthandValue(backgroundRepeatShorthand()); 144 case CSSPropertyBackground: 145 return getLayeredShorthandValue(backgroundShorthand()); 146 case CSSPropertyBorder: 147 return borderPropertyValue(OmitUncommonValues); 148 case CSSPropertyBorderTop: 149 return getShorthandValue(borderTopShorthand()); 150 case CSSPropertyBorderRight: 151 return getShorthandValue(borderRightShorthand()); 152 case CSSPropertyBorderBottom: 153 return getShorthandValue(borderBottomShorthand()); 154 case CSSPropertyBorderLeft: 155 return getShorthandValue(borderLeftShorthand()); 156 case CSSPropertyOutline: 157 return getShorthandValue(outlineShorthand()); 158 case CSSPropertyBorderColor: 159 return get4Values(borderColorShorthand()); 160 case CSSPropertyBorderWidth: 161 return get4Values(borderWidthShorthand()); 162 case CSSPropertyBorderStyle: 163 return get4Values(borderStyleShorthand()); 164 case CSSPropertyWebkitColumnRule: 165 return getShorthandValue(webkitColumnRuleShorthand()); 166 case CSSPropertyWebkitColumns: 167 return getShorthandValue(webkitColumnsShorthand()); 168 case CSSPropertyWebkitFlex: 169 return getShorthandValue(webkitFlexShorthand()); 170 case CSSPropertyWebkitFlexFlow: 171 return getShorthandValue(webkitFlexFlowShorthand()); 172 case CSSPropertyWebkitGridColumn: 173 return getShorthandValue(webkitGridColumnShorthand()); 174 case CSSPropertyWebkitGridRow: 175 return getShorthandValue(webkitGridRowShorthand()); 176 case CSSPropertyFont: 177 return fontValue(); 178 case CSSPropertyMargin: 179 return get4Values(marginShorthand()); 180 case CSSPropertyWebkitMarginCollapse: 181 return getShorthandValue(webkitMarginCollapseShorthand()); 182 case CSSPropertyOverflow: 183 return getCommonValue(overflowShorthand()); 184 case CSSPropertyPadding: 185 return get4Values(paddingShorthand()); 186 case CSSPropertyTransition: 187 return getLayeredShorthandValue(transitionShorthand()); 188 case CSSPropertyListStyle: 189 return getShorthandValue(listStyleShorthand()); 190 case CSSPropertyWebkitMarquee: 191 return getShorthandValue(webkitMarqueeShorthand()); 192 case CSSPropertyWebkitMaskPosition: 193 return getLayeredShorthandValue(webkitMaskPositionShorthand()); 194 case CSSPropertyWebkitMaskRepeat: 195 return getLayeredShorthandValue(webkitMaskRepeatShorthand()); 196 case CSSPropertyWebkitMask: 197 return getLayeredShorthandValue(webkitMaskShorthand()); 198 case CSSPropertyWebkitTextEmphasis: 199 return getShorthandValue(webkitTextEmphasisShorthand()); 200 case CSSPropertyWebkitTextStroke: 201 return getShorthandValue(webkitTextStrokeShorthand()); 202 case CSSPropertyWebkitTransformOrigin: 203 return getShorthandValue(webkitTransformOriginShorthand()); 204 case CSSPropertyWebkitTransition: 205 return getLayeredShorthandValue(webkitTransitionShorthand()); 206 case CSSPropertyWebkitAnimation: 207 return getLayeredShorthandValue(webkitAnimationShorthand()); 208#if ENABLE(SVG) 209 case CSSPropertyMarker: { 210 RefPtr<CSSValue> value = getPropertyCSSValue(CSSPropertyMarkerStart); 211 if (value) 212 return value->cssText(); 213 return String(); 214 } 215#endif 216 case CSSPropertyBorderRadius: 217 return get4Values(borderRadiusShorthand()); 218 default: 219 return String(); 220 } 221} 222 223String StylePropertySet::borderSpacingValue(const StylePropertyShorthand& shorthand) const 224{ 225 RefPtr<CSSValue> horizontalValue = getPropertyCSSValue(shorthand.properties()[0]); 226 RefPtr<CSSValue> verticalValue = getPropertyCSSValue(shorthand.properties()[1]); 227 228 // While standard border-spacing property does not allow specifying border-spacing-vertical without 229 // specifying border-spacing-horizontal <http://www.w3.org/TR/CSS21/tables.html#separated-borders>, 230 // -webkit-border-spacing-vertical can be set without -webkit-border-spacing-horizontal. 231 if (!horizontalValue || !verticalValue) 232 return String(); 233 234 String horizontalValueCSSText = horizontalValue->cssText(); 235 String verticalValueCSSText = verticalValue->cssText(); 236 if (horizontalValueCSSText == verticalValueCSSText) 237 return horizontalValueCSSText; 238 return horizontalValueCSSText + ' ' + verticalValueCSSText; 239} 240 241void StylePropertySet::appendFontLonghandValueIfExplicit(CSSPropertyID propertyID, StringBuilder& result, String& commonValue) const 242{ 243 int foundPropertyIndex = findPropertyIndex(propertyID); 244 if (foundPropertyIndex == -1) 245 return; // All longhands must have at least implicit values if "font" is specified. 246 247 if (propertyAt(foundPropertyIndex).isImplicit()) { 248 commonValue = String(); 249 return; 250 } 251 252 char prefix = '\0'; 253 switch (propertyID) { 254 case CSSPropertyFontStyle: 255 break; // No prefix. 256 case CSSPropertyFontFamily: 257 case CSSPropertyFontVariant: 258 case CSSPropertyFontWeight: 259 prefix = ' '; 260 break; 261 case CSSPropertyLineHeight: 262 prefix = '/'; 263 break; 264 default: 265 ASSERT_NOT_REACHED(); 266 } 267 268 if (prefix && !result.isEmpty()) 269 result.append(prefix); 270 String value = propertyAt(foundPropertyIndex).value()->cssText(); 271 result.append(value); 272 if (!commonValue.isNull() && commonValue != value) 273 commonValue = String(); 274} 275 276String StylePropertySet::fontValue() const 277{ 278 int fontSizePropertyIndex = findPropertyIndex(CSSPropertyFontSize); 279 int fontFamilyPropertyIndex = findPropertyIndex(CSSPropertyFontFamily); 280 if (fontSizePropertyIndex == -1 || fontFamilyPropertyIndex == -1) 281 return emptyString(); 282 283 PropertyReference fontSizeProperty = propertyAt(fontSizePropertyIndex); 284 PropertyReference fontFamilyProperty = propertyAt(fontFamilyPropertyIndex); 285 if (fontSizeProperty.isImplicit() || fontFamilyProperty.isImplicit()) 286 return emptyString(); 287 288 String commonValue = fontSizeProperty.value()->cssText(); 289 StringBuilder result; 290 appendFontLonghandValueIfExplicit(CSSPropertyFontStyle, result, commonValue); 291 appendFontLonghandValueIfExplicit(CSSPropertyFontVariant, result, commonValue); 292 appendFontLonghandValueIfExplicit(CSSPropertyFontWeight, result, commonValue); 293 if (!result.isEmpty()) 294 result.append(' '); 295 result.append(fontSizeProperty.value()->cssText()); 296 appendFontLonghandValueIfExplicit(CSSPropertyLineHeight, result, commonValue); 297 if (!result.isEmpty()) 298 result.append(' '); 299 result.append(fontFamilyProperty.value()->cssText()); 300 if (isInitialOrInherit(commonValue)) 301 return commonValue; 302 return result.toString(); 303} 304 305String StylePropertySet::get4Values(const StylePropertyShorthand& shorthand) const 306{ 307 // Assume the properties are in the usual order top, right, bottom, left. 308 int topValueIndex = findPropertyIndex(shorthand.properties()[0]); 309 int rightValueIndex = findPropertyIndex(shorthand.properties()[1]); 310 int bottomValueIndex = findPropertyIndex(shorthand.properties()[2]); 311 int leftValueIndex = findPropertyIndex(shorthand.properties()[3]); 312 313 if (topValueIndex == -1 || rightValueIndex == -1 || bottomValueIndex == -1 || leftValueIndex == -1) 314 return String(); 315 316 PropertyReference top = propertyAt(topValueIndex); 317 PropertyReference right = propertyAt(rightValueIndex); 318 PropertyReference bottom = propertyAt(bottomValueIndex); 319 PropertyReference left = propertyAt(leftValueIndex); 320 321 // All 4 properties must be specified. 322 if (!top.value() || !right.value() || !bottom.value() || !left.value()) 323 return String(); 324 325 if (top.isInherited() && right.isInherited() && bottom.isInherited() && left.isInherited()) 326 return getValueName(CSSValueInherit); 327 328 if (top.value()->isInitialValue() || right.value()->isInitialValue() || bottom.value()->isInitialValue() || left.value()->isInitialValue()) { 329 if (top.value()->isInitialValue() && right.value()->isInitialValue() && bottom.value()->isInitialValue() && left.value()->isInitialValue() && !top.isImplicit()) { 330 // All components are "initial" and "top" is not implicit. 331 return getValueName(CSSValueInitial); 332 } 333 return String(); 334 } 335 if (top.isImportant() != right.isImportant() || right.isImportant() != bottom.isImportant() || bottom.isImportant() != left.isImportant()) 336 return String(); 337 338 bool showLeft = !right.value()->equals(*left.value()); 339 bool showBottom = !top.value()->equals(*bottom.value()) || showLeft; 340 bool showRight = !top.value()->equals(*right.value()) || showBottom; 341 342 StringBuilder result; 343 result.append(top.value()->cssText()); 344 if (showRight) { 345 result.append(' '); 346 result.append(right.value()->cssText()); 347 } 348 if (showBottom) { 349 result.append(' '); 350 result.append(bottom.value()->cssText()); 351 } 352 if (showLeft) { 353 result.append(' '); 354 result.append(left.value()->cssText()); 355 } 356 return result.toString(); 357} 358 359String StylePropertySet::getLayeredShorthandValue(const StylePropertyShorthand& shorthand) const 360{ 361 StringBuilder result; 362 363 const unsigned size = shorthand.length(); 364 // Begin by collecting the properties into an array. 365 Vector< RefPtr<CSSValue> > values(size); 366 size_t numLayers = 0; 367 368 for (unsigned i = 0; i < size; ++i) { 369 values[i] = getPropertyCSSValue(shorthand.properties()[i]); 370 if (values[i]) { 371 if (values[i]->isBaseValueList()) { 372 CSSValueList* valueList = static_cast<CSSValueList*>(values[i].get()); 373 numLayers = max(valueList->length(), numLayers); 374 } else 375 numLayers = max<size_t>(1U, numLayers); 376 } 377 } 378 379 String commonValue; 380 bool commonValueInitialized = false; 381 382 // Now stitch the properties together. Implicit initial values are flagged as such and 383 // can safely be omitted. 384 for (size_t i = 0; i < numLayers; i++) { 385 StringBuilder layerResult; 386 bool useRepeatXShorthand = false; 387 bool useRepeatYShorthand = false; 388 bool useSingleWordShorthand = false; 389 bool foundPositionYCSSProperty = false; 390 for (unsigned j = 0; j < size; j++) { 391 RefPtr<CSSValue> value; 392 if (values[j]) { 393 if (values[j]->isBaseValueList()) 394 value = static_cast<CSSValueList*>(values[j].get())->item(i); 395 else { 396 value = values[j]; 397 398 // Color only belongs in the last layer. 399 if (shorthand.properties()[j] == CSSPropertyBackgroundColor) { 400 if (i != numLayers - 1) 401 value = 0; 402 } else if (i != 0) // Other singletons only belong in the first layer. 403 value = 0; 404 } 405 } 406 407 // We need to report background-repeat as it was written in the CSS. If the property is implicit, 408 // then it was written with only one value. Here we figure out which value that was so we can 409 // report back correctly. 410 if ((shorthand.properties()[j] == CSSPropertyBackgroundRepeatX && isPropertyImplicit(shorthand.properties()[j])) 411 || (shorthand.properties()[j] == CSSPropertyWebkitMaskRepeatX && isPropertyImplicit(shorthand.properties()[j]))) { 412 413 // BUG 49055: make sure the value was not reset in the layer check just above. 414 if ((j < size - 1 && shorthand.properties()[j + 1] == CSSPropertyBackgroundRepeatY && value) 415 || (j < size - 1 && shorthand.properties()[j + 1] == CSSPropertyWebkitMaskRepeatY && value)) { 416 RefPtr<CSSValue> yValue; 417 RefPtr<CSSValue> nextValue = values[j + 1]; 418 if (nextValue->isValueList()) 419 yValue = static_cast<CSSValueList*>(nextValue.get())->itemWithoutBoundsCheck(i); 420 else 421 yValue = nextValue; 422 423 if (!value->isPrimitiveValue() || !yValue->isPrimitiveValue()) 424 continue; 425 426 int xId = static_cast<CSSPrimitiveValue*>(value.get())->getIdent(); 427 int yId = static_cast<CSSPrimitiveValue*>(yValue.get())->getIdent(); 428 if (xId != yId) { 429 if (xId == CSSValueRepeat && yId == CSSValueNoRepeat) { 430 useRepeatXShorthand = true; 431 ++j; 432 } else if (xId == CSSValueNoRepeat && yId == CSSValueRepeat) { 433 useRepeatYShorthand = true; 434 continue; 435 } 436 } else { 437 useSingleWordShorthand = true; 438 ++j; 439 } 440 } 441 } 442 443 String valueText; 444 if (value && !value->isImplicitInitialValue()) { 445 if (!layerResult.isEmpty()) 446 layerResult.append(' '); 447 if (foundPositionYCSSProperty 448 && (shorthand.properties()[j] == CSSPropertyBackgroundSize || shorthand.properties()[j] == CSSPropertyWebkitMaskSize)) 449 layerResult.appendLiteral("/ "); 450 if (!foundPositionYCSSProperty 451 && (shorthand.properties()[j] == CSSPropertyBackgroundSize || shorthand.properties()[j] == CSSPropertyWebkitMaskSize)) 452 continue; 453 454 if (useRepeatXShorthand) { 455 useRepeatXShorthand = false; 456 layerResult.append(getValueName(CSSValueRepeatX)); 457 } else if (useRepeatYShorthand) { 458 useRepeatYShorthand = false; 459 layerResult.append(getValueName(CSSValueRepeatY)); 460 } else { 461 if (useSingleWordShorthand) 462 useSingleWordShorthand = false; 463 valueText = value->cssText(); 464 layerResult.append(valueText); 465 } 466 467 if (shorthand.properties()[j] == CSSPropertyBackgroundPositionY 468 || shorthand.properties()[j] == CSSPropertyWebkitMaskPositionY) { 469 foundPositionYCSSProperty = true; 470 471 // background-position is a special case: if only the first offset is specified, 472 // the second one defaults to "center", not the same value. 473 if (commonValueInitialized && commonValue != "initial" && commonValue != "inherit") 474 commonValue = String(); 475 } 476 } 477 478 if (!commonValueInitialized) { 479 commonValue = valueText; 480 commonValueInitialized = true; 481 } else if (!commonValue.isNull() && commonValue != valueText) 482 commonValue = String(); 483 } 484 485 if (!layerResult.isEmpty()) { 486 if (!result.isEmpty()) 487 result.appendLiteral(", "); 488 result.append(layerResult); 489 } 490 } 491 492 if (isInitialOrInherit(commonValue)) 493 return commonValue; 494 495 if (result.isEmpty()) 496 return String(); 497 return result.toString(); 498} 499 500String StylePropertySet::getShorthandValue(const StylePropertyShorthand& shorthand) const 501{ 502 String commonValue; 503 StringBuilder result; 504 for (unsigned i = 0; i < shorthand.length(); ++i) { 505 if (!isPropertyImplicit(shorthand.properties()[i])) { 506 RefPtr<CSSValue> value = getPropertyCSSValue(shorthand.properties()[i]); 507 if (!value) 508 return String(); 509 String valueText = value->cssText(); 510 if (!i) 511 commonValue = valueText; 512 else if (!commonValue.isNull() && commonValue != valueText) 513 commonValue = String(); 514 if (value->isInitialValue()) 515 continue; 516 if (!result.isEmpty()) 517 result.append(' '); 518 result.append(valueText); 519 } else 520 commonValue = String(); 521 } 522 if (isInitialOrInherit(commonValue)) 523 return commonValue; 524 if (result.isEmpty()) 525 return String(); 526 return result.toString(); 527} 528 529// only returns a non-null value if all properties have the same, non-null value 530String StylePropertySet::getCommonValue(const StylePropertyShorthand& shorthand) const 531{ 532 String res; 533 bool lastPropertyWasImportant = false; 534 for (unsigned i = 0; i < shorthand.length(); ++i) { 535 RefPtr<CSSValue> value = getPropertyCSSValue(shorthand.properties()[i]); 536 // FIXME: CSSInitialValue::cssText should generate the right value. 537 if (!value) 538 return String(); 539 String text = value->cssText(); 540 if (text.isNull()) 541 return String(); 542 if (res.isNull()) 543 res = text; 544 else if (res != text) 545 return String(); 546 547 bool currentPropertyIsImportant = propertyIsImportant(shorthand.properties()[i]); 548 if (i && lastPropertyWasImportant != currentPropertyIsImportant) 549 return String(); 550 lastPropertyWasImportant = currentPropertyIsImportant; 551 } 552 return res; 553} 554 555String StylePropertySet::borderPropertyValue(CommonValueMode valueMode) const 556{ 557 const StylePropertyShorthand properties[3] = { borderWidthShorthand(), borderStyleShorthand(), borderColorShorthand() }; 558 String commonValue; 559 StringBuilder result; 560 for (size_t i = 0; i < WTF_ARRAY_LENGTH(properties); ++i) { 561 String value = getCommonValue(properties[i]); 562 if (value.isNull()) { 563 if (valueMode == ReturnNullOnUncommonValues) 564 return String(); 565 ASSERT(valueMode == OmitUncommonValues); 566 continue; 567 } 568 if (!i) 569 commonValue = value; 570 else if (!commonValue.isNull() && commonValue != value) 571 commonValue = String(); 572 if (value == "initial") 573 continue; 574 if (!result.isEmpty()) 575 result.append(' '); 576 result.append(value); 577 } 578 if (isInitialOrInherit(commonValue)) 579 return commonValue; 580 return result.isEmpty() ? String() : result.toString(); 581} 582 583PassRefPtr<CSSValue> StylePropertySet::getPropertyCSSValue(CSSPropertyID propertyID) const 584{ 585 int foundPropertyIndex = findPropertyIndex(propertyID); 586 if (foundPropertyIndex == -1) 587 return 0; 588 return propertyAt(foundPropertyIndex).value(); 589} 590 591bool MutableStylePropertySet::removeShorthandProperty(CSSPropertyID propertyID) 592{ 593 StylePropertyShorthand shorthand = shorthandForProperty(propertyID); 594 if (!shorthand.length()) 595 return false; 596 597 bool ret = removePropertiesInSet(shorthand.properties(), shorthand.length()); 598 599 CSSPropertyID prefixingVariant = prefixingVariantForPropertyId(propertyID); 600 if (prefixingVariant == propertyID) 601 return ret; 602 603 StylePropertyShorthand shorthandPrefixingVariant = shorthandForProperty(prefixingVariant); 604 return removePropertiesInSet(shorthandPrefixingVariant.properties(), shorthandPrefixingVariant.length()); 605} 606 607bool MutableStylePropertySet::removeProperty(CSSPropertyID propertyID, String* returnText) 608{ 609 if (removeShorthandProperty(propertyID)) { 610 // FIXME: Return an equivalent shorthand when possible. 611 if (returnText) 612 *returnText = ""; 613 return true; 614 } 615 616 int foundPropertyIndex = findPropertyIndex(propertyID); 617 if (foundPropertyIndex == -1) { 618 if (returnText) 619 *returnText = ""; 620 return false; 621 } 622 623 if (returnText) 624 *returnText = propertyAt(foundPropertyIndex).value()->cssText(); 625 626 // A more efficient removal strategy would involve marking entries as empty 627 // and sweeping them when the vector grows too big. 628 m_propertyVector.remove(foundPropertyIndex); 629 630 removePrefixedOrUnprefixedProperty(propertyID); 631 632 return true; 633} 634 635void MutableStylePropertySet::removePrefixedOrUnprefixedProperty(CSSPropertyID propertyID) 636{ 637 int foundPropertyIndex = findPropertyIndex(prefixingVariantForPropertyId(propertyID)); 638 if (foundPropertyIndex == -1) 639 return; 640 m_propertyVector.remove(foundPropertyIndex); 641} 642 643bool StylePropertySet::propertyIsImportant(CSSPropertyID propertyID) const 644{ 645 int foundPropertyIndex = findPropertyIndex(propertyID); 646 if (foundPropertyIndex != -1) 647 return propertyAt(foundPropertyIndex).isImportant(); 648 649 StylePropertyShorthand shorthand = shorthandForProperty(propertyID); 650 if (!shorthand.length()) 651 return false; 652 653 for (unsigned i = 0; i < shorthand.length(); ++i) { 654 if (!propertyIsImportant(shorthand.properties()[i])) 655 return false; 656 } 657 return true; 658} 659 660String StylePropertySet::getPropertyShorthand(CSSPropertyID propertyID) const 661{ 662 int foundPropertyIndex = findPropertyIndex(propertyID); 663 if (foundPropertyIndex == -1) 664 return String(); 665 return getPropertyNameString(propertyAt(foundPropertyIndex).shorthandID()); 666} 667 668bool StylePropertySet::isPropertyImplicit(CSSPropertyID propertyID) const 669{ 670 int foundPropertyIndex = findPropertyIndex(propertyID); 671 if (foundPropertyIndex == -1) 672 return false; 673 return propertyAt(foundPropertyIndex).isImplicit(); 674} 675 676bool MutableStylePropertySet::setProperty(CSSPropertyID propertyID, const String& value, bool important, StyleSheetContents* contextStyleSheet) 677{ 678 // Setting the value to an empty string just removes the property in both IE and Gecko. 679 // Setting it to null seems to produce less consistent results, but we treat it just the same. 680 if (value.isEmpty()) 681 return removeProperty(propertyID); 682 683 // When replacing an existing property value, this moves the property to the end of the list. 684 // Firefox preserves the position, and MSIE moves the property to the beginning. 685 return CSSParser::parseValue(this, propertyID, value, important, cssParserMode(), contextStyleSheet); 686} 687 688void MutableStylePropertySet::setProperty(CSSPropertyID propertyID, PassRefPtr<CSSValue> prpValue, bool important) 689{ 690 StylePropertyShorthand shorthand = shorthandForProperty(propertyID); 691 if (!shorthand.length()) { 692 setProperty(CSSProperty(propertyID, prpValue, important)); 693 return; 694 } 695 696 removePropertiesInSet(shorthand.properties(), shorthand.length()); 697 698 RefPtr<CSSValue> value = prpValue; 699 for (unsigned i = 0; i < shorthand.length(); ++i) 700 m_propertyVector.append(CSSProperty(shorthand.properties()[i], value, important)); 701} 702 703void MutableStylePropertySet::setProperty(const CSSProperty& property, CSSProperty* slot) 704{ 705 if (!removeShorthandProperty(property.id())) { 706 CSSProperty* toReplace = slot ? slot : findCSSPropertyWithID(property.id()); 707 if (toReplace) { 708 *toReplace = property; 709 setPrefixingVariantProperty(property); 710 return; 711 } 712 } 713 appendPrefixingVariantProperty(property); 714} 715 716void MutableStylePropertySet::appendPrefixingVariantProperty(const CSSProperty& property) 717{ 718 m_propertyVector.append(property); 719 CSSPropertyID prefixingVariant = prefixingVariantForPropertyId(property.id()); 720 if (prefixingVariant == property.id()) 721 return; 722 m_propertyVector.append(CSSProperty(prefixingVariant, property.value(), property.isImportant(), property.shorthandID(), property.metadata().m_implicit)); 723} 724 725void MutableStylePropertySet::setPrefixingVariantProperty(const CSSProperty& property) 726{ 727 CSSPropertyID prefixingVariant = prefixingVariantForPropertyId(property.id()); 728 CSSProperty* toReplace = findCSSPropertyWithID(prefixingVariant); 729 if (toReplace) 730 *toReplace = CSSProperty(prefixingVariant, property.value(), property.isImportant(), property.shorthandID(), property.metadata().m_implicit); 731} 732 733bool MutableStylePropertySet::setProperty(CSSPropertyID propertyID, int identifier, bool important) 734{ 735 setProperty(CSSProperty(propertyID, cssValuePool().createIdentifierValue(identifier), important)); 736 return true; 737} 738 739void MutableStylePropertySet::parseDeclaration(const String& styleDeclaration, StyleSheetContents* contextStyleSheet) 740{ 741 m_propertyVector.clear(); 742 743 CSSParserContext context(cssParserMode()); 744 if (contextStyleSheet) { 745 context = contextStyleSheet->parserContext(); 746 context.mode = cssParserMode(); 747 } 748 CSSParser parser(context); 749 parser.parseDeclaration(this, styleDeclaration, 0, contextStyleSheet); 750} 751 752void MutableStylePropertySet::addParsedProperties(const Vector<CSSProperty>& properties) 753{ 754 m_propertyVector.reserveCapacity(m_propertyVector.size() + properties.size()); 755 for (unsigned i = 0; i < properties.size(); ++i) 756 addParsedProperty(properties[i]); 757} 758 759void MutableStylePropertySet::addParsedProperty(const CSSProperty& property) 760{ 761 // Only add properties that have no !important counterpart present 762 if (!propertyIsImportant(property.id()) || property.isImportant()) 763 setProperty(property); 764} 765 766String StylePropertySet::asText() const 767{ 768 StringBuilder result; 769 770 int positionXPropertyIndex = -1; 771 int positionYPropertyIndex = -1; 772 int repeatXPropertyIndex = -1; 773 int repeatYPropertyIndex = -1; 774 775 BitArray<numCSSProperties> shorthandPropertyUsed; 776 BitArray<numCSSProperties> shorthandPropertyAppeared; 777 778 unsigned size = propertyCount(); 779 unsigned numDecls = 0; 780 for (unsigned n = 0; n < size; ++n) { 781 PropertyReference property = propertyAt(n); 782 CSSPropertyID propertyID = property.id(); 783 CSSPropertyID shorthandPropertyID = CSSPropertyInvalid; 784 CSSPropertyID borderFallbackShorthandProperty = CSSPropertyInvalid; 785 String value; 786 787 switch (propertyID) { 788#if ENABLE(CSS_VARIABLES) 789 case CSSPropertyVariable: 790 if (numDecls++) 791 result.append(' '); 792 result.append(property.cssText()); 793 continue; 794#endif 795 case CSSPropertyBackgroundPositionX: 796 positionXPropertyIndex = n; 797 continue; 798 case CSSPropertyBackgroundPositionY: 799 positionYPropertyIndex = n; 800 continue; 801 case CSSPropertyBackgroundRepeatX: 802 repeatXPropertyIndex = n; 803 continue; 804 case CSSPropertyBackgroundRepeatY: 805 repeatYPropertyIndex = n; 806 continue; 807 case CSSPropertyBorderTopWidth: 808 case CSSPropertyBorderRightWidth: 809 case CSSPropertyBorderBottomWidth: 810 case CSSPropertyBorderLeftWidth: 811 if (!borderFallbackShorthandProperty) 812 borderFallbackShorthandProperty = CSSPropertyBorderWidth; 813 case CSSPropertyBorderTopStyle: 814 case CSSPropertyBorderRightStyle: 815 case CSSPropertyBorderBottomStyle: 816 case CSSPropertyBorderLeftStyle: 817 if (!borderFallbackShorthandProperty) 818 borderFallbackShorthandProperty = CSSPropertyBorderStyle; 819 case CSSPropertyBorderTopColor: 820 case CSSPropertyBorderRightColor: 821 case CSSPropertyBorderBottomColor: 822 case CSSPropertyBorderLeftColor: 823 if (!borderFallbackShorthandProperty) 824 borderFallbackShorthandProperty = CSSPropertyBorderColor; 825 826 // FIXME: Deal with cases where only some of border-(top|right|bottom|left) are specified. 827 if (!shorthandPropertyAppeared.get(CSSPropertyBorder - firstCSSProperty)) { 828 value = borderPropertyValue(ReturnNullOnUncommonValues); 829 if (value.isNull()) 830 shorthandPropertyAppeared.set(CSSPropertyBorder - firstCSSProperty); 831 else 832 shorthandPropertyID = CSSPropertyBorder; 833 } else if (shorthandPropertyUsed.get(CSSPropertyBorder - firstCSSProperty)) 834 shorthandPropertyID = CSSPropertyBorder; 835 if (!shorthandPropertyID) 836 shorthandPropertyID = borderFallbackShorthandProperty; 837 break; 838 case CSSPropertyWebkitBorderHorizontalSpacing: 839 case CSSPropertyWebkitBorderVerticalSpacing: 840 shorthandPropertyID = CSSPropertyBorderSpacing; 841 break; 842 case CSSPropertyFontFamily: 843 case CSSPropertyLineHeight: 844 case CSSPropertyFontSize: 845 case CSSPropertyFontStyle: 846 case CSSPropertyFontVariant: 847 case CSSPropertyFontWeight: 848 // Don't use CSSPropertyFont because old UAs can't recognize them but are important for editing. 849 break; 850 case CSSPropertyListStyleType: 851 case CSSPropertyListStylePosition: 852 case CSSPropertyListStyleImage: 853 shorthandPropertyID = CSSPropertyListStyle; 854 break; 855 case CSSPropertyMarginTop: 856 case CSSPropertyMarginRight: 857 case CSSPropertyMarginBottom: 858 case CSSPropertyMarginLeft: 859 shorthandPropertyID = CSSPropertyMargin; 860 break; 861 case CSSPropertyOutlineWidth: 862 case CSSPropertyOutlineStyle: 863 case CSSPropertyOutlineColor: 864 shorthandPropertyID = CSSPropertyOutline; 865 break; 866 case CSSPropertyOverflowX: 867 case CSSPropertyOverflowY: 868 shorthandPropertyID = CSSPropertyOverflow; 869 break; 870 case CSSPropertyPaddingTop: 871 case CSSPropertyPaddingRight: 872 case CSSPropertyPaddingBottom: 873 case CSSPropertyPaddingLeft: 874 shorthandPropertyID = CSSPropertyPadding; 875 break; 876 case CSSPropertyTransitionProperty: 877 case CSSPropertyTransitionDuration: 878 case CSSPropertyTransitionTimingFunction: 879 case CSSPropertyTransitionDelay: 880 shorthandPropertyID = CSSPropertyTransition; 881 break; 882 case CSSPropertyWebkitAnimationName: 883 case CSSPropertyWebkitAnimationDuration: 884 case CSSPropertyWebkitAnimationTimingFunction: 885 case CSSPropertyWebkitAnimationDelay: 886 case CSSPropertyWebkitAnimationIterationCount: 887 case CSSPropertyWebkitAnimationDirection: 888 case CSSPropertyWebkitAnimationFillMode: 889 shorthandPropertyID = CSSPropertyWebkitAnimation; 890 break; 891 case CSSPropertyWebkitFlexDirection: 892 case CSSPropertyWebkitFlexWrap: 893 shorthandPropertyID = CSSPropertyWebkitFlexFlow; 894 break; 895 case CSSPropertyWebkitFlexBasis: 896 case CSSPropertyWebkitFlexGrow: 897 case CSSPropertyWebkitFlexShrink: 898 shorthandPropertyID = CSSPropertyWebkitFlex; 899 break; 900 case CSSPropertyWebkitMaskPositionX: 901 case CSSPropertyWebkitMaskPositionY: 902 case CSSPropertyWebkitMaskRepeatX: 903 case CSSPropertyWebkitMaskRepeatY: 904 case CSSPropertyWebkitMaskImage: 905 case CSSPropertyWebkitMaskRepeat: 906 case CSSPropertyWebkitMaskPosition: 907 case CSSPropertyWebkitMaskClip: 908 case CSSPropertyWebkitMaskOrigin: 909 shorthandPropertyID = CSSPropertyWebkitMask; 910 break; 911 case CSSPropertyWebkitTransformOriginX: 912 case CSSPropertyWebkitTransformOriginY: 913 case CSSPropertyWebkitTransformOriginZ: 914 shorthandPropertyID = CSSPropertyWebkitTransformOrigin; 915 break; 916 case CSSPropertyWebkitTransitionProperty: 917 case CSSPropertyWebkitTransitionDuration: 918 case CSSPropertyWebkitTransitionTimingFunction: 919 case CSSPropertyWebkitTransitionDelay: 920 shorthandPropertyID = CSSPropertyWebkitTransition; 921 break; 922 default: 923 break; 924 } 925 926 unsigned shortPropertyIndex = shorthandPropertyID - firstCSSProperty; 927 if (shorthandPropertyID) { 928 if (shorthandPropertyUsed.get(shortPropertyIndex)) 929 continue; 930 if (!shorthandPropertyAppeared.get(shortPropertyIndex) && value.isNull()) 931 value = getPropertyValue(shorthandPropertyID); 932 shorthandPropertyAppeared.set(shortPropertyIndex); 933 } 934 935 if (!value.isNull()) { 936 propertyID = shorthandPropertyID; 937 shorthandPropertyUsed.set(shortPropertyIndex); 938 } else 939 value = property.value()->cssText(); 940 941 if (value == "initial" && !CSSProperty::isInheritedProperty(propertyID)) 942 continue; 943 944 if (numDecls++) 945 result.append(' '); 946 result.append(getPropertyName(propertyID)); 947 result.appendLiteral(": "); 948 result.append(value); 949 if (property.isImportant()) 950 result.appendLiteral(" !important"); 951 result.append(';'); 952 } 953 954 // FIXME: This is a not-so-nice way to turn x/y positions into single background-position in output. 955 // It is required because background-position-x/y are non-standard properties and WebKit generated output 956 // would not work in Firefox (<rdar://problem/5143183>) 957 // It would be a better solution if background-position was CSS_PAIR. 958 if (positionXPropertyIndex != -1 && positionYPropertyIndex != -1 && propertyAt(positionXPropertyIndex).isImportant() == propertyAt(positionYPropertyIndex).isImportant()) { 959 PropertyReference positionXProperty = propertyAt(positionXPropertyIndex); 960 PropertyReference positionYProperty = propertyAt(positionYPropertyIndex); 961 962 if (numDecls++) 963 result.append(' '); 964 result.appendLiteral("background-position: "); 965 if (positionXProperty.value()->isValueList() || positionYProperty.value()->isValueList()) 966 result.append(getLayeredShorthandValue(backgroundPositionShorthand())); 967 else { 968 result.append(positionXProperty.value()->cssText()); 969 result.append(' '); 970 result.append(positionYProperty.value()->cssText()); 971 } 972 if (positionXProperty.isImportant()) 973 result.appendLiteral(" !important"); 974 result.append(';'); 975 } else { 976 if (positionXPropertyIndex != -1) { 977 if (numDecls++) 978 result.append(' '); 979 result.append(propertyAt(positionXPropertyIndex).cssText()); 980 } 981 if (positionYPropertyIndex != -1) { 982 if (numDecls++) 983 result.append(' '); 984 result.append(propertyAt(positionYPropertyIndex).cssText()); 985 } 986 } 987 988 // FIXME: We need to do the same for background-repeat. 989 if (repeatXPropertyIndex != -1 && repeatYPropertyIndex != -1 && propertyAt(repeatXPropertyIndex).isImportant() == propertyAt(repeatYPropertyIndex).isImportant()) { 990 PropertyReference repeatXProperty = propertyAt(repeatXPropertyIndex); 991 PropertyReference repeatYProperty = propertyAt(repeatYPropertyIndex); 992 993 if (numDecls++) 994 result.append(' '); 995 result.appendLiteral("background-repeat: "); 996 if (repeatXProperty.value()->isValueList() || repeatYProperty.value()->isValueList()) 997 result.append(getLayeredShorthandValue(backgroundRepeatShorthand())); 998 else { 999 result.append(repeatXProperty.value()->cssText()); 1000 result.append(' '); 1001 result.append(repeatYProperty.value()->cssText()); 1002 } 1003 if (repeatXProperty.isImportant()) 1004 result.appendLiteral(" !important"); 1005 result.append(';'); 1006 } else { 1007 if (repeatXPropertyIndex != -1) { 1008 if (numDecls++) 1009 result.append(' '); 1010 result.append(propertyAt(repeatXPropertyIndex).cssText()); 1011 } 1012 if (repeatYPropertyIndex != -1) { 1013 if (numDecls++) 1014 result.append(' '); 1015 result.append(propertyAt(repeatYPropertyIndex).cssText()); 1016 } 1017 } 1018 1019 ASSERT(!numDecls ^ !result.isEmpty()); 1020 return result.toString(); 1021} 1022 1023void MutableStylePropertySet::mergeAndOverrideOnConflict(const StylePropertySet* other) 1024{ 1025 unsigned size = other->propertyCount(); 1026 for (unsigned i = 0; i < size; ++i) 1027 addParsedProperty(other->propertyAt(i).toCSSProperty()); 1028} 1029 1030void StylePropertySet::addSubresourceStyleURLs(ListHashSet<KURL>& urls, StyleSheetContents* contextStyleSheet) const 1031{ 1032 unsigned size = propertyCount(); 1033 for (unsigned i = 0; i < size; ++i) 1034 propertyAt(i).value()->addSubresourceStyleURLs(urls, contextStyleSheet); 1035} 1036 1037bool StylePropertySet::hasFailedOrCanceledSubresources() const 1038{ 1039 unsigned size = propertyCount(); 1040 for (unsigned i = 0; i < size; ++i) { 1041 if (propertyAt(i).value()->hasFailedOrCanceledSubresources()) 1042 return true; 1043 } 1044 return false; 1045} 1046 1047// This is the list of properties we want to copy in the copyBlockProperties() function. 1048// It is the list of CSS properties that apply specially to block-level elements. 1049static const CSSPropertyID blockProperties[] = { 1050 CSSPropertyOrphans, 1051 CSSPropertyOverflow, // This can be also be applied to replaced elements 1052 CSSPropertyWebkitAspectRatio, 1053 CSSPropertyWebkitColumnCount, 1054 CSSPropertyWebkitColumnGap, 1055 CSSPropertyWebkitColumnRuleColor, 1056 CSSPropertyWebkitColumnRuleStyle, 1057 CSSPropertyWebkitColumnRuleWidth, 1058 CSSPropertyWebkitColumnBreakBefore, 1059 CSSPropertyWebkitColumnBreakAfter, 1060 CSSPropertyWebkitColumnBreakInside, 1061 CSSPropertyWebkitColumnWidth, 1062 CSSPropertyPageBreakAfter, 1063 CSSPropertyPageBreakBefore, 1064 CSSPropertyPageBreakInside, 1065#if ENABLE(CSS_REGIONS) 1066 CSSPropertyWebkitRegionBreakAfter, 1067 CSSPropertyWebkitRegionBreakBefore, 1068 CSSPropertyWebkitRegionBreakInside, 1069#endif 1070 CSSPropertyTextAlign, 1071#if ENABLE(CSS3_TEXT) 1072 CSSPropertyWebkitTextAlignLast, 1073 CSSPropertyWebkitTextJustify, 1074#endif // CSS3_TEXT 1075 CSSPropertyTextIndent, 1076 CSSPropertyWidows 1077}; 1078 1079void MutableStylePropertySet::clear() 1080{ 1081 m_propertyVector.clear(); 1082} 1083 1084const unsigned numBlockProperties = WTF_ARRAY_LENGTH(blockProperties); 1085 1086PassRefPtr<MutableStylePropertySet> StylePropertySet::copyBlockProperties() const 1087{ 1088 return copyPropertiesInSet(blockProperties, numBlockProperties); 1089} 1090 1091void MutableStylePropertySet::removeBlockProperties() 1092{ 1093 removePropertiesInSet(blockProperties, numBlockProperties); 1094} 1095 1096bool MutableStylePropertySet::removePropertiesInSet(const CSSPropertyID* set, unsigned length) 1097{ 1098 if (m_propertyVector.isEmpty()) 1099 return false; 1100 1101 // FIXME: This is always used with static sets and in that case constructing the hash repeatedly is pretty pointless. 1102 HashSet<CSSPropertyID> toRemove; 1103 for (unsigned i = 0; i < length; ++i) 1104 toRemove.add(set[i]); 1105 1106 Vector<CSSProperty> newProperties; 1107 newProperties.reserveInitialCapacity(m_propertyVector.size()); 1108 1109 unsigned size = m_propertyVector.size(); 1110 for (unsigned n = 0; n < size; ++n) { 1111 const CSSProperty& property = m_propertyVector.at(n); 1112 // Not quite sure if the isImportant test is needed but it matches the existing behavior. 1113 if (!property.isImportant()) { 1114 if (toRemove.contains(property.id())) 1115 continue; 1116 } 1117 newProperties.append(property); 1118 } 1119 1120 bool changed = newProperties.size() != m_propertyVector.size(); 1121 m_propertyVector = newProperties; 1122 return changed; 1123} 1124 1125int StylePropertySet::findPropertyIndex(CSSPropertyID propertyID) const 1126{ 1127 for (int n = propertyCount() - 1 ; n >= 0; --n) { 1128 if (propertyID == propertyAt(n).id()) 1129 return n; 1130 } 1131 return -1; 1132} 1133 1134CSSProperty* MutableStylePropertySet::findCSSPropertyWithID(CSSPropertyID propertyID) 1135{ 1136 int foundPropertyIndex = findPropertyIndex(propertyID); 1137 if (foundPropertyIndex == -1) 1138 return 0; 1139 return &m_propertyVector.at(foundPropertyIndex); 1140} 1141 1142bool StylePropertySet::propertyMatches(CSSPropertyID propertyID, const CSSValue* propertyValue) const 1143{ 1144 int foundPropertyIndex = findPropertyIndex(propertyID); 1145 if (foundPropertyIndex == -1) 1146 return false; 1147 return propertyAt(foundPropertyIndex).value()->equals(*propertyValue); 1148} 1149 1150void MutableStylePropertySet::removeEquivalentProperties(const StylePropertySet* style) 1151{ 1152 Vector<CSSPropertyID> propertiesToRemove; 1153 unsigned size = m_propertyVector.size(); 1154 for (unsigned i = 0; i < size; ++i) { 1155 PropertyReference property = propertyAt(i); 1156 if (style->propertyMatches(property.id(), property.value())) 1157 propertiesToRemove.append(property.id()); 1158 } 1159 // FIXME: This should use mass removal. 1160 for (unsigned i = 0; i < propertiesToRemove.size(); ++i) 1161 removeProperty(propertiesToRemove[i]); 1162} 1163 1164void MutableStylePropertySet::removeEquivalentProperties(const ComputedStyleExtractor* computedStyle) 1165{ 1166 Vector<CSSPropertyID> propertiesToRemove; 1167 unsigned size = m_propertyVector.size(); 1168 for (unsigned i = 0; i < size; ++i) { 1169 PropertyReference property = propertyAt(i); 1170 if (computedStyle->propertyMatches(property.id(), property.value())) 1171 propertiesToRemove.append(property.id()); 1172 } 1173 // FIXME: This should use mass removal. 1174 for (unsigned i = 0; i < propertiesToRemove.size(); ++i) 1175 removeProperty(propertiesToRemove[i]); 1176} 1177 1178PassRefPtr<MutableStylePropertySet> StylePropertySet::mutableCopy() const 1179{ 1180 return adoptRef(new MutableStylePropertySet(*this)); 1181} 1182 1183PassRefPtr<MutableStylePropertySet> StylePropertySet::copyPropertiesInSet(const CSSPropertyID* set, unsigned length) const 1184{ 1185 Vector<CSSProperty, 256> list; 1186 list.reserveInitialCapacity(length); 1187 for (unsigned i = 0; i < length; ++i) { 1188 RefPtr<CSSValue> value = getPropertyCSSValue(set[i]); 1189 if (value) 1190 list.append(CSSProperty(set[i], value.release(), false)); 1191 } 1192 return MutableStylePropertySet::create(list.data(), list.size()); 1193} 1194 1195PropertySetCSSStyleDeclaration* MutableStylePropertySet::cssStyleDeclaration() 1196{ 1197 if (!m_ownsCSSOMWrapper) 1198 return 0; 1199 return propertySetCSSOMWrapperMap().get(this); 1200} 1201 1202CSSStyleDeclaration* MutableStylePropertySet::ensureCSSStyleDeclaration() 1203{ 1204 if (m_ownsCSSOMWrapper) { 1205 ASSERT(!static_cast<CSSStyleDeclaration*>(propertySetCSSOMWrapperMap().get(this))->parentRule()); 1206 ASSERT(!propertySetCSSOMWrapperMap().get(this)->parentElement()); 1207 return propertySetCSSOMWrapperMap().get(this); 1208 } 1209 m_ownsCSSOMWrapper = true; 1210 PropertySetCSSStyleDeclaration* cssomWrapper = new PropertySetCSSStyleDeclaration(this); 1211 propertySetCSSOMWrapperMap().add(this, adoptPtr(cssomWrapper)); 1212 return cssomWrapper; 1213} 1214 1215CSSStyleDeclaration* MutableStylePropertySet::ensureInlineCSSStyleDeclaration(StyledElement* parentElement) 1216{ 1217 if (m_ownsCSSOMWrapper) { 1218 ASSERT(propertySetCSSOMWrapperMap().get(this)->parentElement() == parentElement); 1219 return propertySetCSSOMWrapperMap().get(this); 1220 } 1221 m_ownsCSSOMWrapper = true; 1222 PropertySetCSSStyleDeclaration* cssomWrapper = new InlineCSSStyleDeclaration(this, parentElement); 1223 propertySetCSSOMWrapperMap().add(this, adoptPtr(cssomWrapper)); 1224 return cssomWrapper; 1225} 1226 1227unsigned StylePropertySet::averageSizeInBytes() 1228{ 1229 // Please update this if the storage scheme changes so that this longer reflects the actual size. 1230 return sizeForImmutableStylePropertySetWithPropertyCount(4); 1231} 1232 1233// See the function above if you need to update this. 1234struct SameSizeAsStylePropertySet : public RefCounted<SameSizeAsStylePropertySet> { 1235 unsigned bitfield; 1236}; 1237COMPILE_ASSERT(sizeof(StylePropertySet) == sizeof(SameSizeAsStylePropertySet), style_property_set_should_stay_small); 1238 1239#ifndef NDEBUG 1240void StylePropertySet::showStyle() 1241{ 1242 fprintf(stderr, "%s\n", asText().ascii().data()); 1243} 1244#endif 1245 1246PassRefPtr<MutableStylePropertySet> MutableStylePropertySet::create(CSSParserMode cssParserMode) 1247{ 1248 return adoptRef(new MutableStylePropertySet(cssParserMode)); 1249} 1250 1251PassRefPtr<MutableStylePropertySet> MutableStylePropertySet::create(const CSSProperty* properties, unsigned count) 1252{ 1253 return adoptRef(new MutableStylePropertySet(properties, count)); 1254} 1255 1256String StylePropertySet::PropertyReference::cssName() const 1257{ 1258#if ENABLE(CSS_VARIABLES) 1259 if (id() == CSSPropertyVariable) { 1260 ASSERT(propertyValue()->isVariableValue()); 1261 if (!propertyValue()->isVariableValue()) 1262 return emptyString(); // Should not happen, but if it does, avoid a bad cast. 1263 return "-webkit-var-" + static_cast<const CSSVariableValue*>(propertyValue())->name(); 1264 } 1265#endif 1266 return getPropertyNameString(id()); 1267} 1268 1269String StylePropertySet::PropertyReference::cssText() const 1270{ 1271 StringBuilder result; 1272 result.append(cssName()); 1273 result.appendLiteral(": "); 1274 result.append(propertyValue()->cssText()); 1275 if (isImportant()) 1276 result.appendLiteral(" !important"); 1277 result.append(';'); 1278 return result.toString(); 1279} 1280 1281 1282} // namespace WebCore 1283