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