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