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