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 CSSPropertyImageRendering: // auto | optimizeSpeed |
136 case CSSPropertyColorRendering: // optimizeQuality | inherit
137 if (id == CSSValueAuto || id == CSSValueOptimizespeed ||
138 id == CSSValueOptimizequality)
139 valid_primitive = true;
140 break;
141
142 case CSSPropertyColorProfile: // auto | sRGB | <name> | <uri> inherit
143 if (id == CSSValueAuto || id == CSSValueSrgb)
144 valid_primitive = true;
145 break;
146
147 case CSSPropertyColorInterpolation: // auto | sRGB | linearRGB | inherit
148 case CSSPropertyColorInterpolationFilters:
149 if (id == CSSValueAuto || id == CSSValueSrgb || id == CSSValueLinearrgb)
150 valid_primitive = true;
151 break;
152
153 /* Start of supported CSS properties with validation. This is needed for parseShortHand to work
154 * correctly and allows optimization in applyRule(..)
155 */
156
157 case CSSPropertyTextAnchor: // start | middle | end | inherit
158 if (id == CSSValueStart || id == CSSValueMiddle || id == CSSValueEnd)
159 valid_primitive = true;
160 break;
161
162 case CSSPropertyGlyphOrientationVertical: // auto | <angle> | inherit
163 if (id == CSSValueAuto) {
164 valid_primitive = true;
165 break;
166 }
167 /* fallthrough intentional */
168 case CSSPropertyGlyphOrientationHorizontal: // <angle> (restricted to _deg_ per SVG 1.1 spec) | inherit
169 if (value->unit == CSSPrimitiveValue::CSS_DEG || value->unit == CSSPrimitiveValue::CSS_NUMBER) {
170 parsedValue = CSSPrimitiveValue::create(value->fValue, CSSPrimitiveValue::CSS_DEG);
171
172 if (parsedValue)
173 m_valueList->next();
174 }
175 break;
176
177 case CSSPropertyFill: // <paint> | inherit
178 case CSSPropertyStroke: // <paint> | inherit
179 {
180 if (id == CSSValueNone)
181 parsedValue = SVGPaint::create(SVGPaint::SVG_PAINTTYPE_NONE);
182 else if (id == CSSValueCurrentcolor)
183 parsedValue = SVGPaint::create(SVGPaint::SVG_PAINTTYPE_CURRENTCOLOR);
184 else if (value->unit == CSSPrimitiveValue::CSS_URI) {
185 RGBA32 c = Color::transparent;
186 if (m_valueList->next() && parseColorFromValue(m_valueList->current(), c, true)) {
187 parsedValue = SVGPaint::create(value->string, c);
188 } else
189 parsedValue = SVGPaint::create(SVGPaint::SVG_PAINTTYPE_URI, value->string);
190 } else
191 parsedValue = parseSVGPaint();
192
193 if (parsedValue)
194 m_valueList->next();
195 }
196 break;
197
198 case CSSPropertyColor: // <color> | inherit
199 if ((id >= CSSValueAqua && id <= CSSValueWindowtext) ||
200 (id >= CSSValueAliceblue && id <= CSSValueYellowgreen))
201 parsedValue = SVGColor::create(value->string);
202 else
203 parsedValue = parseSVGColor();
204
205 if (parsedValue)
206 m_valueList->next();
207 break;
208
209 case CSSPropertyStopColor: // TODO : icccolor
210 case CSSPropertyFloodColor:
211 case CSSPropertyLightingColor:
212 if ((id >= CSSValueAqua && id <= CSSValueWindowtext) ||
213 (id >= CSSValueAliceblue && id <= CSSValueYellowgreen))
214 parsedValue = SVGColor::create(value->string);
215 else if (id == CSSValueCurrentcolor)
216 parsedValue = SVGColor::createCurrentColor();
217 else // TODO : svgcolor (iccColor)
218 parsedValue = parseSVGColor();
219
220 if (parsedValue)
221 m_valueList->next();
222
223 break;
224
225 case CSSPropertyWritingMode:
226 // lr-tb | rl_tb | tb-rl | lr | rl | tb | inherit
227 if (id >= CSSValueLrTb && id <= CSSValueTb)
228 valid_primitive = true;
229 break;
230
231 case CSSPropertyStrokeWidth: // <length> | inherit
232 case CSSPropertyStrokeDashoffset:
233 valid_primitive = validUnit(value, FLength | FPercent, false);
234 break;
235 case CSSPropertyStrokeDasharray: // none | <dasharray> | inherit
236 if (id == CSSValueNone)
237 valid_primitive = true;
238 else
239 parsedValue = parseSVGStrokeDasharray();
240
241 break;
242
243 case CSSPropertyKerning: // auto | normal | <length> | inherit
244 if (id == CSSValueAuto || id == CSSValueNormal)
245 valid_primitive = true;
246 else
247 valid_primitive = validUnit(value, FLength, false);
248 break;
249
250 case CSSPropertyClipPath: // <uri> | none | inherit
251 case CSSPropertyFilter:
252 if (id == CSSValueNone)
253 valid_primitive = true;
254 else if (value->unit == CSSPrimitiveValue::CSS_URI) {
255 parsedValue = CSSPrimitiveValue::create(value->string, (CSSPrimitiveValue::UnitTypes) value->unit);
256 if (parsedValue)
257 m_valueList->next();
258 }
259 break;
260 case CSSPropertyWebkitSvgShadow:
261 if (id == CSSValueNone)
262 valid_primitive = true;
263 else
264 return parseShadow(propId, important);
265
266 /* shorthand properties */
267 case CSSPropertyMarker:
268 {
269 ShorthandScope scope(this, propId);
270 m_implicitShorthand = true;
271 if (!parseValue(CSSPropertyMarkerStart, important))
272 return false;
273 if (m_valueList->current()) {
274 rollbackLastProperties(1);
275 return false;
276 }
277 CSSValue* value = m_parsedProperties[m_numParsedProperties - 1]->value();
278 addProperty(CSSPropertyMarkerMid, value, important);
279 addProperty(CSSPropertyMarkerEnd, value, important);
280 m_implicitShorthand = false;
281 return true;
282 }
283 default:
284 // If you crash here, it's because you added a css property and are not handling it
285 // in either this switch statement or the one in CSSParser::parseValue
286 ASSERT_WITH_MESSAGE(0, "unimplemented propertyID: %d", propId);
287 return false;
288 }
289
290 if (valid_primitive) {
291 if (id != 0)
292 parsedValue = CSSPrimitiveValue::createIdentifier(id);
293 else if (value->unit == CSSPrimitiveValue::CSS_STRING)
294 parsedValue = CSSPrimitiveValue::create(value->string, (CSSPrimitiveValue::UnitTypes) value->unit);
295 else if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
296 parsedValue = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit);
297 else if (value->unit >= CSSParserValue::Q_EMS)
298 parsedValue = CSSQuirkPrimitiveValue::create(value->fValue, CSSPrimitiveValue::CSS_EMS);
299 m_valueList->next();
300 }
301 if (!parsedValue || (m_valueList->current() && !inShorthand()))
302 return false;
303
304 addProperty(propId, parsedValue.release(), important);
305 return true;
306 }
307
parseSVGStrokeDasharray()308 PassRefPtr<CSSValue> CSSParser::parseSVGStrokeDasharray()
309 {
310 RefPtr<CSSValueList> ret = CSSValueList::createCommaSeparated();
311 CSSParserValue* value = m_valueList->current();
312 bool valid_primitive = true;
313 while (value) {
314 valid_primitive = validUnit(value, FLength | FPercent |FNonNeg, false);
315 if (!valid_primitive)
316 break;
317 if (value->id != 0)
318 ret->append(CSSPrimitiveValue::createIdentifier(value->id));
319 else if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
320 ret->append(CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit));
321 value = m_valueList->next();
322 if (value && value->unit == CSSParserValue::Operator && value->iValue == ',')
323 value = m_valueList->next();
324 }
325 if (!valid_primitive)
326 return 0;
327 return ret.release();
328 }
329
parseSVGPaint()330 PassRefPtr<CSSValue> CSSParser::parseSVGPaint()
331 {
332 RGBA32 c = Color::transparent;
333 if (!parseColorFromValue(m_valueList->current(), c, true))
334 return SVGPaint::create();
335 return SVGPaint::create(Color(c));
336 }
337
parseSVGColor()338 PassRefPtr<CSSValue> CSSParser::parseSVGColor()
339 {
340 RGBA32 c = Color::transparent;
341 if (!parseColorFromValue(m_valueList->current(), c, true))
342 return 0;
343 return SVGColor::create(Color(c));
344 }
345
346 }
347
348 #endif // ENABLE(SVG)
349
350 // vim:ts=4:noet
351