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