4f663afd4160fd47ee9e86220b9c1cbb30d88158
[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 CSSPropertyShapeRendering:
218         {
219             HANDLE_INHERIT_AND_INITIAL(shapeRendering, ShapeRendering)
220             if (primitiveValue)
221                 svgstyle->setShapeRendering(*primitiveValue);
222             break;
223         }
224         // end of ident only properties
225         case CSSPropertyFill:
226         {
227             if (isInherit) {
228                 const SVGRenderStyle* svgParentStyle = m_parentStyle->svgStyle();
229                 svgstyle->setFillPaint(svgParentStyle->fillPaintType(), svgParentStyle->fillPaintColor(), svgParentStyle->fillPaintUri());
230                 return;
231             }
232             if (isInitial) {
233                 svgstyle->setFillPaint(SVGRenderStyle::initialFillPaintType(), SVGRenderStyle::initialFillPaintColor(), SVGRenderStyle::initialFillPaintUri());
234                 return;
235             }
236             if (value->isSVGPaint()) {
237                 SVGPaint* svgPaint = static_cast<SVGPaint*>(value);
238                 svgstyle->setFillPaint(svgPaint->paintType(), colorFromSVGColorCSSValue(svgPaint, m_style->color()), svgPaint->uri());
239             }
240             break;
241         }
242         case CSSPropertyStroke:
243         {
244             if (isInherit) {
245                 const SVGRenderStyle* svgParentStyle = m_parentStyle->svgStyle();
246                 svgstyle->setStrokePaint(svgParentStyle->strokePaintType(), svgParentStyle->strokePaintColor(), svgParentStyle->strokePaintUri());
247                 return;
248             }
249             if (isInitial) {
250                 svgstyle->setStrokePaint(SVGRenderStyle::initialStrokePaintType(), SVGRenderStyle::initialStrokePaintColor(), SVGRenderStyle::initialStrokePaintUri());
251                 return;
252             }
253             if (value->isSVGPaint()) {
254                 SVGPaint* svgPaint = static_cast<SVGPaint*>(value);
255                 svgstyle->setStrokePaint(svgPaint->paintType(), colorFromSVGColorCSSValue(svgPaint, m_style->color()), svgPaint->uri());
256             }
257             break;
258         }
259         case CSSPropertyStrokeWidth:
260         {
261             HANDLE_INHERIT_AND_INITIAL(strokeWidth, StrokeWidth)
262             if (primitiveValue)
263                 svgstyle->setStrokeWidth(SVGLength::fromCSSPrimitiveValue(primitiveValue));
264             break;
265         }
266         case CSSPropertyStrokeDasharray:
267         {
268             HANDLE_INHERIT_AND_INITIAL(strokeDashArray, StrokeDashArray)
269             if (!value->isValueList()) {
270                 svgstyle->setStrokeDashArray(SVGRenderStyle::initialStrokeDashArray());
271                 break;
272             }
273
274             CSSValueList* dashes = static_cast<CSSValueList*>(value);
275
276             Vector<SVGLength> array;
277             size_t length = dashes->length();
278             for (size_t i = 0; i < length; ++i) {
279                 CSSValue* currValue = dashes->itemWithoutBoundsCheck(i);
280                 if (!currValue->isPrimitiveValue())
281                     continue;
282
283                 CSSPrimitiveValue* dash = static_cast<CSSPrimitiveValue*>(dashes->itemWithoutBoundsCheck(i));
284                 array.append(SVGLength::fromCSSPrimitiveValue(dash));
285             }
286
287             svgstyle->setStrokeDashArray(array);
288             break;
289         }
290         case CSSPropertyStrokeDashoffset:
291         {
292             HANDLE_INHERIT_AND_INITIAL(strokeDashOffset, StrokeDashOffset)
293             if (primitiveValue)
294                 svgstyle->setStrokeDashOffset(SVGLength::fromCSSPrimitiveValue(primitiveValue));
295             break;
296         }
297         case CSSPropertyFillOpacity:
298         {
299             HANDLE_INHERIT_AND_INITIAL(fillOpacity, FillOpacity)
300             if (!primitiveValue)
301                 return;
302         
303             float f = 0.0f;    
304             int type = primitiveValue->primitiveType();
305             if (type == CSSPrimitiveValue::CSS_PERCENTAGE)
306                 f = primitiveValue->getFloatValue() / 100.0f;
307             else if (type == CSSPrimitiveValue::CSS_NUMBER)
308                 f = primitiveValue->getFloatValue();
309             else
310                 return;
311
312             svgstyle->setFillOpacity(f);
313             break;
314         }
315         case CSSPropertyStrokeOpacity:
316         {
317             HANDLE_INHERIT_AND_INITIAL(strokeOpacity, StrokeOpacity)
318             if (!primitiveValue)
319                 return;
320         
321             float f = 0.0f;    
322             int type = primitiveValue->primitiveType();
323             if (type == CSSPrimitiveValue::CSS_PERCENTAGE)
324                 f = primitiveValue->getFloatValue() / 100.0f;
325             else if (type == CSSPrimitiveValue::CSS_NUMBER)
326                 f = primitiveValue->getFloatValue();
327             else
328                 return;
329
330             svgstyle->setStrokeOpacity(f);
331             break;
332         }
333         case CSSPropertyStopOpacity:
334         {
335             HANDLE_INHERIT_AND_INITIAL(stopOpacity, StopOpacity)
336             if (!primitiveValue)
337                 return;
338         
339             float f = 0.0f;    
340             int type = primitiveValue->primitiveType();
341             if (type == CSSPrimitiveValue::CSS_PERCENTAGE)
342                 f = primitiveValue->getFloatValue() / 100.0f;
343             else if (type == CSSPrimitiveValue::CSS_NUMBER)
344                 f = primitiveValue->getFloatValue();
345             else
346                 return;
347
348             svgstyle->setStopOpacity(f);
349             break;
350         }
351         case CSSPropertyMarkerStart:
352         {
353             HANDLE_INHERIT_AND_INITIAL(markerStartResource, MarkerStartResource)
354             if (!primitiveValue)
355                 return;
356
357             String s;
358             int type = primitiveValue->primitiveType();
359             if (type == CSSPrimitiveValue::CSS_URI)
360                 s = primitiveValue->getStringValue();
361             else
362                 return;
363
364             svgstyle->setMarkerStartResource(SVGURIReference::fragmentIdentifierFromIRIString(s, m_element->document()));
365             break;
366         }
367         case CSSPropertyMarkerMid:
368         {
369             HANDLE_INHERIT_AND_INITIAL(markerMidResource, MarkerMidResource)
370             if (!primitiveValue)
371                 return;
372
373             String s;
374             int type = primitiveValue->primitiveType();
375             if (type == CSSPrimitiveValue::CSS_URI)
376                 s = primitiveValue->getStringValue();
377             else
378                 return;
379
380             svgstyle->setMarkerMidResource(SVGURIReference::fragmentIdentifierFromIRIString(s, m_element->document()));
381             break;
382         }
383         case CSSPropertyMarkerEnd:
384         {
385             HANDLE_INHERIT_AND_INITIAL(markerEndResource, MarkerEndResource)
386             if (!primitiveValue)
387                 return;
388
389             String s;
390             int type = primitiveValue->primitiveType();
391             if (type == CSSPrimitiveValue::CSS_URI)
392                 s = primitiveValue->getStringValue();
393             else
394                 return;
395
396             svgstyle->setMarkerEndResource(SVGURIReference::fragmentIdentifierFromIRIString(s, m_element->document()));
397             break;
398         }
399         case CSSPropertyStrokeLinecap:
400         {
401             HANDLE_INHERIT_AND_INITIAL(capStyle, CapStyle)
402             if (primitiveValue)
403                 svgstyle->setCapStyle(*primitiveValue);
404             break;
405         }
406         case CSSPropertyStrokeMiterlimit:
407         {
408             HANDLE_INHERIT_AND_INITIAL(strokeMiterLimit, StrokeMiterLimit)
409             if (!primitiveValue)
410                 return;
411
412             float f = 0.0f;
413             int type = primitiveValue->primitiveType();
414             if (type == CSSPrimitiveValue::CSS_NUMBER)
415                 f = primitiveValue->getFloatValue();
416             else
417                 return;
418
419             svgstyle->setStrokeMiterLimit(f);
420             break;
421         }
422         case CSSPropertyFilter:
423         {
424             HANDLE_INHERIT_AND_INITIAL(filterResource, FilterResource)
425             if (!primitiveValue)
426                 return;
427
428             String s;
429             int type = primitiveValue->primitiveType();
430             if (type == CSSPrimitiveValue::CSS_URI)
431                 s = primitiveValue->getStringValue();
432             else
433                 return;
434
435             svgstyle->setFilterResource(SVGURIReference::fragmentIdentifierFromIRIString(s, m_element->document()));
436             break;
437         }
438         case CSSPropertyMask:
439         {
440             HANDLE_INHERIT_AND_INITIAL(maskerResource, MaskerResource)
441             if (!primitiveValue)
442                 return;
443
444             String s;
445             int type = primitiveValue->primitiveType();
446             if (type == CSSPrimitiveValue::CSS_URI)
447                 s = primitiveValue->getStringValue();
448             else
449                 return;
450             
451             svgstyle->setMaskerResource(SVGURIReference::fragmentIdentifierFromIRIString(s, m_element->document()));
452             break;
453         }
454         case CSSPropertyClipPath:
455         {
456             HANDLE_INHERIT_AND_INITIAL(clipperResource, ClipperResource)
457             if (!primitiveValue)
458                 return;
459
460             String s;
461             int type = primitiveValue->primitiveType();
462             if (type == CSSPrimitiveValue::CSS_URI)
463                 s = primitiveValue->getStringValue();
464             else
465                 return;
466
467             svgstyle->setClipperResource(SVGURIReference::fragmentIdentifierFromIRIString(s, m_element->document()));
468             break;
469         }
470         case CSSPropertyTextAnchor:
471         {
472             HANDLE_INHERIT_AND_INITIAL(textAnchor, TextAnchor)
473             if (primitiveValue)
474                 svgstyle->setTextAnchor(*primitiveValue);
475             break;
476         }
477         case CSSPropertyWritingMode:
478         {
479             HANDLE_INHERIT_AND_INITIAL(writingMode, WritingMode)
480             if (primitiveValue)
481                 svgstyle->setWritingMode(*primitiveValue);
482             break;
483         }
484         case CSSPropertyStopColor:
485         {
486             HANDLE_INHERIT_AND_INITIAL(stopColor, StopColor);
487             if (value->isSVGColor())
488                 svgstyle->setStopColor(colorFromSVGColorCSSValue(static_cast<SVGColor*>(value), m_style->color()));
489             break;
490         }
491        case CSSPropertyLightingColor:
492         {
493             HANDLE_INHERIT_AND_INITIAL(lightingColor, LightingColor);
494             if (value->isSVGColor())
495                 svgstyle->setLightingColor(colorFromSVGColorCSSValue(static_cast<SVGColor*>(value), m_style->color()));
496             break;
497         }
498         case CSSPropertyFloodOpacity:
499         {
500             HANDLE_INHERIT_AND_INITIAL(floodOpacity, FloodOpacity)
501             if (!primitiveValue)
502                 return;
503
504             float f = 0.0f;
505             int type = primitiveValue->primitiveType();
506             if (type == CSSPrimitiveValue::CSS_PERCENTAGE)
507                 f = primitiveValue->getFloatValue() / 100.0f;
508             else if (type == CSSPrimitiveValue::CSS_NUMBER)
509                 f = primitiveValue->getFloatValue();
510             else
511                 return;
512
513             svgstyle->setFloodOpacity(f);
514             break;
515         }
516         case CSSPropertyFloodColor:
517         {
518             HANDLE_INHERIT_AND_INITIAL(floodColor, FloodColor);
519             if (value->isSVGColor())
520                 svgstyle->setFloodColor(colorFromSVGColorCSSValue(static_cast<SVGColor*>(value), m_style->color()));
521             break;
522         }
523         case CSSPropertyGlyphOrientationHorizontal:
524         {
525             HANDLE_INHERIT_AND_INITIAL(glyphOrientationHorizontal, GlyphOrientationHorizontal)
526             if (!primitiveValue)
527                 return;
528
529             if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_DEG) {
530                 int orientation = angleToGlyphOrientation(primitiveValue->getFloatValue());
531                 ASSERT(orientation != -1);
532
533                 svgstyle->setGlyphOrientationHorizontal((EGlyphOrientation) orientation);
534             }
535
536             break;
537         }
538         case CSSPropertyGlyphOrientationVertical:
539         {
540             HANDLE_INHERIT_AND_INITIAL(glyphOrientationVertical, GlyphOrientationVertical)
541             if (!primitiveValue)
542                 return;
543
544             if (primitiveValue->primitiveType() == CSSPrimitiveValue::CSS_DEG) {
545                 int orientation = angleToGlyphOrientation(primitiveValue->getFloatValue());
546                 ASSERT(orientation != -1);
547
548                 svgstyle->setGlyphOrientationVertical((EGlyphOrientation) orientation);
549             } else if (primitiveValue->getIdent() == CSSValueAuto)
550                 svgstyle->setGlyphOrientationVertical(GO_AUTO);
551
552             break;
553         }
554         case CSSPropertyEnableBackground:
555             // Silently ignoring this property for now
556             // http://bugs.webkit.org/show_bug.cgi?id=6022
557             break;
558         case CSSPropertyWebkitSvgShadow: {
559             if (isInherit)
560                 return svgstyle->setShadow(adoptPtr(m_parentStyle->svgStyle()->shadow() ? new ShadowData(*m_parentStyle->svgStyle()->shadow()) : 0));
561             if (isInitial || primitiveValue) // initial | none
562                 return svgstyle->setShadow(nullptr);
563
564             if (!value->isValueList())
565                 return;
566
567             CSSValueList *list = static_cast<CSSValueList*>(value);
568             if (!list->length())
569                 return;
570
571             CSSValue* firstValue = list->itemWithoutBoundsCheck(0);
572             if (!firstValue->isShadowValue())
573                 return;
574             ShadowValue* item = static_cast<ShadowValue*>(firstValue);
575             int x = item->x->computeLength<int>(style(), m_rootElementStyle);
576             int y = item->y->computeLength<int>(style(), m_rootElementStyle);
577             int blur = item->blur ? item->blur->computeLength<int>(style(), m_rootElementStyle) : 0;
578             Color color;
579             if (item->color)
580                 color = getColorFromPrimitiveValue(item->color.get());
581
582             // -webkit-svg-shadow does should not have a spread or style
583             ASSERT(!item->spread);
584             ASSERT(!item->style);
585                 
586             OwnPtr<ShadowData> shadowData = adoptPtr(new ShadowData(x, y, blur, 0, Normal, false, color.isValid() ? color : Color::transparent));
587             svgstyle->setShadow(shadowData.release());
588             return;
589         }
590         case CSSPropertyVectorEffect: {
591             HANDLE_INHERIT_AND_INITIAL(vectorEffect, VectorEffect)
592             if (!primitiveValue)
593                 break;
594
595             svgstyle->setVectorEffect(*primitiveValue);
596             break;
597         }
598         default:
599             // If you crash here, it's because you added a css property and are not handling it
600             // in either this switch statement or the one in CSSStyleSelector::applyProperty
601             ASSERT_WITH_MESSAGE(0, "unimplemented propertyID: %d", id);
602             return;
603     }
604 }
605
606 }
607
608 #endif