5da593f484cc4fed48c8344036c895efd79edb60
[WebKit-https.git] / WebCore / css / SVGCSSStyleSelector.cpp
1 /*
2     Copyright (C) 2005 Apple Computer, Inc.
3     Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org>
4                   2004, 2005 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 file is part of the KDE project
14
15     This library is free software; you can redistribute it and/or
16     modify it under the terms of the GNU Library General Public
17     License as published by the Free Software Foundation; either
18     version 2 of the License, or (at your option) any later version.
19
20     This library is distributed in the hope that it will be useful,
21     but WITHOUT ANY WARRANTY; without even the implied warranty of
22     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23     Library General Public License for more details.
24
25     You should have received a copy of the GNU Library General Public License
26     along with this library; see the file COPYING.LIB.  If not, write to
27     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
28     Boston, MA 02110-1301, USA.
29 */
30
31 #include "config.h"
32
33 #if ENABLE(SVG)
34 #include "CSSStyleSelector.h"
35
36 #include "CSSPrimitiveValueMappings.h"
37 #include "CSSPropertyNames.h"
38 #include "CSSValueList.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 <stdlib.h>
46 #include <wtf/MathExtras.h>
47
48 #define HANDLE_INHERIT(prop, Prop) \
49 if (isInherit) \
50 {\
51     svgstyle->set##Prop(parentStyle->svgStyle()->prop());\
52     return;\
53 }
54
55 #define HANDLE_INHERIT_AND_INITIAL(prop, Prop) \
56 HANDLE_INHERIT(prop, Prop) \
57 else if (isInitial) \
58     svgstyle->set##Prop(SVGRenderStyle::initial##Prop());
59
60 #define HANDLE_INHERIT_COND(propID, prop, Prop) \
61 if (id == propID) \
62 {\
63     svgstyle->set##Prop(parentStyle->svgStyle()->prop());\
64     return;\
65 }
66
67 #define HANDLE_INITIAL_COND(propID, Prop) \
68 if (id == propID) \
69 {\
70     svgstyle->set##Prop(SVGRenderStyle::initial##Prop());\
71     return;\
72 }
73
74 #define HANDLE_INITIAL_COND_WITH_VALUE(propID, Prop, Value) \
75 if (id == propID) { \
76     svgstyle->set##Prop(SVGRenderStyle::initial##Value()); \
77     return; \
78 }
79
80 namespace WebCore {
81
82 static float roundToNearestGlyphOrientationAngle(float angle)
83 {
84     angle = fabsf(fmodf(angle, 360.0f));
85
86     if (angle <= 45.0f || angle > 315.0f)
87         return 0.0f;
88     else if (angle > 45.0f && angle <= 135.0f)
89         return 90.0f;
90     else if (angle > 135.0f && angle <= 225.0f)
91         return 180.0f;
92
93     return 270.0f;
94 }
95
96 static int angleToGlyphOrientation(float angle)
97 {
98     angle = roundToNearestGlyphOrientationAngle(angle);
99
100     if (angle == 0.0f)
101         return GO_0DEG;
102     else if (angle == 90.0f)
103         return GO_90DEG;
104     else if (angle == 180.0f)
105         return GO_180DEG;
106     else if (angle == 270.0f)
107         return GO_270DEG;
108
109     return -1;
110 }
111
112 void CSSStyleSelector::applySVGProperty(int id, CSSValue* value)
113 {
114     CSSPrimitiveValue* primitiveValue = 0;
115     if (value->isPrimitiveValue())
116         primitiveValue = static_cast<CSSPrimitiveValue*>(value);
117
118     SVGRenderStyle* svgstyle = style->accessSVGStyle();
119     unsigned short valueType = value->cssValueType();
120     
121     bool isInherit = parentNode && valueType == CSSPrimitiveValue::CSS_INHERIT;
122     bool isInitial = valueType == CSSPrimitiveValue::CSS_INITIAL || (!parentNode && valueType == CSSPrimitiveValue::CSS_INHERIT);
123
124     // What follows is a list that maps the CSS properties into their
125     // corresponding front-end RenderStyle values. Shorthands(e.g. border,
126     // background) occur in this list as well and are only hit when mapping
127     // "inherit" or "initial" into front-end values.
128     switch (id)
129     {
130         // ident only properties
131         case CSS_PROP_ALIGNMENT_BASELINE:
132         {
133             HANDLE_INHERIT_AND_INITIAL(alignmentBaseline, AlignmentBaseline)
134             if (!primitiveValue)
135                 break;
136             
137             svgstyle->setAlignmentBaseline(*primitiveValue);
138             break;
139         }
140         case CSS_PROP_BASELINE_SHIFT:
141         {
142             HANDLE_INHERIT_AND_INITIAL(baselineShift, BaselineShift);
143             if (!primitiveValue)
144                 break;
145
146             if (primitiveValue->getIdent()) {
147                 switch (primitiveValue->getIdent()) {
148                 case CSS_VAL_BASELINE:
149                     svgstyle->setBaselineShift(BS_BASELINE);
150                     break;
151                 case CSS_VAL_SUB:
152                     svgstyle->setBaselineShift(BS_SUB);
153                     break;
154                 case CSS_VAL_SUPER:
155                     svgstyle->setBaselineShift(BS_SUPER);
156                     break;
157                 default:
158                     break;
159                 }
160             } else {
161                 svgstyle->setBaselineShift(BS_LENGTH);
162                 svgstyle->setBaselineShiftValue(primitiveValue);
163             }
164
165             break;
166         }
167         case CSS_PROP_KERNING:
168         {
169             if (isInherit) {
170                 HANDLE_INHERIT_COND(CSS_PROP_KERNING, kerning, Kerning)
171                 return;
172             }
173             else if (isInitial) {
174                 HANDLE_INITIAL_COND_WITH_VALUE(CSS_PROP_KERNING, Kerning, Kerning)
175                 return;
176             }
177
178             svgstyle->setKerning(primitiveValue);
179             break;
180         }
181         case CSS_PROP_POINTER_EVENTS:
182         {
183             HANDLE_INHERIT_AND_INITIAL(pointerEvents, PointerEvents)
184             if (!primitiveValue)
185                 break;
186             
187             svgstyle->setPointerEvents(*primitiveValue);
188             break;
189         }
190         case CSS_PROP_DOMINANT_BASELINE:
191         {
192             HANDLE_INHERIT_AND_INITIAL(dominantBaseline, DominantBaseline)
193             if (primitiveValue)
194                 svgstyle->setDominantBaseline(*primitiveValue);
195             break;
196         }
197         case CSS_PROP_COLOR_INTERPOLATION:
198         {
199             HANDLE_INHERIT_AND_INITIAL(colorInterpolation, ColorInterpolation)
200             if (primitiveValue)
201                 svgstyle->setColorInterpolation(*primitiveValue);
202             break;
203         }
204         case CSS_PROP_COLOR_INTERPOLATION_FILTERS:
205         {
206             HANDLE_INHERIT_AND_INITIAL(colorInterpolationFilters, ColorInterpolationFilters)
207             if (primitiveValue)
208                 svgstyle->setColorInterpolationFilters(*primitiveValue);
209             break;
210         }
211         case CSS_PROP_COLOR_RENDERING:
212         {
213             HANDLE_INHERIT_AND_INITIAL(colorRendering, ColorRendering)
214             if (primitiveValue)
215                 svgstyle->setColorRendering(*primitiveValue);
216             break;
217         }
218         case CSS_PROP_CLIP_RULE:
219         {
220             HANDLE_INHERIT_AND_INITIAL(clipRule, ClipRule)
221             if (primitiveValue)
222                 svgstyle->setClipRule(*primitiveValue);
223             break;
224         }
225         case CSS_PROP_FILL_RULE:
226         {
227             HANDLE_INHERIT_AND_INITIAL(fillRule, FillRule)
228             if (primitiveValue)
229                 svgstyle->setFillRule(*primitiveValue);
230             break;
231         }
232         case CSS_PROP_STROKE_LINEJOIN:
233         {
234             HANDLE_INHERIT_AND_INITIAL(joinStyle, JoinStyle)
235             if (primitiveValue)
236                 svgstyle->setJoinStyle(*primitiveValue);
237             break;
238         }
239         case CSS_PROP_IMAGE_RENDERING:
240         {
241             HANDLE_INHERIT_AND_INITIAL(imageRendering, ImageRendering)
242             if (primitiveValue)
243                 svgstyle->setImageRendering(*primitiveValue);
244             break;
245         }
246         case CSS_PROP_SHAPE_RENDERING:
247         {
248             HANDLE_INHERIT_AND_INITIAL(shapeRendering, ShapeRendering)
249             if (primitiveValue)
250                 svgstyle->setShapeRendering(*primitiveValue);
251             break;
252         }
253         case CSS_PROP_TEXT_RENDERING:
254         {
255             HANDLE_INHERIT_AND_INITIAL(textRendering, TextRendering)
256             if (primitiveValue)
257                 svgstyle->setTextRendering(*primitiveValue);
258             break;
259         }
260         // end of ident only properties
261         case CSS_PROP_FILL:
262         {
263             HANDLE_INHERIT_AND_INITIAL(fillPaint, FillPaint)
264             if (!primitiveValue && value) {
265                 SVGPaint *paint = static_cast<SVGPaint*>(value);
266                 if (paint)
267                     svgstyle->setFillPaint(paint);
268             }
269             
270             break;
271         }
272         case CSS_PROP_STROKE:
273         {
274             HANDLE_INHERIT_AND_INITIAL(strokePaint, StrokePaint)
275             if (!primitiveValue && value) {
276                 SVGPaint *paint = static_cast<SVGPaint*>(value);
277                 if (paint)
278                     svgstyle->setStrokePaint(paint);
279             }
280             
281             break;
282         }
283         case CSS_PROP_STROKE_WIDTH:
284         {
285             HANDLE_INHERIT_AND_INITIAL(strokeWidth, StrokeWidth)
286             if (!primitiveValue)
287                 return;
288         
289             svgstyle->setStrokeWidth(primitiveValue);
290             break;
291         }
292         case CSS_PROP_STROKE_DASHARRAY:
293         {
294             HANDLE_INHERIT_AND_INITIAL(strokeDashArray, StrokeDashArray)
295             if (!primitiveValue && value) {
296                 CSSValueList* dashes = static_cast<CSSValueList*>(value);
297                 if (dashes)
298                     svgstyle->setStrokeDashArray(dashes);
299             }
300         
301             break;
302         }
303         case CSS_PROP_STROKE_DASHOFFSET:
304         {
305             HANDLE_INHERIT_AND_INITIAL(strokeDashOffset, StrokeDashOffset)
306             if (!primitiveValue)
307                 return;
308
309             svgstyle->setStrokeDashOffset(primitiveValue);
310             break;
311         }
312         case CSS_PROP_FILL_OPACITY:
313         {
314             HANDLE_INHERIT_AND_INITIAL(fillOpacity, FillOpacity)
315             if (!primitiveValue)
316                 return;
317         
318             float f = 0.0f;    
319             int type = primitiveValue->primitiveType();
320             if (type == CSSPrimitiveValue::CSS_PERCENTAGE)
321                 f = primitiveValue->getFloatValue() / 100.0f;
322             else if (type == CSSPrimitiveValue::CSS_NUMBER)
323                 f = primitiveValue->getFloatValue();
324             else
325                 return;
326
327             svgstyle->setFillOpacity(f);
328             break;
329         }
330         case CSS_PROP_STROKE_OPACITY:
331         {
332             HANDLE_INHERIT_AND_INITIAL(strokeOpacity, StrokeOpacity)
333             if (!primitiveValue)
334                 return;
335         
336             float f = 0.0f;    
337             int type = primitiveValue->primitiveType();
338             if (type == CSSPrimitiveValue::CSS_PERCENTAGE)
339                 f = primitiveValue->getFloatValue() / 100.0f;
340             else if (type == CSSPrimitiveValue::CSS_NUMBER)
341                 f = primitiveValue->getFloatValue();
342             else
343                 return;
344
345             svgstyle->setStrokeOpacity(f);
346             break;
347         }
348         case CSS_PROP_STOP_OPACITY:
349         {
350             HANDLE_INHERIT_AND_INITIAL(stopOpacity, StopOpacity)
351             if (!primitiveValue)
352                 return;
353         
354             float f = 0.0f;    
355             int type = primitiveValue->primitiveType();
356             if (type == CSSPrimitiveValue::CSS_PERCENTAGE)
357                 f = primitiveValue->getFloatValue() / 100.0f;
358             else if (type == CSSPrimitiveValue::CSS_NUMBER)
359                 f = primitiveValue->getFloatValue();
360             else
361                 return;
362
363             svgstyle->setStopOpacity(f);
364             break;
365         }
366         case CSS_PROP_MARKER_START:
367         {
368             HANDLE_INHERIT_AND_INITIAL(startMarker, StartMarker)
369             if (!primitiveValue)
370                 return;
371
372             String s;
373             int type = primitiveValue->primitiveType();
374             if (type == CSSPrimitiveValue::CSS_URI)
375                 s = primitiveValue->getStringValue();
376             else
377                 return;
378
379             svgstyle->setStartMarker(s);
380             break;
381         }
382         case CSS_PROP_MARKER_MID:
383         {
384             HANDLE_INHERIT_AND_INITIAL(midMarker, MidMarker)
385             if (!primitiveValue)
386                 return;
387
388             String s;
389             int type = primitiveValue->primitiveType();
390             if (type == CSSPrimitiveValue::CSS_URI)
391                 s = primitiveValue->getStringValue();
392             else
393                 return;
394
395             svgstyle->setMidMarker(s);
396             break;
397         }
398         case CSS_PROP_MARKER_END:
399         {
400             HANDLE_INHERIT_AND_INITIAL(endMarker, EndMarker)
401             if (!primitiveValue)
402                 return;
403
404             String s;
405             int type = primitiveValue->primitiveType();
406             if (type == CSSPrimitiveValue::CSS_URI)
407                 s = primitiveValue->getStringValue();
408             else
409                 return;
410
411             svgstyle->setEndMarker(s);
412             break;
413         }
414         case CSS_PROP_STROKE_LINECAP:
415         {
416             HANDLE_INHERIT_AND_INITIAL(capStyle, CapStyle)
417             if (primitiveValue)
418                 svgstyle->setCapStyle(*primitiveValue);
419             break;
420         }
421         case CSS_PROP_STROKE_MITERLIMIT:
422         {
423             HANDLE_INHERIT_AND_INITIAL(strokeMiterLimit, StrokeMiterLimit)
424             if (!primitiveValue)
425                 return;
426
427             float f = 0.0f;
428             int type = primitiveValue->primitiveType();
429             if (type == CSSPrimitiveValue::CSS_NUMBER)
430                 f = primitiveValue->getFloatValue();
431             else
432                 return;
433
434             svgstyle->setStrokeMiterLimit(f);
435             break;
436         }
437         case CSS_PROP_FILTER:
438         {
439             HANDLE_INHERIT_AND_INITIAL(filter, Filter)
440             if (!primitiveValue)
441                 return;
442
443             String s;
444             int type = primitiveValue->primitiveType();
445             if (type == CSSPrimitiveValue::CSS_URI)
446                 s = primitiveValue->getStringValue();
447             else
448                 return;
449             svgstyle->setFilter(s);
450             break;
451         }
452         case CSS_PROP_MASK:
453         {
454             HANDLE_INHERIT_AND_INITIAL(maskElement, MaskElement)
455             if (!primitiveValue)
456                 return;
457
458             String s;
459             int type = primitiveValue->primitiveType();
460             if (type == CSSPrimitiveValue::CSS_URI)
461                 s = primitiveValue->getStringValue();
462             else
463                 return;
464
465             svgstyle->setMaskElement(s);
466             break;
467         }
468         case CSS_PROP_CLIP_PATH:
469         {
470             HANDLE_INHERIT_AND_INITIAL(clipPath, ClipPath)
471             if (!primitiveValue)
472                 return;
473
474             String s;
475             int type = primitiveValue->primitiveType();
476             if (type == CSSPrimitiveValue::CSS_URI)
477                 s = primitiveValue->getStringValue();
478             else
479                 return;
480
481             svgstyle->setClipPath(s);
482             break;
483         }
484         case CSS_PROP_TEXT_ANCHOR:
485         {
486             HANDLE_INHERIT_AND_INITIAL(textAnchor, TextAnchor)
487             if (primitiveValue)
488                 svgstyle->setTextAnchor(*primitiveValue);
489             break;
490         }
491         case CSS_PROP_WRITING_MODE:
492         {
493             HANDLE_INHERIT_AND_INITIAL(writingMode, WritingMode)
494             if (primitiveValue)
495                 svgstyle->setWritingMode(*primitiveValue);
496             break;
497         }
498         case CSS_PROP_STOP_COLOR:
499         {
500             HANDLE_INHERIT_AND_INITIAL(stopColor, StopColor);
501
502             SVGColor* c = static_cast<SVGColor*>(value);
503             if (!c)
504                 return CSSStyleSelector::applyProperty(id, value);
505
506             Color col;
507             if (c->colorType() == SVGColor::SVG_COLORTYPE_CURRENTCOLOR)
508                 col = style->color();
509             else
510                 col = c->color();
511
512             svgstyle->setStopColor(col);
513             break;
514         }
515        case CSS_PROP_LIGHTING_COLOR:
516         {
517             HANDLE_INHERIT_AND_INITIAL(lightingColor, LightingColor);
518
519             SVGColor* c = static_cast<SVGColor*>(value);
520             if (!c)
521                 return CSSStyleSelector::applyProperty(id, value);
522
523             Color col;
524             if (c->colorType() == SVGColor::SVG_COLORTYPE_CURRENTCOLOR)
525                 col = style->color();
526             else
527                 col = c->color();
528
529             svgstyle->setLightingColor(col);
530             break;
531         }
532         case CSS_PROP_FLOOD_OPACITY:
533         {
534             HANDLE_INHERIT_AND_INITIAL(floodOpacity, FloodOpacity)
535             if (!primitiveValue)
536                 return;
537
538             float f = 0.0f;
539             int type = primitiveValue->primitiveType();
540             if (type == CSSPrimitiveValue::CSS_PERCENTAGE)
541                 f = primitiveValue->getFloatValue() / 100.0f;
542             else if (type == CSSPrimitiveValue::CSS_NUMBER)
543                 f = primitiveValue->getFloatValue();
544             else
545                 return;
546
547             svgstyle->setFloodOpacity(f);
548             break;
549         }
550         case CSS_PROP_FLOOD_COLOR:
551         {
552             Color col;
553             if (isInitial)
554                 col = SVGRenderStyle::initialFloodColor();
555             else {
556                 SVGColor *c = static_cast<SVGColor*>(value);
557                 if (!c)
558                     return CSSStyleSelector::applyProperty(id, value);
559
560                 if (c->colorType() == SVGColor::SVG_COLORTYPE_CURRENTCOLOR)
561                     col = style->color();
562                 else
563                     col = c->color();
564             }
565
566             svgstyle->setFloodColor(col);
567             break;
568         }
569         case CSS_PROP_GLYPH_ORIENTATION_HORIZONTAL:
570         {
571             HANDLE_INHERIT_AND_INITIAL(glyphOrientationHorizontal, GlyphOrientationHorizontal)
572             if (!primitiveValue)
573                 return;
574
575             if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_DEG) {
576                 int orientation = angleToGlyphOrientation(primitiveValue->getFloatValue());
577                 ASSERT(orientation != -1);
578
579                 svgstyle->setGlyphOrientationHorizontal((EGlyphOrientation) orientation);
580             }
581
582             break;
583         }
584         case CSS_PROP_GLYPH_ORIENTATION_VERTICAL:
585         {
586             HANDLE_INHERIT_AND_INITIAL(glyphOrientationVertical, GlyphOrientationVertical)
587             if (!primitiveValue)
588                 return;
589
590             if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_DEG) {
591                 int orientation = angleToGlyphOrientation(primitiveValue->getFloatValue());
592                 ASSERT(orientation != -1);
593
594                 svgstyle->setGlyphOrientationVertical((EGlyphOrientation) orientation);
595             } else if (primitiveValue->getIdent() == CSS_VAL_AUTO)
596                 svgstyle->setGlyphOrientationVertical(GO_AUTO);
597
598             break;
599         }
600         case CSS_PROP_ENABLE_BACKGROUND:
601             // Silently ignoring this property for now
602             // http://bugs.webkit.org/show_bug.cgi?id=6022
603             break;
604         default:
605             // If you crash here, it's because you added a css property and are not handling it
606             // in either this switch statement or the one in CSSStyleSelector::applyProperty
607             ASSERT_WITH_MESSAGE(0, "unimplemented propertyID: %d", id);
608             return;
609     }
610 }
611
612 }
613
614 // vim:ts=4:noet
615 #endif // ENABLE(SVG)