1 /* 2 * (C) 1999-2003 Lars Knoll (knoll (at) kde.org) 3 * Copyright (C) 2004, 2005, 2006, 2007, 2008 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 "CSSPrimitiveValue.h" 23 24 #include "CSSHelper.h" 25 #include "CSSParser.h" 26 #include "CSSPropertyNames.h" 27 #include "CSSStyleSheet.h" 28 #include "CSSValueKeywords.h" 29 #include "Color.h" 30 #include "Counter.h" 31 #include "ExceptionCode.h" 32 #include "Node.h" 33 #include "Pair.h" 34 #include "RGBColor.h" 35 #include "Rect.h" 36 #include "RenderStyle.h" 37 #include <wtf/ASCIICType.h> 38 #include <wtf/DecimalNumber.h> 39 #include <wtf/MathExtras.h> 40 #include <wtf/StdLibExtras.h> 41 #include <wtf/text/StringBuffer.h> 42 43 #if ENABLE(DASHBOARD_SUPPORT) 44 #include "DashboardRegion.h" 45 #endif 46 47 using namespace WTF; 48 49 namespace WebCore { 50 51 static CSSPrimitiveValue::UnitCategory unitCategory(CSSPrimitiveValue::UnitTypes type) 52 { 53 // Here we violate the spec (http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSPrimitiveValue) and allow conversions 54 // between CSS_PX and relative lengths (see cssPixelsPerInch comment in CSSHelper.h for the topic treatment). 55 switch (type) { 56 case CSSPrimitiveValue::CSS_NUMBER: 57 return CSSPrimitiveValue::UNumber; 58 case CSSPrimitiveValue::CSS_PERCENTAGE: 59 return CSSPrimitiveValue::UPercent; 60 case CSSPrimitiveValue::CSS_PX: 61 case CSSPrimitiveValue::CSS_CM: 62 case CSSPrimitiveValue::CSS_MM: 63 case CSSPrimitiveValue::CSS_IN: 64 case CSSPrimitiveValue::CSS_PT: 65 case CSSPrimitiveValue::CSS_PC: 66 return CSSPrimitiveValue::ULength; 67 case CSSPrimitiveValue::CSS_MS: 68 case CSSPrimitiveValue::CSS_S: 69 return CSSPrimitiveValue::UTime; 70 case CSSPrimitiveValue::CSS_DEG: 71 case CSSPrimitiveValue::CSS_RAD: 72 case CSSPrimitiveValue::CSS_GRAD: 73 case CSSPrimitiveValue::CSS_TURN: 74 return CSSPrimitiveValue::UAngle; 75 case CSSPrimitiveValue::CSS_HZ: 76 case CSSPrimitiveValue::CSS_KHZ: 77 return CSSPrimitiveValue::UFrequency; 78 default: 79 return CSSPrimitiveValue::UOther; 80 } 81 } 82 83 typedef HashMap<const CSSPrimitiveValue*, String> CSSTextCache; 84 static CSSTextCache& cssTextCache() 85 { 86 DEFINE_STATIC_LOCAL(CSSTextCache, cache, ()); 87 return cache; 88 } 89 90 static const AtomicString& valueOrPropertyName(int valueOrPropertyID) 91 { 92 ASSERT_ARG(valueOrPropertyID, valueOrPropertyID >= 0); 93 ASSERT_ARG(valueOrPropertyID, valueOrPropertyID < numCSSValueKeywords || (valueOrPropertyID >= firstCSSProperty && valueOrPropertyID < firstCSSProperty + numCSSProperties)); 94 95 if (valueOrPropertyID < 0) 96 return nullAtom; 97 98 if (valueOrPropertyID < numCSSValueKeywords) { 99 static AtomicString* cssValueKeywordStrings[numCSSValueKeywords]; 100 if (!cssValueKeywordStrings[valueOrPropertyID]) 101 cssValueKeywordStrings[valueOrPropertyID] = new AtomicString(getValueName(valueOrPropertyID)); 102 return *cssValueKeywordStrings[valueOrPropertyID]; 103 } 104 105 if (valueOrPropertyID >= firstCSSProperty && valueOrPropertyID < firstCSSProperty + numCSSProperties) { 106 static AtomicString* cssPropertyStrings[numCSSProperties]; 107 int propertyIndex = valueOrPropertyID - firstCSSProperty; 108 if (!cssPropertyStrings[propertyIndex]) 109 cssPropertyStrings[propertyIndex] = new AtomicString(getPropertyName(static_cast<CSSPropertyID>(valueOrPropertyID))); 110 return *cssPropertyStrings[propertyIndex]; 111 } 112 113 return nullAtom; 114 } 115 116 CSSPrimitiveValue::CSSPrimitiveValue() 117 : m_type(0) 118 , m_hasCachedCSSText(false) 119 { 120 } 121 122 CSSPrimitiveValue::CSSPrimitiveValue(int ident) 123 : m_type(CSS_IDENT) 124 , m_hasCachedCSSText(false) 125 { 126 m_value.ident = ident; 127 } 128 129 CSSPrimitiveValue::CSSPrimitiveValue(double num, UnitTypes type) 130 : m_type(type) 131 , m_hasCachedCSSText(false) 132 { 133 m_value.num = num; 134 } 135 136 CSSPrimitiveValue::CSSPrimitiveValue(const String& str, UnitTypes type) 137 : m_type(type) 138 , m_hasCachedCSSText(false) 139 { 140 if ((m_value.string = str.impl())) 141 m_value.string->ref(); 142 } 143 144 CSSPrimitiveValue::CSSPrimitiveValue(RGBA32 color) 145 : m_type(CSS_RGBCOLOR) 146 , m_hasCachedCSSText(false) 147 { 148 m_value.rgbcolor = color; 149 } 150 151 CSSPrimitiveValue::CSSPrimitiveValue(const Length& length) 152 : m_hasCachedCSSText(false) 153 { 154 switch (length.type()) { 155 case Auto: 156 m_type = CSS_IDENT; 157 m_value.ident = CSSValueAuto; 158 break; 159 case WebCore::Fixed: 160 m_type = CSS_PX; 161 m_value.num = length.value(); 162 break; 163 case Intrinsic: 164 m_type = CSS_IDENT; 165 m_value.ident = CSSValueIntrinsic; 166 break; 167 case MinIntrinsic: 168 m_type = CSS_IDENT; 169 m_value.ident = CSSValueMinIntrinsic; 170 break; 171 case Percent: 172 m_type = CSS_PERCENTAGE; 173 m_value.num = length.percent(); 174 break; 175 case Relative: 176 ASSERT_NOT_REACHED(); 177 break; 178 } 179 } 180 181 void CSSPrimitiveValue::init(PassRefPtr<Counter> c) 182 { 183 m_type = CSS_COUNTER; 184 m_hasCachedCSSText = false; 185 m_value.counter = c.releaseRef(); 186 } 187 188 void CSSPrimitiveValue::init(PassRefPtr<Rect> r) 189 { 190 m_type = CSS_RECT; 191 m_hasCachedCSSText = false; 192 m_value.rect = r.releaseRef(); 193 } 194 195 #if ENABLE(DASHBOARD_SUPPORT) 196 void CSSPrimitiveValue::init(PassRefPtr<DashboardRegion> r) 197 { 198 m_type = CSS_DASHBOARD_REGION; 199 m_hasCachedCSSText = false; 200 m_value.region = r.releaseRef(); 201 } 202 #endif 203 204 void CSSPrimitiveValue::init(PassRefPtr<Pair> p) 205 { 206 m_type = CSS_PAIR; 207 m_hasCachedCSSText = false; 208 m_value.pair = p.releaseRef(); 209 } 210 211 CSSPrimitiveValue::~CSSPrimitiveValue() 212 { 213 cleanup(); 214 } 215 216 void CSSPrimitiveValue::cleanup() 217 { 218 switch (m_type) { 219 case CSS_STRING: 220 case CSS_URI: 221 case CSS_ATTR: 222 case CSS_PARSER_HEXCOLOR: 223 if (m_value.string) 224 m_value.string->deref(); 225 break; 226 case CSS_COUNTER: 227 m_value.counter->deref(); 228 break; 229 case CSS_RECT: 230 m_value.rect->deref(); 231 break; 232 case CSS_PAIR: 233 m_value.pair->deref(); 234 break; 235 #if ENABLE(DASHBOARD_SUPPORT) 236 case CSS_DASHBOARD_REGION: 237 if (m_value.region) 238 m_value.region->deref(); 239 break; 240 #endif 241 default: 242 break; 243 } 244 245 m_type = 0; 246 if (m_hasCachedCSSText) { 247 cssTextCache().remove(this); 248 m_hasCachedCSSText = false; 249 } 250 } 251 252 int CSSPrimitiveValue::computeLengthInt(RenderStyle* style, RenderStyle* rootStyle) 253 { 254 return roundForImpreciseConversion<int, INT_MAX, INT_MIN>(computeLengthDouble(style, rootStyle)); 255 } 256 257 int CSSPrimitiveValue::computeLengthInt(RenderStyle* style, RenderStyle* rootStyle, double multiplier) 258 { 259 return roundForImpreciseConversion<int, INT_MAX, INT_MIN>(computeLengthDouble(style, rootStyle, multiplier)); 260 } 261 262 // Lengths expect an int that is only 28-bits, so we have to check for a 263 // different overflow. 264 int CSSPrimitiveValue::computeLengthIntForLength(RenderStyle* style, RenderStyle* rootStyle) 265 { 266 return roundForImpreciseConversion<int, intMaxForLength, intMinForLength>(computeLengthDouble(style, rootStyle)); 267 } 268 269 int CSSPrimitiveValue::computeLengthIntForLength(RenderStyle* style, RenderStyle* rootStyle, double multiplier) 270 { 271 return roundForImpreciseConversion<int, intMaxForLength, intMinForLength>(computeLengthDouble(style, rootStyle, multiplier)); 272 } 273 274 short CSSPrimitiveValue::computeLengthShort(RenderStyle* style, RenderStyle* rootStyle) 275 { 276 return roundForImpreciseConversion<short, SHRT_MAX, SHRT_MIN>(computeLengthDouble(style, rootStyle)); 277 } 278 279 short CSSPrimitiveValue::computeLengthShort(RenderStyle* style, RenderStyle* rootStyle, double multiplier) 280 { 281 return roundForImpreciseConversion<short, SHRT_MAX, SHRT_MIN>(computeLengthDouble(style, rootStyle, multiplier)); 282 } 283 284 float CSSPrimitiveValue::computeLengthFloat(RenderStyle* style, RenderStyle* rootStyle, bool computingFontSize) 285 { 286 return static_cast<float>(computeLengthDouble(style, rootStyle, 1.0, computingFontSize)); 287 } 288 289 float CSSPrimitiveValue::computeLengthFloat(RenderStyle* style, RenderStyle* rootStyle, double multiplier, bool computingFontSize) 290 { 291 return static_cast<float>(computeLengthDouble(style, rootStyle, multiplier, computingFontSize)); 292 } 293 294 double CSSPrimitiveValue::computeLengthDouble(RenderStyle* style, RenderStyle* rootStyle, double multiplier, bool computingFontSize) 295 { 296 unsigned short type = primitiveType(); 297 298 // We do not apply the zoom factor when we are computing the value of the font-size property. The zooming 299 // for font sizes is much more complicated, since we have to worry about enforcing the minimum font size preference 300 // as well as enforcing the implicit "smart minimum." In addition the CSS property text-size-adjust is used to 301 // prevent text from zooming at all. Therefore we will not apply the zoom here if we are computing font-size. 302 bool applyZoomMultiplier = !computingFontSize; 303 304 double factor = 1.0; 305 switch (type) { 306 case CSS_EMS: 307 applyZoomMultiplier = false; 308 factor = computingFontSize ? style->fontDescription().specifiedSize() : style->fontDescription().computedSize(); 309 break; 310 case CSS_EXS: 311 // FIXME: We have a bug right now where the zoom will be applied twice to EX units. 312 // We really need to compute EX using fontMetrics for the original specifiedSize and not use 313 // our actual constructed rendering font. 314 applyZoomMultiplier = false; 315 factor = style->fontMetrics().xHeight(); 316 break; 317 case CSS_REMS: 318 applyZoomMultiplier = false; 319 factor = computingFontSize ? rootStyle->fontDescription().specifiedSize() : rootStyle->fontDescription().computedSize(); 320 break; 321 case CSS_PX: 322 break; 323 case CSS_CM: 324 factor = cssPixelsPerInch / 2.54; // (2.54 cm/in) 325 break; 326 case CSS_MM: 327 factor = cssPixelsPerInch / 25.4; 328 break; 329 case CSS_IN: 330 factor = cssPixelsPerInch; 331 break; 332 case CSS_PT: 333 factor = cssPixelsPerInch / 72.0; 334 break; 335 case CSS_PC: 336 // 1 pc == 12 pt 337 factor = cssPixelsPerInch * 12.0 / 72.0; 338 break; 339 default: 340 return -1.0; 341 } 342 343 double result = getDoubleValue() * factor; 344 if (!applyZoomMultiplier || multiplier == 1.0) 345 return result; 346 347 // Any original result that was >= 1 should not be allowed to fall below 1. This keeps border lines from 348 // vanishing. 349 double zoomedResult = result * multiplier; 350 if (result >= 1.0) 351 zoomedResult = max(1.0, zoomedResult); 352 return zoomedResult; 353 } 354 355 void CSSPrimitiveValue::setFloatValue(unsigned short, double, ExceptionCode& ec) 356 { 357 // Keeping values immutable makes optimizations easier and allows sharing of the primitive value objects. 358 // No other engine supports mutating style through this API. Computed style is always read-only anyway. 359 // Supporting setter would require making primitive value copy-on-write and taking care of style invalidation. 360 ec = NO_MODIFICATION_ALLOWED_ERR; 361 } 362 363 static double conversionToCanonicalUnitsScaleFactor(unsigned short unitType) 364 { 365 double factor = 1.0; 366 // FIXME: the switch can be replaced by an array of scale factors. 367 switch (unitType) { 368 // These are "canonical" units in their respective categories. 369 case CSSPrimitiveValue::CSS_PX: 370 case CSSPrimitiveValue::CSS_DEG: 371 case CSSPrimitiveValue::CSS_MS: 372 case CSSPrimitiveValue::CSS_HZ: 373 break; 374 case CSSPrimitiveValue::CSS_CM: 375 factor = cssPixelsPerInch / 2.54; // (2.54 cm/in) 376 break; 377 case CSSPrimitiveValue::CSS_MM: 378 factor = cssPixelsPerInch / 25.4; 379 break; 380 case CSSPrimitiveValue::CSS_IN: 381 factor = cssPixelsPerInch; 382 break; 383 case CSSPrimitiveValue::CSS_PT: 384 factor = cssPixelsPerInch / 72.0; 385 break; 386 case CSSPrimitiveValue::CSS_PC: 387 factor = cssPixelsPerInch * 12.0 / 72.0; // 1 pc == 12 pt 388 break; 389 case CSSPrimitiveValue::CSS_RAD: 390 factor = 180 / piDouble; 391 break; 392 case CSSPrimitiveValue::CSS_GRAD: 393 factor = 0.9; 394 break; 395 case CSSPrimitiveValue::CSS_TURN: 396 factor = 360; 397 break; 398 case CSSPrimitiveValue::CSS_S: 399 case CSSPrimitiveValue::CSS_KHZ: 400 factor = 1000; 401 break; 402 default: 403 break; 404 } 405 406 return factor; 407 } 408 409 double CSSPrimitiveValue::getDoubleValue(unsigned short unitType, ExceptionCode& ec) const 410 { 411 double result = 0; 412 bool success = getDoubleValueInternal(static_cast<UnitTypes>(unitType), &result); 413 if (!success) { 414 ec = INVALID_ACCESS_ERR; 415 return 0.0; 416 } 417 418 ec = 0; 419 return result; 420 } 421 422 double CSSPrimitiveValue::getDoubleValue(unsigned short unitType) const 423 { 424 double result = 0; 425 getDoubleValueInternal(static_cast<UnitTypes>(unitType), &result); 426 return result; 427 } 428 429 CSSPrimitiveValue::UnitTypes CSSPrimitiveValue::canonicalUnitTypeForCategory(UnitCategory category) 430 { 431 // The canonical unit type is chosen according to the way CSSParser::validUnit() chooses the default unit 432 // in each category (based on unitflags). 433 switch (category) { 434 case UNumber: 435 return CSS_NUMBER; 436 case ULength: 437 return CSS_PX; 438 case UPercent: 439 return CSS_UNKNOWN; // Cannot convert between numbers and percent. 440 case UTime: 441 return CSS_MS; 442 case UAngle: 443 return CSS_DEG; 444 case UFrequency: 445 return CSS_HZ; 446 default: 447 return CSS_UNKNOWN; 448 } 449 } 450 451 bool CSSPrimitiveValue::getDoubleValueInternal(UnitTypes requestedUnitType, double* result) const 452 { 453 if (m_type < CSS_NUMBER || (m_type > CSS_DIMENSION && m_type < CSS_TURN) || requestedUnitType < CSS_NUMBER || (requestedUnitType > CSS_DIMENSION && requestedUnitType < CSS_TURN)) 454 return false; 455 if (requestedUnitType == m_type || requestedUnitType == CSS_DIMENSION) { 456 *result = m_value.num; 457 return true; 458 } 459 460 UnitTypes sourceUnitType = static_cast<UnitTypes>(m_type); 461 UnitCategory sourceCategory = unitCategory(sourceUnitType); 462 ASSERT(sourceCategory != UOther); 463 464 UnitTypes targetUnitType = requestedUnitType; 465 UnitCategory targetCategory = unitCategory(targetUnitType); 466 ASSERT(targetCategory != UOther); 467 468 // Cannot convert between unrelated unit categories if one of them is not UNumber. 469 if (sourceCategory != targetCategory && sourceCategory != UNumber && targetCategory != UNumber) 470 return false; 471 472 if (targetCategory == UNumber) { 473 // We interpret conversion to CSS_NUMBER as conversion to a canonical unit in this value's category. 474 targetUnitType = canonicalUnitTypeForCategory(sourceCategory); 475 if (targetUnitType == CSS_UNKNOWN) 476 return false; 477 } 478 479 if (sourceUnitType == CSS_NUMBER) { 480 // We interpret conversion from CSS_NUMBER in the same way as CSSParser::validUnit() while using non-strict mode. 481 sourceUnitType = canonicalUnitTypeForCategory(targetCategory); 482 if (sourceUnitType == CSS_UNKNOWN) 483 return false; 484 } 485 486 double convertedValue = m_value.num; 487 488 // First convert the value from m_type to canonical type. 489 double factor = conversionToCanonicalUnitsScaleFactor(sourceUnitType); 490 convertedValue *= factor; 491 492 // Now convert from canonical type to the target unitType. 493 factor = conversionToCanonicalUnitsScaleFactor(targetUnitType); 494 convertedValue /= factor; 495 496 *result = convertedValue; 497 return true; 498 } 499 500 void CSSPrimitiveValue::setStringValue(unsigned short, const String&, ExceptionCode& ec) 501 { 502 // Keeping values immutable makes optimizations easier and allows sharing of the primitive value objects. 503 // No other engine supports mutating style through this API. Computed style is always read-only anyway. 504 // Supporting setter would require making primitive value copy-on-write and taking care of style invalidation. 505 ec = NO_MODIFICATION_ALLOWED_ERR; 506 } 507 508 String CSSPrimitiveValue::getStringValue(ExceptionCode& ec) const 509 { 510 ec = 0; 511 switch (m_type) { 512 case CSS_STRING: 513 case CSS_ATTR: 514 case CSS_URI: 515 return m_value.string; 516 case CSS_IDENT: 517 return valueOrPropertyName(m_value.ident); 518 default: 519 ec = INVALID_ACCESS_ERR; 520 break; 521 } 522 523 return String(); 524 } 525 526 String CSSPrimitiveValue::getStringValue() const 527 { 528 switch (m_type) { 529 case CSS_STRING: 530 case CSS_ATTR: 531 case CSS_URI: 532 return m_value.string; 533 case CSS_IDENT: 534 return valueOrPropertyName(m_value.ident); 535 default: 536 break; 537 } 538 539 return String(); 540 } 541 542 Counter* CSSPrimitiveValue::getCounterValue(ExceptionCode& ec) const 543 { 544 ec = 0; 545 if (m_type != CSS_COUNTER) { 546 ec = INVALID_ACCESS_ERR; 547 return 0; 548 } 549 550 return m_value.counter; 551 } 552 553 Rect* CSSPrimitiveValue::getRectValue(ExceptionCode& ec) const 554 { 555 ec = 0; 556 if (m_type != CSS_RECT) { 557 ec = INVALID_ACCESS_ERR; 558 return 0; 559 } 560 561 return m_value.rect; 562 } 563 564 PassRefPtr<RGBColor> CSSPrimitiveValue::getRGBColorValue(ExceptionCode& ec) const 565 { 566 ec = 0; 567 if (m_type != CSS_RGBCOLOR) { 568 ec = INVALID_ACCESS_ERR; 569 return 0; 570 } 571 572 // FIMXE: This should not return a new object for each invocation. 573 return RGBColor::create(m_value.rgbcolor); 574 } 575 576 Pair* CSSPrimitiveValue::getPairValue(ExceptionCode& ec) const 577 { 578 ec = 0; 579 if (m_type != CSS_PAIR) { 580 ec = INVALID_ACCESS_ERR; 581 return 0; 582 } 583 584 return m_value.pair; 585 } 586 587 unsigned short CSSPrimitiveValue::cssValueType() const 588 { 589 return CSS_PRIMITIVE_VALUE; 590 } 591 592 bool CSSPrimitiveValue::parseString(const String& /*string*/, bool /*strict*/) 593 { 594 // FIXME 595 return false; 596 } 597 598 int CSSPrimitiveValue::getIdent() const 599 { 600 if (m_type != CSS_IDENT) 601 return 0; 602 return m_value.ident; 603 } 604 605 static String formatNumber(double number) 606 { 607 DecimalNumber decimal(number); 608 609 StringBuffer buffer(decimal.bufferLengthForStringDecimal()); 610 unsigned length = decimal.toStringDecimal(buffer.characters(), buffer.length()); 611 ASSERT_UNUSED(length, length == buffer.length()); 612 613 return String::adopt(buffer); 614 } 615 616 String CSSPrimitiveValue::cssText() const 617 { 618 // FIXME: return the original value instead of a generated one (e.g. color 619 // name if it was specified) - check what spec says about this 620 621 if (m_hasCachedCSSText) { 622 ASSERT(cssTextCache().contains(this)); 623 return cssTextCache().get(this); 624 } 625 626 String text; 627 switch (m_type) { 628 case CSS_UNKNOWN: 629 // FIXME 630 break; 631 case CSS_NUMBER: 632 case CSS_PARSER_INTEGER: 633 text = formatNumber(m_value.num); 634 break; 635 case CSS_PERCENTAGE: 636 text = formatNumber(m_value.num) + "%"; 637 break; 638 case CSS_EMS: 639 text = formatNumber(m_value.num) + "em"; 640 break; 641 case CSS_EXS: 642 text = formatNumber(m_value.num) + "ex"; 643 break; 644 case CSS_REMS: 645 text = formatNumber(m_value.num) + "rem"; 646 break; 647 case CSS_PX: 648 text = formatNumber(m_value.num) + "px"; 649 break; 650 case CSS_CM: 651 text = formatNumber(m_value.num) + "cm"; 652 break; 653 case CSS_MM: 654 text = formatNumber(m_value.num) + "mm"; 655 break; 656 case CSS_IN: 657 text = formatNumber(m_value.num) + "in"; 658 break; 659 case CSS_PT: 660 text = formatNumber(m_value.num) + "pt"; 661 break; 662 case CSS_PC: 663 text = formatNumber(m_value.num) + "pc"; 664 break; 665 case CSS_DEG: 666 text = formatNumber(m_value.num) + "deg"; 667 break; 668 case CSS_RAD: 669 text = formatNumber(m_value.num) + "rad"; 670 break; 671 case CSS_GRAD: 672 text = formatNumber(m_value.num) + "grad"; 673 break; 674 case CSS_MS: 675 text = formatNumber(m_value.num) + "ms"; 676 break; 677 case CSS_S: 678 text = formatNumber(m_value.num) + "s"; 679 break; 680 case CSS_HZ: 681 text = formatNumber(m_value.num) + "hz"; 682 break; 683 case CSS_KHZ: 684 text = formatNumber(m_value.num) + "khz"; 685 break; 686 case CSS_TURN: 687 text = formatNumber(m_value.num) + "turn"; 688 break; 689 case CSS_DIMENSION: 690 // FIXME 691 break; 692 case CSS_STRING: 693 text = quoteCSSStringIfNeeded(m_value.string); 694 break; 695 case CSS_URI: 696 text = "url(" + quoteCSSURLIfNeeded(m_value.string) + ")"; 697 break; 698 case CSS_IDENT: 699 text = valueOrPropertyName(m_value.ident); 700 break; 701 case CSS_ATTR: { 702 DEFINE_STATIC_LOCAL(const String, attrParen, ("attr(")); 703 704 Vector<UChar> result; 705 result.reserveInitialCapacity(6 + m_value.string->length()); 706 707 append(result, attrParen); 708 append(result, m_value.string); 709 result.uncheckedAppend(')'); 710 711 text = String::adopt(result); 712 break; 713 } 714 case CSS_COUNTER_NAME: 715 text = "counter("; 716 text += m_value.string; 717 text += ")"; 718 break; 719 case CSS_COUNTER: 720 text = "counter("; 721 text += String::number(m_value.num); 722 text += ")"; 723 // FIXME: Add list-style and separator 724 break; 725 case CSS_RECT: { 726 DEFINE_STATIC_LOCAL(const String, rectParen, ("rect(")); 727 728 Rect* rectVal = getRectValue(); 729 Vector<UChar> result; 730 result.reserveInitialCapacity(32); 731 append(result, rectParen); 732 733 append(result, rectVal->top()->cssText()); 734 result.append(' '); 735 736 append(result, rectVal->right()->cssText()); 737 result.append(' '); 738 739 append(result, rectVal->bottom()->cssText()); 740 result.append(' '); 741 742 append(result, rectVal->left()->cssText()); 743 result.append(')'); 744 745 text = String::adopt(result); 746 break; 747 } 748 case CSS_RGBCOLOR: 749 case CSS_PARSER_HEXCOLOR: { 750 DEFINE_STATIC_LOCAL(const String, commaSpace, (", ")); 751 DEFINE_STATIC_LOCAL(const String, rgbParen, ("rgb(")); 752 DEFINE_STATIC_LOCAL(const String, rgbaParen, ("rgba(")); 753 754 RGBA32 rgbColor = m_value.rgbcolor; 755 if (m_type == CSS_PARSER_HEXCOLOR) 756 Color::parseHexColor(m_value.string, rgbColor); 757 Color color(rgbColor); 758 759 Vector<UChar> result; 760 result.reserveInitialCapacity(32); 761 if (color.hasAlpha()) 762 append(result, rgbaParen); 763 else 764 append(result, rgbParen); 765 766 appendNumber(result, static_cast<unsigned char>(color.red())); 767 append(result, commaSpace); 768 769 appendNumber(result, static_cast<unsigned char>(color.green())); 770 append(result, commaSpace); 771 772 appendNumber(result, static_cast<unsigned char>(color.blue())); 773 if (color.hasAlpha()) { 774 append(result, commaSpace); 775 append(result, String::number(color.alpha() / 256.0f)); 776 } 777 778 result.append(')'); 779 text = String::adopt(result); 780 break; 781 } 782 case CSS_PAIR: 783 text = m_value.pair->first()->cssText(); 784 text += " "; 785 text += m_value.pair->second()->cssText(); 786 break; 787 #if ENABLE(DASHBOARD_SUPPORT) 788 case CSS_DASHBOARD_REGION: 789 for (DashboardRegion* region = getDashboardRegionValue(); region; region = region->m_next.get()) { 790 if (!text.isEmpty()) 791 text.append(' '); 792 text += "dashboard-region("; 793 text += region->m_label; 794 if (region->m_isCircle) 795 text += " circle"; 796 else if (region->m_isRectangle) 797 text += " rectangle"; 798 else 799 break; 800 if (region->top()->m_type == CSS_IDENT && region->top()->getIdent() == CSSValueInvalid) { 801 ASSERT(region->right()->m_type == CSS_IDENT); 802 ASSERT(region->bottom()->m_type == CSS_IDENT); 803 ASSERT(region->left()->m_type == CSS_IDENT); 804 ASSERT(region->right()->getIdent() == CSSValueInvalid); 805 ASSERT(region->bottom()->getIdent() == CSSValueInvalid); 806 ASSERT(region->left()->getIdent() == CSSValueInvalid); 807 } else { 808 text.append(' '); 809 text += region->top()->cssText() + " "; 810 text += region->right()->cssText() + " "; 811 text += region->bottom()->cssText() + " "; 812 text += region->left()->cssText(); 813 } 814 text += ")"; 815 } 816 break; 817 #endif 818 case CSS_PARSER_OPERATOR: { 819 char c = static_cast<char>(m_value.ident); 820 text = String(&c, 1U); 821 break; 822 } 823 case CSS_PARSER_IDENTIFIER: 824 text = quoteCSSStringIfNeeded(m_value.string); 825 break; 826 } 827 828 ASSERT(!cssTextCache().contains(this)); 829 cssTextCache().set(this, text); 830 m_hasCachedCSSText = true; 831 return text; 832 } 833 834 void CSSPrimitiveValue::addSubresourceStyleURLs(ListHashSet<KURL>& urls, const CSSStyleSheet* styleSheet) 835 { 836 if (m_type == CSS_URI) 837 addSubresourceURL(urls, styleSheet->completeURL(m_value.string)); 838 } 839 840 } // namespace WebCore 841