0e593d38964cd0f172fc9025bd5c7975f9f5a5b0
[WebKit-https.git] / WebCore / ksvg2 / css / SVGCSSParser.cpp
1 /*
2     Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org>
3                   2004, 2005, 2007 Rob Buis <buis@kde.org>
4     Copyright (C) 2005, 2006 Apple Computer, Inc.
5
6     This file is part of the KDE project
7
8     This library is free software; you can redistribute it and/or
9     modify it under the terms of the GNU Library General Public
10     License as published by the Free Software Foundation; either
11     version 2 of the License, or (at your option) any later version.
12
13     This library is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16     Library General Public License for more details.
17
18     You should have received a copy of the GNU Library General Public License
19     along with this library; see the file COPYING.LIB.  If not, write to
20     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21     Boston, MA 02110-1301, USA.
22 */
23
24 #include "config.h"
25 #if ENABLE(SVG)
26
27 #include "CSSInheritedValue.h"
28 #include "CSSInitialValue.h"
29 #include "CSSParser.h"
30 #include "CSSProperty.h"
31 #include "CSSPropertyNames.h"
32 #include "CSSQuirkPrimitiveValue.h"
33 #include "CSSValueKeywords.h"
34 #include "CSSValueList.h"
35 #include "SVGPaint.h"
36 #include "ksvgcssproperties.c"
37 #include "ksvgcssvalues.c"
38 #include "DeprecatedString.h"
39
40 using namespace std;
41
42 namespace WebCore {
43
44 bool CSSParser::parseSVGValue(int propId, bool important)
45 {
46     Value* value = valueList->current();
47     if (!value)
48         return false;
49
50     int id = value->id;
51
52     bool valid_primitive = false;
53     CSSValue* parsedValue = 0;
54
55     switch (propId) {
56     /* The comment to the right defines all valid value of these
57      * properties as defined in SVG 1.1, Appendix N. Property index */
58     case SVGCSS_PROP_ALIGNMENT_BASELINE:
59     // auto | baseline | before-edge | text-before-edge | middle |
60     // central | after-edge | text-after-edge | ideographic | alphabetic |
61     // hanging | mathematical | inherit
62         if (id == CSS_VAL_AUTO || id == CSS_VAL_BASELINE || id == CSS_VAL_MIDDLE ||
63           (id >= SVGCSS_VAL_BEFORE_EDGE && id <= SVGCSS_VAL_MATHEMATICAL))
64             valid_primitive = true;
65         break;
66
67     case SVGCSS_PROP_BASELINE_SHIFT:
68     // baseline | super | sub | <percentage> | <length> | inherit
69         if (id == CSS_VAL_BASELINE || id == CSS_VAL_SUB ||
70            id >= CSS_VAL_SUPER)
71             valid_primitive = true;
72         else
73             valid_primitive = validUnit(value, FLength|FPercent, false);
74         break;
75
76     case SVGCSS_PROP_DOMINANT_BASELINE:
77     // auto | use-script | no-change | reset-size | ideographic |
78     // alphabetic | hanging | mathematical | central | middle |
79     // text-after-edge | text-before-edge | inherit
80         if (id == CSS_VAL_AUTO || id == CSS_VAL_MIDDLE ||
81           (id >= SVGCSS_VAL_USE_SCRIPT && id <= SVGCSS_VAL_RESET_SIZE) ||
82           (id >= SVGCSS_VAL_CENTRAL && id <= SVGCSS_VAL_MATHEMATICAL))
83             valid_primitive = true;
84         break;
85
86     case SVGCSS_PROP_ENABLE_BACKGROUND:
87     // accumulate | new [x] [y] [width] [height] | inherit
88         if (id == SVGCSS_VAL_ACCUMULATE) // TODO : new
89             valid_primitive = true;
90         break;
91
92     case SVGCSS_PROP_MARKER_START:
93     case SVGCSS_PROP_MARKER_MID:
94     case SVGCSS_PROP_MARKER_END:
95     case SVGCSS_PROP_MASK:
96         if (id == CSS_VAL_NONE)
97             valid_primitive = true;
98         else if (value->unit == CSSPrimitiveValue::CSS_URI) {
99             parsedValue = new CSSPrimitiveValue(domString(value->string), CSSPrimitiveValue::CSS_URI);
100             if (parsedValue)
101                 valueList->next();
102         }
103         break;
104
105     case SVGCSS_PROP_CLIP_RULE:            // nonzero | evenodd | inherit
106     case SVGCSS_PROP_FILL_RULE:
107         if (id == SVGCSS_VAL_NONZERO || id == SVGCSS_VAL_EVENODD)
108             valid_primitive = true;
109         break;
110
111     case SVGCSS_PROP_STROKE_MITERLIMIT:   // <miterlimit> | inherit
112         valid_primitive = validUnit(value, FNumber|FNonNeg, false);
113         break;
114
115     case SVGCSS_PROP_STROKE_LINEJOIN:   // miter | round | bevel | inherit
116         if (id == SVGCSS_VAL_MITER || id == CSS_VAL_ROUND || id == SVGCSS_VAL_BEVEL)
117             valid_primitive = true;
118         break;
119
120     case SVGCSS_PROP_STROKE_LINECAP:    // butt | round | square | inherit
121         if (id == SVGCSS_VAL_BUTT || id == CSS_VAL_ROUND || id == CSS_VAL_SQUARE)
122             valid_primitive = true;
123         break;
124
125     case SVGCSS_PROP_STROKE_OPACITY:   // <opacity-value> | inherit
126     case SVGCSS_PROP_FILL_OPACITY:
127     case SVGCSS_PROP_STOP_OPACITY:
128     case SVGCSS_PROP_FLOOD_OPACITY:
129         valid_primitive = (!id && validUnit(value, FNumber|FPercent, false));
130         break;
131
132     case SVGCSS_PROP_SHAPE_RENDERING:
133     // auto | optimizeSpeed | crispEdges | geometricPrecision | inherit
134         if (id == CSS_VAL_AUTO || id == SVGCSS_VAL_OPTIMIZESPEED ||
135             id == SVGCSS_VAL_CRISPEDGES || id == SVGCSS_VAL_GEOMETRICPRECISION)
136             valid_primitive = true;
137         break;
138
139     case SVGCSS_PROP_TEXT_RENDERING:   // auto | optimizeSpeed | optimizeLegibility | geometricPrecision | inherit
140         if (id == CSS_VAL_AUTO || id == SVGCSS_VAL_OPTIMIZESPEED || id == SVGCSS_VAL_OPTIMIZELEGIBILITY ||
141        id == SVGCSS_VAL_GEOMETRICPRECISION)
142             valid_primitive = true;
143         break;
144
145     case SVGCSS_PROP_IMAGE_RENDERING:  // auto | optimizeSpeed |
146     case SVGCSS_PROP_COLOR_RENDERING:  // optimizeQuality | inherit
147         if (id == CSS_VAL_AUTO || id == SVGCSS_VAL_OPTIMIZESPEED ||
148             id == SVGCSS_VAL_OPTIMIZEQUALITY)
149             valid_primitive = true;
150         break;
151
152     case SVGCSS_PROP_COLOR_PROFILE: // auto | sRGB | <name> | <uri> inherit
153         if (id == CSS_VAL_AUTO || id == SVGCSS_VAL_SRGB)
154             valid_primitive = true;
155         break;
156
157     case SVGCSS_PROP_COLOR_INTERPOLATION:   // auto | sRGB | linearRGB | inherit
158     case SVGCSS_PROP_COLOR_INTERPOLATION_FILTERS:  
159         if (id == CSS_VAL_AUTO || id == SVGCSS_VAL_SRGB || id == SVGCSS_VAL_LINEARRGB)
160             valid_primitive = true;
161         break;
162
163     /* Start of supported CSS properties with validation. This is needed for parseShortHand to work
164      * correctly and allows optimization in applyRule(..)
165      */
166
167     case SVGCSS_PROP_POINTER_EVENTS:
168     // none | visiblePainted | visibleFill | visibleStroke | visible |
169     // painted | fill | stroke | none | all | inherit
170         if (id == CSS_VAL_VISIBLE || id == CSS_VAL_NONE ||
171           (id >= SVGCSS_VAL_VISIBLEPAINTED && id <= SVGCSS_VAL_ALL))
172             valid_primitive = true;
173         break;
174
175     case SVGCSS_PROP_TEXT_ANCHOR:    // start | middle | end | inherit
176         if (id == CSS_VAL_START || id == CSS_VAL_MIDDLE || id == CSS_VAL_END)
177             valid_primitive = true;
178         break;
179
180     case SVGCSS_PROP_GLYPH_ORIENTATION_VERTICAL: // auto | <angle> | inherit
181         if (id == CSS_VAL_AUTO) {
182             valid_primitive = true;
183             break;
184         }
185         /* fallthrough intentional */
186     case SVGCSS_PROP_GLYPH_ORIENTATION_HORIZONTAL: // <angle> | inherit
187         if (value->unit == CSSPrimitiveValue::CSS_DEG)
188             parsedValue = new CSSPrimitiveValue(value->fValue, CSSPrimitiveValue::CSS_DEG);
189         else if (value->unit == CSSPrimitiveValue::CSS_GRAD)
190             parsedValue = new CSSPrimitiveValue(value->fValue, CSSPrimitiveValue::CSS_GRAD);
191         else if (value->unit == CSSPrimitiveValue::CSS_RAD)
192             parsedValue = new CSSPrimitiveValue(value->fValue, CSSPrimitiveValue::CSS_RAD);
193         break;
194
195     case SVGCSS_PROP_FILL:                 // <paint> | inherit
196     case SVGCSS_PROP_STROKE:               // <paint> | inherit
197         {
198             if (id == CSS_VAL_NONE)
199                 parsedValue = new SVGPaint(SVGPaint::SVG_PAINTTYPE_NONE);
200             else if (id == SVGCSS_VAL_CURRENTCOLOR)
201                 parsedValue = new SVGPaint(SVGPaint::SVG_PAINTTYPE_CURRENTCOLOR);
202             else if (value->unit == CSSPrimitiveValue::CSS_URI) {
203                 RGBA32 c = Color::transparent;
204                 if (valueList->next() && parseColorFromValue(valueList->current(), c, true)) {
205                     parsedValue = new SVGPaint(domString(value->string), c);
206                 } else
207                     parsedValue = new SVGPaint(SVGPaint::SVG_PAINTTYPE_URI, domString(value->string));
208             } else
209                 parsedValue = parseSVGPaint();
210
211             if (parsedValue)
212                 valueList->next();
213         }
214         break;
215
216     case CSS_PROP_COLOR:                // <color> | inherit
217         if ((id >= CSS_VAL_AQUA && id <= CSS_VAL_WINDOWTEXT) ||
218            (id >= SVGCSS_VAL_ALICEBLUE && id <= SVGCSS_VAL_YELLOWGREEN))
219             parsedValue = new SVGColor(domString(value->string));
220         else
221             parsedValue = parseSVGColor();
222
223         if (parsedValue)
224             valueList->next();
225         break;
226
227     case SVGCSS_PROP_STOP_COLOR: // TODO : icccolor
228     case SVGCSS_PROP_FLOOD_COLOR:
229     case SVGCSS_PROP_LIGHTING_COLOR:
230         if ((id >= CSS_VAL_AQUA && id <= CSS_VAL_WINDOWTEXT) ||
231            (id >= SVGCSS_VAL_ALICEBLUE && id <= SVGCSS_VAL_YELLOWGREEN))
232             parsedValue = new SVGColor(domString(value->string));
233         else if (id == SVGCSS_VAL_CURRENTCOLOR)
234             parsedValue = new SVGColor(SVGColor::SVG_COLORTYPE_CURRENTCOLOR);
235         else // TODO : svgcolor (iccColor)
236             parsedValue = parseSVGColor();
237
238         if (parsedValue)
239             valueList->next();
240
241         break;
242
243     case SVGCSS_PROP_WRITING_MODE:
244     // lr-tb | rl_tb | tb-rl | lr | rl | tb | inherit
245         if (id >= SVGCSS_VAL_LR_TB && id <= SVGCSS_VAL_TB)
246             valid_primitive = true;
247         break;
248
249     case SVGCSS_PROP_STROKE_WIDTH:         // <length> | inherit
250     case SVGCSS_PROP_STROKE_DASHOFFSET:
251         valid_primitive = validUnit(value, FLength | FPercent, false);
252         break;
253     case SVGCSS_PROP_STROKE_DASHARRAY:     // none | <dasharray> | inherit
254         if (id == CSS_VAL_NONE)
255             valid_primitive = true;
256         else
257             parsedValue = parseSVGStrokeDasharray();
258
259         break;
260
261     case SVGCSS_PROP_KERNING:              // auto | normal | <length> | inherit
262         if (id == CSS_VAL_AUTO || id == CSS_VAL_NORMAL)
263             valid_primitive = true;
264         else
265             valid_primitive = validUnit(value, FLength, false);
266         break;
267
268     case SVGCSS_PROP_CLIP_PATH:    // <uri> | none | inherit
269     case SVGCSS_PROP_FILTER:
270         if (id == CSS_VAL_NONE)
271             valid_primitive = true;
272         else if (value->unit == CSSPrimitiveValue::CSS_URI) {
273             parsedValue = new CSSPrimitiveValue(domString(value->string), (CSSPrimitiveValue::UnitTypes) value->unit);
274             if (parsedValue)
275                 valueList->next();
276         }
277         break;
278
279     /* shorthand properties */
280     case SVGCSS_PROP_MARKER:
281     {
282         if (!parseValue(SVGCSS_PROP_MARKER_START, important))
283             return false;
284         CSSValue *value = parsedProperties[numParsedProperties - 1]->value();
285         m_implicitShorthand = true;
286         addProperty(SVGCSS_PROP_MARKER_MID, value, important);
287         addProperty(SVGCSS_PROP_MARKER_END, value, important);
288         m_implicitShorthand = false;
289         return true;
290     }
291     default:
292         return false;
293     }
294
295     if (valid_primitive) {
296         if (id != 0)
297             parsedValue = new CSSPrimitiveValue(id);
298         else if (value->unit == CSSPrimitiveValue::CSS_STRING)
299             parsedValue = new CSSPrimitiveValue(domString(value->string), (CSSPrimitiveValue::UnitTypes) value->unit);
300         else if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
301             parsedValue = new CSSPrimitiveValue(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit);
302         else if (value->unit >= Value::Q_EMS)
303             parsedValue = new CSSQuirkPrimitiveValue(value->fValue, CSSPrimitiveValue::CSS_EMS);
304         valueList->next();
305     }
306     if (parsedValue) {
307         if (!valueList->current() || inShorthand()) {
308             addProperty(propId, parsedValue, important);
309             return true;
310         }
311         delete parsedValue;
312     }
313     return false;
314 }
315
316 CSSValue* CSSParser::parseSVGStrokeDasharray()
317 {
318     CSSValueList* ret = new CSSValueList;
319     Value* value = valueList->current();
320     bool valid_primitive = true;
321     while (value) {
322         valid_primitive = validUnit(value, FLength | FPercent |FNonNeg, false);
323         if (!valid_primitive)
324             break;
325         if (value->id != 0)
326             ret->append(new CSSPrimitiveValue(value->id));
327         else if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
328             ret->append(new CSSPrimitiveValue(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit));
329         value = valueList->next();
330         if (value && value->unit == Value::Operator && value->iValue == ',')
331             value = valueList->next();
332     }
333     if (!valid_primitive) {
334         delete ret;
335         ret = 0;
336     }
337
338     return ret;
339 }
340
341 CSSValue* CSSParser::parseSVGPaint()
342 {
343     RGBA32 c = Color::transparent;
344     if (!parseColorFromValue(valueList->current(), c, true))
345         return new SVGPaint();
346     return new SVGPaint(Color(c));
347 }
348
349 CSSValue* CSSParser::parseSVGColor()
350 {
351     RGBA32 c = Color::transparent;
352     if (!parseColorFromValue(valueList->current(), c, true))
353         return 0;
354     return new SVGColor(Color(c));
355 }
356
357 }
358
359 #endif // ENABLE(SVG)
360
361 // vim:ts=4:noet