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 "CSSPropertyNames.h" 26 #include "CSSStyleSheet.h" 27 #include "CSSValueKeywords.h" 28 #include "Color.h" 29 #include "Counter.h" 30 #include "ExceptionCode.h" 31 #include "Node.h" 32 #include "Pair.h" 33 #include "RGBColor.h" 34 #include "Rect.h" 35 #include "RenderStyle.h" 36 #include <wtf/ASCIICType.h> 37 #include <wtf/StdLibExtras.h> 38 39 #if ENABLE(DASHBOARD_SUPPORT) 40 #include "DashboardRegion.h" 41 #endif 42 43 using namespace WTF; 44 45 namespace WebCore { 46 47 // A more stylish solution than sharing would be to turn CSSPrimitiveValue (or CSSValues in general) into non-virtual, 48 // non-refcounted simple type with value semantics. In practice these sharing tricks get similar memory benefits 49 // with less need for refactoring. 50 51 PassRefPtr<CSSPrimitiveValue> CSSPrimitiveValue::createIdentifier(int ident) 52 { 53 static RefPtr<CSSPrimitiveValue>* identValueCache = new RefPtr<CSSPrimitiveValue>[numCSSValueKeywords]; 54 if (ident >= 0 && ident < numCSSValueKeywords) { 55 RefPtr<CSSPrimitiveValue> primitiveValue = identValueCache[ident]; 56 if (!primitiveValue) { 57 primitiveValue = adoptRef(new CSSPrimitiveValue(ident)); 58 identValueCache[ident] = primitiveValue; 59 } 60 return primitiveValue.release(); 61 } 62 return adoptRef(new CSSPrimitiveValue(ident)); 63 } 64 65 PassRefPtr<CSSPrimitiveValue> CSSPrimitiveValue::createColor(unsigned rgbValue) 66 { 67 typedef HashMap<unsigned, RefPtr<CSSPrimitiveValue> > ColorValueCache; 68 static ColorValueCache* colorValueCache = new ColorValueCache; 69 // These are the empty and deleted values of the hash table. 70 if (rgbValue == Color::transparent) { 71 static CSSPrimitiveValue* colorTransparent = new CSSPrimitiveValue(Color::transparent); 72 return colorTransparent; 73 } 74 if (rgbValue == Color::white) { 75 static CSSPrimitiveValue* colorWhite = new CSSPrimitiveValue(Color::white); 76 return colorWhite; 77 } 78 RefPtr<CSSPrimitiveValue> primitiveValue = colorValueCache->get(rgbValue); 79 if (primitiveValue) 80 return primitiveValue.release(); 81 primitiveValue = adoptRef(new CSSPrimitiveValue(rgbValue)); 82 // Just wipe out the cache and start rebuilding when it gets too big. 83 const int maxColorCacheSize = 512; 84 if (colorValueCache->size() >= maxColorCacheSize) 85 colorValueCache->clear(); 86 colorValueCache->add(rgbValue, primitiveValue); 87 88 return primitiveValue.release(); 89 } 90 91 PassRefPtr<CSSPrimitiveValue> CSSPrimitiveValue::create(double value, UnitTypes type) 92 { 93 // Small integers are very common. Try to share them. 94 const int cachedIntegerCount = 128; 95 // Other common primitive types have UnitTypes smaller than this. 96 const int maxCachedUnitType = CSS_PX; 97 typedef RefPtr<CSSPrimitiveValue>(* IntegerValueCache)[maxCachedUnitType + 1]; 98 static IntegerValueCache integerValueCache = new RefPtr<CSSPrimitiveValue>[cachedIntegerCount][maxCachedUnitType + 1]; 99 if (type <= maxCachedUnitType && value >= 0 && value < cachedIntegerCount) { 100 int intValue = static_cast<int>(value); 101 if (value == intValue) { 102 RefPtr<CSSPrimitiveValue> primitiveValue = integerValueCache[intValue][type]; 103 if (!primitiveValue) { 104 primitiveValue = adoptRef(new CSSPrimitiveValue(value, type)); 105 integerValueCache[intValue][type] = primitiveValue; 106 } 107 return primitiveValue.release(); 108 } 109 } 110 111 return adoptRef(new CSSPrimitiveValue(value, type)); 112 } 113 114 PassRefPtr<CSSPrimitiveValue> CSSPrimitiveValue::create(const String& value, UnitTypes type) 115 { 116 return adoptRef(new CSSPrimitiveValue(value, type)); 117 } 118 119 static const char* valueOrPropertyName(int valueOrPropertyID) 120 { 121 if (const char* valueName = getValueName(valueOrPropertyID)) 122 return valueName; 123 return getPropertyName(static_cast<CSSPropertyID>(valueOrPropertyID)); 124 } 125 126 // "ident" from the CSS tokenizer, minus backslash-escape sequences 127 static bool isCSSTokenizerIdentifier(const String& string) 128 { 129 const UChar* p = string.characters(); 130 const UChar* end = p + string.length(); 131 132 // -? 133 if (p != end && p[0] == '-') 134 ++p; 135 136 // {nmstart} 137 if (p == end || !(p[0] == '_' || p[0] >= 128 || isASCIIAlpha(p[0]))) 138 return false; 139 ++p; 140 141 // {nmchar}* 142 for (; p != end; ++p) { 143 if (!(p[0] == '_' || p[0] == '-' || p[0] >= 128 || isASCIIAlphanumeric(p[0]))) 144 return false; 145 } 146 147 return true; 148 } 149 150 // "url" from the CSS tokenizer, minus backslash-escape sequences 151 static bool isCSSTokenizerURL(const String& string) 152 { 153 const UChar* p = string.characters(); 154 const UChar* end = p + string.length(); 155 156 for (; p != end; ++p) { 157 UChar c = p[0]; 158 switch (c) { 159 case '!': 160 case '#': 161 case '$': 162 case '%': 163 case '&': 164 break; 165 default: 166 if (c < '*') 167 return false; 168 if (c <= '~') 169 break; 170 if (c < 128) 171 return false; 172 } 173 } 174 175 return true; 176 } 177 178 // We use single quotes for now because markup.cpp uses double quotes. 179 static String quoteString(const String& string) 180 { 181 // FIXME: Also need to escape characters like '\n'. 182 String s = string; 183 s.replace('\\', "\\\\"); 184 s.replace('\'', "\\'"); 185 return "'" + s + "'"; 186 } 187 188 static String quoteStringIfNeeded(const String& string) 189 { 190 return isCSSTokenizerIdentifier(string) ? string : quoteString(string); 191 } 192 193 static String quoteURLIfNeeded(const String& string) 194 { 195 return isCSSTokenizerURL(string) ? string : quoteString(string); 196 } 197 198 CSSPrimitiveValue::CSSPrimitiveValue() 199 : m_type(0) 200 { 201 } 202 203 CSSPrimitiveValue::CSSPrimitiveValue(int ident) 204 : m_type(CSS_IDENT) 205 { 206 m_value.ident = ident; 207 } 208 209 CSSPrimitiveValue::CSSPrimitiveValue(double num, UnitTypes type) 210 : m_type(type) 211 { 212 m_value.num = num; 213 } 214 215 CSSPrimitiveValue::CSSPrimitiveValue(const String& str, UnitTypes type) 216 : m_type(type) 217 { 218 if ((m_value.string = str.impl())) 219 m_value.string->ref(); 220 } 221 222 CSSPrimitiveValue::CSSPrimitiveValue(RGBA32 color) 223 : m_type(CSS_RGBCOLOR) 224 { 225 m_value.rgbcolor = color; 226 } 227 228 CSSPrimitiveValue::CSSPrimitiveValue(const Length& length) 229 { 230 switch (length.type()) { 231 case Auto: 232 m_type = CSS_IDENT; 233 m_value.ident = CSSValueAuto; 234 break; 235 case WebCore::Fixed: 236 m_type = CSS_PX; 237 m_value.num = length.value(); 238 break; 239 case Intrinsic: 240 m_type = CSS_IDENT; 241 m_value.ident = CSSValueIntrinsic; 242 break; 243 case MinIntrinsic: 244 m_type = CSS_IDENT; 245 m_value.ident = CSSValueMinIntrinsic; 246 break; 247 case Percent: 248 m_type = CSS_PERCENTAGE; 249 m_value.num = length.percent(); 250 break; 251 case Relative: 252 case Static: 253 ASSERT_NOT_REACHED(); 254 break; 255 } 256 } 257 258 void CSSPrimitiveValue::init(PassRefPtr<Counter> c) 259 { 260 m_type = CSS_COUNTER; 261 m_value.counter = c.releaseRef(); 262 } 263 264 void CSSPrimitiveValue::init(PassRefPtr<Rect> r) 265 { 266 m_type = CSS_RECT; 267 m_value.rect = r.releaseRef(); 268 } 269 270 #if ENABLE(DASHBOARD_SUPPORT) 271 void CSSPrimitiveValue::init(PassRefPtr<DashboardRegion> r) 272 { 273 m_type = CSS_DASHBOARD_REGION; 274 m_value.region = r.releaseRef(); 275 } 276 #endif 277 278 void CSSPrimitiveValue::init(PassRefPtr<Pair> p) 279 { 280 m_type = CSS_PAIR; 281 m_value.pair = p.releaseRef(); 282 } 283 284 CSSPrimitiveValue::~CSSPrimitiveValue() 285 { 286 cleanup(); 287 } 288 289 void CSSPrimitiveValue::cleanup() 290 { 291 switch (m_type) { 292 case CSS_STRING: 293 case CSS_URI: 294 case CSS_ATTR: 295 case CSS_PARSER_VARIABLE_FUNCTION_SYNTAX: 296 case CSS_PARSER_HEXCOLOR: 297 if (m_value.string) 298 m_value.string->deref(); 299 break; 300 case CSS_COUNTER: 301 m_value.counter->deref(); 302 break; 303 case CSS_RECT: 304 m_value.rect->deref(); 305 break; 306 case CSS_PAIR: 307 m_value.pair->deref(); 308 break; 309 #if ENABLE(DASHBOARD_SUPPORT) 310 case CSS_DASHBOARD_REGION: 311 if (m_value.region) 312 m_value.region->deref(); 313 break; 314 #endif 315 default: 316 break; 317 } 318 319 m_type = 0; 320 } 321 322 int CSSPrimitiveValue::computeLengthInt(RenderStyle* style, RenderStyle* rootStyle) 323 { 324 double result = computeLengthDouble(style, rootStyle); 325 326 // This conversion is imprecise, often resulting in values of, e.g., 44.99998. We 327 // need to go ahead and round if we're really close to the next integer value. 328 result += result < 0 ? -0.01 : +0.01; 329 330 if (result > INT_MAX || result < INT_MIN) 331 return 0; 332 return static_cast<int>(result); 333 } 334 335 int CSSPrimitiveValue::computeLengthInt(RenderStyle* style, RenderStyle* rootStyle, double multiplier) 336 { 337 double result = computeLengthDouble(style, rootStyle, multiplier); 338 339 // This conversion is imprecise, often resulting in values of, e.g., 44.99998. We 340 // need to go ahead and round if we're really close to the next integer value. 341 result += result < 0 ? -0.01 : +0.01; 342 343 if (result > INT_MAX || result < INT_MIN) 344 return 0; 345 return static_cast<int>(result); 346 } 347 348 const int intMaxForLength = 0x7ffffff; // max value for a 28-bit int 349 const int intMinForLength = (-0x7ffffff - 1); // min value for a 28-bit int 350 351 // Lengths expect an int that is only 28-bits, so we have to check for a different overflow. 352 int CSSPrimitiveValue::computeLengthIntForLength(RenderStyle* style, RenderStyle* rootStyle) 353 { 354 double result = computeLengthDouble(style, rootStyle); 355 356 // This conversion is imprecise, often resulting in values of, e.g., 44.99998. We 357 // need to go ahead and round if we're really close to the next integer value. 358 result += result < 0 ? -0.01 : +0.01; 359 360 if (result > intMaxForLength || result < intMinForLength) 361 return 0; 362 return static_cast<int>(result); 363 } 364 365 // Lengths expect an int that is only 28-bits, so we have to check for a different overflow. 366 int CSSPrimitiveValue::computeLengthIntForLength(RenderStyle* style, RenderStyle* rootStyle, double multiplier) 367 { 368 double result = computeLengthDouble(style, rootStyle, multiplier); 369 370 // This conversion is imprecise, often resulting in values of, e.g., 44.99998. We 371 // need to go ahead and round if we're really close to the next integer value. 372 result += result < 0 ? -0.01 : +0.01; 373 374 if (result > intMaxForLength || result < intMinForLength) 375 return 0; 376 return static_cast<int>(result); 377 } 378 379 short CSSPrimitiveValue::computeLengthShort(RenderStyle* style, RenderStyle* rootStyle) 380 { 381 double result = computeLengthDouble(style, rootStyle); 382 383 // This conversion is imprecise, often resulting in values of, e.g., 44.99998. We 384 // need to go ahead and round if we're really close to the next integer value. 385 result += result < 0 ? -0.01 : +0.01; 386 387 if (result > SHRT_MAX || result < SHRT_MIN) 388 return 0; 389 return static_cast<short>(result); 390 } 391 392 short CSSPrimitiveValue::computeLengthShort(RenderStyle* style, RenderStyle* rootStyle, double multiplier) 393 { 394 double result = computeLengthDouble(style, rootStyle, multiplier); 395 396 // This conversion is imprecise, often resulting in values of, e.g., 44.99998. We 397 // need to go ahead and round if we're really close to the next integer value. 398 result += result < 0 ? -0.01 : +0.01; 399 400 if (result > SHRT_MAX || result < SHRT_MIN) 401 return 0; 402 return static_cast<short>(result); 403 } 404 405 float CSSPrimitiveValue::computeLengthFloat(RenderStyle* style, RenderStyle* rootStyle, bool computingFontSize) 406 { 407 return static_cast<float>(computeLengthDouble(style, rootStyle, 1.0, computingFontSize)); 408 } 409 410 float CSSPrimitiveValue::computeLengthFloat(RenderStyle* style, RenderStyle* rootStyle, double multiplier, bool computingFontSize) 411 { 412 return static_cast<float>(computeLengthDouble(style, rootStyle, multiplier, computingFontSize)); 413 } 414 415 double CSSPrimitiveValue::computeLengthDouble(RenderStyle* style, RenderStyle* rootStyle, double multiplier, bool computingFontSize) 416 { 417 unsigned short type = primitiveType(); 418 419 // We do not apply the zoom factor when we are computing the value of the font-size property. The zooming 420 // for font sizes is much more complicated, since we have to worry about enforcing the minimum font size preference 421 // as well as enforcing the implicit "smart minimum." In addition the CSS property text-size-adjust is used to 422 // prevent text from zooming at all. Therefore we will not apply the zoom here if we are computing font-size. 423 bool applyZoomMultiplier = !computingFontSize; 424 425 double factor = 1.0; 426 switch (type) { 427 case CSS_EMS: 428 applyZoomMultiplier = false; 429 factor = computingFontSize ? style->fontDescription().specifiedSize() : style->fontDescription().computedSize(); 430 break; 431 case CSS_EXS: 432 // FIXME: We have a bug right now where the zoom will be applied twice to EX units. 433 // We really need to compute EX using fontMetrics for the original specifiedSize and not use 434 // our actual constructed rendering font. 435 applyZoomMultiplier = false; 436 factor = style->font().xHeight(); 437 break; 438 case CSS_REMS: 439 applyZoomMultiplier = false; 440 factor = computingFontSize ? rootStyle->fontDescription().specifiedSize() : rootStyle->fontDescription().computedSize(); 441 break; 442 case CSS_PX: 443 break; 444 case CSS_CM: 445 factor = cssPixelsPerInch / 2.54; // (2.54 cm/in) 446 break; 447 case CSS_MM: 448 factor = cssPixelsPerInch / 25.4; 449 break; 450 case CSS_IN: 451 factor = cssPixelsPerInch; 452 break; 453 case CSS_PT: 454 factor = cssPixelsPerInch / 72.0; 455 break; 456 case CSS_PC: 457 // 1 pc == 12 pt 458 factor = cssPixelsPerInch * 12.0 / 72.0; 459 break; 460 default: 461 return -1.0; 462 } 463 464 double result = getDoubleValue() * factor; 465 if (!applyZoomMultiplier || multiplier == 1.0) 466 return result; 467 468 // Any original result that was >= 1 should not be allowed to fall below 1. This keeps border lines from 469 // vanishing. 470 double zoomedResult = result * multiplier; 471 if (result >= 1.0) 472 zoomedResult = max(1.0, zoomedResult); 473 return zoomedResult; 474 } 475 476 void CSSPrimitiveValue::setFloatValue(unsigned short unitType, double floatValue, ExceptionCode& ec) 477 { 478 ec = 0; 479 480 if (m_type < CSS_NUMBER || m_type > CSS_DIMENSION || unitType < CSS_NUMBER || unitType > CSS_DIMENSION) { 481 ec = INVALID_ACCESS_ERR; 482 return; 483 } 484 485 cleanup(); 486 487 //if(m_type > CSS_DIMENSION) throw DOMException(INVALID_ACCESS_ERR); 488 m_value.num = floatValue; 489 m_type = unitType; 490 } 491 492 static double scaleFactorForConversion(unsigned short unitType) 493 { 494 double factor = 1.0; 495 switch (unitType) { 496 case CSSPrimitiveValue::CSS_PX: 497 break; 498 case CSSPrimitiveValue::CSS_CM: 499 factor = cssPixelsPerInch / 2.54; // (2.54 cm/in) 500 break; 501 case CSSPrimitiveValue::CSS_MM: 502 factor = cssPixelsPerInch / 25.4; 503 break; 504 case CSSPrimitiveValue::CSS_IN: 505 factor = cssPixelsPerInch; 506 break; 507 case CSSPrimitiveValue::CSS_PT: 508 factor = cssPixelsPerInch / 72.0; 509 break; 510 case CSSPrimitiveValue::CSS_PC: 511 factor = cssPixelsPerInch * 12.0 / 72.0; // 1 pc == 12 pt 512 break; 513 default: 514 break; 515 } 516 517 return factor; 518 } 519 520 double CSSPrimitiveValue::getDoubleValue(unsigned short unitType, ExceptionCode& ec) 521 { 522 ec = 0; 523 if (m_type < CSS_NUMBER || m_type > CSS_DIMENSION || unitType < CSS_NUMBER || unitType > CSS_DIMENSION) { 524 ec = INVALID_ACCESS_ERR; 525 return 0.0; 526 } 527 528 if (unitType == m_type || unitType < CSS_PX || unitType > CSS_PC) 529 return m_value.num; 530 531 double convertedValue = m_value.num; 532 533 // First convert the value from m_type into CSSPixels 534 double factor = scaleFactorForConversion(m_type); 535 convertedValue *= factor; 536 537 // Now convert from CSSPixels to the specified unitType 538 factor = scaleFactorForConversion(unitType); 539 convertedValue /= factor; 540 541 return convertedValue; 542 } 543 544 double CSSPrimitiveValue::getDoubleValue(unsigned short unitType) 545 { 546 if (m_type < CSS_NUMBER || m_type > CSS_DIMENSION || unitType < CSS_NUMBER || unitType > CSS_DIMENSION) 547 return 0; 548 549 if (unitType == m_type || unitType < CSS_PX || unitType > CSS_PC) 550 return m_value.num; 551 552 double convertedValue = m_value.num; 553 554 // First convert the value from m_type into CSSPixels 555 double factor = scaleFactorForConversion(m_type); 556 convertedValue *= factor; 557 558 // Now convert from CSSPixels to the specified unitType 559 factor = scaleFactorForConversion(unitType); 560 convertedValue /= factor; 561 562 return convertedValue; 563 } 564 565 566 void CSSPrimitiveValue::setStringValue(unsigned short stringType, const String& stringValue, ExceptionCode& ec) 567 { 568 ec = 0; 569 570 if (m_type < CSS_STRING || m_type > CSS_ATTR || stringType < CSS_STRING || stringType > CSS_ATTR) { 571 ec = INVALID_ACCESS_ERR; 572 return; 573 } 574 575 cleanup(); 576 577 if (stringType != CSS_IDENT) { 578 m_value.string = stringValue.impl(); 579 m_value.string->ref(); 580 m_type = stringType; 581 } 582 // FIXME: parse ident 583 } 584 585 String CSSPrimitiveValue::getStringValue(ExceptionCode& ec) const 586 { 587 ec = 0; 588 switch (m_type) { 589 case CSS_STRING: 590 case CSS_ATTR: 591 case CSS_URI: 592 case CSS_PARSER_VARIABLE_FUNCTION_SYNTAX: 593 return m_value.string; 594 case CSS_IDENT: 595 return valueOrPropertyName(m_value.ident); 596 default: 597 ec = INVALID_ACCESS_ERR; 598 break; 599 } 600 601 return String(); 602 } 603 604 String CSSPrimitiveValue::getStringValue() const 605 { 606 switch (m_type) { 607 case CSS_STRING: 608 case CSS_ATTR: 609 case CSS_URI: 610 case CSS_PARSER_VARIABLE_FUNCTION_SYNTAX: 611 return m_value.string; 612 case CSS_IDENT: 613 return valueOrPropertyName(m_value.ident); 614 default: 615 break; 616 } 617 618 return String(); 619 } 620 621 Counter* CSSPrimitiveValue::getCounterValue(ExceptionCode& ec) const 622 { 623 ec = 0; 624 if (m_type != CSS_COUNTER) { 625 ec = INVALID_ACCESS_ERR; 626 return 0; 627 } 628 629 return m_value.counter; 630 } 631 632 Rect* CSSPrimitiveValue::getRectValue(ExceptionCode& ec) const 633 { 634 ec = 0; 635 if (m_type != CSS_RECT) { 636 ec = INVALID_ACCESS_ERR; 637 return 0; 638 } 639 640 return m_value.rect; 641 } 642 643 PassRefPtr<RGBColor> CSSPrimitiveValue::getRGBColorValue(ExceptionCode& ec) const 644 { 645 ec = 0; 646 if (m_type != CSS_RGBCOLOR) { 647 ec = INVALID_ACCESS_ERR; 648 return 0; 649 } 650 651 // FIMXE: This should not return a new object for each invocation. 652 return RGBColor::create(m_value.rgbcolor); 653 } 654 655 Pair* CSSPrimitiveValue::getPairValue(ExceptionCode& ec) const 656 { 657 ec = 0; 658 if (m_type != CSS_PAIR) { 659 ec = INVALID_ACCESS_ERR; 660 return 0; 661 } 662 663 return m_value.pair; 664 } 665 666 unsigned short CSSPrimitiveValue::cssValueType() const 667 { 668 return CSS_PRIMITIVE_VALUE; 669 } 670 671 bool CSSPrimitiveValue::parseString(const String& /*string*/, bool /*strict*/) 672 { 673 // FIXME 674 return false; 675 } 676 677 int CSSPrimitiveValue::getIdent() 678 { 679 if (m_type != CSS_IDENT) 680 return 0; 681 return m_value.ident; 682 } 683 684 String CSSPrimitiveValue::cssText() const 685 { 686 // FIXME: return the original value instead of a generated one (e.g. color 687 // name if it was specified) - check what spec says about this 688 String text; 689 switch (m_type) { 690 case CSS_UNKNOWN: 691 // FIXME 692 break; 693 case CSS_NUMBER: 694 case CSS_PARSER_INTEGER: 695 text = String::number(m_value.num); 696 break; 697 case CSS_PERCENTAGE: 698 text = String::format("%.6lg%%", m_value.num); 699 break; 700 case CSS_EMS: 701 text = String::format("%.6lgem", m_value.num); 702 break; 703 case CSS_EXS: 704 text = String::format("%.6lgex", m_value.num); 705 break; 706 case CSS_REMS: 707 text = String::format("%.6lgrem", m_value.num); 708 break; 709 case CSS_PX: 710 text = String::format("%.6lgpx", m_value.num); 711 break; 712 case CSS_CM: 713 text = String::format("%.6lgcm", m_value.num); 714 break; 715 case CSS_MM: 716 text = String::format("%.6lgmm", m_value.num); 717 break; 718 case CSS_IN: 719 text = String::format("%.6lgin", m_value.num); 720 break; 721 case CSS_PT: 722 text = String::format("%.6lgpt", m_value.num); 723 break; 724 case CSS_PC: 725 text = String::format("%.6lgpc", m_value.num); 726 break; 727 case CSS_DEG: 728 text = String::format("%.6lgdeg", m_value.num); 729 break; 730 case CSS_RAD: 731 text = String::format("%.6lgrad", m_value.num); 732 break; 733 case CSS_GRAD: 734 text = String::format("%.6lggrad", m_value.num); 735 break; 736 case CSS_MS: 737 text = String::format("%.6lgms", m_value.num); 738 break; 739 case CSS_S: 740 text = String::format("%.6lgs", m_value.num); 741 break; 742 case CSS_HZ: 743 text = String::format("%.6lghz", m_value.num); 744 break; 745 case CSS_KHZ: 746 text = String::format("%.6lgkhz", m_value.num); 747 break; 748 case CSS_TURN: 749 text = String::format("%.6lgturn", m_value.num); 750 break; 751 case CSS_DIMENSION: 752 // FIXME 753 break; 754 case CSS_STRING: 755 text = quoteStringIfNeeded(m_value.string); 756 break; 757 case CSS_URI: 758 text = "url(" + quoteURLIfNeeded(m_value.string) + ")"; 759 break; 760 case CSS_IDENT: 761 text = valueOrPropertyName(m_value.ident); 762 break; 763 case CSS_ATTR: { 764 DEFINE_STATIC_LOCAL(const String, attrParen, ("attr(")); 765 766 Vector<UChar> result; 767 result.reserveInitialCapacity(6 + m_value.string->length()); 768 769 append(result, attrParen); 770 append(result, m_value.string); 771 result.uncheckedAppend(')'); 772 773 return String::adopt(result); 774 } 775 case CSS_COUNTER: 776 text = "counter("; 777 text += String::number(m_value.num); 778 text += ")"; 779 // FIXME: Add list-style and separator 780 break; 781 case CSS_RECT: { 782 DEFINE_STATIC_LOCAL(const String, rectParen, ("rect(")); 783 784 Rect* rectVal = getRectValue(); 785 Vector<UChar> result; 786 result.reserveInitialCapacity(32); 787 append(result, rectParen); 788 789 append(result, rectVal->top()->cssText()); 790 result.append(' '); 791 792 append(result, rectVal->right()->cssText()); 793 result.append(' '); 794 795 append(result, rectVal->bottom()->cssText()); 796 result.append(' '); 797 798 append(result, rectVal->left()->cssText()); 799 result.append(')'); 800 801 return String::adopt(result); 802 } 803 case CSS_RGBCOLOR: 804 case CSS_PARSER_HEXCOLOR: { 805 DEFINE_STATIC_LOCAL(const String, commaSpace, (", ")); 806 DEFINE_STATIC_LOCAL(const String, rgbParen, ("rgb(")); 807 DEFINE_STATIC_LOCAL(const String, rgbaParen, ("rgba(")); 808 809 RGBA32 rgbColor = m_value.rgbcolor; 810 if (m_type == CSS_PARSER_HEXCOLOR) 811 Color::parseHexColor(m_value.string, rgbColor); 812 Color color(rgbColor); 813 814 Vector<UChar> result; 815 result.reserveInitialCapacity(32); 816 if (color.hasAlpha()) 817 append(result, rgbaParen); 818 else 819 append(result, rgbParen); 820 821 appendNumber(result, static_cast<unsigned char>(color.red())); 822 append(result, commaSpace); 823 824 appendNumber(result, static_cast<unsigned char>(color.green())); 825 append(result, commaSpace); 826 827 appendNumber(result, static_cast<unsigned char>(color.blue())); 828 if (color.hasAlpha()) { 829 append(result, commaSpace); 830 append(result, String::number(static_cast<float>(color.alpha()) / 256.0f)); 831 } 832 833 result.append(')'); 834 return String::adopt(result); 835 } 836 case CSS_PAIR: 837 text = m_value.pair->first()->cssText(); 838 text += " "; 839 text += m_value.pair->second()->cssText(); 840 break; 841 #if ENABLE(DASHBOARD_SUPPORT) 842 case CSS_DASHBOARD_REGION: 843 for (DashboardRegion* region = getDashboardRegionValue(); region; region = region->m_next.get()) { 844 if (!text.isEmpty()) 845 text.append(' '); 846 text += "dashboard-region("; 847 text += region->m_label; 848 if (region->m_isCircle) 849 text += " circle"; 850 else if (region->m_isRectangle) 851 text += " rectangle"; 852 else 853 break; 854 if (region->top()->m_type == CSS_IDENT && region->top()->getIdent() == CSSValueInvalid) { 855 ASSERT(region->right()->m_type == CSS_IDENT); 856 ASSERT(region->bottom()->m_type == CSS_IDENT); 857 ASSERT(region->left()->m_type == CSS_IDENT); 858 ASSERT(region->right()->getIdent() == CSSValueInvalid); 859 ASSERT(region->bottom()->getIdent() == CSSValueInvalid); 860 ASSERT(region->left()->getIdent() == CSSValueInvalid); 861 } else { 862 text.append(' '); 863 text += region->top()->cssText() + " "; 864 text += region->right()->cssText() + " "; 865 text += region->bottom()->cssText() + " "; 866 text += region->left()->cssText(); 867 } 868 text += ")"; 869 } 870 break; 871 #endif 872 case CSS_PARSER_VARIABLE_FUNCTION_SYNTAX: 873 text = "-webkit-var("; 874 text += m_value.string; 875 text += ")"; 876 break; 877 case CSS_PARSER_OPERATOR: { 878 char c = static_cast<char>(m_value.ident); 879 text = String(&c, 1U); 880 break; 881 } 882 case CSS_PARSER_IDENTIFIER: 883 text = quoteStringIfNeeded(m_value.string); 884 break; 885 } 886 return text; 887 } 888 889 CSSParserValue CSSPrimitiveValue::parserValue() const 890 { 891 // We only have to handle a subset of types. 892 CSSParserValue value; 893 value.id = 0; 894 value.isInt = false; 895 value.unit = CSSPrimitiveValue::CSS_IDENT; 896 switch (m_type) { 897 case CSS_NUMBER: 898 case CSS_PERCENTAGE: 899 case CSS_EMS: 900 case CSS_EXS: 901 case CSS_REMS: 902 case CSS_PX: 903 case CSS_CM: 904 case CSS_MM: 905 case CSS_IN: 906 case CSS_PT: 907 case CSS_PC: 908 case CSS_DEG: 909 case CSS_RAD: 910 case CSS_GRAD: 911 case CSS_MS: 912 case CSS_S: 913 case CSS_HZ: 914 case CSS_KHZ: 915 case CSS_DIMENSION: 916 case CSS_TURN: 917 value.fValue = m_value.num; 918 value.unit = m_type; 919 break; 920 case CSS_STRING: 921 case CSS_URI: 922 case CSS_PARSER_VARIABLE_FUNCTION_SYNTAX: 923 case CSS_PARSER_HEXCOLOR: 924 value.string.characters = const_cast<UChar*>(m_value.string->characters()); 925 value.string.length = m_value.string->length(); 926 value.unit = m_type; 927 break; 928 case CSS_IDENT: { 929 value.id = m_value.ident; 930 String name = valueOrPropertyName(m_value.ident); 931 value.string.characters = const_cast<UChar*>(name.characters()); 932 value.string.length = name.length(); 933 break; 934 } 935 case CSS_PARSER_OPERATOR: 936 value.iValue = m_value.ident; 937 value.unit = CSSParserValue::Operator; 938 break; 939 case CSS_PARSER_INTEGER: 940 value.fValue = m_value.num; 941 value.unit = CSSPrimitiveValue::CSS_NUMBER; 942 value.isInt = true; 943 break; 944 case CSS_PARSER_IDENTIFIER: 945 value.string.characters = const_cast<UChar*>(m_value.string->characters()); 946 value.string.length = m_value.string->length(); 947 value.unit = CSSPrimitiveValue::CSS_IDENT; 948 break; 949 case CSS_UNKNOWN: 950 case CSS_ATTR: 951 case CSS_COUNTER: 952 case CSS_RECT: 953 case CSS_RGBCOLOR: 954 case CSS_PAIR: 955 #if ENABLE(DASHBOARD_SUPPORT) 956 case CSS_DASHBOARD_REGION: 957 #endif 958 ASSERT_NOT_REACHED(); 959 break; 960 } 961 962 return value; 963 } 964 965 void CSSPrimitiveValue::addSubresourceStyleURLs(ListHashSet<KURL>& urls, const CSSStyleSheet* styleSheet) 966 { 967 if (m_type == CSS_URI) 968 addSubresourceURL(urls, styleSheet->completeURL(m_value.string)); 969 } 970 971 } // namespace WebCore 972