1 /* 2 Copyright (C) 2005 Apple Computer, Inc. 3 Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann (at) kde.org> 4 2004, 2005, 2008 Rob Buis <buis (at) kde.org> 5 Copyright (C) 2007 Alexey Proskuryakov <ap (at) webkit.org> 6 7 Based on khtml css code by: 8 Copyright(C) 1999-2003 Lars Knoll(knoll (at) kde.org) 9 (C) 2003 Apple Computer, Inc. 10 (C) 2004 Allan Sandfeld Jensen(kde (at) carewolf.com) 11 (C) 2004 Germain Garand(germain (at) ebooksfrance.org) 12 13 This library is free software; you can redistribute it and/or 14 modify it under the terms of the GNU Library General Public 15 License as published by the Free Software Foundation; either 16 version 2 of the License, or (at your option) any later version. 17 18 This library is distributed in the hope that it will be useful, 19 but WITHOUT ANY WARRANTY; without even the implied warranty of 20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 21 Library General Public License for more details. 22 23 You should have received a copy of the GNU Library General Public License 24 along with this library; see the file COPYING.LIB. If not, write to 25 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 26 Boston, MA 02110-1301, USA. 27 */ 28 29 #include "config.h" 30 31 #if ENABLE(SVG) 32 #include "CSSStyleSelector.h" 33 34 #include "CSSPrimitiveValueMappings.h" 35 #include "CSSPropertyNames.h" 36 #include "CSSValueList.h" 37 #include "Document.h" 38 #include "ShadowValue.h" 39 #include "SVGColor.h" 40 #include "SVGNames.h" 41 #include "SVGPaint.h" 42 #include "SVGRenderStyle.h" 43 #include "SVGRenderStyleDefs.h" 44 #include "SVGStyledElement.h" 45 #include "SVGURIReference.h" 46 #include <stdlib.h> 47 #include <wtf/MathExtras.h> 48 49 #define HANDLE_INHERIT(prop, Prop) \ 50 if (isInherit) \ 51 { \ 52 svgstyle->set##Prop(m_parentStyle->svgStyle()->prop()); \ 53 return; \ 54 } 55 56 #define HANDLE_INHERIT_AND_INITIAL(prop, Prop) \ 57 HANDLE_INHERIT(prop, Prop) \ 58 if (isInitial) { \ 59 svgstyle->set##Prop(SVGRenderStyle::initial##Prop()); \ 60 return; \ 61 } 62 63 namespace WebCore { 64 65 static float roundToNearestGlyphOrientationAngle(float angle) 66 { 67 angle = fabsf(fmodf(angle, 360.0f)); 68 69 if (angle <= 45.0f || angle > 315.0f) 70 return 0.0f; 71 else if (angle > 45.0f && angle <= 135.0f) 72 return 90.0f; 73 else if (angle > 135.0f && angle <= 225.0f) 74 return 180.0f; 75 76 return 270.0f; 77 } 78 79 static int angleToGlyphOrientation(float angle) 80 { 81 angle = roundToNearestGlyphOrientationAngle(angle); 82 83 if (angle == 0.0f) 84 return GO_0DEG; 85 else if (angle == 90.0f) 86 return GO_90DEG; 87 else if (angle == 180.0f) 88 return GO_180DEG; 89 else if (angle == 270.0f) 90 return GO_270DEG; 91 92 return -1; 93 } 94 95 static Color colorFromSVGColorCSSValue(SVGColor* svgColor, const Color& fgColor) 96 { 97 Color color; 98 if (svgColor->colorType() == SVGColor::SVG_COLORTYPE_CURRENTCOLOR) 99 color = fgColor; 100 else 101 color = svgColor->color(); 102 return color; 103 } 104 105 void CSSStyleSelector::applySVGProperty(int id, CSSValue* value) 106 { 107 ASSERT(value); 108 CSSPrimitiveValue* primitiveValue = 0; 109 if (value->isPrimitiveValue()) 110 primitiveValue = static_cast<CSSPrimitiveValue*>(value); 111 112 SVGRenderStyle* svgstyle = m_style->accessSVGStyle(); 113 unsigned short valueType = value->cssValueType(); 114 115 bool isInherit = m_parentNode && valueType == CSSPrimitiveValue::CSS_INHERIT; 116 bool isInitial = valueType == CSSPrimitiveValue::CSS_INITIAL || (!m_parentNode && valueType == CSSPrimitiveValue::CSS_INHERIT); 117 118 // What follows is a list that maps the CSS properties into their 119 // corresponding front-end RenderStyle values. Shorthands(e.g. border, 120 // background) occur in this list as well and are only hit when mapping 121 // "inherit" or "initial" into front-end values. 122 switch (id) 123 { 124 // ident only properties 125 case CSSPropertyAlignmentBaseline: 126 { 127 HANDLE_INHERIT_AND_INITIAL(alignmentBaseline, AlignmentBaseline) 128 if (!primitiveValue) 129 break; 130 131 svgstyle->setAlignmentBaseline(*primitiveValue); 132 break; 133 } 134 case CSSPropertyBaselineShift: 135 { 136 HANDLE_INHERIT_AND_INITIAL(baselineShift, BaselineShift); 137 if (!primitiveValue) 138 break; 139 140 if (primitiveValue->getIdent()) { 141 switch (primitiveValue->getIdent()) { 142 case CSSValueBaseline: 143 svgstyle->setBaselineShift(BS_BASELINE); 144 break; 145 case CSSValueSub: 146 svgstyle->setBaselineShift(BS_SUB); 147 break; 148 case CSSValueSuper: 149 svgstyle->setBaselineShift(BS_SUPER); 150 break; 151 default: 152 break; 153 } 154 } else { 155 svgstyle->setBaselineShift(BS_LENGTH); 156 svgstyle->setBaselineShiftValue(SVGLength::fromCSSPrimitiveValue(primitiveValue)); 157 } 158 159 break; 160 } 161 case CSSPropertyKerning: 162 { 163 HANDLE_INHERIT_AND_INITIAL(kerning, Kerning); 164 if (primitiveValue) 165 svgstyle->setKerning(SVGLength::fromCSSPrimitiveValue(primitiveValue)); 166 break; 167 } 168 case CSSPropertyDominantBaseline: 169 { 170 HANDLE_INHERIT_AND_INITIAL(dominantBaseline, DominantBaseline) 171 if (primitiveValue) 172 svgstyle->setDominantBaseline(*primitiveValue); 173 break; 174 } 175 case CSSPropertyColorInterpolation: 176 { 177 HANDLE_INHERIT_AND_INITIAL(colorInterpolation, ColorInterpolation) 178 if (primitiveValue) 179 svgstyle->setColorInterpolation(*primitiveValue); 180 break; 181 } 182 case CSSPropertyColorInterpolationFilters: 183 { 184 HANDLE_INHERIT_AND_INITIAL(colorInterpolationFilters, ColorInterpolationFilters) 185 if (primitiveValue) 186 svgstyle->setColorInterpolationFilters(*primitiveValue); 187 break; 188 } 189 case CSSPropertyColorRendering: 190 { 191 HANDLE_INHERIT_AND_INITIAL(colorRendering, ColorRendering) 192 if (primitiveValue) 193 svgstyle->setColorRendering(*primitiveValue); 194 break; 195 } 196 case CSSPropertyClipRule: 197 { 198 HANDLE_INHERIT_AND_INITIAL(clipRule, ClipRule) 199 if (primitiveValue) 200 svgstyle->setClipRule(*primitiveValue); 201 break; 202 } 203 case CSSPropertyFillRule: 204 { 205 HANDLE_INHERIT_AND_INITIAL(fillRule, FillRule) 206 if (primitiveValue) 207 svgstyle->setFillRule(*primitiveValue); 208 break; 209 } 210 case CSSPropertyStrokeLinejoin: 211 { 212 HANDLE_INHERIT_AND_INITIAL(joinStyle, JoinStyle) 213 if (primitiveValue) 214 svgstyle->setJoinStyle(*primitiveValue); 215 break; 216 } 217 case CSSPropertyImageRendering: 218 { 219 HANDLE_INHERIT_AND_INITIAL(imageRendering, ImageRendering) 220 if (primitiveValue) 221 svgstyle->setImageRendering(*primitiveValue); 222 break; 223 } 224 case CSSPropertyShapeRendering: 225 { 226 HANDLE_INHERIT_AND_INITIAL(shapeRendering, ShapeRendering) 227 if (primitiveValue) 228 svgstyle->setShapeRendering(*primitiveValue); 229 break; 230 } 231 // end of ident only properties 232 case CSSPropertyFill: 233 { 234 HANDLE_INHERIT_AND_INITIAL(fillPaint, FillPaint) 235 if (value->isSVGPaint()) 236 svgstyle->setFillPaint(static_cast<SVGPaint*>(value)); 237 break; 238 } 239 case CSSPropertyStroke: 240 { 241 HANDLE_INHERIT_AND_INITIAL(strokePaint, StrokePaint) 242 if (value->isSVGPaint()) 243 svgstyle->setStrokePaint(static_cast<SVGPaint*>(value)); 244 245 break; 246 } 247 case CSSPropertyStrokeWidth: 248 { 249 HANDLE_INHERIT_AND_INITIAL(strokeWidth, StrokeWidth) 250 if (primitiveValue) 251 svgstyle->setStrokeWidth(SVGLength::fromCSSPrimitiveValue(primitiveValue)); 252 break; 253 } 254 case CSSPropertyStrokeDasharray: 255 { 256 HANDLE_INHERIT_AND_INITIAL(strokeDashArray, StrokeDashArray) 257 if (!value->isValueList()) 258 break; 259 260 CSSValueList* dashes = static_cast<CSSValueList*>(value); 261 262 Vector<SVGLength> array; 263 size_t length = dashes->length(); 264 for (size_t i = 0; i < length; ++i) { 265 CSSValue* currValue = dashes->itemWithoutBoundsCheck(i); 266 if (!currValue->isPrimitiveValue()) 267 continue; 268 269 CSSPrimitiveValue* dash = static_cast<CSSPrimitiveValue*>(dashes->itemWithoutBoundsCheck(i)); 270 array.append(SVGLength::fromCSSPrimitiveValue(dash)); 271 } 272 273 svgstyle->setStrokeDashArray(array); 274 break; 275 } 276 case CSSPropertyStrokeDashoffset: 277 { 278 HANDLE_INHERIT_AND_INITIAL(strokeDashOffset, StrokeDashOffset) 279 if (primitiveValue) 280 svgstyle->setStrokeDashOffset(SVGLength::fromCSSPrimitiveValue(primitiveValue)); 281 break; 282 } 283 case CSSPropertyFillOpacity: 284 { 285 HANDLE_INHERIT_AND_INITIAL(fillOpacity, FillOpacity) 286 if (!primitiveValue) 287 return; 288 289 float f = 0.0f; 290 int type = primitiveValue->primitiveType(); 291 if (type == CSSPrimitiveValue::CSS_PERCENTAGE) 292 f = primitiveValue->getFloatValue() / 100.0f; 293 else if (type == CSSPrimitiveValue::CSS_NUMBER) 294 f = primitiveValue->getFloatValue(); 295 else 296 return; 297 298 svgstyle->setFillOpacity(f); 299 break; 300 } 301 case CSSPropertyStrokeOpacity: 302 { 303 HANDLE_INHERIT_AND_INITIAL(strokeOpacity, StrokeOpacity) 304 if (!primitiveValue) 305 return; 306 307 float f = 0.0f; 308 int type = primitiveValue->primitiveType(); 309 if (type == CSSPrimitiveValue::CSS_PERCENTAGE) 310 f = primitiveValue->getFloatValue() / 100.0f; 311 else if (type == CSSPrimitiveValue::CSS_NUMBER) 312 f = primitiveValue->getFloatValue(); 313 else 314 return; 315 316 svgstyle->setStrokeOpacity(f); 317 break; 318 } 319 case CSSPropertyStopOpacity: 320 { 321 HANDLE_INHERIT_AND_INITIAL(stopOpacity, StopOpacity) 322 if (!primitiveValue) 323 return; 324 325 float f = 0.0f; 326 int type = primitiveValue->primitiveType(); 327 if (type == CSSPrimitiveValue::CSS_PERCENTAGE) 328 f = primitiveValue->getFloatValue() / 100.0f; 329 else if (type == CSSPrimitiveValue::CSS_NUMBER) 330 f = primitiveValue->getFloatValue(); 331 else 332 return; 333 334 svgstyle->setStopOpacity(f); 335 break; 336 } 337 case CSSPropertyMarkerStart: 338 { 339 HANDLE_INHERIT_AND_INITIAL(markerStartResource, MarkerStartResource) 340 if (!primitiveValue) 341 return; 342 343 String s; 344 int type = primitiveValue->primitiveType(); 345 if (type == CSSPrimitiveValue::CSS_URI) 346 s = primitiveValue->getStringValue(); 347 else 348 return; 349 350 svgstyle->setMarkerStartResource(SVGURIReference::getTarget(s)); 351 break; 352 } 353 case CSSPropertyMarkerMid: 354 { 355 HANDLE_INHERIT_AND_INITIAL(markerMidResource, MarkerMidResource) 356 if (!primitiveValue) 357 return; 358 359 String s; 360 int type = primitiveValue->primitiveType(); 361 if (type == CSSPrimitiveValue::CSS_URI) 362 s = primitiveValue->getStringValue(); 363 else 364 return; 365 366 svgstyle->setMarkerMidResource(SVGURIReference::getTarget(s)); 367 break; 368 } 369 case CSSPropertyMarkerEnd: 370 { 371 HANDLE_INHERIT_AND_INITIAL(markerEndResource, MarkerEndResource) 372 if (!primitiveValue) 373 return; 374 375 String s; 376 int type = primitiveValue->primitiveType(); 377 if (type == CSSPrimitiveValue::CSS_URI) 378 s = primitiveValue->getStringValue(); 379 else 380 return; 381 382 svgstyle->setMarkerEndResource(SVGURIReference::getTarget(s)); 383 break; 384 } 385 case CSSPropertyStrokeLinecap: 386 { 387 HANDLE_INHERIT_AND_INITIAL(capStyle, CapStyle) 388 if (primitiveValue) 389 svgstyle->setCapStyle(*primitiveValue); 390 break; 391 } 392 case CSSPropertyStrokeMiterlimit: 393 { 394 HANDLE_INHERIT_AND_INITIAL(strokeMiterLimit, StrokeMiterLimit) 395 if (!primitiveValue) 396 return; 397 398 float f = 0.0f; 399 int type = primitiveValue->primitiveType(); 400 if (type == CSSPrimitiveValue::CSS_NUMBER) 401 f = primitiveValue->getFloatValue(); 402 else 403 return; 404 405 svgstyle->setStrokeMiterLimit(f); 406 break; 407 } 408 case CSSPropertyFilter: 409 { 410 HANDLE_INHERIT_AND_INITIAL(filterResource, FilterResource) 411 if (!primitiveValue) 412 return; 413 414 String s; 415 int type = primitiveValue->primitiveType(); 416 if (type == CSSPrimitiveValue::CSS_URI) 417 s = primitiveValue->getStringValue(); 418 else 419 return; 420 421 svgstyle->setFilterResource(SVGURIReference::getTarget(s)); 422 break; 423 } 424 case CSSPropertyMask: 425 { 426 HANDLE_INHERIT_AND_INITIAL(maskerResource, MaskerResource) 427 if (!primitiveValue) 428 return; 429 430 String s; 431 int type = primitiveValue->primitiveType(); 432 if (type == CSSPrimitiveValue::CSS_URI) 433 s = primitiveValue->getStringValue(); 434 else 435 return; 436 437 svgstyle->setMaskerResource(SVGURIReference::getTarget(s)); 438 break; 439 } 440 case CSSPropertyClipPath: 441 { 442 HANDLE_INHERIT_AND_INITIAL(clipperResource, ClipperResource) 443 if (!primitiveValue) 444 return; 445 446 String s; 447 int type = primitiveValue->primitiveType(); 448 if (type == CSSPrimitiveValue::CSS_URI) 449 s = primitiveValue->getStringValue(); 450 else 451 return; 452 453 svgstyle->setClipperResource(SVGURIReference::getTarget(s)); 454 break; 455 } 456 case CSSPropertyTextAnchor: 457 { 458 HANDLE_INHERIT_AND_INITIAL(textAnchor, TextAnchor) 459 if (primitiveValue) 460 svgstyle->setTextAnchor(*primitiveValue); 461 break; 462 } 463 case CSSPropertyWritingMode: 464 { 465 HANDLE_INHERIT_AND_INITIAL(writingMode, WritingMode) 466 if (primitiveValue) 467 svgstyle->setWritingMode(*primitiveValue); 468 break; 469 } 470 case CSSPropertyStopColor: 471 { 472 HANDLE_INHERIT_AND_INITIAL(stopColor, StopColor); 473 if (value->isSVGColor()) 474 svgstyle->setStopColor(colorFromSVGColorCSSValue(static_cast<SVGColor*>(value), m_style->color())); 475 break; 476 } 477 case CSSPropertyLightingColor: 478 { 479 HANDLE_INHERIT_AND_INITIAL(lightingColor, LightingColor); 480 if (value->isSVGColor()) 481 svgstyle->setLightingColor(colorFromSVGColorCSSValue(static_cast<SVGColor*>(value), m_style->color())); 482 break; 483 } 484 case CSSPropertyFloodOpacity: 485 { 486 HANDLE_INHERIT_AND_INITIAL(floodOpacity, FloodOpacity) 487 if (!primitiveValue) 488 return; 489 490 float f = 0.0f; 491 int type = primitiveValue->primitiveType(); 492 if (type == CSSPrimitiveValue::CSS_PERCENTAGE) 493 f = primitiveValue->getFloatValue() / 100.0f; 494 else if (type == CSSPrimitiveValue::CSS_NUMBER) 495 f = primitiveValue->getFloatValue(); 496 else 497 return; 498 499 svgstyle->setFloodOpacity(f); 500 break; 501 } 502 case CSSPropertyFloodColor: 503 { 504 HANDLE_INHERIT_AND_INITIAL(floodColor, FloodColor); 505 if (value->isSVGColor()) 506 svgstyle->setFloodColor(colorFromSVGColorCSSValue(static_cast<SVGColor*>(value), m_style->color())); 507 break; 508 } 509 case CSSPropertyGlyphOrientationHorizontal: 510 { 511 HANDLE_INHERIT_AND_INITIAL(glyphOrientationHorizontal, GlyphOrientationHorizontal) 512 if (!primitiveValue) 513 return; 514 515 if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_DEG) { 516 int orientation = angleToGlyphOrientation(primitiveValue->getFloatValue()); 517 ASSERT(orientation != -1); 518 519 svgstyle->setGlyphOrientationHorizontal((EGlyphOrientation) orientation); 520 } 521 522 break; 523 } 524 case CSSPropertyGlyphOrientationVertical: 525 { 526 HANDLE_INHERIT_AND_INITIAL(glyphOrientationVertical, GlyphOrientationVertical) 527 if (!primitiveValue) 528 return; 529 530 if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_DEG) { 531 int orientation = angleToGlyphOrientation(primitiveValue->getFloatValue()); 532 ASSERT(orientation != -1); 533 534 svgstyle->setGlyphOrientationVertical((EGlyphOrientation) orientation); 535 } else if (primitiveValue->getIdent() == CSSValueAuto) 536 svgstyle->setGlyphOrientationVertical(GO_AUTO); 537 538 break; 539 } 540 case CSSPropertyEnableBackground: 541 // Silently ignoring this property for now 542 // http://bugs.webkit.org/show_bug.cgi?id=6022 543 break; 544 case CSSPropertyWebkitSvgShadow: { 545 if (isInherit) 546 return svgstyle->setShadow(m_parentStyle->svgStyle()->shadow() ? new ShadowData(*m_parentStyle->svgStyle()->shadow()) : 0); 547 if (isInitial || primitiveValue) // initial | none 548 return svgstyle->setShadow(0); 549 550 if (!value->isValueList()) 551 return; 552 553 CSSValueList *list = static_cast<CSSValueList*>(value); 554 if (!list->length()) 555 return; 556 557 CSSValue* firstValue = list->itemWithoutBoundsCheck(0); 558 if (!firstValue->isShadowValue()) 559 return; 560 ShadowValue* item = static_cast<ShadowValue*>(firstValue); 561 int x = item->x->computeLengthInt(style(), m_rootElementStyle); 562 int y = item->y->computeLengthInt(style(), m_rootElementStyle); 563 int blur = item->blur ? item->blur->computeLengthInt(style(), m_rootElementStyle) : 0; 564 Color color; 565 if (item->color) 566 color = getColorFromPrimitiveValue(item->color.get()); 567 568 // -webkit-svg-shadow does should not have a spread or style 569 ASSERT(!item->spread); 570 ASSERT(!item->style); 571 572 ShadowData* shadowData = new ShadowData(x, y, blur, 0, Normal, false, color.isValid() ? color : Color::transparent); 573 svgstyle->setShadow(shadowData); 574 return; 575 } 576 case CSSPropertyVectorEffect: { 577 HANDLE_INHERIT_AND_INITIAL(vectorEffect, VectorEffect) 578 if (!primitiveValue) 579 break; 580 581 svgstyle->setVectorEffect(*primitiveValue); 582 break; 583 } 584 default: 585 // If you crash here, it's because you added a css property and are not handling it 586 // in either this switch statement or the one in CSSStyleSelector::applyProperty 587 ASSERT_WITH_MESSAGE(0, "unimplemented propertyID: %d", id); 588 return; 589 } 590 } 591 592 } 593 594 #endif 595