1 /*
2 Copyright (C) 2008 Eric Seidel <eric@webkit.org>
3 Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org>
4 2004, 2005, 2007 Rob Buis <buis@kde.org>
5 Copyright (C) 2005, 2006 Apple Computer, Inc.
6
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public
9 License as published by the Free Software Foundation; either
10 version 2 of the License, or (at your option) any later version.
11
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Library General Public License for more details.
16
17 You should have received a copy of the GNU Library General Public License
18 along with this library; see the file COPYING.LIB. If not, write to
19 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 Boston, MA 02110-1301, USA.
21 */
22
23 #include "config.h"
24
25 #if ENABLE(SVG)
26 #include "CSSInheritedValue.h"
27 #include "CSSInitialValue.h"
28 #include "CSSParser.h"
29 #include "CSSProperty.h"
30 #include "CSSPropertyNames.h"
31 #include "CSSQuirkPrimitiveValue.h"
32 #include "CSSValueKeywords.h"
33 #include "CSSValueList.h"
34 #include "SVGPaint.h"
35
36 using namespace std;
37
38 namespace WebCore {
39
parseSVGValue(int propId,bool important)40 bool CSSParser::parseSVGValue(int propId, bool important)
41 {
42 CSSParserValue* value = m_valueList->current();
43 if (!value)
44 return false;
45
46 int id = value->id;
47
48 bool valid_primitive = false;
49 RefPtr<CSSValue> parsedValue;
50
51 switch (propId) {
52 /* The comment to the right defines all valid value of these
53 * properties as defined in SVG 1.1, Appendix N. Property index */
54 case CSSPropertyAlignmentBaseline:
55 // auto | baseline | before-edge | text-before-edge | middle |
56 // central | after-edge | text-after-edge | ideographic | alphabetic |
57 // hanging | mathematical | inherit
58 if (id == CSSValueAuto || id == CSSValueBaseline || id == CSSValueMiddle ||
59 (id >= CSSValueBeforeEdge && id <= CSSValueMathematical))
60 valid_primitive = true;
61 break;
62
63 case CSSPropertyBaselineShift:
64 // baseline | super | sub | <percentage> | <length> | inherit
65 if (id == CSSValueBaseline || id == CSSValueSub ||
66 id >= CSSValueSuper)
67 valid_primitive = true;
68 else
69 valid_primitive = validUnit(value, FLength|FPercent, false);
70 break;
71
72 case CSSPropertyDominantBaseline:
73 // auto | use-script | no-change | reset-size | ideographic |
74 // alphabetic | hanging | mathematical | central | middle |
75 // text-after-edge | text-before-edge | inherit
76 if (id == CSSValueAuto || id == CSSValueMiddle ||
77 (id >= CSSValueUseScript && id <= CSSValueResetSize) ||
78 (id >= CSSValueCentral && id <= CSSValueMathematical))
79 valid_primitive = true;
80 break;
81
82 case CSSPropertyEnableBackground:
83 // accumulate | new [x] [y] [width] [height] | inherit
84 if (id == CSSValueAccumulate) // TODO : new
85 valid_primitive = true;
86 break;
87
88 case CSSPropertyMarkerStart:
89 case CSSPropertyMarkerMid:
90 case CSSPropertyMarkerEnd:
91 case CSSPropertyMask:
92 if (id == CSSValueNone)
93 valid_primitive = true;
94 else if (value->unit == CSSPrimitiveValue::CSS_URI) {
95 parsedValue = CSSPrimitiveValue::create(value->string, CSSPrimitiveValue::CSS_URI);
96 if (parsedValue)
97 m_valueList->next();
98 }
99 break;
100
101 case CSSPropertyClipRule: // nonzero | evenodd | inherit
102 case CSSPropertyFillRule:
103 if (id == CSSValueNonzero || id == CSSValueEvenodd)
104 valid_primitive = true;
105 break;
106
107 case CSSPropertyStrokeMiterlimit: // <miterlimit> | inherit
108 valid_primitive = validUnit(value, FNumber|FNonNeg, false);
109 break;
110
111 case CSSPropertyStrokeLinejoin: // miter | round | bevel | inherit
112 if (id == CSSValueMiter || id == CSSValueRound || id == CSSValueBevel)
113 valid_primitive = true;
114 break;
115
116 case CSSPropertyStrokeLinecap: // butt | round | square | inherit
117 if (id == CSSValueButt || id == CSSValueRound || id == CSSValueSquare)
118 valid_primitive = true;
119 break;
120
121 case CSSPropertyStrokeOpacity: // <opacity-value> | inherit
122 case CSSPropertyFillOpacity:
123 case CSSPropertyStopOpacity:
124 case CSSPropertyFloodOpacity:
125 valid_primitive = (!id && validUnit(value, FNumber|FPercent, false));
126 break;
127
128 case CSSPropertyShapeRendering:
129 // auto | optimizeSpeed | crispEdges | geometricPrecision | inherit
130 if (id == CSSValueAuto || id == CSSValueOptimizespeed ||
131 id == CSSValueCrispedges || id == CSSValueGeometricprecision)
132 valid_primitive = true;
133 break;
134
135 case CSSPropertyTextRendering: // auto | optimizeSpeed | optimizeLegibility | geometricPrecision | inherit
136 if (id == CSSValueAuto || id == CSSValueOptimizespeed || id == CSSValueOptimizelegibility ||
137 id == CSSValueGeometricprecision)
138 valid_primitive = true;
139 break;
140
141 case CSSPropertyImageRendering: // auto | optimizeSpeed |
142 case CSSPropertyColorRendering: // optimizeQuality | inherit
143 if (id == CSSValueAuto || id == CSSValueOptimizespeed ||
144 id == CSSValueOptimizequality)
145 valid_primitive = true;
146 break;
147
148 case CSSPropertyColorProfile: // auto | sRGB | <name> | <uri> inherit
149 if (id == CSSValueAuto || id == CSSValueSrgb)
150 valid_primitive = true;
151 break;
152
153 case CSSPropertyColorInterpolation: // auto | sRGB | linearRGB | inherit
154 case CSSPropertyColorInterpolationFilters:
155 if (id == CSSValueAuto || id == CSSValueSrgb || id == CSSValueLinearrgb)
156 valid_primitive = true;
157 break;
158
159 /* Start of supported CSS properties with validation. This is needed for parseShortHand to work
160 * correctly and allows optimization in applyRule(..)
161 */
162
163 case CSSPropertyTextAnchor: // start | middle | end | inherit
164 if (id == CSSValueStart || id == CSSValueMiddle || id == CSSValueEnd)
165 valid_primitive = true;
166 break;
167
168 case CSSPropertyGlyphOrientationVertical: // auto | <angle> | inherit
169 if (id == CSSValueAuto) {
170 valid_primitive = true;
171 break;
172 }
173 /* fallthrough intentional */
174 case CSSPropertyGlyphOrientationHorizontal: // <angle> (restricted to _deg_ per SVG 1.1 spec) | inherit
175 if (value->unit == CSSPrimitiveValue::CSS_DEG || value->unit == CSSPrimitiveValue::CSS_NUMBER) {
176 parsedValue = CSSPrimitiveValue::create(value->fValue, CSSPrimitiveValue::CSS_DEG);
177
178 if (parsedValue)
179 m_valueList->next();
180 }
181 break;
182
183 case CSSPropertyFill: // <paint> | inherit
184 case CSSPropertyStroke: // <paint> | inherit
185 {
186 if (id == CSSValueNone)
187 parsedValue = SVGPaint::create(SVGPaint::SVG_PAINTTYPE_NONE);
188 else if (id == CSSValueCurrentcolor)
189 parsedValue = SVGPaint::create(SVGPaint::SVG_PAINTTYPE_CURRENTCOLOR);
190 else if (value->unit == CSSPrimitiveValue::CSS_URI) {
191 RGBA32 c = Color::transparent;
192 if (m_valueList->next() && parseColorFromValue(m_valueList->current(), c, true)) {
193 parsedValue = SVGPaint::create(value->string, c);
194 } else
195 parsedValue = SVGPaint::create(SVGPaint::SVG_PAINTTYPE_URI, value->string);
196 } else
197 parsedValue = parseSVGPaint();
198
199 if (parsedValue)
200 m_valueList->next();
201 }
202 break;
203
204 case CSSPropertyColor: // <color> | inherit
205 if ((id >= CSSValueAqua && id <= CSSValueWindowtext) ||
206 (id >= CSSValueAliceblue && id <= CSSValueYellowgreen))
207 parsedValue = SVGColor::create(value->string);
208 else
209 parsedValue = parseSVGColor();
210
211 if (parsedValue)
212 m_valueList->next();
213 break;
214
215 case CSSPropertyStopColor: // TODO : icccolor
216 case CSSPropertyFloodColor:
217 case CSSPropertyLightingColor:
218 if ((id >= CSSValueAqua && id <= CSSValueWindowtext) ||
219 (id >= CSSValueAliceblue && id <= CSSValueYellowgreen))
220 parsedValue = SVGColor::create(value->string);
221 else if (id == CSSValueCurrentcolor)
222 parsedValue = SVGColor::createCurrentColor();
223 else // TODO : svgcolor (iccColor)
224 parsedValue = parseSVGColor();
225
226 if (parsedValue)
227 m_valueList->next();
228
229 break;
230
231 case CSSPropertyWritingMode:
232 // lr-tb | rl_tb | tb-rl | lr | rl | tb | inherit
233 if (id >= CSSValueLrTb && id <= CSSValueTb)
234 valid_primitive = true;
235 break;
236
237 case CSSPropertyStrokeWidth: // <length> | inherit
238 case CSSPropertyStrokeDashoffset:
239 valid_primitive = validUnit(value, FLength | FPercent, false);
240 break;
241 case CSSPropertyStrokeDasharray: // none | <dasharray> | inherit
242 if (id == CSSValueNone)
243 valid_primitive = true;
244 else
245 parsedValue = parseSVGStrokeDasharray();
246
247 break;
248
249 case CSSPropertyKerning: // auto | normal | <length> | inherit
250 if (id == CSSValueAuto || id == CSSValueNormal)
251 valid_primitive = true;
252 else
253 valid_primitive = validUnit(value, FLength, false);
254 break;
255
256 case CSSPropertyClipPath: // <uri> | none | inherit
257 case CSSPropertyFilter:
258 if (id == CSSValueNone)
259 valid_primitive = true;
260 else if (value->unit == CSSPrimitiveValue::CSS_URI) {
261 parsedValue = CSSPrimitiveValue::create(value->string, (CSSPrimitiveValue::UnitTypes) value->unit);
262 if (parsedValue)
263 m_valueList->next();
264 }
265 break;
266
267 /* shorthand properties */
268 case CSSPropertyMarker:
269 {
270 ShorthandScope scope(this, propId);
271 m_implicitShorthand = true;
272 if (!parseValue(CSSPropertyMarkerStart, important))
273 return false;
274 if (m_valueList->current()) {
275 rollbackLastProperties(1);
276 return false;
277 }
278 CSSValue* value = m_parsedProperties[m_numParsedProperties - 1]->value();
279 addProperty(CSSPropertyMarkerMid, value, important);
280 addProperty(CSSPropertyMarkerEnd, value, important);
281 m_implicitShorthand = false;
282 return true;
283 }
284 default:
285 // If you crash here, it's because you added a css property and are not handling it
286 // in either this switch statement or the one in CSSParser::parseValue
287 ASSERT_WITH_MESSAGE(0, "unimplemented propertyID: %d", propId);
288 return false;
289 }
290
291 if (valid_primitive) {
292 if (id != 0)
293 parsedValue = CSSPrimitiveValue::createIdentifier(id);
294 else if (value->unit == CSSPrimitiveValue::CSS_STRING)
295 parsedValue = CSSPrimitiveValue::create(value->string, (CSSPrimitiveValue::UnitTypes) value->unit);
296 else if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
297 parsedValue = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit);
298 else if (value->unit >= CSSParserValue::Q_EMS)
299 parsedValue = CSSQuirkPrimitiveValue::create(value->fValue, CSSPrimitiveValue::CSS_EMS);
300 m_valueList->next();
301 }
302 if (!parsedValue || (m_valueList->current() && !inShorthand()))
303 return false;
304
305 addProperty(propId, parsedValue.release(), important);
306 return true;
307 }
308
parseSVGStrokeDasharray()309 PassRefPtr<CSSValue> CSSParser::parseSVGStrokeDasharray()
310 {
311 RefPtr<CSSValueList> ret = CSSValueList::createCommaSeparated();
312 CSSParserValue* value = m_valueList->current();
313 bool valid_primitive = true;
314 while (value) {
315 valid_primitive = validUnit(value, FLength | FPercent |FNonNeg, false);
316 if (!valid_primitive)
317 break;
318 if (value->id != 0)
319 ret->append(CSSPrimitiveValue::createIdentifier(value->id));
320 else if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
321 ret->append(CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit));
322 value = m_valueList->next();
323 if (value && value->unit == CSSParserValue::Operator && value->iValue == ',')
324 value = m_valueList->next();
325 }
326 if (!valid_primitive)
327 return 0;
328 return ret.release();
329 }
330
parseSVGPaint()331 PassRefPtr<CSSValue> CSSParser::parseSVGPaint()
332 {
333 RGBA32 c = Color::transparent;
334 if (!parseColorFromValue(m_valueList->current(), c, true))
335 return SVGPaint::create();
336 return SVGPaint::create(Color(c));
337 }
338
parseSVGColor()339 PassRefPtr<CSSValue> CSSParser::parseSVGColor()
340 {
341 RGBA32 c = Color::transparent;
342 if (!parseColorFromValue(m_valueList->current(), c, true))
343 return 0;
344 return SVGColor::create(Color(c));
345 }
346
347 }
348
349 #endif // ENABLE(SVG)
350
351 // vim:ts=4:noet
352