1/* 2 Copyright (C) 2005 Apple Computer, Inc. 3 Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org> 4 2004, 2005, 2008 Rob Buis <buis@kde.org> 5 Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org> 6 7 Based on khtml css code by: 8 Copyright(C) 1999-2003 Lars Knoll(knoll@kde.org) 9 (C) 2003 Apple Computer, Inc. 10 (C) 2004 Allan Sandfeld Jensen(kde@carewolf.com) 11 (C) 2004 Germain Garand(germain@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 "StyleResolver.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) \ 50if (isInherit) \ 51{ \ 52 svgstyle->set##Prop(state.parentStyle()->svgStyle()->prop()); \ 53 return; \ 54} 55 56#define HANDLE_INHERIT_AND_INITIAL(prop, Prop) \ 57HANDLE_INHERIT(prop, Prop) \ 58if (isInitial) { \ 59 svgstyle->set##Prop(SVGRenderStyle::initial##Prop()); \ 60 return; \ 61} 62 63namespace WebCore { 64 65static 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 79static 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 95static 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 105void StyleResolver::applySVGProperty(CSSPropertyID id, CSSValue* value) 106{ 107 ASSERT(value); 108 CSSPrimitiveValue* primitiveValue = 0; 109 if (value->isPrimitiveValue()) 110 primitiveValue = static_cast<CSSPrimitiveValue*>(value); 111 112 const State& state = m_state; 113 SVGRenderStyle* svgstyle = state.style()->accessSVGStyle(); 114 115 bool isInherit = state.parentNode() && value->isInheritedValue(); 116 bool isInitial = value->isInitialValue() || (!state.parentNode() && value->isInheritedValue()); 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 CSSPropertyColorProfile: 190 { 191 // Not implemented. 192 break; 193 } 194 case CSSPropertyColorRendering: 195 { 196 HANDLE_INHERIT_AND_INITIAL(colorRendering, ColorRendering) 197 if (primitiveValue) 198 svgstyle->setColorRendering(*primitiveValue); 199 break; 200 } 201 case CSSPropertyClipRule: 202 { 203 HANDLE_INHERIT_AND_INITIAL(clipRule, ClipRule) 204 if (primitiveValue) 205 svgstyle->setClipRule(*primitiveValue); 206 break; 207 } 208 case CSSPropertyFillRule: 209 { 210 HANDLE_INHERIT_AND_INITIAL(fillRule, FillRule) 211 if (primitiveValue) 212 svgstyle->setFillRule(*primitiveValue); 213 break; 214 } 215 case CSSPropertyStrokeLinejoin: 216 { 217 HANDLE_INHERIT_AND_INITIAL(joinStyle, JoinStyle) 218 if (primitiveValue) 219 svgstyle->setJoinStyle(*primitiveValue); 220 break; 221 } 222 case CSSPropertyShapeRendering: 223 { 224 HANDLE_INHERIT_AND_INITIAL(shapeRendering, ShapeRendering) 225 if (primitiveValue) 226 svgstyle->setShapeRendering(*primitiveValue); 227 break; 228 } 229 // end of ident only properties 230 case CSSPropertyFill: 231 { 232 if (isInherit) { 233 const SVGRenderStyle* svgParentStyle = state.parentStyle()->svgStyle(); 234 svgstyle->setFillPaint(svgParentStyle->fillPaintType(), svgParentStyle->fillPaintColor(), svgParentStyle->fillPaintUri(), applyPropertyToRegularStyle(), applyPropertyToVisitedLinkStyle()); 235 return; 236 } 237 if (isInitial) { 238 svgstyle->setFillPaint(SVGRenderStyle::initialFillPaintType(), SVGRenderStyle::initialFillPaintColor(), SVGRenderStyle::initialFillPaintUri(), applyPropertyToRegularStyle(), applyPropertyToVisitedLinkStyle()); 239 return; 240 } 241 if (value->isSVGPaint()) { 242 SVGPaint* svgPaint = static_cast<SVGPaint*>(value); 243 svgstyle->setFillPaint(svgPaint->paintType(), colorFromSVGColorCSSValue(svgPaint, state.style()->color()), svgPaint->uri(), applyPropertyToRegularStyle(), applyPropertyToVisitedLinkStyle()); 244 } 245 break; 246 } 247 case CSSPropertyStroke: 248 { 249 if (isInherit) { 250 const SVGRenderStyle* svgParentStyle = state.parentStyle()->svgStyle(); 251 svgstyle->setStrokePaint(svgParentStyle->strokePaintType(), svgParentStyle->strokePaintColor(), svgParentStyle->strokePaintUri(), applyPropertyToRegularStyle(), applyPropertyToVisitedLinkStyle()); 252 return; 253 } 254 if (isInitial) { 255 svgstyle->setStrokePaint(SVGRenderStyle::initialStrokePaintType(), SVGRenderStyle::initialStrokePaintColor(), SVGRenderStyle::initialStrokePaintUri(), applyPropertyToRegularStyle(), applyPropertyToVisitedLinkStyle()); 256 return; 257 } 258 if (value->isSVGPaint()) { 259 SVGPaint* svgPaint = static_cast<SVGPaint*>(value); 260 svgstyle->setStrokePaint(svgPaint->paintType(), colorFromSVGColorCSSValue(svgPaint, state.style()->color()), svgPaint->uri(), applyPropertyToRegularStyle(), applyPropertyToVisitedLinkStyle()); 261 } 262 break; 263 } 264 case CSSPropertyStrokeWidth: 265 { 266 HANDLE_INHERIT_AND_INITIAL(strokeWidth, StrokeWidth) 267 if (primitiveValue) 268 svgstyle->setStrokeWidth(SVGLength::fromCSSPrimitiveValue(primitiveValue)); 269 break; 270 } 271 case CSSPropertyStrokeDasharray: 272 { 273 HANDLE_INHERIT_AND_INITIAL(strokeDashArray, StrokeDashArray) 274 if (!value->isValueList()) { 275 svgstyle->setStrokeDashArray(SVGRenderStyle::initialStrokeDashArray()); 276 break; 277 } 278 279 CSSValueList* dashes = static_cast<CSSValueList*>(value); 280 281 Vector<SVGLength> array; 282 size_t length = dashes->length(); 283 for (size_t i = 0; i < length; ++i) { 284 CSSValue* currValue = dashes->itemWithoutBoundsCheck(i); 285 if (!currValue->isPrimitiveValue()) 286 continue; 287 288 CSSPrimitiveValue* dash = static_cast<CSSPrimitiveValue*>(dashes->itemWithoutBoundsCheck(i)); 289 array.append(SVGLength::fromCSSPrimitiveValue(dash)); 290 } 291 292 svgstyle->setStrokeDashArray(array); 293 break; 294 } 295 case CSSPropertyStrokeDashoffset: 296 { 297 HANDLE_INHERIT_AND_INITIAL(strokeDashOffset, StrokeDashOffset) 298 if (primitiveValue) 299 svgstyle->setStrokeDashOffset(SVGLength::fromCSSPrimitiveValue(primitiveValue)); 300 break; 301 } 302 case CSSPropertyFillOpacity: 303 { 304 HANDLE_INHERIT_AND_INITIAL(fillOpacity, FillOpacity) 305 if (!primitiveValue) 306 return; 307 308 float f = 0.0f; 309 int type = primitiveValue->primitiveType(); 310 if (type == CSSPrimitiveValue::CSS_PERCENTAGE) 311 f = primitiveValue->getFloatValue() / 100.0f; 312 else if (type == CSSPrimitiveValue::CSS_NUMBER) 313 f = primitiveValue->getFloatValue(); 314 else 315 return; 316 317 svgstyle->setFillOpacity(f); 318 break; 319 } 320 case CSSPropertyStrokeOpacity: 321 { 322 HANDLE_INHERIT_AND_INITIAL(strokeOpacity, StrokeOpacity) 323 if (!primitiveValue) 324 return; 325 326 float f = 0.0f; 327 int type = primitiveValue->primitiveType(); 328 if (type == CSSPrimitiveValue::CSS_PERCENTAGE) 329 f = primitiveValue->getFloatValue() / 100.0f; 330 else if (type == CSSPrimitiveValue::CSS_NUMBER) 331 f = primitiveValue->getFloatValue(); 332 else 333 return; 334 335 svgstyle->setStrokeOpacity(f); 336 break; 337 } 338 case CSSPropertyStopOpacity: 339 { 340 HANDLE_INHERIT_AND_INITIAL(stopOpacity, StopOpacity) 341 if (!primitiveValue) 342 return; 343 344 float f = 0.0f; 345 int type = primitiveValue->primitiveType(); 346 if (type == CSSPrimitiveValue::CSS_PERCENTAGE) 347 f = primitiveValue->getFloatValue() / 100.0f; 348 else if (type == CSSPrimitiveValue::CSS_NUMBER) 349 f = primitiveValue->getFloatValue(); 350 else 351 return; 352 353 svgstyle->setStopOpacity(f); 354 break; 355 } 356 case CSSPropertyMarkerStart: 357 { 358 HANDLE_INHERIT_AND_INITIAL(markerStartResource, MarkerStartResource) 359 if (!primitiveValue) 360 return; 361 362 String s; 363 int type = primitiveValue->primitiveType(); 364 if (type == CSSPrimitiveValue::CSS_URI) 365 s = primitiveValue->getStringValue(); 366 367 svgstyle->setMarkerStartResource(SVGURIReference::fragmentIdentifierFromIRIString(s, state.document())); 368 break; 369 } 370 case CSSPropertyMarkerMid: 371 { 372 HANDLE_INHERIT_AND_INITIAL(markerMidResource, MarkerMidResource) 373 if (!primitiveValue) 374 return; 375 376 String s; 377 int type = primitiveValue->primitiveType(); 378 if (type == CSSPrimitiveValue::CSS_URI) 379 s = primitiveValue->getStringValue(); 380 381 svgstyle->setMarkerMidResource(SVGURIReference::fragmentIdentifierFromIRIString(s, state.document())); 382 break; 383 } 384 case CSSPropertyMarkerEnd: 385 { 386 HANDLE_INHERIT_AND_INITIAL(markerEndResource, MarkerEndResource) 387 if (!primitiveValue) 388 return; 389 390 String s; 391 int type = primitiveValue->primitiveType(); 392 if (type == CSSPrimitiveValue::CSS_URI) 393 s = primitiveValue->getStringValue(); 394 395 svgstyle->setMarkerEndResource(SVGURIReference::fragmentIdentifierFromIRIString(s, state.document())); 396 break; 397 } 398 case CSSPropertyStrokeLinecap: 399 { 400 HANDLE_INHERIT_AND_INITIAL(capStyle, CapStyle) 401 if (primitiveValue) 402 svgstyle->setCapStyle(*primitiveValue); 403 break; 404 } 405 case CSSPropertyStrokeMiterlimit: 406 { 407 HANDLE_INHERIT_AND_INITIAL(strokeMiterLimit, StrokeMiterLimit) 408 if (!primitiveValue) 409 return; 410 411 float f = 0.0f; 412 int type = primitiveValue->primitiveType(); 413 if (type == CSSPrimitiveValue::CSS_NUMBER) 414 f = primitiveValue->getFloatValue(); 415 else 416 return; 417 418 svgstyle->setStrokeMiterLimit(f); 419 break; 420 } 421 case CSSPropertyFilter: 422 { 423 HANDLE_INHERIT_AND_INITIAL(filterResource, FilterResource) 424 if (!primitiveValue) 425 return; 426 427 String s; 428 int type = primitiveValue->primitiveType(); 429 if (type == CSSPrimitiveValue::CSS_URI) 430 s = primitiveValue->getStringValue(); 431 432 svgstyle->setFilterResource(SVGURIReference::fragmentIdentifierFromIRIString(s, state.document())); 433 break; 434 } 435 case CSSPropertyMask: 436 { 437 HANDLE_INHERIT_AND_INITIAL(maskerResource, MaskerResource) 438 if (!primitiveValue) 439 return; 440 441 String s; 442 int type = primitiveValue->primitiveType(); 443 if (type == CSSPrimitiveValue::CSS_URI) 444 s = primitiveValue->getStringValue(); 445 446 svgstyle->setMaskerResource(SVGURIReference::fragmentIdentifierFromIRIString(s, state.document())); 447 break; 448 } 449 case CSSPropertyClipPath: 450 { 451 HANDLE_INHERIT_AND_INITIAL(clipperResource, ClipperResource) 452 if (!primitiveValue) 453 return; 454 455 String s; 456 int type = primitiveValue->primitiveType(); 457 if (type == CSSPrimitiveValue::CSS_URI) 458 s = primitiveValue->getStringValue(); 459 460 svgstyle->setClipperResource(SVGURIReference::fragmentIdentifierFromIRIString(s, state.document())); 461 break; 462 } 463 case CSSPropertyTextAnchor: 464 { 465 HANDLE_INHERIT_AND_INITIAL(textAnchor, TextAnchor) 466 if (primitiveValue) 467 svgstyle->setTextAnchor(*primitiveValue); 468 break; 469 } 470 case CSSPropertyWritingMode: 471 { 472 HANDLE_INHERIT_AND_INITIAL(writingMode, WritingMode) 473 if (primitiveValue) 474 svgstyle->setWritingMode(*primitiveValue); 475 break; 476 } 477 case CSSPropertyStopColor: 478 { 479 HANDLE_INHERIT_AND_INITIAL(stopColor, StopColor); 480 if (value->isSVGColor()) 481 svgstyle->setStopColor(colorFromSVGColorCSSValue(static_cast<SVGColor*>(value), state.style()->color())); 482 break; 483 } 484 case CSSPropertyLightingColor: 485 { 486 HANDLE_INHERIT_AND_INITIAL(lightingColor, LightingColor); 487 if (value->isSVGColor()) 488 svgstyle->setLightingColor(colorFromSVGColorCSSValue(static_cast<SVGColor*>(value), state.style()->color())); 489 break; 490 } 491 case CSSPropertyFloodOpacity: 492 { 493 HANDLE_INHERIT_AND_INITIAL(floodOpacity, FloodOpacity) 494 if (!primitiveValue) 495 return; 496 497 float f = 0.0f; 498 int type = primitiveValue->primitiveType(); 499 if (type == CSSPrimitiveValue::CSS_PERCENTAGE) 500 f = primitiveValue->getFloatValue() / 100.0f; 501 else if (type == CSSPrimitiveValue::CSS_NUMBER) 502 f = primitiveValue->getFloatValue(); 503 else 504 return; 505 506 svgstyle->setFloodOpacity(f); 507 break; 508 } 509 case CSSPropertyFloodColor: 510 { 511 HANDLE_INHERIT_AND_INITIAL(floodColor, FloodColor); 512 if (value->isSVGColor()) 513 svgstyle->setFloodColor(colorFromSVGColorCSSValue(static_cast<SVGColor*>(value), state.style()->color())); 514 break; 515 } 516 case CSSPropertyGlyphOrientationHorizontal: 517 { 518 HANDLE_INHERIT_AND_INITIAL(glyphOrientationHorizontal, GlyphOrientationHorizontal) 519 if (!primitiveValue) 520 return; 521 522 if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_DEG) { 523 int orientation = angleToGlyphOrientation(primitiveValue->getFloatValue()); 524 ASSERT(orientation != -1); 525 526 svgstyle->setGlyphOrientationHorizontal((EGlyphOrientation) orientation); 527 } 528 529 break; 530 } 531 case CSSPropertyGlyphOrientationVertical: 532 { 533 HANDLE_INHERIT_AND_INITIAL(glyphOrientationVertical, GlyphOrientationVertical) 534 if (!primitiveValue) 535 return; 536 537 if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_DEG) { 538 int orientation = angleToGlyphOrientation(primitiveValue->getFloatValue()); 539 ASSERT(orientation != -1); 540 541 svgstyle->setGlyphOrientationVertical((EGlyphOrientation) orientation); 542 } else if (primitiveValue->getIdent() == CSSValueAuto) 543 svgstyle->setGlyphOrientationVertical(GO_AUTO); 544 545 break; 546 } 547 case CSSPropertyEnableBackground: 548 // Silently ignoring this property for now 549 // http://bugs.webkit.org/show_bug.cgi?id=6022 550 break; 551 case CSSPropertyWebkitSvgShadow: { 552 if (isInherit) 553 return svgstyle->setShadow(adoptPtr(state.parentStyle()->svgStyle()->shadow() ? new ShadowData(*state.parentStyle()->svgStyle()->shadow()) : 0)); 554 if (isInitial || primitiveValue) // initial | none 555 return svgstyle->setShadow(nullptr); 556 557 if (!value->isValueList()) 558 return; 559 560 CSSValueList *list = static_cast<CSSValueList*>(value); 561 if (!list->length()) 562 return; 563 564 CSSValue* firstValue = list->itemWithoutBoundsCheck(0); 565 if (!firstValue->isShadowValue()) 566 return; 567 ShadowValue* item = static_cast<ShadowValue*>(firstValue); 568 IntPoint location(item->x->computeLength<int>(state.style(), state.rootElementStyle()), 569 item->y->computeLength<int>(state.style(), state.rootElementStyle())); 570 int blur = item->blur ? item->blur->computeLength<int>(state.style(), state.rootElementStyle()) : 0; 571 Color color; 572 if (item->color) 573 color = colorFromPrimitiveValue(item->color.get()); 574 575 // -webkit-svg-shadow does should not have a spread or style 576 ASSERT(!item->spread); 577 ASSERT(!item->style); 578 579 OwnPtr<ShadowData> shadowData = adoptPtr(new ShadowData(location, blur, 0, Normal, false, color.isValid() ? color : Color::transparent)); 580 svgstyle->setShadow(shadowData.release()); 581 return; 582 } 583 case CSSPropertyVectorEffect: { 584 HANDLE_INHERIT_AND_INITIAL(vectorEffect, VectorEffect) 585 if (!primitiveValue) 586 break; 587 588 svgstyle->setVectorEffect(*primitiveValue); 589 break; 590 } 591 case CSSPropertyBufferedRendering: { 592 HANDLE_INHERIT_AND_INITIAL(bufferedRendering, BufferedRendering) 593 if (!primitiveValue) 594 break; 595 596 svgstyle->setBufferedRendering(*primitiveValue); 597 break; 598 } 599 case CSSPropertyMaskType: { 600 HANDLE_INHERIT_AND_INITIAL(maskType, MaskType) 601 if (!primitiveValue) 602 break; 603 604 svgstyle->setMaskType(*primitiveValue); 605 break; 606 } 607 default: 608 // If you crash here, it's because you added a css property and are not handling it 609 // in either this switch statement or the one in StyleResolver::applyProperty 610 ASSERT_WITH_MESSAGE(0, "unimplemented propertyID: %d", id); 611 return; 612 } 613} 614 615} 616 617#endif 618