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 "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) \
50if (isInherit) \
51{ \
52    svgstyle->set##Prop(m_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 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