1 /* 2 * (C) 1999-2003 Lars Knoll (knoll (at) kde.org) 3 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2012 Apple Inc. All rights reserved. 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Library General Public 7 * License as published by the Free Software Foundation; either 8 * version 2 of the License, or (at your option) any later version. 9 * 10 * This library is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * Library General Public License for more details. 14 * 15 * You should have received a copy of the GNU Library General Public License 16 * along with this library; see the file COPYING.LIB. If not, write to 17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 18 * Boston, MA 02110-1301, USA. 19 */ 20 21 #include "config.h" 22 #include "core/css/CSSPrimitiveValue.h" 23 24 #include "bindings/v8/ExceptionState.h" 25 #include "core/css/CSSBasicShapes.h" 26 #include "core/css/CSSCalculationValue.h" 27 #include "core/css/CSSHelper.h" 28 #include "core/css/CSSMarkup.h" 29 #include "core/css/CSSToLengthConversionData.h" 30 #include "core/css/Counter.h" 31 #include "core/css/Pair.h" 32 #include "core/css/RGBColor.h" 33 #include "core/css/Rect.h" 34 #include "core/css/StyleSheetContents.h" 35 #include "core/dom/ExceptionCode.h" 36 #include "core/dom/Node.h" 37 #include "core/rendering/style/RenderStyle.h" 38 #include "platform/Decimal.h" 39 #include "platform/LayoutUnit.h" 40 #include "platform/fonts/FontMetrics.h" 41 #include "wtf/StdLibExtras.h" 42 #include "wtf/text/StringBuffer.h" 43 #include "wtf/text/StringBuilder.h" 44 45 using namespace WTF; 46 47 namespace WebCore { 48 49 // Max/min values for CSS, needs to slightly smaller/larger than the true max/min values to allow for rounding without overflowing. 50 // Subtract two (rather than one) to allow for values to be converted to float and back without exceeding the LayoutUnit::max. 51 const int maxValueForCssLength = INT_MAX / kFixedPointDenominator - 2; 52 const int minValueForCssLength = INT_MIN / kFixedPointDenominator + 2; 53 54 static inline bool isValidCSSUnitTypeForDoubleConversion(CSSPrimitiveValue::UnitType unitType) 55 { 56 switch (unitType) { 57 case CSSPrimitiveValue::CSS_CALC: 58 case CSSPrimitiveValue::CSS_CALC_PERCENTAGE_WITH_NUMBER: 59 case CSSPrimitiveValue::CSS_CALC_PERCENTAGE_WITH_LENGTH: 60 case CSSPrimitiveValue::CSS_CM: 61 case CSSPrimitiveValue::CSS_DEG: 62 case CSSPrimitiveValue::CSS_DIMENSION: 63 case CSSPrimitiveValue::CSS_DPPX: 64 case CSSPrimitiveValue::CSS_DPI: 65 case CSSPrimitiveValue::CSS_DPCM: 66 case CSSPrimitiveValue::CSS_EMS: 67 case CSSPrimitiveValue::CSS_EXS: 68 case CSSPrimitiveValue::CSS_GRAD: 69 case CSSPrimitiveValue::CSS_HZ: 70 case CSSPrimitiveValue::CSS_IN: 71 case CSSPrimitiveValue::CSS_KHZ: 72 case CSSPrimitiveValue::CSS_MM: 73 case CSSPrimitiveValue::CSS_MS: 74 case CSSPrimitiveValue::CSS_NUMBER: 75 case CSSPrimitiveValue::CSS_PERCENTAGE: 76 case CSSPrimitiveValue::CSS_PC: 77 case CSSPrimitiveValue::CSS_PT: 78 case CSSPrimitiveValue::CSS_PX: 79 case CSSPrimitiveValue::CSS_RAD: 80 case CSSPrimitiveValue::CSS_REMS: 81 case CSSPrimitiveValue::CSS_CHS: 82 case CSSPrimitiveValue::CSS_S: 83 case CSSPrimitiveValue::CSS_TURN: 84 case CSSPrimitiveValue::CSS_VW: 85 case CSSPrimitiveValue::CSS_VH: 86 case CSSPrimitiveValue::CSS_VMIN: 87 case CSSPrimitiveValue::CSS_VMAX: 88 case CSSPrimitiveValue::CSS_FR: 89 return true; 90 case CSSPrimitiveValue::CSS_ATTR: 91 case CSSPrimitiveValue::CSS_COUNTER: 92 case CSSPrimitiveValue::CSS_COUNTER_NAME: 93 case CSSPrimitiveValue::CSS_IDENT: 94 case CSSPrimitiveValue::CSS_PROPERTY_ID: 95 case CSSPrimitiveValue::CSS_VALUE_ID: 96 case CSSPrimitiveValue::CSS_PAIR: 97 case CSSPrimitiveValue::CSS_PARSER_HEXCOLOR: 98 case CSSPrimitiveValue::CSS_PARSER_IDENTIFIER: 99 case CSSPrimitiveValue::CSS_PARSER_INTEGER: 100 case CSSPrimitiveValue::CSS_PARSER_OPERATOR: 101 case CSSPrimitiveValue::CSS_RECT: 102 case CSSPrimitiveValue::CSS_QUAD: 103 case CSSPrimitiveValue::CSS_RGBCOLOR: 104 case CSSPrimitiveValue::CSS_SHAPE: 105 case CSSPrimitiveValue::CSS_STRING: 106 case CSSPrimitiveValue::CSS_UNICODE_RANGE: 107 case CSSPrimitiveValue::CSS_UNKNOWN: 108 case CSSPrimitiveValue::CSS_URI: 109 return false; 110 } 111 112 ASSERT_NOT_REACHED(); 113 return false; 114 } 115 116 typedef HashMap<String, CSSPrimitiveValue::UnitType> StringToUnitTable; 117 118 StringToUnitTable createStringToUnitTable() 119 { 120 StringToUnitTable table; 121 table.set(String("em"), CSSPrimitiveValue::CSS_EMS); 122 table.set(String("ex"), CSSPrimitiveValue::CSS_EXS); 123 table.set(String("px"), CSSPrimitiveValue::CSS_PX); 124 table.set(String("cm"), CSSPrimitiveValue::CSS_CM); 125 table.set(String("mm"), CSSPrimitiveValue::CSS_MM); 126 table.set(String("in"), CSSPrimitiveValue::CSS_IN); 127 table.set(String("pt"), CSSPrimitiveValue::CSS_PT); 128 table.set(String("pc"), CSSPrimitiveValue::CSS_PC); 129 table.set(String("deg"), CSSPrimitiveValue::CSS_DEG); 130 table.set(String("rad"), CSSPrimitiveValue::CSS_RAD); 131 table.set(String("grad"), CSSPrimitiveValue::CSS_GRAD); 132 table.set(String("ms"), CSSPrimitiveValue::CSS_MS); 133 table.set(String("s"), CSSPrimitiveValue::CSS_S); 134 table.set(String("hz"), CSSPrimitiveValue::CSS_HZ); 135 table.set(String("khz"), CSSPrimitiveValue::CSS_KHZ); 136 table.set(String("dpi"), CSSPrimitiveValue::CSS_DPI); 137 table.set(String("dpcm"), CSSPrimitiveValue::CSS_DPCM); 138 table.set(String("dppx"), CSSPrimitiveValue::CSS_DPPX); 139 table.set(String("vw"), CSSPrimitiveValue::CSS_VW); 140 table.set(String("vh"), CSSPrimitiveValue::CSS_VH); 141 table.set(String("vmax"), CSSPrimitiveValue::CSS_VMIN); 142 table.set(String("vmin"), CSSPrimitiveValue::CSS_VMAX); 143 return table; 144 } 145 146 147 CSSPrimitiveValue::UnitType CSSPrimitiveValue::fromName(const String& unit) 148 { 149 DEFINE_STATIC_LOCAL(StringToUnitTable, unitTable, (createStringToUnitTable())); 150 return unitTable.get(unit.lower()); 151 } 152 153 CSSPrimitiveValue::UnitCategory CSSPrimitiveValue::unitCategory(UnitType type) 154 { 155 // Here we violate the spec (http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSPrimitiveValue) and allow conversions 156 // between CSS_PX and relative lengths (see cssPixelsPerInch comment in core/css/CSSHelper.h for the topic treatment). 157 switch (type) { 158 case CSS_NUMBER: 159 return CSSPrimitiveValue::UNumber; 160 case CSS_PERCENTAGE: 161 return CSSPrimitiveValue::UPercent; 162 case CSS_PX: 163 case CSS_CM: 164 case CSS_MM: 165 case CSS_IN: 166 case CSS_PT: 167 case CSS_PC: 168 return CSSPrimitiveValue::ULength; 169 case CSS_MS: 170 case CSS_S: 171 return CSSPrimitiveValue::UTime; 172 case CSS_DEG: 173 case CSS_RAD: 174 case CSS_GRAD: 175 case CSS_TURN: 176 return CSSPrimitiveValue::UAngle; 177 case CSS_HZ: 178 case CSS_KHZ: 179 return CSSPrimitiveValue::UFrequency; 180 case CSS_DPPX: 181 case CSS_DPI: 182 case CSS_DPCM: 183 return CSSPrimitiveValue::UResolution; 184 default: 185 return CSSPrimitiveValue::UOther; 186 } 187 } 188 189 bool CSSPrimitiveValue::colorIsDerivedFromElement() const 190 { 191 int valueID = getValueID(); 192 switch (valueID) { 193 case CSSValueWebkitText: 194 case CSSValueWebkitLink: 195 case CSSValueWebkitActivelink: 196 case CSSValueCurrentcolor: 197 return true; 198 default: 199 return false; 200 } 201 } 202 203 typedef HashMap<const CSSPrimitiveValue*, String> CSSTextCache; 204 static CSSTextCache& cssTextCache() 205 { 206 DEFINE_STATIC_LOCAL(CSSTextCache, cache, ()); 207 return cache; 208 } 209 210 CSSPrimitiveValue::UnitType CSSPrimitiveValue::primitiveType() const 211 { 212 if (m_primitiveUnitType == CSS_PROPERTY_ID || m_primitiveUnitType == CSS_VALUE_ID) 213 return CSS_IDENT; 214 215 if (m_primitiveUnitType != CSS_CALC) 216 return static_cast<UnitType>(m_primitiveUnitType); 217 218 switch (m_value.calc->category()) { 219 case CalcNumber: 220 return CSS_NUMBER; 221 case CalcPercent: 222 return CSS_PERCENTAGE; 223 case CalcLength: 224 return CSS_PX; 225 case CalcPercentNumber: 226 return CSS_CALC_PERCENTAGE_WITH_NUMBER; 227 case CalcPercentLength: 228 return CSS_CALC_PERCENTAGE_WITH_LENGTH; 229 case CalcOther: 230 return CSS_UNKNOWN; 231 } 232 return CSS_UNKNOWN; 233 } 234 235 static const AtomicString& propertyName(CSSPropertyID propertyID) 236 { 237 ASSERT_ARG(propertyID, propertyID >= 0); 238 ASSERT_ARG(propertyID, (propertyID >= firstCSSProperty && propertyID < firstCSSProperty + numCSSProperties)); 239 240 if (propertyID < 0) 241 return nullAtom; 242 243 return getPropertyNameAtomicString(propertyID); 244 } 245 246 static const AtomicString& valueName(CSSValueID valueID) 247 { 248 ASSERT_ARG(valueID, valueID >= 0); 249 ASSERT_ARG(valueID, valueID < numCSSValueKeywords); 250 251 if (valueID < 0) 252 return nullAtom; 253 254 static AtomicString* keywordStrings = new AtomicString[numCSSValueKeywords]; // Leaked intentionally. 255 AtomicString& keywordString = keywordStrings[valueID]; 256 if (keywordString.isNull()) 257 keywordString = getValueName(valueID); 258 return keywordString; 259 } 260 261 CSSPrimitiveValue::CSSPrimitiveValue(CSSValueID valueID) 262 : CSSValue(PrimitiveClass) 263 { 264 m_primitiveUnitType = CSS_VALUE_ID; 265 m_value.valueID = valueID; 266 } 267 268 CSSPrimitiveValue::CSSPrimitiveValue(CSSPropertyID propertyID) 269 : CSSValue(PrimitiveClass) 270 { 271 m_primitiveUnitType = CSS_PROPERTY_ID; 272 m_value.propertyID = propertyID; 273 } 274 275 CSSPrimitiveValue::CSSPrimitiveValue(int parserOperator, UnitType type) 276 : CSSValue(PrimitiveClass) 277 { 278 ASSERT(type == CSS_PARSER_OPERATOR); 279 m_primitiveUnitType = CSS_PARSER_OPERATOR; 280 m_value.parserOperator = parserOperator; 281 } 282 283 CSSPrimitiveValue::CSSPrimitiveValue(double num, UnitType type) 284 : CSSValue(PrimitiveClass) 285 { 286 m_primitiveUnitType = type; 287 ASSERT(std::isfinite(num)); 288 m_value.num = num; 289 } 290 291 CSSPrimitiveValue::CSSPrimitiveValue(const String& str, UnitType type) 292 : CSSValue(PrimitiveClass) 293 { 294 m_primitiveUnitType = type; 295 if ((m_value.string = str.impl())) 296 m_value.string->ref(); 297 } 298 299 CSSPrimitiveValue::CSSPrimitiveValue(const LengthSize& lengthSize, const RenderStyle& style) 300 : CSSValue(PrimitiveClass) 301 { 302 init(lengthSize, style); 303 } 304 305 CSSPrimitiveValue::CSSPrimitiveValue(RGBA32 color, UnitType type) 306 : CSSValue(PrimitiveClass) 307 { 308 ASSERT(type == CSS_RGBCOLOR); 309 m_primitiveUnitType = CSS_RGBCOLOR; 310 m_value.rgbcolor = color; 311 } 312 313 CSSPrimitiveValue::CSSPrimitiveValue(const Length& length, float zoom) 314 : CSSValue(PrimitiveClass) 315 { 316 switch (length.type()) { 317 case Auto: 318 m_primitiveUnitType = CSS_VALUE_ID; 319 m_value.valueID = CSSValueAuto; 320 break; 321 case Intrinsic: 322 m_primitiveUnitType = CSS_VALUE_ID; 323 m_value.valueID = CSSValueIntrinsic; 324 break; 325 case MinIntrinsic: 326 m_primitiveUnitType = CSS_VALUE_ID; 327 m_value.valueID = CSSValueMinIntrinsic; 328 break; 329 case MinContent: 330 m_primitiveUnitType = CSS_VALUE_ID; 331 m_value.valueID = CSSValueMinContent; 332 break; 333 case MaxContent: 334 m_primitiveUnitType = CSS_VALUE_ID; 335 m_value.valueID = CSSValueMaxContent; 336 break; 337 case FillAvailable: 338 m_primitiveUnitType = CSS_VALUE_ID; 339 m_value.valueID = CSSValueWebkitFillAvailable; 340 break; 341 case FitContent: 342 m_primitiveUnitType = CSS_VALUE_ID; 343 m_value.valueID = CSSValueWebkitFitContent; 344 break; 345 case ExtendToZoom: 346 m_primitiveUnitType = CSS_VALUE_ID; 347 m_value.valueID = CSSValueInternalExtendToZoom; 348 break; 349 case Percent: 350 m_primitiveUnitType = CSS_PERCENTAGE; 351 ASSERT(std::isfinite(length.percent())); 352 m_value.num = length.percent(); 353 break; 354 case Fixed: 355 m_primitiveUnitType = CSS_PX; 356 m_value.num = length.value() / zoom; 357 break; 358 case Calculated: { 359 const CalculationValue& calc = length.calculationValue(); 360 if (calc.pixels() && calc.percent()) { 361 init(CSSCalcValue::create( 362 CSSCalcValue::createExpressionNode(calc.pixels() / zoom, calc.percent()), 363 calc.isNonNegative() ? ValueRangeNonNegative : ValueRangeAll)); 364 break; 365 } 366 if (calc.percent()) { 367 m_primitiveUnitType = CSS_PERCENTAGE; 368 m_value.num = calc.percent(); 369 } else { 370 m_primitiveUnitType = CSS_PX; 371 m_value.num = calc.pixels() / zoom; 372 } 373 if (m_value.num < 0 && calc.isNonNegative()) 374 m_value.num = 0; 375 break; 376 } 377 case DeviceWidth: 378 case DeviceHeight: 379 case Undefined: 380 ASSERT_NOT_REACHED(); 381 break; 382 } 383 } 384 385 void CSSPrimitiveValue::init(const LengthSize& lengthSize, const RenderStyle& style) 386 { 387 m_primitiveUnitType = CSS_PAIR; 388 m_hasCachedCSSText = false; 389 m_value.pair = Pair::create(create(lengthSize.width(), style.effectiveZoom()), create(lengthSize.height(), style.effectiveZoom()), Pair::KeepIdenticalValues).leakRef(); 390 } 391 392 void CSSPrimitiveValue::init(PassRefPtrWillBeRawPtr<Counter> c) 393 { 394 m_primitiveUnitType = CSS_COUNTER; 395 m_hasCachedCSSText = false; 396 m_value.counter = c.leakRef(); 397 } 398 399 void CSSPrimitiveValue::init(PassRefPtrWillBeRawPtr<Rect> r) 400 { 401 m_primitiveUnitType = CSS_RECT; 402 m_hasCachedCSSText = false; 403 m_value.rect = r.leakRef(); 404 } 405 406 void CSSPrimitiveValue::init(PassRefPtrWillBeRawPtr<Quad> quad) 407 { 408 m_primitiveUnitType = CSS_QUAD; 409 m_hasCachedCSSText = false; 410 m_value.quad = quad.leakRef(); 411 } 412 413 void CSSPrimitiveValue::init(PassRefPtrWillBeRawPtr<Pair> p) 414 { 415 m_primitiveUnitType = CSS_PAIR; 416 m_hasCachedCSSText = false; 417 m_value.pair = p.leakRef(); 418 } 419 420 void CSSPrimitiveValue::init(PassRefPtrWillBeRawPtr<CSSCalcValue> c) 421 { 422 m_primitiveUnitType = CSS_CALC; 423 m_hasCachedCSSText = false; 424 m_value.calc = c.leakRef(); 425 } 426 427 void CSSPrimitiveValue::init(PassRefPtrWillBeRawPtr<CSSBasicShape> shape) 428 { 429 m_primitiveUnitType = CSS_SHAPE; 430 m_hasCachedCSSText = false; 431 m_value.shape = shape.leakRef(); 432 } 433 434 CSSPrimitiveValue::~CSSPrimitiveValue() 435 { 436 cleanup(); 437 } 438 439 void CSSPrimitiveValue::cleanup() 440 { 441 switch (static_cast<UnitType>(m_primitiveUnitType)) { 442 case CSS_STRING: 443 case CSS_URI: 444 case CSS_ATTR: 445 case CSS_COUNTER_NAME: 446 case CSS_PARSER_HEXCOLOR: 447 if (m_value.string) 448 m_value.string->deref(); 449 break; 450 case CSS_COUNTER: 451 // We must not call deref() when oilpan is enabled because m_value.counter is traced. 452 #if !ENABLE(OILPAN) 453 m_value.counter->deref(); 454 #endif 455 break; 456 case CSS_RECT: 457 // We must not call deref() when oilpan is enabled because m_value.rect is traced. 458 #if !ENABLE(OILPAN) 459 m_value.rect->deref(); 460 #endif 461 break; 462 case CSS_QUAD: 463 // We must not call deref() when oilpan is enabled because m_value.quad is traced. 464 #if !ENABLE(OILPAN) 465 m_value.quad->deref(); 466 #endif 467 break; 468 case CSS_PAIR: 469 // We must not call deref() when oilpan is enabled because m_value.pair is traced. 470 #if !ENABLE(OILPAN) 471 m_value.pair->deref(); 472 #endif 473 break; 474 case CSS_CALC: 475 // We must not call deref() when oilpan is enabled because m_value.calc is traced. 476 #if !ENABLE(OILPAN) 477 m_value.calc->deref(); 478 #endif 479 break; 480 case CSS_CALC_PERCENTAGE_WITH_NUMBER: 481 case CSS_CALC_PERCENTAGE_WITH_LENGTH: 482 ASSERT_NOT_REACHED(); 483 break; 484 case CSS_SHAPE: 485 // We must not call deref() when oilpan is enabled because m_value.shape is traced. 486 #if !ENABLE(OILPAN) 487 m_value.shape->deref(); 488 #endif 489 break; 490 case CSS_NUMBER: 491 case CSS_PARSER_INTEGER: 492 case CSS_PERCENTAGE: 493 case CSS_EMS: 494 case CSS_EXS: 495 case CSS_REMS: 496 case CSS_CHS: 497 case CSS_PX: 498 case CSS_CM: 499 case CSS_MM: 500 case CSS_IN: 501 case CSS_PT: 502 case CSS_PC: 503 case CSS_DEG: 504 case CSS_RAD: 505 case CSS_GRAD: 506 case CSS_MS: 507 case CSS_S: 508 case CSS_HZ: 509 case CSS_KHZ: 510 case CSS_TURN: 511 case CSS_VW: 512 case CSS_VH: 513 case CSS_VMIN: 514 case CSS_VMAX: 515 case CSS_DPPX: 516 case CSS_DPI: 517 case CSS_DPCM: 518 case CSS_FR: 519 case CSS_IDENT: 520 case CSS_RGBCOLOR: 521 case CSS_DIMENSION: 522 case CSS_UNKNOWN: 523 case CSS_UNICODE_RANGE: 524 case CSS_PARSER_OPERATOR: 525 case CSS_PARSER_IDENTIFIER: 526 case CSS_PROPERTY_ID: 527 case CSS_VALUE_ID: 528 break; 529 } 530 m_primitiveUnitType = 0; 531 if (m_hasCachedCSSText) { 532 cssTextCache().remove(this); 533 m_hasCachedCSSText = false; 534 } 535 } 536 537 double CSSPrimitiveValue::computeDegrees() 538 { 539 switch (m_primitiveUnitType) { 540 case CSS_DEG: 541 return getDoubleValue(); 542 case CSS_RAD: 543 return rad2deg(getDoubleValue()); 544 case CSS_GRAD: 545 return grad2deg(getDoubleValue()); 546 case CSS_TURN: 547 return turn2deg(getDoubleValue()); 548 default: 549 ASSERT_NOT_REACHED(); 550 return 0; 551 } 552 } 553 554 template<> int CSSPrimitiveValue::computeLength(const CSSToLengthConversionData& conversionData) 555 { 556 return roundForImpreciseConversion<int>(computeLengthDouble(conversionData)); 557 } 558 559 template<> unsigned CSSPrimitiveValue::computeLength(const CSSToLengthConversionData& conversionData) 560 { 561 return roundForImpreciseConversion<unsigned>(computeLengthDouble(conversionData)); 562 } 563 564 template<> Length CSSPrimitiveValue::computeLength(const CSSToLengthConversionData& conversionData) 565 { 566 return Length(clampTo<float>(computeLengthDouble(conversionData), minValueForCssLength, maxValueForCssLength), Fixed); 567 } 568 569 template<> short CSSPrimitiveValue::computeLength(const CSSToLengthConversionData& conversionData) 570 { 571 return roundForImpreciseConversion<short>(computeLengthDouble(conversionData)); 572 } 573 574 template<> unsigned short CSSPrimitiveValue::computeLength(const CSSToLengthConversionData& conversionData) 575 { 576 return roundForImpreciseConversion<unsigned short>(computeLengthDouble(conversionData)); 577 } 578 579 template<> float CSSPrimitiveValue::computeLength(const CSSToLengthConversionData& conversionData) 580 { 581 return static_cast<float>(computeLengthDouble(conversionData)); 582 } 583 584 template<> double CSSPrimitiveValue::computeLength(const CSSToLengthConversionData& conversionData) 585 { 586 return computeLengthDouble(conversionData); 587 } 588 589 double CSSPrimitiveValue::computeLengthDouble(const CSSToLengthConversionData& conversionData) 590 { 591 // The logic in this function is duplicated in MediaValues::computeLength 592 // because MediaValues::computeLength needs nearly identical logic, but we haven't found a way to make 593 // CSSPrimitiveValue::computeLengthDouble more generic (to solve both cases) without hurting performance. 594 if (m_primitiveUnitType == CSS_CALC) 595 return m_value.calc->computeLengthPx(conversionData); 596 597 const RenderStyle& style = conversionData.style(); 598 const RenderStyle* rootStyle = conversionData.rootStyle(); 599 bool computingFontSize = conversionData.computingFontSize(); 600 601 double factor; 602 603 switch (primitiveType()) { 604 case CSS_EMS: 605 factor = computingFontSize ? style.fontDescription().specifiedSize() : style.fontDescription().computedSize(); 606 break; 607 case CSS_EXS: 608 // FIXME: We have a bug right now where the zoom will be applied twice to EX units. 609 // We really need to compute EX using fontMetrics for the original specifiedSize and not use 610 // our actual constructed rendering font. 611 if (style.fontMetrics().hasXHeight()) 612 factor = style.fontMetrics().xHeight(); 613 else 614 factor = (computingFontSize ? style.fontDescription().specifiedSize() : style.fontDescription().computedSize()) / 2.0; 615 break; 616 case CSS_REMS: 617 if (rootStyle) 618 factor = computingFontSize ? rootStyle->fontDescription().specifiedSize() : rootStyle->fontDescription().computedSize(); 619 else 620 factor = 1.0; 621 break; 622 case CSS_CHS: 623 factor = style.fontMetrics().zeroWidth(); 624 break; 625 case CSS_PX: 626 factor = 1.0; 627 break; 628 case CSS_CM: 629 factor = cssPixelsPerCentimeter; 630 break; 631 case CSS_MM: 632 factor = cssPixelsPerMillimeter; 633 break; 634 case CSS_IN: 635 factor = cssPixelsPerInch; 636 break; 637 case CSS_PT: 638 factor = cssPixelsPerPoint; 639 break; 640 case CSS_PC: 641 factor = cssPixelsPerPica; 642 break; 643 case CSS_VW: 644 factor = conversionData.viewportWidthPercent(); 645 break; 646 case CSS_VH: 647 factor = conversionData.viewportHeightPercent(); 648 break; 649 case CSS_VMIN: 650 factor = conversionData.viewportMinPercent(); 651 break; 652 case CSS_VMAX: 653 factor = conversionData.viewportMaxPercent(); 654 break; 655 case CSS_CALC_PERCENTAGE_WITH_LENGTH: 656 case CSS_CALC_PERCENTAGE_WITH_NUMBER: 657 ASSERT_NOT_REACHED(); 658 return -1.0; 659 default: 660 ASSERT_NOT_REACHED(); 661 return -1.0; 662 } 663 664 // We do not apply the zoom factor when we are computing the value of the font-size property. The zooming 665 // for font sizes is much more complicated, since we have to worry about enforcing the minimum font size preference 666 // as well as enforcing the implicit "smart minimum." 667 double result = getDoubleValue() * factor; 668 if (computingFontSize || isFontRelativeLength()) 669 return result; 670 671 return result * conversionData.zoom(); 672 } 673 674 void CSSPrimitiveValue::accumulateLengthArray(CSSLengthArray& lengthArray, double multiplier) const 675 { 676 ASSERT(lengthArray.size() == LengthUnitTypeCount); 677 678 if (m_primitiveUnitType == CSS_CALC) { 679 cssCalcValue()->accumulateLengthArray(lengthArray, multiplier); 680 return; 681 } 682 683 LengthUnitType lengthType; 684 if (unitTypeToLengthUnitType(static_cast<UnitType>(m_primitiveUnitType), lengthType)) 685 lengthArray.at(lengthType) += m_value.num * conversionToCanonicalUnitsScaleFactor(static_cast<UnitType>(m_primitiveUnitType)) * multiplier; 686 } 687 688 void CSSPrimitiveValue::setFloatValue(unsigned short, double, ExceptionState& exceptionState) 689 { 690 // Keeping values immutable makes optimizations easier and allows sharing of the primitive value objects. 691 // No other engine supports mutating style through this API. Computed style is always read-only anyway. 692 // Supporting setter would require making primitive value copy-on-write and taking care of style invalidation. 693 exceptionState.throwDOMException(NoModificationAllowedError, "CSSPrimitiveValue objects are read-only."); 694 } 695 696 double CSSPrimitiveValue::conversionToCanonicalUnitsScaleFactor(UnitType unitType) 697 { 698 double factor = 1.0; 699 // FIXME: the switch can be replaced by an array of scale factors. 700 switch (unitType) { 701 // These are "canonical" units in their respective categories. 702 case CSS_PX: 703 case CSS_DEG: 704 case CSS_MS: 705 case CSS_HZ: 706 break; 707 case CSS_CM: 708 factor = cssPixelsPerCentimeter; 709 break; 710 case CSS_DPCM: 711 factor = 1 / cssPixelsPerCentimeter; 712 break; 713 case CSS_MM: 714 factor = cssPixelsPerMillimeter; 715 break; 716 case CSS_IN: 717 factor = cssPixelsPerInch; 718 break; 719 case CSS_DPI: 720 factor = 1 / cssPixelsPerInch; 721 break; 722 case CSS_PT: 723 factor = cssPixelsPerPoint; 724 break; 725 case CSS_PC: 726 factor = cssPixelsPerPica; 727 break; 728 case CSS_RAD: 729 factor = 180 / piDouble; 730 break; 731 case CSS_GRAD: 732 factor = 0.9; 733 break; 734 case CSS_TURN: 735 factor = 360; 736 break; 737 case CSS_S: 738 case CSS_KHZ: 739 factor = 1000; 740 break; 741 default: 742 break; 743 } 744 745 return factor; 746 } 747 748 double CSSPrimitiveValue::getDoubleValue(UnitType unitType, ExceptionState& exceptionState) const 749 { 750 double result = 0; 751 bool success = getDoubleValueInternal(unitType, &result); 752 if (!success) { 753 exceptionState.throwDOMException(InvalidAccessError, "Failed to obtain a double value."); 754 return 0.0; 755 } 756 757 return result; 758 } 759 760 double CSSPrimitiveValue::getDoubleValue(UnitType unitType) const 761 { 762 double result = 0; 763 getDoubleValueInternal(unitType, &result); 764 return result; 765 } 766 767 double CSSPrimitiveValue::getDoubleValue() const 768 { 769 return m_primitiveUnitType != CSS_CALC ? m_value.num : m_value.calc->doubleValue(); 770 } 771 772 CSSPrimitiveValue::UnitType CSSPrimitiveValue::canonicalUnitTypeForCategory(UnitCategory category) 773 { 774 // The canonical unit type is chosen according to the way BisonCSSParser::validUnit() chooses the default unit 775 // in each category (based on unitflags). 776 switch (category) { 777 case UNumber: 778 return CSS_NUMBER; 779 case ULength: 780 return CSS_PX; 781 case UPercent: 782 return CSS_UNKNOWN; // Cannot convert between numbers and percent. 783 case UTime: 784 return CSS_MS; 785 case UAngle: 786 return CSS_DEG; 787 case UFrequency: 788 return CSS_HZ; 789 case UResolution: 790 return CSS_DPPX; 791 default: 792 return CSS_UNKNOWN; 793 } 794 } 795 796 bool CSSPrimitiveValue::getDoubleValueInternal(UnitType requestedUnitType, double* result) const 797 { 798 if (!isValidCSSUnitTypeForDoubleConversion(static_cast<UnitType>(m_primitiveUnitType)) || !isValidCSSUnitTypeForDoubleConversion(requestedUnitType)) 799 return false; 800 801 UnitType sourceUnitType = primitiveType(); 802 if (requestedUnitType == sourceUnitType || requestedUnitType == CSS_DIMENSION) { 803 *result = getDoubleValue(); 804 return true; 805 } 806 807 UnitCategory sourceCategory = unitCategory(sourceUnitType); 808 ASSERT(sourceCategory != UOther); 809 810 UnitType targetUnitType = requestedUnitType; 811 UnitCategory targetCategory = unitCategory(targetUnitType); 812 ASSERT(targetCategory != UOther); 813 814 // Cannot convert between unrelated unit categories if one of them is not UNumber. 815 if (sourceCategory != targetCategory && sourceCategory != UNumber && targetCategory != UNumber) 816 return false; 817 818 if (targetCategory == UNumber) { 819 // We interpret conversion to CSS_NUMBER as conversion to a canonical unit in this value's category. 820 targetUnitType = canonicalUnitTypeForCategory(sourceCategory); 821 if (targetUnitType == CSS_UNKNOWN) 822 return false; 823 } 824 825 if (sourceUnitType == CSS_NUMBER) { 826 // We interpret conversion from CSS_NUMBER in the same way as BisonCSSParser::validUnit() while using non-strict mode. 827 sourceUnitType = canonicalUnitTypeForCategory(targetCategory); 828 if (sourceUnitType == CSS_UNKNOWN) 829 return false; 830 } 831 832 double convertedValue = getDoubleValue(); 833 834 // First convert the value from m_primitiveUnitType to canonical type. 835 double factor = conversionToCanonicalUnitsScaleFactor(sourceUnitType); 836 convertedValue *= factor; 837 838 // Now convert from canonical type to the target unitType. 839 factor = conversionToCanonicalUnitsScaleFactor(targetUnitType); 840 convertedValue /= factor; 841 842 *result = convertedValue; 843 return true; 844 } 845 846 bool CSSPrimitiveValue::unitTypeToLengthUnitType(UnitType unitType, LengthUnitType& lengthType) 847 { 848 switch (unitType) { 849 case CSSPrimitiveValue::CSS_PX: 850 case CSSPrimitiveValue::CSS_CM: 851 case CSSPrimitiveValue::CSS_MM: 852 case CSSPrimitiveValue::CSS_IN: 853 case CSSPrimitiveValue::CSS_PT: 854 case CSSPrimitiveValue::CSS_PC: 855 lengthType = UnitTypePixels; 856 return true; 857 case CSSPrimitiveValue::CSS_EMS: 858 lengthType = UnitTypeFontSize; 859 return true; 860 case CSSPrimitiveValue::CSS_EXS: 861 lengthType = UnitTypeFontXSize; 862 return true; 863 case CSSPrimitiveValue::CSS_REMS: 864 lengthType = UnitTypeRootFontSize; 865 return true; 866 case CSSPrimitiveValue::CSS_CHS: 867 lengthType = UnitTypeZeroCharacterWidth; 868 return true; 869 case CSSPrimitiveValue::CSS_PERCENTAGE: 870 lengthType = UnitTypePercentage; 871 return true; 872 case CSSPrimitiveValue::CSS_VW: 873 lengthType = UnitTypeViewportWidth; 874 return true; 875 case CSSPrimitiveValue::CSS_VH: 876 lengthType = UnitTypeViewportHeight; 877 return true; 878 case CSSPrimitiveValue::CSS_VMIN: 879 lengthType = UnitTypeViewportMin; 880 return true; 881 case CSSPrimitiveValue::CSS_VMAX: 882 lengthType = UnitTypeViewportMax; 883 return true; 884 default: 885 return false; 886 } 887 } 888 889 CSSPrimitiveValue::UnitType CSSPrimitiveValue::lengthUnitTypeToUnitType(LengthUnitType type) 890 { 891 switch (type) { 892 case UnitTypePixels: 893 return CSSPrimitiveValue::CSS_PX; 894 case UnitTypeFontSize: 895 return CSSPrimitiveValue::CSS_EMS; 896 case UnitTypeFontXSize: 897 return CSSPrimitiveValue::CSS_EXS; 898 case UnitTypeRootFontSize: 899 return CSSPrimitiveValue::CSS_REMS; 900 case UnitTypeZeroCharacterWidth: 901 return CSSPrimitiveValue::CSS_CHS; 902 case UnitTypePercentage: 903 return CSSPrimitiveValue::CSS_PERCENTAGE; 904 case UnitTypeViewportWidth: 905 return CSSPrimitiveValue::CSS_VW; 906 case UnitTypeViewportHeight: 907 return CSSPrimitiveValue::CSS_VH; 908 case UnitTypeViewportMin: 909 return CSSPrimitiveValue::CSS_VMIN; 910 case UnitTypeViewportMax: 911 return CSSPrimitiveValue::CSS_VMAX; 912 case LengthUnitTypeCount: 913 break; 914 } 915 ASSERT_NOT_REACHED(); 916 return CSSPrimitiveValue::CSS_UNKNOWN; 917 } 918 919 void CSSPrimitiveValue::setStringValue(unsigned short, const String&, ExceptionState& exceptionState) 920 { 921 // Keeping values immutable makes optimizations easier and allows sharing of the primitive value objects. 922 // No other engine supports mutating style through this API. Computed style is always read-only anyway. 923 // Supporting setter would require making primitive value copy-on-write and taking care of style invalidation. 924 exceptionState.throwDOMException(NoModificationAllowedError, "CSSPrimitiveValue objects are read-only."); 925 } 926 927 String CSSPrimitiveValue::getStringValue(ExceptionState& exceptionState) const 928 { 929 switch (m_primitiveUnitType) { 930 case CSS_STRING: 931 case CSS_ATTR: 932 case CSS_URI: 933 return m_value.string; 934 case CSS_VALUE_ID: 935 return valueName(m_value.valueID); 936 case CSS_PROPERTY_ID: 937 return propertyName(m_value.propertyID); 938 default: 939 exceptionState.throwDOMException(InvalidAccessError, "This object's value cannot be represented as a string."); 940 break; 941 } 942 943 return String(); 944 } 945 946 String CSSPrimitiveValue::getStringValue() const 947 { 948 switch (m_primitiveUnitType) { 949 case CSS_STRING: 950 case CSS_ATTR: 951 case CSS_URI: 952 return m_value.string; 953 case CSS_VALUE_ID: 954 return valueName(m_value.valueID); 955 case CSS_PROPERTY_ID: 956 return propertyName(m_value.propertyID); 957 default: 958 break; 959 } 960 961 return String(); 962 } 963 964 Counter* CSSPrimitiveValue::getCounterValue(ExceptionState& exceptionState) const 965 { 966 if (m_primitiveUnitType != CSS_COUNTER) { 967 exceptionState.throwDOMException(InvalidAccessError, "This object is not a counter value."); 968 return 0; 969 } 970 971 return m_value.counter; 972 } 973 974 Rect* CSSPrimitiveValue::getRectValue(ExceptionState& exceptionState) const 975 { 976 if (m_primitiveUnitType != CSS_RECT) { 977 exceptionState.throwDOMException(InvalidAccessError, "This object is not a rect value."); 978 return 0; 979 } 980 981 return m_value.rect; 982 } 983 984 Quad* CSSPrimitiveValue::getQuadValue(ExceptionState& exceptionState) const 985 { 986 if (m_primitiveUnitType != CSS_QUAD) { 987 exceptionState.throwDOMException(InvalidAccessError, "This object is not a quad value."); 988 return 0; 989 } 990 991 return m_value.quad; 992 } 993 994 PassRefPtrWillBeRawPtr<RGBColor> CSSPrimitiveValue::getRGBColorValue(ExceptionState& exceptionState) const 995 { 996 if (m_primitiveUnitType != CSS_RGBCOLOR) { 997 exceptionState.throwDOMException(InvalidAccessError, "This object is not an RGB color value."); 998 return nullptr; 999 } 1000 1001 // FIMXE: This should not return a new object for each invocation. 1002 return RGBColor::create(m_value.rgbcolor); 1003 } 1004 1005 Pair* CSSPrimitiveValue::getPairValue(ExceptionState& exceptionState) const 1006 { 1007 if (m_primitiveUnitType != CSS_PAIR) { 1008 exceptionState.throwDOMException(InvalidAccessError, "This object is not a pair value."); 1009 return 0; 1010 } 1011 1012 return m_value.pair; 1013 } 1014 1015 static String formatNumber(double number, const char* suffix, unsigned suffixLength) 1016 { 1017 Decimal decimal = Decimal::fromDouble(number); 1018 String result = decimal.toString(); 1019 result.append(suffix, suffixLength); 1020 return result; 1021 } 1022 1023 template <unsigned characterCount> 1024 ALWAYS_INLINE static String formatNumber(double number, const char (&characters)[characterCount]) 1025 { 1026 return formatNumber(number, characters, characterCount - 1); 1027 } 1028 1029 static String formatNumber(double number, const char* characters) 1030 { 1031 return formatNumber(number, characters, strlen(characters)); 1032 } 1033 1034 const char* CSSPrimitiveValue::unitTypeToString(UnitType type) 1035 { 1036 switch (type) { 1037 case CSS_NUMBER: 1038 case CSS_PARSER_INTEGER: 1039 return ""; 1040 case CSS_PERCENTAGE: 1041 return "%"; 1042 case CSS_EMS: 1043 return "em"; 1044 case CSS_EXS: 1045 return "ex"; 1046 case CSS_REMS: 1047 return "rem"; 1048 case CSS_CHS: 1049 return "ch"; 1050 case CSS_PX: 1051 return "px"; 1052 case CSS_CM: 1053 return "cm"; 1054 case CSS_DPPX: 1055 return "dppx"; 1056 case CSS_DPI: 1057 return "dpi"; 1058 case CSS_DPCM: 1059 return "dpcm"; 1060 case CSS_MM: 1061 return "mm"; 1062 case CSS_IN: 1063 return "in"; 1064 case CSS_PT: 1065 return "pt"; 1066 case CSS_PC: 1067 return "pc"; 1068 case CSS_DEG: 1069 return "deg"; 1070 case CSS_RAD: 1071 return "rad"; 1072 case CSS_GRAD: 1073 return "grad"; 1074 case CSS_MS: 1075 return "ms"; 1076 case CSS_S: 1077 return "s"; 1078 case CSS_HZ: 1079 return "hz"; 1080 case CSS_KHZ: 1081 return "khz"; 1082 case CSS_TURN: 1083 return "turn"; 1084 case CSS_FR: 1085 return "fr"; 1086 case CSS_VW: 1087 return "vw"; 1088 case CSS_VH: 1089 return "vh"; 1090 case CSS_VMIN: 1091 return "vmin"; 1092 case CSS_VMAX: 1093 return "vmax"; 1094 case CSS_UNKNOWN: 1095 case CSS_DIMENSION: 1096 case CSS_STRING: 1097 case CSS_URI: 1098 case CSS_VALUE_ID: 1099 case CSS_PROPERTY_ID: 1100 case CSS_ATTR: 1101 case CSS_COUNTER_NAME: 1102 case CSS_COUNTER: 1103 case CSS_RECT: 1104 case CSS_QUAD: 1105 case CSS_RGBCOLOR: 1106 case CSS_PARSER_HEXCOLOR: 1107 case CSS_PAIR: 1108 case CSS_PARSER_OPERATOR: 1109 case CSS_PARSER_IDENTIFIER: 1110 case CSS_CALC: 1111 case CSS_SHAPE: 1112 case CSS_IDENT: 1113 case CSS_UNICODE_RANGE: 1114 case CSS_CALC_PERCENTAGE_WITH_NUMBER: 1115 case CSS_CALC_PERCENTAGE_WITH_LENGTH: 1116 break; 1117 }; 1118 ASSERT_NOT_REACHED(); 1119 return ""; 1120 } 1121 1122 String CSSPrimitiveValue::customCSSText(CSSTextFormattingFlags formattingFlag) const 1123 { 1124 // FIXME: return the original value instead of a generated one (e.g. color 1125 // name if it was specified) - check what spec says about this 1126 1127 if (m_hasCachedCSSText) { 1128 ASSERT(cssTextCache().contains(this)); 1129 return cssTextCache().get(this); 1130 } 1131 1132 String text; 1133 switch (m_primitiveUnitType) { 1134 case CSS_UNKNOWN: 1135 // FIXME 1136 break; 1137 case CSS_NUMBER: 1138 case CSS_PARSER_INTEGER: 1139 case CSS_PERCENTAGE: 1140 case CSS_EMS: 1141 case CSS_EXS: 1142 case CSS_REMS: 1143 case CSS_CHS: 1144 case CSS_PX: 1145 case CSS_CM: 1146 case CSS_DPPX: 1147 case CSS_DPI: 1148 case CSS_DPCM: 1149 case CSS_MM: 1150 case CSS_IN: 1151 case CSS_PT: 1152 case CSS_PC: 1153 case CSS_DEG: 1154 case CSS_RAD: 1155 case CSS_GRAD: 1156 case CSS_MS: 1157 case CSS_S: 1158 case CSS_HZ: 1159 case CSS_KHZ: 1160 case CSS_TURN: 1161 case CSS_FR: 1162 case CSS_VW: 1163 case CSS_VH: 1164 case CSS_VMIN: 1165 case CSS_VMAX: 1166 text = formatNumber(m_value.num, unitTypeToString((UnitType)m_primitiveUnitType)); 1167 case CSS_DIMENSION: 1168 // FIXME: We currently don't handle CSS_DIMENSION properly as we don't store 1169 // the actual dimension, just the numeric value as a string. 1170 break; 1171 case CSS_STRING: 1172 text = formattingFlag == AlwaysQuoteCSSString ? quoteCSSString(m_value.string) : quoteCSSStringIfNeeded(m_value.string); 1173 break; 1174 case CSS_URI: 1175 text = "url(" + quoteCSSURLIfNeeded(m_value.string) + ")"; 1176 break; 1177 case CSS_VALUE_ID: 1178 text = valueName(m_value.valueID); 1179 break; 1180 case CSS_PROPERTY_ID: 1181 text = propertyName(m_value.propertyID); 1182 break; 1183 case CSS_ATTR: { 1184 StringBuilder result; 1185 result.reserveCapacity(6 + m_value.string->length()); 1186 result.appendLiteral("attr("); 1187 result.append(m_value.string); 1188 result.append(')'); 1189 1190 text = result.toString(); 1191 break; 1192 } 1193 case CSS_COUNTER_NAME: 1194 text = "counter(" + String(m_value.string) + ')'; 1195 break; 1196 case CSS_COUNTER: { 1197 StringBuilder result; 1198 String separator = m_value.counter->separator(); 1199 if (separator.isEmpty()) 1200 result.appendLiteral("counter("); 1201 else 1202 result.appendLiteral("counters("); 1203 1204 result.append(m_value.counter->identifier()); 1205 if (!separator.isEmpty()) { 1206 result.appendLiteral(", "); 1207 result.append(quoteCSSStringIfNeeded(separator)); 1208 } 1209 String listStyle = m_value.counter->listStyle(); 1210 if (!listStyle.isEmpty()) { 1211 result.appendLiteral(", "); 1212 result.append(listStyle); 1213 } 1214 result.append(')'); 1215 1216 text = result.toString(); 1217 break; 1218 } 1219 case CSS_RECT: 1220 text = getRectValue()->cssText(); 1221 break; 1222 case CSS_QUAD: 1223 text = getQuadValue()->cssText(); 1224 break; 1225 case CSS_RGBCOLOR: 1226 case CSS_PARSER_HEXCOLOR: { 1227 RGBA32 rgbColor = m_value.rgbcolor; 1228 if (m_primitiveUnitType == CSS_PARSER_HEXCOLOR) 1229 Color::parseHexColor(m_value.string, rgbColor); 1230 Color color(rgbColor); 1231 text = color.serializedAsCSSComponentValue(); 1232 break; 1233 } 1234 case CSS_PAIR: 1235 text = getPairValue()->cssText(); 1236 break; 1237 case CSS_PARSER_OPERATOR: { 1238 char c = static_cast<char>(m_value.parserOperator); 1239 text = String(&c, 1U); 1240 break; 1241 } 1242 case CSS_PARSER_IDENTIFIER: 1243 text = quoteCSSStringIfNeeded(m_value.string); 1244 break; 1245 case CSS_CALC: 1246 text = m_value.calc->cssText(); 1247 break; 1248 case CSS_SHAPE: 1249 text = m_value.shape->cssText(); 1250 break; 1251 } 1252 1253 ASSERT(!cssTextCache().contains(this)); 1254 cssTextCache().set(this, text); 1255 m_hasCachedCSSText = true; 1256 return text; 1257 } 1258 1259 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPrimitiveValue::cloneForCSSOM() const 1260 { 1261 RefPtrWillBeRawPtr<CSSPrimitiveValue> result = nullptr; 1262 1263 switch (m_primitiveUnitType) { 1264 case CSS_STRING: 1265 case CSS_URI: 1266 case CSS_ATTR: 1267 case CSS_COUNTER_NAME: 1268 result = CSSPrimitiveValue::create(m_value.string, static_cast<UnitType>(m_primitiveUnitType)); 1269 break; 1270 case CSS_COUNTER: 1271 result = CSSPrimitiveValue::create(m_value.counter->cloneForCSSOM()); 1272 break; 1273 case CSS_RECT: 1274 result = CSSPrimitiveValue::create(m_value.rect->cloneForCSSOM()); 1275 break; 1276 case CSS_QUAD: 1277 result = CSSPrimitiveValue::create(m_value.quad->cloneForCSSOM()); 1278 break; 1279 case CSS_PAIR: 1280 // Pair is not exposed to the CSSOM, no need for a deep clone. 1281 result = CSSPrimitiveValue::create(m_value.pair); 1282 break; 1283 case CSS_CALC: 1284 // CSSCalcValue is not exposed to the CSSOM, no need for a deep clone. 1285 result = CSSPrimitiveValue::create(m_value.calc); 1286 break; 1287 case CSS_SHAPE: 1288 // CSSShapeValue is not exposed to the CSSOM, no need for a deep clone. 1289 result = CSSPrimitiveValue::create(m_value.shape); 1290 break; 1291 case CSS_NUMBER: 1292 case CSS_PARSER_INTEGER: 1293 case CSS_PERCENTAGE: 1294 case CSS_EMS: 1295 case CSS_EXS: 1296 case CSS_REMS: 1297 case CSS_CHS: 1298 case CSS_PX: 1299 case CSS_CM: 1300 case CSS_MM: 1301 case CSS_IN: 1302 case CSS_PT: 1303 case CSS_PC: 1304 case CSS_DEG: 1305 case CSS_RAD: 1306 case CSS_GRAD: 1307 case CSS_MS: 1308 case CSS_S: 1309 case CSS_HZ: 1310 case CSS_KHZ: 1311 case CSS_TURN: 1312 case CSS_VW: 1313 case CSS_VH: 1314 case CSS_VMIN: 1315 case CSS_VMAX: 1316 case CSS_DPPX: 1317 case CSS_DPI: 1318 case CSS_DPCM: 1319 case CSS_FR: 1320 result = CSSPrimitiveValue::create(m_value.num, static_cast<UnitType>(m_primitiveUnitType)); 1321 break; 1322 case CSS_PROPERTY_ID: 1323 result = CSSPrimitiveValue::createIdentifier(m_value.propertyID); 1324 break; 1325 case CSS_VALUE_ID: 1326 result = CSSPrimitiveValue::createIdentifier(m_value.valueID); 1327 break; 1328 case CSS_RGBCOLOR: 1329 result = CSSPrimitiveValue::createColor(m_value.rgbcolor); 1330 break; 1331 case CSS_DIMENSION: 1332 case CSS_UNKNOWN: 1333 case CSS_PARSER_OPERATOR: 1334 case CSS_PARSER_IDENTIFIER: 1335 case CSS_PARSER_HEXCOLOR: 1336 ASSERT_NOT_REACHED(); 1337 break; 1338 } 1339 if (result) 1340 result->setCSSOMSafe(); 1341 1342 return result; 1343 } 1344 1345 bool CSSPrimitiveValue::equals(const CSSPrimitiveValue& other) const 1346 { 1347 if (m_primitiveUnitType != other.m_primitiveUnitType) 1348 return false; 1349 1350 switch (m_primitiveUnitType) { 1351 case CSS_UNKNOWN: 1352 return false; 1353 case CSS_NUMBER: 1354 case CSS_PARSER_INTEGER: 1355 case CSS_PERCENTAGE: 1356 case CSS_EMS: 1357 case CSS_EXS: 1358 case CSS_REMS: 1359 case CSS_PX: 1360 case CSS_CM: 1361 case CSS_DPPX: 1362 case CSS_DPI: 1363 case CSS_DPCM: 1364 case CSS_MM: 1365 case CSS_IN: 1366 case CSS_PT: 1367 case CSS_PC: 1368 case CSS_DEG: 1369 case CSS_RAD: 1370 case CSS_GRAD: 1371 case CSS_MS: 1372 case CSS_S: 1373 case CSS_HZ: 1374 case CSS_KHZ: 1375 case CSS_TURN: 1376 case CSS_VW: 1377 case CSS_VH: 1378 case CSS_VMIN: 1379 case CSS_VMAX: 1380 case CSS_DIMENSION: 1381 case CSS_FR: 1382 return m_value.num == other.m_value.num; 1383 case CSS_PROPERTY_ID: 1384 return propertyName(m_value.propertyID) == propertyName(other.m_value.propertyID); 1385 case CSS_VALUE_ID: 1386 return valueName(m_value.valueID) == valueName(other.m_value.valueID); 1387 case CSS_STRING: 1388 case CSS_URI: 1389 case CSS_ATTR: 1390 case CSS_COUNTER_NAME: 1391 case CSS_PARSER_IDENTIFIER: 1392 case CSS_PARSER_HEXCOLOR: 1393 return equal(m_value.string, other.m_value.string); 1394 case CSS_COUNTER: 1395 return m_value.counter && other.m_value.counter && m_value.counter->equals(*other.m_value.counter); 1396 case CSS_RECT: 1397 return m_value.rect && other.m_value.rect && m_value.rect->equals(*other.m_value.rect); 1398 case CSS_QUAD: 1399 return m_value.quad && other.m_value.quad && m_value.quad->equals(*other.m_value.quad); 1400 case CSS_RGBCOLOR: 1401 return m_value.rgbcolor == other.m_value.rgbcolor; 1402 case CSS_PAIR: 1403 return m_value.pair && other.m_value.pair && m_value.pair->equals(*other.m_value.pair); 1404 case CSS_PARSER_OPERATOR: 1405 return m_value.parserOperator == other.m_value.parserOperator; 1406 case CSS_CALC: 1407 return m_value.calc && other.m_value.calc && m_value.calc->equals(*other.m_value.calc); 1408 case CSS_SHAPE: 1409 return m_value.shape && other.m_value.shape && m_value.shape->equals(*other.m_value.shape); 1410 } 1411 return false; 1412 } 1413 1414 void CSSPrimitiveValue::traceAfterDispatch(Visitor* visitor) 1415 { 1416 switch (m_primitiveUnitType) { 1417 case CSS_COUNTER: 1418 visitor->trace(m_value.counter); 1419 break; 1420 case CSS_RECT: 1421 visitor->trace(m_value.rect); 1422 break; 1423 case CSS_QUAD: 1424 visitor->trace(m_value.quad); 1425 break; 1426 case CSS_PAIR: 1427 visitor->trace(m_value.pair); 1428 break; 1429 case CSS_CALC: 1430 visitor->trace(m_value.calc); 1431 break; 1432 case CSS_SHAPE: 1433 visitor->trace(m_value.shape); 1434 break; 1435 default: 1436 break; 1437 } 1438 CSSValue::traceAfterDispatch(visitor); 1439 } 1440 1441 } // namespace WebCore 1442