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 if (rootStyle) 320 factor = computingFontSize ? rootStyle->fontDescription().specifiedSize() : rootStyle->fontDescription().computedSize(); 321 break; 322 case CSS_PX: 323 break; 324 case CSS_CM: 325 factor = cssPixelsPerInch / 2.54; // (2.54 cm/in) 326 break; 327 case CSS_MM: 328 factor = cssPixelsPerInch / 25.4; 329 break; 330 case CSS_IN: 331 factor = cssPixelsPerInch; 332 break; 333 case CSS_PT: 334 factor = cssPixelsPerInch / 72.0; 335 break; 336 case CSS_PC: 337 // 1 pc == 12 pt 338 factor = cssPixelsPerInch * 12.0 / 72.0; 339 break; 340 default: 341 return -1.0; 342 } 343 344 double result = getDoubleValue() * factor; 345 if (!applyZoomMultiplier || multiplier == 1.0) 346 return result; 347 348 // Any original result that was >= 1 should not be allowed to fall below 1. This keeps border lines from 349 // vanishing. 350 double zoomedResult = result * multiplier; 351 if (result >= 1.0) 352 zoomedResult = max(1.0, zoomedResult); 353 return zoomedResult; 354 } 355 356 void CSSPrimitiveValue::setFloatValue(unsigned short, double, ExceptionCode& ec) 357 { 358 // Keeping values immutable makes optimizations easier and allows sharing of the primitive value objects. 359 // No other engine supports mutating style through this API. Computed style is always read-only anyway. 360 // Supporting setter would require making primitive value copy-on-write and taking care of style invalidation. 361 ec = NO_MODIFICATION_ALLOWED_ERR; 362 } 363 364 static double conversionToCanonicalUnitsScaleFactor(unsigned short unitType) 365 { 366 double factor = 1.0; 367 // FIXME: the switch can be replaced by an array of scale factors. 368 switch (unitType) { 369 // These are "canonical" units in their respective categories. 370 case CSSPrimitiveValue::CSS_PX: 371 case CSSPrimitiveValue::CSS_DEG: 372 case CSSPrimitiveValue::CSS_MS: 373 case CSSPrimitiveValue::CSS_HZ: 374 break; 375 case CSSPrimitiveValue::CSS_CM: 376 factor = cssPixelsPerInch / 2.54; // (2.54 cm/in) 377 break; 378 case CSSPrimitiveValue::CSS_MM: 379 factor = cssPixelsPerInch / 25.4; 380 break; 381 case CSSPrimitiveValue::CSS_IN: 382 factor = cssPixelsPerInch; 383 break; 384 case CSSPrimitiveValue::CSS_PT: 385 factor = cssPixelsPerInch / 72.0; 386 break; 387 case CSSPrimitiveValue::CSS_PC: 388 factor = cssPixelsPerInch * 12.0 / 72.0; // 1 pc == 12 pt 389 break; 390 case CSSPrimitiveValue::CSS_RAD: 391 factor = 180 / piDouble; 392 break; 393 case CSSPrimitiveValue::CSS_GRAD: 394 factor = 0.9; 395 break; 396 case CSSPrimitiveValue::CSS_TURN: 397 factor = 360; 398 break; 399 case CSSPrimitiveValue::CSS_S: 400 case CSSPrimitiveValue::CSS_KHZ: 401 factor = 1000; 402 break; 403 default: 404 break; 405 } 406 407 return factor; 408 } 409 410 double CSSPrimitiveValue::getDoubleValue(unsigned short unitType, ExceptionCode& ec) const 411 { 412 double result = 0; 413 bool success = getDoubleValueInternal(static_cast<UnitTypes>(unitType), &result); 414 if (!success) { 415 ec = INVALID_ACCESS_ERR; 416 return 0.0; 417 } 418 419 ec = 0; 420 return result; 421 } 422 423 double CSSPrimitiveValue::getDoubleValue(unsigned short unitType) const 424 { 425 double result = 0; 426 getDoubleValueInternal(static_cast<UnitTypes>(unitType), &result); 427 return result; 428 } 429 430 CSSPrimitiveValue::UnitTypes CSSPrimitiveValue::canonicalUnitTypeForCategory(UnitCategory category) 431 { 432 // The canonical unit type is chosen according to the way CSSParser::validUnit() chooses the default unit 433 // in each category (based on unitflags). 434 switch (category) { 435 case UNumber: 436 return CSS_NUMBER; 437 case ULength: 438 return CSS_PX; 439 case UPercent: 440 return CSS_UNKNOWN; // Cannot convert between numbers and percent. 441 case UTime: 442 return CSS_MS; 443 case UAngle: 444 return CSS_DEG; 445 case UFrequency: 446 return CSS_HZ; 447 default: 448 return CSS_UNKNOWN; 449 } 450 } 451 452 bool CSSPrimitiveValue::getDoubleValueInternal(UnitTypes requestedUnitType, double* result) const 453 { 454 if (m_type < CSS_NUMBER || (m_type > CSS_DIMENSION && m_type < CSS_TURN) || requestedUnitType < CSS_NUMBER || (requestedUnitType > CSS_DIMENSION && requestedUnitType < CSS_TURN)) 455 return false; 456 if (requestedUnitType == m_type || requestedUnitType == CSS_DIMENSION) { 457 *result = m_value.num; 458 return true; 459 } 460 461 UnitTypes sourceUnitType = static_cast<UnitTypes>(m_type); 462 UnitCategory sourceCategory = unitCategory(sourceUnitType); 463 ASSERT(sourceCategory != UOther); 464 465 UnitTypes targetUnitType = requestedUnitType; 466 UnitCategory targetCategory = unitCategory(targetUnitType); 467 ASSERT(targetCategory != UOther); 468 469 // Cannot convert between unrelated unit categories if one of them is not UNumber. 470 if (sourceCategory != targetCategory && sourceCategory != UNumber && targetCategory != UNumber) 471 return false; 472 473 if (targetCategory == UNumber) { 474 // We interpret conversion to CSS_NUMBER as conversion to a canonical unit in this value's category. 475 targetUnitType = canonicalUnitTypeForCategory(sourceCategory); 476 if (targetUnitType == CSS_UNKNOWN) 477 return false; 478 } 479 480 if (sourceUnitType == CSS_NUMBER) { 481 // We interpret conversion from CSS_NUMBER in the same way as CSSParser::validUnit() while using non-strict mode. 482 sourceUnitType = canonicalUnitTypeForCategory(targetCategory); 483 if (sourceUnitType == CSS_UNKNOWN) 484 return false; 485 } 486 487 double convertedValue = m_value.num; 488 489 // First convert the value from m_type to canonical type. 490 double factor = conversionToCanonicalUnitsScaleFactor(sourceUnitType); 491 convertedValue *= factor; 492 493 // Now convert from canonical type to the target unitType. 494 factor = conversionToCanonicalUnitsScaleFactor(targetUnitType); 495 convertedValue /= factor; 496 497 *result = convertedValue; 498 return true; 499 } 500 501 void CSSPrimitiveValue::setStringValue(unsigned short, const String&, ExceptionCode& ec) 502 { 503 // Keeping values immutable makes optimizations easier and allows sharing of the primitive value objects. 504 // No other engine supports mutating style through this API. Computed style is always read-only anyway. 505 // Supporting setter would require making primitive value copy-on-write and taking care of style invalidation. 506 ec = NO_MODIFICATION_ALLOWED_ERR; 507 } 508 509 String CSSPrimitiveValue::getStringValue(ExceptionCode& ec) const 510 { 511 ec = 0; 512 switch (m_type) { 513 case CSS_STRING: 514 case CSS_ATTR: 515 case CSS_URI: 516 return m_value.string; 517 case CSS_IDENT: 518 return valueOrPropertyName(m_value.ident); 519 default: 520 ec = INVALID_ACCESS_ERR; 521 break; 522 } 523 524 return String(); 525 } 526 527 String CSSPrimitiveValue::getStringValue() const 528 { 529 switch (m_type) { 530 case CSS_STRING: 531 case CSS_ATTR: 532 case CSS_URI: 533 return m_value.string; 534 case CSS_IDENT: 535 return valueOrPropertyName(m_value.ident); 536 default: 537 break; 538 } 539 540 return String(); 541 } 542 543 Counter* CSSPrimitiveValue::getCounterValue(ExceptionCode& ec) const 544 { 545 ec = 0; 546 if (m_type != CSS_COUNTER) { 547 ec = INVALID_ACCESS_ERR; 548 return 0; 549 } 550 551 return m_value.counter; 552 } 553 554 Rect* CSSPrimitiveValue::getRectValue(ExceptionCode& ec) const 555 { 556 ec = 0; 557 if (m_type != CSS_RECT) { 558 ec = INVALID_ACCESS_ERR; 559 return 0; 560 } 561 562 return m_value.rect; 563 } 564 565 PassRefPtr<RGBColor> CSSPrimitiveValue::getRGBColorValue(ExceptionCode& ec) const 566 { 567 ec = 0; 568 if (m_type != CSS_RGBCOLOR) { 569 ec = INVALID_ACCESS_ERR; 570 return 0; 571 } 572 573 // FIMXE: This should not return a new object for each invocation. 574 return RGBColor::create(m_value.rgbcolor); 575 } 576 577 Pair* CSSPrimitiveValue::getPairValue(ExceptionCode& ec) const 578 { 579 ec = 0; 580 if (m_type != CSS_PAIR) { 581 ec = INVALID_ACCESS_ERR; 582 return 0; 583 } 584 585 return m_value.pair; 586 } 587 588 unsigned short CSSPrimitiveValue::cssValueType() const 589 { 590 return CSS_PRIMITIVE_VALUE; 591 } 592 593 bool CSSPrimitiveValue::parseString(const String& /*string*/, bool /*strict*/) 594 { 595 // FIXME 596 return false; 597 } 598 599 int CSSPrimitiveValue::getIdent() const 600 { 601 if (m_type != CSS_IDENT) 602 return 0; 603 return m_value.ident; 604 } 605 606 static String formatNumber(double number) 607 { 608 DecimalNumber decimal(number); 609 610 StringBuffer buffer(decimal.bufferLengthForStringDecimal()); 611 unsigned length = decimal.toStringDecimal(buffer.characters(), buffer.length()); 612 ASSERT_UNUSED(length, length == buffer.length()); 613 614 return String::adopt(buffer); 615 } 616 617 String CSSPrimitiveValue::cssText() const 618 { 619 // FIXME: return the original value instead of a generated one (e.g. color 620 // name if it was specified) - check what spec says about this 621 622 if (m_hasCachedCSSText) { 623 ASSERT(cssTextCache().contains(this)); 624 return cssTextCache().get(this); 625 } 626 627 String text; 628 switch (m_type) { 629 case CSS_UNKNOWN: 630 // FIXME 631 break; 632 case CSS_NUMBER: 633 case CSS_PARSER_INTEGER: 634 text = formatNumber(m_value.num); 635 break; 636 case CSS_PERCENTAGE: 637 text = formatNumber(m_value.num) + "%"; 638 break; 639 case CSS_EMS: 640 text = formatNumber(m_value.num) + "em"; 641 break; 642 case CSS_EXS: 643 text = formatNumber(m_value.num) + "ex"; 644 break; 645 case CSS_REMS: 646 text = formatNumber(m_value.num) + "rem"; 647 break; 648 case CSS_PX: 649 text = formatNumber(m_value.num) + "px"; 650 break; 651 case CSS_CM: 652 text = formatNumber(m_value.num) + "cm"; 653 break; 654 case CSS_MM: 655 text = formatNumber(m_value.num) + "mm"; 656 break; 657 case CSS_IN: 658 text = formatNumber(m_value.num) + "in"; 659 break; 660 case CSS_PT: 661 text = formatNumber(m_value.num) + "pt"; 662 break; 663 case CSS_PC: 664 text = formatNumber(m_value.num) + "pc"; 665 break; 666 case CSS_DEG: 667 text = formatNumber(m_value.num) + "deg"; 668 break; 669 case CSS_RAD: 670 text = formatNumber(m_value.num) + "rad"; 671 break; 672 case CSS_GRAD: 673 text = formatNumber(m_value.num) + "grad"; 674 break; 675 case CSS_MS: 676 text = formatNumber(m_value.num) + "ms"; 677 break; 678 case CSS_S: 679 text = formatNumber(m_value.num) + "s"; 680 break; 681 case CSS_HZ: 682 text = formatNumber(m_value.num) + "hz"; 683 break; 684 case CSS_KHZ: 685 text = formatNumber(m_value.num) + "khz"; 686 break; 687 case CSS_TURN: 688 text = formatNumber(m_value.num) + "turn"; 689 break; 690 case CSS_DIMENSION: 691 // FIXME 692 break; 693 case CSS_STRING: 694 text = quoteCSSStringIfNeeded(m_value.string); 695 break; 696 case CSS_URI: 697 text = "url(" + quoteCSSURLIfNeeded(m_value.string) + ")"; 698 break; 699 case CSS_IDENT: 700 text = valueOrPropertyName(m_value.ident); 701 break; 702 case CSS_ATTR: { 703 DEFINE_STATIC_LOCAL(const String, attrParen, ("attr(")); 704 705 Vector<UChar> result; 706 result.reserveInitialCapacity(6 + m_value.string->length()); 707 708 append(result, attrParen); 709 append(result, m_value.string); 710 result.uncheckedAppend(')'); 711 712 text = String::adopt(result); 713 break; 714 } 715 case CSS_COUNTER_NAME: 716 text = "counter("; 717 text += m_value.string; 718 text += ")"; 719 break; 720 case CSS_COUNTER: 721 text = "counter("; 722 text += String::number(m_value.num); 723 text += ")"; 724 // FIXME: Add list-style and separator 725 break; 726 case CSS_RECT: { 727 DEFINE_STATIC_LOCAL(const String, rectParen, ("rect(")); 728 729 Rect* rectVal = getRectValue(); 730 Vector<UChar> result; 731 result.reserveInitialCapacity(32); 732 append(result, rectParen); 733 734 append(result, rectVal->top()->cssText()); 735 result.append(' '); 736 737 append(result, rectVal->right()->cssText()); 738 result.append(' '); 739 740 append(result, rectVal->bottom()->cssText()); 741 result.append(' '); 742 743 append(result, rectVal->left()->cssText()); 744 result.append(')'); 745 746 text = String::adopt(result); 747 break; 748 } 749 case CSS_RGBCOLOR: 750 case CSS_PARSER_HEXCOLOR: { 751 DEFINE_STATIC_LOCAL(const String, commaSpace, (", ")); 752 DEFINE_STATIC_LOCAL(const String, rgbParen, ("rgb(")); 753 DEFINE_STATIC_LOCAL(const String, rgbaParen, ("rgba(")); 754 755 RGBA32 rgbColor = m_value.rgbcolor; 756 if (m_type == CSS_PARSER_HEXCOLOR) 757 Color::parseHexColor(m_value.string, rgbColor); 758 Color color(rgbColor); 759 760 Vector<UChar> result; 761 result.reserveInitialCapacity(32); 762 if (color.hasAlpha()) 763 append(result, rgbaParen); 764 else 765 append(result, rgbParen); 766 767 appendNumber(result, static_cast<unsigned char>(color.red())); 768 append(result, commaSpace); 769 770 appendNumber(result, static_cast<unsigned char>(color.green())); 771 append(result, commaSpace); 772 773 appendNumber(result, static_cast<unsigned char>(color.blue())); 774 if (color.hasAlpha()) { 775 append(result, commaSpace); 776 append(result, String::number(color.alpha() / 256.0f)); 777 } 778 779 result.append(')'); 780 text = String::adopt(result); 781 break; 782 } 783 case CSS_PAIR: 784 text = m_value.pair->first()->cssText(); 785 text += " "; 786 text += m_value.pair->second()->cssText(); 787 break; 788 #if ENABLE(DASHBOARD_SUPPORT) 789 case CSS_DASHBOARD_REGION: 790 for (DashboardRegion* region = getDashboardRegionValue(); region; region = region->m_next.get()) { 791 if (!text.isEmpty()) 792 text.append(' '); 793 text += "dashboard-region("; 794 text += region->m_label; 795 if (region->m_isCircle) 796 text += " circle"; 797 else if (region->m_isRectangle) 798 text += " rectangle"; 799 else 800 break; 801 if (region->top()->m_type == CSS_IDENT && region->top()->getIdent() == CSSValueInvalid) { 802 ASSERT(region->right()->m_type == CSS_IDENT); 803 ASSERT(region->bottom()->m_type == CSS_IDENT); 804 ASSERT(region->left()->m_type == CSS_IDENT); 805 ASSERT(region->right()->getIdent() == CSSValueInvalid); 806 ASSERT(region->bottom()->getIdent() == CSSValueInvalid); 807 ASSERT(region->left()->getIdent() == CSSValueInvalid); 808 } else { 809 text.append(' '); 810 text += region->top()->cssText() + " "; 811 text += region->right()->cssText() + " "; 812 text += region->bottom()->cssText() + " "; 813 text += region->left()->cssText(); 814 } 815 text += ")"; 816 } 817 break; 818 #endif 819 case CSS_PARSER_OPERATOR: { 820 char c = static_cast<char>(m_value.ident); 821 text = String(&c, 1U); 822 break; 823 } 824 case CSS_PARSER_IDENTIFIER: 825 text = quoteCSSStringIfNeeded(m_value.string); 826 break; 827 } 828 829 ASSERT(!cssTextCache().contains(this)); 830 cssTextCache().set(this, text); 831 m_hasCachedCSSText = true; 832 return text; 833 } 834 835 void CSSPrimitiveValue::addSubresourceStyleURLs(ListHashSet<KURL>& urls, const CSSStyleSheet* styleSheet) 836 { 837 if (m_type == CSS_URI) 838 addSubresourceURL(urls, styleSheet->completeURL(m_value.string)); 839 } 840 841 } // namespace WebCore 842