- add third_party src.
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / css / SVGCSSParser.cpp
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 #include "CSSPropertyNames.h"
26 #include "CSSValueKeywords.h"
27 #include "RuntimeEnabledFeatures.h"
28 #include "core/css/CSSParser.h"
29 #include "core/css/CSSValueList.h"
30 #include "core/rendering/RenderTheme.h"
31 #include "core/svg/SVGPaint.h"
32
33 using namespace std;
34
35 namespace WebCore {
36
37 static bool isSystemColor(int id)
38 {
39     return (id >= CSSValueActiveborder && id <= CSSValueWindowtext) || id == CSSValueMenu;
40 }
41
42 bool CSSParser::parseSVGValue(CSSPropertyID propId, bool important)
43 {
44     CSSParserValue* value = m_valueList->current();
45     if (!value)
46         return false;
47
48     CSSValueID id = value->id;
49
50     bool valid_primitive = false;
51     RefPtr<CSSValue> parsedValue;
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 CSSPropertyAlignmentBaseline:
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 == CSSValueAuto || id == CSSValueBaseline || id == CSSValueMiddle ||
61           (id >= CSSValueBeforeEdge && id <= CSSValueMathematical))
62             valid_primitive = true;
63         break;
64
65     case CSSPropertyBaselineShift:
66     // baseline | super | sub | <percentage> | <length> | inherit
67         if (id == CSSValueBaseline || id == CSSValueSub ||
68            id >= CSSValueSuper)
69             valid_primitive = true;
70         else
71             valid_primitive = validUnit(value, FLength | FPercent, SVGAttributeMode);
72         break;
73
74     case CSSPropertyDominantBaseline:
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 == CSSValueAuto || id == CSSValueMiddle ||
79           (id >= CSSValueUseScript && id <= CSSValueResetSize) ||
80           (id >= CSSValueCentral && id <= CSSValueMathematical))
81             valid_primitive = true;
82         break;
83
84     case CSSPropertyEnableBackground:
85     // accumulate | new [x] [y] [width] [height] | inherit
86         if (id == CSSValueAccumulate) // TODO : new
87             valid_primitive = true;
88         break;
89
90     case CSSPropertyMarkerStart:
91     case CSSPropertyMarkerMid:
92     case CSSPropertyMarkerEnd:
93     case CSSPropertyMask:
94         if (id == CSSValueNone)
95             valid_primitive = true;
96         else if (value->unit == CSSPrimitiveValue::CSS_URI) {
97             parsedValue = CSSPrimitiveValue::create(value->string, CSSPrimitiveValue::CSS_URI);
98             if (parsedValue)
99                 m_valueList->next();
100         }
101         break;
102
103     case CSSPropertyClipRule:            // nonzero | evenodd | inherit
104     case CSSPropertyFillRule:
105         if (id == CSSValueNonzero || id == CSSValueEvenodd)
106             valid_primitive = true;
107         break;
108
109     case CSSPropertyStrokeMiterlimit:   // <miterlimit> | inherit
110         valid_primitive = validUnit(value, FNumber | FNonNeg, SVGAttributeMode);
111         break;
112
113     case CSSPropertyStrokeLinejoin:   // miter | round | bevel | inherit
114         if (id == CSSValueMiter || id == CSSValueRound || id == CSSValueBevel)
115             valid_primitive = true;
116         break;
117
118     case CSSPropertyStrokeLinecap:    // butt | round | square | inherit
119         if (id == CSSValueButt || id == CSSValueRound || id == CSSValueSquare)
120             valid_primitive = true;
121         break;
122
123     case CSSPropertyStrokeOpacity:   // <opacity-value> | inherit
124     case CSSPropertyFillOpacity:
125     case CSSPropertyStopOpacity:
126     case CSSPropertyFloodOpacity:
127         valid_primitive = (!id && validUnit(value, FNumber | FPercent, SVGAttributeMode));
128         break;
129
130     case CSSPropertyShapeRendering:
131     // auto | optimizeSpeed | crispEdges | geometricPrecision | inherit
132         if (id == CSSValueAuto || id == CSSValueOptimizespeed ||
133             id == CSSValueCrispedges || id == CSSValueGeometricprecision)
134             valid_primitive = true;
135         break;
136
137     case CSSPropertyImageRendering:  // auto | optimizeSpeed |
138     case CSSPropertyColorRendering:  // optimizeQuality | inherit
139         if (id == CSSValueAuto || id == CSSValueOptimizespeed ||
140             id == CSSValueOptimizequality)
141             valid_primitive = true;
142         break;
143
144     case CSSPropertyBufferedRendering: // auto | dynamic | static
145         if (id == CSSValueAuto || id == CSSValueDynamic || id == CSSValueStatic)
146             valid_primitive = true;
147         break;
148
149     case CSSPropertyColorProfile: // auto | sRGB | <name> | <uri> inherit
150         if (id == CSSValueAuto || id == CSSValueSrgb)
151             valid_primitive = true;
152         break;
153
154     case CSSPropertyColorInterpolation:   // auto | sRGB | linearRGB | inherit
155     case CSSPropertyColorInterpolationFilters:
156         if (id == CSSValueAuto || id == CSSValueSrgb || id == CSSValueLinearrgb)
157             valid_primitive = true;
158         break;
159
160     /* Start of supported CSS properties with validation. This is needed for parseShortHand to work
161      * correctly and allows optimization in applyRule(..)
162      */
163
164     case CSSPropertyTextAnchor:    // start | middle | end | inherit
165         if (id == CSSValueStart || id == CSSValueMiddle || id == CSSValueEnd)
166             valid_primitive = true;
167         break;
168
169     case CSSPropertyGlyphOrientationVertical: // auto | <angle> | inherit
170         if (id == CSSValueAuto) {
171             valid_primitive = true;
172             break;
173         }
174     /* fallthrough intentional */
175     case CSSPropertyGlyphOrientationHorizontal: // <angle> (restricted to _deg_ per SVG 1.1 spec) | inherit
176         if (value->unit == CSSPrimitiveValue::CSS_DEG || value->unit == CSSPrimitiveValue::CSS_NUMBER) {
177             parsedValue = CSSPrimitiveValue::create(value->fValue, CSSPrimitiveValue::CSS_DEG);
178
179             if (parsedValue)
180                 m_valueList->next();
181         }
182         break;
183
184     case CSSPropertyFill:                 // <paint> | inherit
185     case CSSPropertyStroke:               // <paint> | inherit
186         {
187             if (id == CSSValueNone)
188                 parsedValue = SVGPaint::createNone();
189             else if (id == CSSValueCurrentcolor)
190                 parsedValue = SVGPaint::createCurrentColor();
191             else if (isSystemColor(id))
192                 parsedValue = SVGPaint::createColor(RenderTheme::theme().systemColor(id));
193             else if (value->unit == CSSPrimitiveValue::CSS_URI) {
194                 RGBA32 c = Color::transparent;
195                 if (m_valueList->next()) {
196                     if (parseColorFromValue(m_valueList->current(), c))
197                         parsedValue = SVGPaint::createURIAndColor(value->string, c);
198                     else if (m_valueList->current()->id == CSSValueNone)
199                         parsedValue = SVGPaint::createURIAndNone(value->string);
200                 }
201                 if (!parsedValue)
202                     parsedValue = SVGPaint::createURI(value->string);
203             } else
204                 parsedValue = parseSVGPaint();
205
206             if (parsedValue)
207                 m_valueList->next();
208         }
209         break;
210
211     case CSSPropertyStopColor: // TODO : icccolor
212     case CSSPropertyFloodColor:
213     case CSSPropertyLightingColor:
214         if (isSystemColor(id))
215             parsedValue = SVGColor::createFromColor(RenderTheme::theme().systemColor(id));
216         else if ((id >= CSSValueAqua && id <= CSSValueTransparent) ||
217                 (id >= CSSValueAliceblue && id <= CSSValueYellowgreen) || id == CSSValueGrey)
218             parsedValue = SVGColor::createFromString(value->string);
219         else if (id == CSSValueCurrentcolor)
220             parsedValue = SVGColor::createCurrentColor();
221         else // TODO : svgcolor (iccColor)
222             parsedValue = parseSVGColor();
223
224         if (parsedValue)
225             m_valueList->next();
226
227         break;
228
229     case CSSPropertyPaintOrder:
230         if (!RuntimeEnabledFeatures::svgPaintOrderEnabled())
231             return false;
232
233         if (m_valueList->size() == 1 && id == CSSValueNormal)
234             valid_primitive = true;
235         else if ((parsedValue = parsePaintOrder()))
236             m_valueList->next();
237         break;
238
239     case CSSPropertyVectorEffect: // none | non-scaling-stroke | inherit
240         if (id == CSSValueNone || id == CSSValueNonScalingStroke)
241             valid_primitive = true;
242         break;
243
244     case CSSPropertyWritingMode:
245     // lr-tb | rl_tb | tb-rl | lr | rl | tb | inherit
246         if (id == CSSValueLrTb || id == CSSValueRlTb || id == CSSValueTbRl || id == CSSValueLr || id == CSSValueRl || id == CSSValueTb)
247             valid_primitive = true;
248         break;
249
250     case CSSPropertyStrokeWidth:         // <length> | inherit
251     case CSSPropertyStrokeDashoffset:
252         valid_primitive = validUnit(value, FLength | FPercent, SVGAttributeMode);
253         break;
254     case CSSPropertyStrokeDasharray:     // none | <dasharray> | inherit
255         if (id == CSSValueNone)
256             valid_primitive = true;
257         else
258             parsedValue = parseSVGStrokeDasharray();
259
260         break;
261
262     case CSSPropertyKerning:              // auto | normal | <length> | inherit
263         if (id == CSSValueAuto || id == CSSValueNormal)
264             valid_primitive = true;
265         else
266             valid_primitive = validUnit(value, FLength, SVGAttributeMode);
267         break;
268
269     case CSSPropertyClipPath:    // <uri> | none | inherit
270     case CSSPropertyFilter:
271         if (id == CSSValueNone)
272             valid_primitive = true;
273         else if (value->unit == CSSPrimitiveValue::CSS_URI) {
274             parsedValue = CSSPrimitiveValue::create(value->string, (CSSPrimitiveValue::UnitTypes) value->unit);
275             if (parsedValue)
276                 m_valueList->next();
277         }
278         break;
279     case CSSPropertyMaskType: // luminance | alpha | inherit
280         if (id == CSSValueLuminance || id == CSSValueAlpha)
281             valid_primitive = true;
282         break;
283
284     /* shorthand properties */
285     case CSSPropertyMarker:
286     {
287         ShorthandScope scope(this, propId);
288         CSSParser::ImplicitScope implicitScope(this, PropertyImplicit);
289         if (!parseValue(CSSPropertyMarkerStart, important))
290             return false;
291         if (m_valueList->current()) {
292             rollbackLastProperties(1);
293             return false;
294         }
295         CSSValue* value = m_parsedProperties.last().value();
296         addProperty(CSSPropertyMarkerMid, value, important);
297         addProperty(CSSPropertyMarkerEnd, value, important);
298         return true;
299     }
300     default:
301         // If you crash here, it's because you added a css property and are not handling it
302         // in either this switch statement or the one in CSSParser::parseValue
303         ASSERT_WITH_MESSAGE(0, "unimplemented propertyID: %d", propId);
304         return false;
305     }
306
307     if (valid_primitive) {
308         if (id != 0)
309             parsedValue = CSSPrimitiveValue::createIdentifier(id);
310         else if (value->unit == CSSPrimitiveValue::CSS_STRING)
311             parsedValue = CSSPrimitiveValue::create(value->string, (CSSPrimitiveValue::UnitTypes) value->unit);
312         else if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
313             parsedValue = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit);
314         else if (value->unit >= CSSParserValue::Q_EMS)
315             parsedValue = CSSPrimitiveValue::createAllowingMarginQuirk(value->fValue, CSSPrimitiveValue::CSS_EMS);
316         if (isCalculation(value)) {
317             // FIXME calc() http://webkit.org/b/16662 : actually create a CSSPrimitiveValue here, ie
318             // parsedValue = CSSPrimitiveValue::create(m_parsedCalculation.release());
319             m_parsedCalculation.release();
320             parsedValue = 0;
321         }
322         m_valueList->next();
323     }
324     if (!parsedValue || (m_valueList->current() && !inShorthand()))
325         return false;
326
327     addProperty(propId, parsedValue.release(), important);
328     return true;
329 }
330
331 PassRefPtr<CSSValue> CSSParser::parseSVGStrokeDasharray()
332 {
333     RefPtr<CSSValueList> ret = CSSValueList::createCommaSeparated();
334     CSSParserValue* value = m_valueList->current();
335     bool valid_primitive = true;
336     while (value) {
337         valid_primitive = validUnit(value, FLength | FPercent | FNonNeg, SVGAttributeMode);
338         if (!valid_primitive)
339             break;
340         if (value->id != 0)
341             ret->append(CSSPrimitiveValue::createIdentifier(value->id));
342         else if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
343             ret->append(CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit));
344         value = m_valueList->next();
345         if (value && value->unit == CSSParserValue::Operator && value->iValue == ',')
346             value = m_valueList->next();
347     }
348     if (!valid_primitive)
349         return 0;
350     return ret.release();
351 }
352
353 PassRefPtr<CSSValue> CSSParser::parseSVGPaint()
354 {
355     RGBA32 c = Color::transparent;
356     if (!parseColorFromValue(m_valueList->current(), c))
357         return SVGPaint::createUnknown();
358     return SVGPaint::createColor(Color(c));
359 }
360
361 PassRefPtr<CSSValue> CSSParser::parseSVGColor()
362 {
363     RGBA32 c = Color::transparent;
364     if (!parseColorFromValue(m_valueList->current(), c))
365         return 0;
366     return SVGColor::createFromColor(Color(c));
367 }
368
369 // normal | [ fill || stroke || markers ]
370 PassRefPtr<CSSValue> CSSParser::parsePaintOrder() const
371 {
372     if (m_valueList->size() > 3)
373         return 0;
374
375     CSSParserValue* value = m_valueList->current();
376     if (!value)
377         return 0;
378
379     RefPtr<CSSValueList> parsedValues = CSSValueList::createSpaceSeparated();
380
381     // The default paint-order is: Fill, Stroke, Markers.
382     bool seenFill = false,
383          seenStroke = false,
384          seenMarkers = false;
385
386     do {
387         switch (value->id) {
388         case CSSValueNormal:
389             // normal inside [fill || stroke || markers] not valid
390             return 0;
391         case CSSValueFill:
392             if (seenFill)
393                 return 0;
394
395             seenFill = true;
396             break;
397         case CSSValueStroke:
398             if (seenStroke)
399                 return 0;
400
401             seenStroke = true;
402             break;
403         case CSSValueMarkers:
404             if (seenMarkers)
405                 return 0;
406
407             seenMarkers = true;
408             break;
409         default:
410             return 0;
411         }
412
413         parsedValues->append(CSSPrimitiveValue::createIdentifier(value->id));
414     } while ((value = m_valueList->next()));
415
416     // fill out the rest of the paint order
417     if (!seenFill)
418         parsedValues->append(CSSPrimitiveValue::createIdentifier(CSSValueFill));
419     if (!seenStroke)
420         parsedValues->append(CSSPrimitiveValue::createIdentifier(CSSValueStroke));
421     if (!seenMarkers)
422         parsedValues->append(CSSPrimitiveValue::createIdentifier(CSSValueMarkers));
423
424     return parsedValues.release();
425 }
426
427 }