2007-10-08 Eric Seidel <eric@webkit.org>
[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 "DeprecatedString.h"
37
38 using namespace std;
39
40 namespace WebCore {
41
42 bool CSSParser::parseSVGValue(int propId, bool important)
43 {
44     Value* value = valueList->current();
45     if (!value)
46         return false;
47
48     int id = value->id;
49
50     bool valid_primitive = false;
51     CSSValue* parsedValue = 0;
52
53     switch (propId) {
54     /* The comment to the right defines all valid value of these
55      * properties as defined in SVG 1.1, Appendix N. Property index */
56     case CSS_PROP_ALIGNMENT_BASELINE:
57     // auto | baseline | before-edge | text-before-edge | middle |
58     // central | after-edge | text-after-edge | ideographic | alphabetic |
59     // hanging | mathematical | inherit
60         if (id == CSS_VAL_AUTO || id == CSS_VAL_BASELINE || id == CSS_VAL_MIDDLE ||
61           (id >= CSS_VAL_BEFORE_EDGE && id <= CSS_VAL_MATHEMATICAL))
62             valid_primitive = true;
63         break;
64
65     case CSS_PROP_BASELINE_SHIFT:
66     // baseline | super | sub | <percentage> | <length> | inherit
67         if (id == CSS_VAL_BASELINE || id == CSS_VAL_SUB ||
68            id >= CSS_VAL_SUPER)
69             valid_primitive = true;
70         else
71             valid_primitive = validUnit(value, FLength|FPercent, false);
72         break;
73
74     case CSS_PROP_DOMINANT_BASELINE:
75     // auto | use-script | no-change | reset-size | ideographic |
76     // alphabetic | hanging | mathematical | central | middle |
77     // text-after-edge | text-before-edge | inherit
78         if (id == CSS_VAL_AUTO || id == CSS_VAL_MIDDLE ||
79           (id >= CSS_VAL_USE_SCRIPT && id <= CSS_VAL_RESET_SIZE) ||
80           (id >= CSS_VAL_CENTRAL && id <= CSS_VAL_MATHEMATICAL))
81             valid_primitive = true;
82         break;
83
84     case CSS_PROP_ENABLE_BACKGROUND:
85     // accumulate | new [x] [y] [width] [height] | inherit
86         if (id == CSS_VAL_ACCUMULATE) // TODO : new
87             valid_primitive = true;
88         break;
89
90     case CSS_PROP_MARKER_START:
91     case CSS_PROP_MARKER_MID:
92     case CSS_PROP_MARKER_END:
93     case CSS_PROP_MASK:
94         if (id == CSS_VAL_NONE)
95             valid_primitive = true;
96         else if (value->unit == CSSPrimitiveValue::CSS_URI) {
97             parsedValue = new CSSPrimitiveValue(domString(value->string), CSSPrimitiveValue::CSS_URI);
98             if (parsedValue)
99                 valueList->next();
100         }
101         break;
102
103     case CSS_PROP_CLIP_RULE:            // nonzero | evenodd | inherit
104     case CSS_PROP_FILL_RULE:
105         if (id == CSS_VAL_NONZERO || id == CSS_VAL_EVENODD)
106             valid_primitive = true;
107         break;
108
109     case CSS_PROP_STROKE_MITERLIMIT:   // <miterlimit> | inherit
110         valid_primitive = validUnit(value, FNumber|FNonNeg, false);
111         break;
112
113     case CSS_PROP_STROKE_LINEJOIN:   // miter | round | bevel | inherit
114         if (id == CSS_VAL_MITER || id == CSS_VAL_ROUND || id == CSS_VAL_BEVEL)
115             valid_primitive = true;
116         break;
117
118     case CSS_PROP_STROKE_LINECAP:    // butt | round | square | inherit
119         if (id == CSS_VAL_BUTT || id == CSS_VAL_ROUND || id == CSS_VAL_SQUARE)
120             valid_primitive = true;
121         break;
122
123     case CSS_PROP_STROKE_OPACITY:   // <opacity-value> | inherit
124     case CSS_PROP_FILL_OPACITY:
125     case CSS_PROP_STOP_OPACITY:
126     case CSS_PROP_FLOOD_OPACITY:
127         valid_primitive = (!id && validUnit(value, FNumber|FPercent, false));
128         break;
129
130     case CSS_PROP_SHAPE_RENDERING:
131     // auto | optimizeSpeed | crispEdges | geometricPrecision | inherit
132         if (id == CSS_VAL_AUTO || id == CSS_VAL_OPTIMIZESPEED ||
133             id == CSS_VAL_CRISPEDGES || id == CSS_VAL_GEOMETRICPRECISION)
134             valid_primitive = true;
135         break;
136
137     case CSS_PROP_TEXT_RENDERING:   // auto | optimizeSpeed | optimizeLegibility | geometricPrecision | inherit
138         if (id == CSS_VAL_AUTO || id == CSS_VAL_OPTIMIZESPEED || id == CSS_VAL_OPTIMIZELEGIBILITY ||
139        id == CSS_VAL_GEOMETRICPRECISION)
140             valid_primitive = true;
141         break;
142
143     case CSS_PROP_IMAGE_RENDERING:  // auto | optimizeSpeed |
144     case CSS_PROP_COLOR_RENDERING:  // optimizeQuality | inherit
145         if (id == CSS_VAL_AUTO || id == CSS_VAL_OPTIMIZESPEED ||
146             id == CSS_VAL_OPTIMIZEQUALITY)
147             valid_primitive = true;
148         break;
149
150     case CSS_PROP_COLOR_PROFILE: // auto | sRGB | <name> | <uri> inherit
151         if (id == CSS_VAL_AUTO || id == CSS_VAL_SRGB)
152             valid_primitive = true;
153         break;
154
155     case CSS_PROP_COLOR_INTERPOLATION:   // auto | sRGB | linearRGB | inherit
156     case CSS_PROP_COLOR_INTERPOLATION_FILTERS:  
157         if (id == CSS_VAL_AUTO || id == CSS_VAL_SRGB || id == CSS_VAL_LINEARRGB)
158             valid_primitive = true;
159         break;
160
161     /* Start of supported CSS properties with validation. This is needed for parseShortHand to work
162      * correctly and allows optimization in applyRule(..)
163      */
164
165     case CSS_PROP_POINTER_EVENTS:
166     // none | visiblePainted | visibleFill | visibleStroke | visible |
167     // painted | fill | stroke | none | all | inherit
168         if (id == CSS_VAL_VISIBLE || id == CSS_VAL_NONE ||
169           (id >= CSS_VAL_VISIBLEPAINTED && id <= CSS_VAL_ALL))
170             valid_primitive = true;
171         break;
172
173     case CSS_PROP_TEXT_ANCHOR:    // start | middle | end | inherit
174         if (id == CSS_VAL_START || id == CSS_VAL_MIDDLE || id == CSS_VAL_END)
175             valid_primitive = true;
176         break;
177
178     case CSS_PROP_GLYPH_ORIENTATION_VERTICAL: // auto | <angle> | inherit
179         if (id == CSS_VAL_AUTO) {
180             valid_primitive = true;
181             break;
182         }
183         /* fallthrough intentional */
184     case CSS_PROP_GLYPH_ORIENTATION_HORIZONTAL: // <angle> | inherit
185         if (value->unit == CSSPrimitiveValue::CSS_DEG)
186             parsedValue = new CSSPrimitiveValue(value->fValue, CSSPrimitiveValue::CSS_DEG);
187         else if (value->unit == CSSPrimitiveValue::CSS_GRAD)
188             parsedValue = new CSSPrimitiveValue(value->fValue, CSSPrimitiveValue::CSS_GRAD);
189         else if (value->unit == CSSPrimitiveValue::CSS_RAD)
190             parsedValue = new CSSPrimitiveValue(value->fValue, CSSPrimitiveValue::CSS_RAD);
191         break;
192
193     case CSS_PROP_FILL:                 // <paint> | inherit
194     case CSS_PROP_STROKE:               // <paint> | inherit
195         {
196             if (id == CSS_VAL_NONE)
197                 parsedValue = new SVGPaint(SVGPaint::SVG_PAINTTYPE_NONE);
198             else if (id == CSS_VAL_CURRENTCOLOR)
199                 parsedValue = new SVGPaint(SVGPaint::SVG_PAINTTYPE_CURRENTCOLOR);
200             else if (value->unit == CSSPrimitiveValue::CSS_URI) {
201                 RGBA32 c = Color::transparent;
202                 if (valueList->next() && parseColorFromValue(valueList->current(), c, true)) {
203                     parsedValue = new SVGPaint(domString(value->string), c);
204                 } else
205                     parsedValue = new SVGPaint(SVGPaint::SVG_PAINTTYPE_URI, domString(value->string));
206             } else
207                 parsedValue = parseSVGPaint();
208
209             if (parsedValue)
210                 valueList->next();
211         }
212         break;
213
214     case CSS_PROP_COLOR:                // <color> | inherit
215         if ((id >= CSS_VAL_AQUA && id <= CSS_VAL_WINDOWTEXT) ||
216            (id >= CSS_VAL_ALICEBLUE && id <= CSS_VAL_YELLOWGREEN))
217             parsedValue = new SVGColor(domString(value->string));
218         else
219             parsedValue = parseSVGColor();
220
221         if (parsedValue)
222             valueList->next();
223         break;
224
225     case CSS_PROP_STOP_COLOR: // TODO : icccolor
226     case CSS_PROP_FLOOD_COLOR:
227     case CSS_PROP_LIGHTING_COLOR:
228         if ((id >= CSS_VAL_AQUA && id <= CSS_VAL_WINDOWTEXT) ||
229            (id >= CSS_VAL_ALICEBLUE && id <= CSS_VAL_YELLOWGREEN))
230             parsedValue = new SVGColor(domString(value->string));
231         else if (id == CSS_VAL_CURRENTCOLOR)
232             parsedValue = new SVGColor(SVGColor::SVG_COLORTYPE_CURRENTCOLOR);
233         else // TODO : svgcolor (iccColor)
234             parsedValue = parseSVGColor();
235
236         if (parsedValue)
237             valueList->next();
238
239         break;
240
241     case CSS_PROP_WRITING_MODE:
242     // lr-tb | rl_tb | tb-rl | lr | rl | tb | inherit
243         if (id >= CSS_VAL_LR_TB && id <= CSS_VAL_TB)
244             valid_primitive = true;
245         break;
246
247     case CSS_PROP_STROKE_WIDTH:         // <length> | inherit
248     case CSS_PROP_STROKE_DASHOFFSET:
249         valid_primitive = validUnit(value, FLength | FPercent, false);
250         break;
251     case CSS_PROP_STROKE_DASHARRAY:     // none | <dasharray> | inherit
252         if (id == CSS_VAL_NONE)
253             valid_primitive = true;
254         else
255             parsedValue = parseSVGStrokeDasharray();
256
257         break;
258
259     case CSS_PROP_KERNING:              // auto | normal | <length> | inherit
260         if (id == CSS_VAL_AUTO || id == CSS_VAL_NORMAL)
261             valid_primitive = true;
262         else
263             valid_primitive = validUnit(value, FLength, false);
264         break;
265
266     case CSS_PROP_CLIP_PATH:    // <uri> | none | inherit
267     case CSS_PROP_FILTER:
268         if (id == CSS_VAL_NONE)
269             valid_primitive = true;
270         else if (value->unit == CSSPrimitiveValue::CSS_URI) {
271             parsedValue = new CSSPrimitiveValue(domString(value->string), (CSSPrimitiveValue::UnitTypes) value->unit);
272             if (parsedValue)
273                 valueList->next();
274         }
275         break;
276
277     /* shorthand properties */
278     case CSS_PROP_MARKER:
279     {
280         if (!parseValue(CSS_PROP_MARKER_START, important))
281             return false;
282         CSSValue *value = parsedProperties[numParsedProperties - 1]->value();
283         m_implicitShorthand = true;
284         addProperty(CSS_PROP_MARKER_MID, value, important);
285         addProperty(CSS_PROP_MARKER_END, value, important);
286         m_implicitShorthand = false;
287         return true;
288     }
289     default:
290         // If you crash here, it's because you added a css property and are not handling it
291         // in either this switch statement or the one in CSSParser::parseValue
292         ASSERT_WITH_MESSAGE(0, "unimplemented propertyID: %d", propId);
293         return false;
294     }
295
296     if (valid_primitive) {
297         if (id != 0)
298             parsedValue = new CSSPrimitiveValue(id);
299         else if (value->unit == CSSPrimitiveValue::CSS_STRING)
300             parsedValue = new CSSPrimitiveValue(domString(value->string), (CSSPrimitiveValue::UnitTypes) value->unit);
301         else if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
302             parsedValue = new CSSPrimitiveValue(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit);
303         else if (value->unit >= Value::Q_EMS)
304             parsedValue = new CSSQuirkPrimitiveValue(value->fValue, CSSPrimitiveValue::CSS_EMS);
305         valueList->next();
306     }
307     if (parsedValue) {
308         if (!valueList->current() || inShorthand()) {
309             addProperty(propId, parsedValue, important);
310             return true;
311         }
312         delete parsedValue;
313     }
314     return false;
315 }
316
317 CSSValue* CSSParser::parseSVGStrokeDasharray()
318 {
319     CSSValueList* ret = new CSSValueList;
320     Value* value = valueList->current();
321     bool valid_primitive = true;
322     while (value) {
323         valid_primitive = validUnit(value, FLength | FPercent |FNonNeg, false);
324         if (!valid_primitive)
325             break;
326         if (value->id != 0)
327             ret->append(new CSSPrimitiveValue(value->id));
328         else if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
329             ret->append(new CSSPrimitiveValue(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit));
330         value = valueList->next();
331         if (value && value->unit == Value::Operator && value->iValue == ',')
332             value = valueList->next();
333     }
334     if (!valid_primitive) {
335         delete ret;
336         ret = 0;
337     }
338
339     return ret;
340 }
341
342 CSSValue* CSSParser::parseSVGPaint()
343 {
344     RGBA32 c = Color::transparent;
345     if (!parseColorFromValue(valueList->current(), c, true))
346         return new SVGPaint();
347     return new SVGPaint(Color(c));
348 }
349
350 CSSValue* CSSParser::parseSVGColor()
351 {
352     RGBA32 c = Color::transparent;
353     if (!parseColorFromValue(valueList->current(), c, true))
354         return 0;
355     return new SVGColor(Color(c));
356 }
357
358 }
359
360 #endif // ENABLE(SVG)
361
362 // vim:ts=4:noet