6b09426ec0d770f4ce450d716f657a7a95c8dfee
[WebKit-https.git] / Source / 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, 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) \
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             if (isInherit) {
235                 const SVGRenderStyle* svgParentStyle = m_parentStyle->svgStyle();
236                 svgstyle->setFillPaint(svgParentStyle->fillPaintType(), svgParentStyle->fillPaintColor(), svgParentStyle->fillPaintUri());
237                 return;
238             }
239             if (isInitial) {
240                 svgstyle->setFillPaint(SVGRenderStyle::initialFillPaintType(), SVGRenderStyle::initialFillPaintColor(), SVGRenderStyle::initialFillPaintUri());
241                 return;
242             }
243             if (value->isSVGPaint()) {
244                 SVGPaint* svgPaint = static_cast<SVGPaint*>(value);
245                 svgstyle->setFillPaint(svgPaint->paintType(), colorFromSVGColorCSSValue(svgPaint, m_style->color()), svgPaint->uri());
246             }
247             break;
248         }
249         case CSSPropertyStroke:
250         {
251             if (isInherit) {
252                 const SVGRenderStyle* svgParentStyle = m_parentStyle->svgStyle();
253                 svgstyle->setStrokePaint(svgParentStyle->strokePaintType(), svgParentStyle->strokePaintColor(), svgParentStyle->strokePaintUri());
254                 return;
255             }
256             if (isInitial) {
257                 svgstyle->setStrokePaint(SVGRenderStyle::initialStrokePaintType(), SVGRenderStyle::initialStrokePaintColor(), SVGRenderStyle::initialStrokePaintUri());
258                 return;
259             }
260             if (value->isSVGPaint()) {
261                 SVGPaint* svgPaint = static_cast<SVGPaint*>(value);
262                 svgstyle->setStrokePaint(svgPaint->paintType(), colorFromSVGColorCSSValue(svgPaint, m_style->color()), svgPaint->uri());
263             }
264             break;
265         }
266         case CSSPropertyStrokeWidth:
267         {
268             HANDLE_INHERIT_AND_INITIAL(strokeWidth, StrokeWidth)
269             if (primitiveValue)
270                 svgstyle->setStrokeWidth(SVGLength::fromCSSPrimitiveValue(primitiveValue));
271             break;
272         }
273         case CSSPropertyStrokeDasharray:
274         {
275             HANDLE_INHERIT_AND_INITIAL(strokeDashArray, StrokeDashArray)
276             if (!value->isValueList())
277                 break;
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             else
367                 return;
368
369             svgstyle->setMarkerStartResource(SVGURIReference::getTarget(s));
370             break;
371         }
372         case CSSPropertyMarkerMid:
373         {
374             HANDLE_INHERIT_AND_INITIAL(markerMidResource, MarkerMidResource)
375             if (!primitiveValue)
376                 return;
377
378             String s;
379             int type = primitiveValue->primitiveType();
380             if (type == CSSPrimitiveValue::CSS_URI)
381                 s = primitiveValue->getStringValue();
382             else
383                 return;
384
385             svgstyle->setMarkerMidResource(SVGURIReference::getTarget(s));
386             break;
387         }
388         case CSSPropertyMarkerEnd:
389         {
390             HANDLE_INHERIT_AND_INITIAL(markerEndResource, MarkerEndResource)
391             if (!primitiveValue)
392                 return;
393
394             String s;
395             int type = primitiveValue->primitiveType();
396             if (type == CSSPrimitiveValue::CSS_URI)
397                 s = primitiveValue->getStringValue();
398             else
399                 return;
400
401             svgstyle->setMarkerEndResource(SVGURIReference::getTarget(s));
402             break;
403         }
404         case CSSPropertyStrokeLinecap:
405         {
406             HANDLE_INHERIT_AND_INITIAL(capStyle, CapStyle)
407             if (primitiveValue)
408                 svgstyle->setCapStyle(*primitiveValue);
409             break;
410         }
411         case CSSPropertyStrokeMiterlimit:
412         {
413             HANDLE_INHERIT_AND_INITIAL(strokeMiterLimit, StrokeMiterLimit)
414             if (!primitiveValue)
415                 return;
416
417             float f = 0.0f;
418             int type = primitiveValue->primitiveType();
419             if (type == CSSPrimitiveValue::CSS_NUMBER)
420                 f = primitiveValue->getFloatValue();
421             else
422                 return;
423
424             svgstyle->setStrokeMiterLimit(f);
425             break;
426         }
427         case CSSPropertyFilter:
428         {
429             HANDLE_INHERIT_AND_INITIAL(filterResource, FilterResource)
430             if (!primitiveValue)
431                 return;
432
433             String s;
434             int type = primitiveValue->primitiveType();
435             if (type == CSSPrimitiveValue::CSS_URI)
436                 s = primitiveValue->getStringValue();
437             else
438                 return;
439
440             svgstyle->setFilterResource(SVGURIReference::getTarget(s));
441             break;
442         }
443         case CSSPropertyMask:
444         {
445             HANDLE_INHERIT_AND_INITIAL(maskerResource, MaskerResource)
446             if (!primitiveValue)
447                 return;
448
449             String s;
450             int type = primitiveValue->primitiveType();
451             if (type == CSSPrimitiveValue::CSS_URI)
452                 s = primitiveValue->getStringValue();
453             else
454                 return;
455             
456             svgstyle->setMaskerResource(SVGURIReference::getTarget(s));
457             break;
458         }
459         case CSSPropertyClipPath:
460         {
461             HANDLE_INHERIT_AND_INITIAL(clipperResource, ClipperResource)
462             if (!primitiveValue)
463                 return;
464
465             String s;
466             int type = primitiveValue->primitiveType();
467             if (type == CSSPrimitiveValue::CSS_URI)
468                 s = primitiveValue->getStringValue();
469             else
470                 return;
471
472             svgstyle->setClipperResource(SVGURIReference::getTarget(s));
473             break;
474         }
475         case CSSPropertyTextAnchor:
476         {
477             HANDLE_INHERIT_AND_INITIAL(textAnchor, TextAnchor)
478             if (primitiveValue)
479                 svgstyle->setTextAnchor(*primitiveValue);
480             break;
481         }
482         case CSSPropertyWritingMode:
483         {
484             HANDLE_INHERIT_AND_INITIAL(writingMode, WritingMode)
485             if (primitiveValue)
486                 svgstyle->setWritingMode(*primitiveValue);
487             break;
488         }
489         case CSSPropertyStopColor:
490         {
491             HANDLE_INHERIT_AND_INITIAL(stopColor, StopColor);
492             if (value->isSVGColor())
493                 svgstyle->setStopColor(colorFromSVGColorCSSValue(static_cast<SVGColor*>(value), m_style->color()));
494             break;
495         }
496        case CSSPropertyLightingColor:
497         {
498             HANDLE_INHERIT_AND_INITIAL(lightingColor, LightingColor);
499             if (value->isSVGColor())
500                 svgstyle->setLightingColor(colorFromSVGColorCSSValue(static_cast<SVGColor*>(value), m_style->color()));
501             break;
502         }
503         case CSSPropertyFloodOpacity:
504         {
505             HANDLE_INHERIT_AND_INITIAL(floodOpacity, FloodOpacity)
506             if (!primitiveValue)
507                 return;
508
509             float f = 0.0f;
510             int type = primitiveValue->primitiveType();
511             if (type == CSSPrimitiveValue::CSS_PERCENTAGE)
512                 f = primitiveValue->getFloatValue() / 100.0f;
513             else if (type == CSSPrimitiveValue::CSS_NUMBER)
514                 f = primitiveValue->getFloatValue();
515             else
516                 return;
517
518             svgstyle->setFloodOpacity(f);
519             break;
520         }
521         case CSSPropertyFloodColor:
522         {
523             HANDLE_INHERIT_AND_INITIAL(floodColor, FloodColor);
524             if (value->isSVGColor())
525                 svgstyle->setFloodColor(colorFromSVGColorCSSValue(static_cast<SVGColor*>(value), m_style->color()));
526             break;
527         }
528         case CSSPropertyGlyphOrientationHorizontal:
529         {
530             HANDLE_INHERIT_AND_INITIAL(glyphOrientationHorizontal, GlyphOrientationHorizontal)
531             if (!primitiveValue)
532                 return;
533
534             if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_DEG) {
535                 int orientation = angleToGlyphOrientation(primitiveValue->getFloatValue());
536                 ASSERT(orientation != -1);
537
538                 svgstyle->setGlyphOrientationHorizontal((EGlyphOrientation) orientation);
539             }
540
541             break;
542         }
543         case CSSPropertyGlyphOrientationVertical:
544         {
545             HANDLE_INHERIT_AND_INITIAL(glyphOrientationVertical, GlyphOrientationVertical)
546             if (!primitiveValue)
547                 return;
548
549             if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_DEG) {
550                 int orientation = angleToGlyphOrientation(primitiveValue->getFloatValue());
551                 ASSERT(orientation != -1);
552
553                 svgstyle->setGlyphOrientationVertical((EGlyphOrientation) orientation);
554             } else if (primitiveValue->getIdent() == CSSValueAuto)
555                 svgstyle->setGlyphOrientationVertical(GO_AUTO);
556
557             break;
558         }
559         case CSSPropertyEnableBackground:
560             // Silently ignoring this property for now
561             // http://bugs.webkit.org/show_bug.cgi?id=6022
562             break;
563         case CSSPropertyWebkitSvgShadow: {
564             if (isInherit)
565                 return svgstyle->setShadow(adoptPtr(m_parentStyle->svgStyle()->shadow() ? new ShadowData(*m_parentStyle->svgStyle()->shadow()) : 0));
566             if (isInitial || primitiveValue) // initial | none
567                 return svgstyle->setShadow(nullptr);
568
569             if (!value->isValueList())
570                 return;
571
572             CSSValueList *list = static_cast<CSSValueList*>(value);
573             if (!list->length())
574                 return;
575
576             CSSValue* firstValue = list->itemWithoutBoundsCheck(0);
577             if (!firstValue->isShadowValue())
578                 return;
579             ShadowValue* item = static_cast<ShadowValue*>(firstValue);
580             int x = item->x->computeLengthInt(style(), m_rootElementStyle);
581             int y = item->y->computeLengthInt(style(), m_rootElementStyle);
582             int blur = item->blur ? item->blur->computeLengthInt(style(), m_rootElementStyle) : 0;
583             Color color;
584             if (item->color)
585                 color = getColorFromPrimitiveValue(item->color.get());
586
587             // -webkit-svg-shadow does should not have a spread or style
588             ASSERT(!item->spread);
589             ASSERT(!item->style);
590                 
591             OwnPtr<ShadowData> shadowData = adoptPtr(new ShadowData(x, y, blur, 0, Normal, false, color.isValid() ? color : Color::transparent));
592             svgstyle->setShadow(shadowData.release());
593             return;
594         }
595         case CSSPropertyVectorEffect: {
596             HANDLE_INHERIT_AND_INITIAL(vectorEffect, VectorEffect)
597             if (!primitiveValue)
598                 break;
599
600             svgstyle->setVectorEffect(*primitiveValue);
601             break;
602         }
603         default:
604             // If you crash here, it's because you added a css property and are not handling it
605             // in either this switch statement or the one in CSSStyleSelector::applyProperty
606             ASSERT_WITH_MESSAGE(0, "unimplemented propertyID: %d", id);
607             return;
608     }
609 }
610
611 }
612
613 #endif