• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, 2010 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 "RenderTheme.h"
35 #include "SVGPaint.h"
36 
37 using namespace std;
38 
39 namespace WebCore {
40 
parseSVGValue(int propId,bool important)41 bool CSSParser::parseSVGValue(int propId, bool important)
42 {
43     CSSParserValue* value = m_valueList->current();
44     if (!value)
45         return false;
46 
47     int id = value->id;
48 
49     bool valid_primitive = false;
50     RefPtr<CSSValue> parsedValue;
51 
52     switch (propId) {
53     /* The comment to the right defines all valid value of these
54      * properties as defined in SVG 1.1, Appendix N. Property index */
55     case CSSPropertyAlignmentBaseline:
56     // auto | baseline | before-edge | text-before-edge | middle |
57     // central | after-edge | text-after-edge | ideographic | alphabetic |
58     // hanging | mathematical | inherit
59         if (id == CSSValueAuto || id == CSSValueBaseline || id == CSSValueMiddle ||
60           (id >= CSSValueBeforeEdge && id <= CSSValueMathematical))
61             valid_primitive = true;
62         break;
63 
64     case CSSPropertyBaselineShift:
65     // baseline | super | sub | <percentage> | <length> | inherit
66         if (id == CSSValueBaseline || id == CSSValueSub ||
67            id >= CSSValueSuper)
68             valid_primitive = true;
69         else
70             valid_primitive = validUnit(value, FLength|FPercent, false);
71         break;
72 
73     case CSSPropertyDominantBaseline:
74     // auto | use-script | no-change | reset-size | ideographic |
75     // alphabetic | hanging | mathematical | central | middle |
76     // text-after-edge | text-before-edge | inherit
77         if (id == CSSValueAuto || id == CSSValueMiddle ||
78           (id >= CSSValueUseScript && id <= CSSValueResetSize) ||
79           (id >= CSSValueCentral && id <= CSSValueMathematical))
80             valid_primitive = true;
81         break;
82 
83     case CSSPropertyEnableBackground:
84     // accumulate | new [x] [y] [width] [height] | inherit
85         if (id == CSSValueAccumulate) // TODO : new
86             valid_primitive = true;
87         break;
88 
89     case CSSPropertyMarkerStart:
90     case CSSPropertyMarkerMid:
91     case CSSPropertyMarkerEnd:
92     case CSSPropertyMask:
93         if (id == CSSValueNone)
94             valid_primitive = true;
95         else if (value->unit == CSSPrimitiveValue::CSS_URI) {
96             parsedValue = CSSPrimitiveValue::create(value->string, CSSPrimitiveValue::CSS_URI);
97             if (parsedValue)
98                 m_valueList->next();
99         }
100         break;
101 
102     case CSSPropertyClipRule:            // nonzero | evenodd | inherit
103     case CSSPropertyFillRule:
104         if (id == CSSValueNonzero || id == CSSValueEvenodd)
105             valid_primitive = true;
106         break;
107 
108     case CSSPropertyStrokeMiterlimit:   // <miterlimit> | inherit
109         valid_primitive = validUnit(value, FNumber|FNonNeg, false);
110         break;
111 
112     case CSSPropertyStrokeLinejoin:   // miter | round | bevel | inherit
113         if (id == CSSValueMiter || id == CSSValueRound || id == CSSValueBevel)
114             valid_primitive = true;
115         break;
116 
117     case CSSPropertyStrokeLinecap:    // butt | round | square | inherit
118         if (id == CSSValueButt || id == CSSValueRound || id == CSSValueSquare)
119             valid_primitive = true;
120         break;
121 
122     case CSSPropertyStrokeOpacity:   // <opacity-value> | inherit
123     case CSSPropertyFillOpacity:
124     case CSSPropertyStopOpacity:
125     case CSSPropertyFloodOpacity:
126         valid_primitive = (!id && validUnit(value, FNumber|FPercent, false));
127         break;
128 
129     case CSSPropertyShapeRendering:
130     // auto | optimizeSpeed | crispEdges | geometricPrecision | inherit
131         if (id == CSSValueAuto || id == CSSValueOptimizespeed ||
132             id == CSSValueCrispedges || id == CSSValueGeometricprecision)
133             valid_primitive = true;
134         break;
135 
136     case CSSPropertyImageRendering:  // auto | optimizeSpeed |
137     case CSSPropertyColorRendering:  // optimizeQuality | inherit
138         if (id == CSSValueAuto || id == CSSValueOptimizespeed ||
139             id == CSSValueOptimizequality)
140             valid_primitive = true;
141         break;
142 
143     case CSSPropertyColorProfile: // auto | sRGB | <name> | <uri> inherit
144         if (id == CSSValueAuto || id == CSSValueSrgb)
145             valid_primitive = true;
146         break;
147 
148     case CSSPropertyColorInterpolation:   // auto | sRGB | linearRGB | inherit
149     case CSSPropertyColorInterpolationFilters:
150         if (id == CSSValueAuto || id == CSSValueSrgb || id == CSSValueLinearrgb)
151             valid_primitive = true;
152         break;
153 
154     /* Start of supported CSS properties with validation. This is needed for parseShortHand to work
155      * correctly and allows optimization in applyRule(..)
156      */
157 
158     case CSSPropertyTextAnchor:    // start | middle | end | inherit
159         if (id == CSSValueStart || id == CSSValueMiddle || id == CSSValueEnd)
160             valid_primitive = true;
161         break;
162 
163     case CSSPropertyGlyphOrientationVertical: // auto | <angle> | inherit
164         if (id == CSSValueAuto) {
165             valid_primitive = true;
166             break;
167         }
168     /* fallthrough intentional */
169     case CSSPropertyGlyphOrientationHorizontal: // <angle> (restricted to _deg_ per SVG 1.1 spec) | inherit
170         if (value->unit == CSSPrimitiveValue::CSS_DEG || value->unit == CSSPrimitiveValue::CSS_NUMBER) {
171             parsedValue = CSSPrimitiveValue::create(value->fValue, CSSPrimitiveValue::CSS_DEG);
172 
173             if (parsedValue)
174                 m_valueList->next();
175         }
176         break;
177 
178     case CSSPropertyFill:                 // <paint> | inherit
179     case CSSPropertyStroke:               // <paint> | inherit
180         {
181             if (id == CSSValueNone)
182                 parsedValue = SVGPaint::createNone();
183             else if (id == CSSValueCurrentcolor)
184                 parsedValue = SVGPaint::createCurrentColor();
185             else if ((id >= CSSValueActiveborder && id <= CSSValueWindowtext) || id == CSSValueMenu)
186                 parsedValue = SVGPaint::createColor(RenderTheme::defaultTheme()->systemColor(id));
187             else if (value->unit == CSSPrimitiveValue::CSS_URI) {
188                 RGBA32 c = Color::transparent;
189                 if (m_valueList->next() && parseColorFromValue(m_valueList->current(), c)) {
190                     parsedValue = SVGPaint::createURIAndColor(value->string, c);
191                 } else
192                     parsedValue = SVGPaint::createURI(value->string);
193             } else
194                 parsedValue = parseSVGPaint();
195 
196             if (parsedValue)
197                 m_valueList->next();
198         }
199         break;
200 
201     case CSSPropertyColor:                // <color> | inherit
202         if ((id >= CSSValueAqua && id <= CSSValueWindowtext) ||
203            (id >= CSSValueAliceblue && id <= CSSValueYellowgreen))
204             parsedValue = SVGColor::createFromString(value->string);
205         else
206             parsedValue = parseSVGColor();
207 
208         if (parsedValue)
209             m_valueList->next();
210         break;
211 
212     case CSSPropertyStopColor: // TODO : icccolor
213     case CSSPropertyFloodColor:
214     case CSSPropertyLightingColor:
215         if ((id >= CSSValueAqua && id <= CSSValueWindowtext) ||
216            (id >= CSSValueAliceblue && id <= CSSValueYellowgreen))
217             parsedValue = SVGColor::createFromString(value->string);
218         else if (id == CSSValueCurrentcolor)
219             parsedValue = SVGColor::createCurrentColor();
220         else // TODO : svgcolor (iccColor)
221             parsedValue = parseSVGColor();
222 
223         if (parsedValue)
224             m_valueList->next();
225 
226         break;
227 
228     case CSSPropertyVectorEffect: // none | non-scaling-stroke | inherit
229         if (id == CSSValueNone || id == CSSValueNonScalingStroke)
230             valid_primitive = true;
231         break;
232 
233     case CSSPropertyWritingMode:
234     // lr-tb | rl_tb | tb-rl | lr | rl | tb | inherit
235         if (id == CSSValueLrTb || id == CSSValueRlTb || id == CSSValueTbRl || id == CSSValueLr || id == CSSValueRl || id == CSSValueTb)
236             valid_primitive = true;
237         break;
238 
239     case CSSPropertyStrokeWidth:         // <length> | inherit
240     case CSSPropertyStrokeDashoffset:
241         valid_primitive = validUnit(value, FLength | FPercent, false);
242         break;
243     case CSSPropertyStrokeDasharray:     // none | <dasharray> | inherit
244         if (id == CSSValueNone)
245             valid_primitive = true;
246         else
247             parsedValue = parseSVGStrokeDasharray();
248 
249         break;
250 
251     case CSSPropertyKerning:              // auto | normal | <length> | inherit
252         if (id == CSSValueAuto || id == CSSValueNormal)
253             valid_primitive = true;
254         else
255             valid_primitive = validUnit(value, FLength, false);
256         break;
257 
258     case CSSPropertyClipPath:    // <uri> | none | inherit
259     case CSSPropertyFilter:
260         if (id == CSSValueNone)
261             valid_primitive = true;
262         else if (value->unit == CSSPrimitiveValue::CSS_URI) {
263             parsedValue = CSSPrimitiveValue::create(value->string, (CSSPrimitiveValue::UnitTypes) value->unit);
264             if (parsedValue)
265                 m_valueList->next();
266         }
267         break;
268     case CSSPropertyWebkitSvgShadow:
269         if (id == CSSValueNone)
270             valid_primitive = true;
271         else
272             return parseShadow(propId, important);
273 
274     /* shorthand properties */
275     case CSSPropertyMarker:
276     {
277         ShorthandScope scope(this, propId);
278         m_implicitShorthand = true;
279         if (!parseValue(CSSPropertyMarkerStart, important))
280             return false;
281         if (m_valueList->current()) {
282             rollbackLastProperties(1);
283             return false;
284         }
285         CSSValue* value = m_parsedProperties[m_numParsedProperties - 1]->value();
286         addProperty(CSSPropertyMarkerMid, value, important);
287         addProperty(CSSPropertyMarkerEnd, value, important);
288         m_implicitShorthand = false;
289         return true;
290     }
291     default:
292         // If you crash here, it's because you added a css property and are not handling it
293         // in either this switch statement or the one in CSSParser::parseValue
294         ASSERT_WITH_MESSAGE(0, "unimplemented propertyID: %d", propId);
295         return false;
296     }
297 
298     if (valid_primitive) {
299         if (id != 0)
300             parsedValue = CSSPrimitiveValue::createIdentifier(id);
301         else if (value->unit == CSSPrimitiveValue::CSS_STRING)
302             parsedValue = CSSPrimitiveValue::create(value->string, (CSSPrimitiveValue::UnitTypes) value->unit);
303         else if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
304             parsedValue = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit);
305         else if (value->unit >= CSSParserValue::Q_EMS)
306             parsedValue = CSSQuirkPrimitiveValue::create(value->fValue, CSSPrimitiveValue::CSS_EMS);
307         m_valueList->next();
308     }
309     if (!parsedValue || (m_valueList->current() && !inShorthand()))
310         return false;
311 
312     addProperty(propId, parsedValue.release(), important);
313     return true;
314 }
315 
parseSVGStrokeDasharray()316 PassRefPtr<CSSValue> CSSParser::parseSVGStrokeDasharray()
317 {
318     RefPtr<CSSValueList> ret = CSSValueList::createCommaSeparated();
319     CSSParserValue* value = m_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(CSSPrimitiveValue::createIdentifier(value->id));
327         else if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
328             ret->append(CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit));
329         value = m_valueList->next();
330         if (value && value->unit == CSSParserValue::Operator && value->iValue == ',')
331             value = m_valueList->next();
332     }
333     if (!valid_primitive)
334         return 0;
335     return ret.release();
336 }
337 
parseSVGPaint()338 PassRefPtr<CSSValue> CSSParser::parseSVGPaint()
339 {
340     RGBA32 c = Color::transparent;
341     if (!parseColorFromValue(m_valueList->current(), c))
342         return SVGPaint::createUnknown();
343     return SVGPaint::createColor(Color(c));
344 }
345 
parseSVGColor()346 PassRefPtr<CSSValue> CSSParser::parseSVGColor()
347 {
348     RGBA32 c = Color::transparent;
349     if (!parseColorFromValue(m_valueList->current(), c))
350         return 0;
351     return SVGColor::createFromColor(Color(c));
352 }
353 
354 }
355 
356 #endif // ENABLE(SVG)
357