Upstream version 5.34.104.0
[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/parser/BisonCSSParser.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 BisonCSSParser::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                     else if (m_valueList->current()->id == CSSValueCurrentcolor)
201                         parsedValue = SVGPaint::createURIAndCurrentColor(value->string);
202                 }
203                 if (!parsedValue)
204                     parsedValue = SVGPaint::createURI(value->string);
205             } else
206                 parsedValue = parseSVGPaint();
207
208             if (parsedValue)
209                 m_valueList->next();
210         }
211         break;
212
213     case CSSPropertyStopColor: // TODO : icccolor
214     case CSSPropertyFloodColor:
215     case CSSPropertyLightingColor:
216         if (isSystemColor(id))
217             parsedValue = SVGColor::createFromColor(RenderTheme::theme().systemColor(id));
218         else if ((id >= CSSValueAqua && id <= CSSValueTransparent) ||
219                 (id >= CSSValueAliceblue && id <= CSSValueYellowgreen) || id == CSSValueGrey)
220             parsedValue = SVGColor::createFromString(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 CSSPropertyPaintOrder:
232         if (!RuntimeEnabledFeatures::svgPaintOrderEnabled())
233             return false;
234
235         if (m_valueList->size() == 1 && id == CSSValueNormal)
236             valid_primitive = true;
237         else if ((parsedValue = parsePaintOrder()))
238             m_valueList->next();
239         break;
240
241     case CSSPropertyVectorEffect: // none | non-scaling-stroke | inherit
242         if (id == CSSValueNone || id == CSSValueNonScalingStroke)
243             valid_primitive = true;
244         break;
245
246     case CSSPropertyWritingMode:
247     // lr-tb | rl_tb | tb-rl | lr | rl | tb | inherit
248         if (id == CSSValueLrTb || id == CSSValueRlTb || id == CSSValueTbRl || id == CSSValueLr || id == CSSValueRl || id == CSSValueTb)
249             valid_primitive = true;
250         break;
251
252     case CSSPropertyStrokeWidth:         // <length> | inherit
253     case CSSPropertyStrokeDashoffset:
254         valid_primitive = validUnit(value, FLength | FPercent, SVGAttributeMode);
255         break;
256     case CSSPropertyStrokeDasharray:     // none | <dasharray> | inherit
257         if (id == CSSValueNone)
258             valid_primitive = true;
259         else
260             parsedValue = parseSVGStrokeDasharray();
261
262         break;
263
264     case CSSPropertyKerning:              // auto | normal | <length> | inherit
265         if (id == CSSValueAuto || id == CSSValueNormal)
266             valid_primitive = true;
267         else
268             valid_primitive = validUnit(value, FLength, SVGAttributeMode);
269         break;
270
271     case CSSPropertyClipPath:    // <uri> | none | inherit
272     case CSSPropertyFilter:
273         if (id == CSSValueNone)
274             valid_primitive = true;
275         else if (value->unit == CSSPrimitiveValue::CSS_URI) {
276             parsedValue = CSSPrimitiveValue::create(value->string, (CSSPrimitiveValue::UnitTypes) value->unit);
277             if (parsedValue)
278                 m_valueList->next();
279         }
280         break;
281     case CSSPropertyMaskType: // luminance | alpha | inherit
282         if (id == CSSValueLuminance || id == CSSValueAlpha)
283             valid_primitive = true;
284         break;
285
286     /* shorthand properties */
287     case CSSPropertyMarker:
288     {
289         ShorthandScope scope(this, propId);
290         BisonCSSParser::ImplicitScope implicitScope(this, PropertyImplicit);
291         if (!parseValue(CSSPropertyMarkerStart, important))
292             return false;
293         if (m_valueList->current()) {
294             rollbackLastProperties(1);
295             return false;
296         }
297         CSSValue* value = m_parsedProperties.last().value();
298         addProperty(CSSPropertyMarkerMid, value, important);
299         addProperty(CSSPropertyMarkerEnd, value, important);
300         return true;
301     }
302     default:
303         // If you crash here, it's because you added a css property and are not handling it
304         // in either this switch statement or the one in BisonCSSParser::parseValue
305         ASSERT_WITH_MESSAGE(0, "unimplemented propertyID: %d", propId);
306         return false;
307     }
308
309     if (valid_primitive) {
310         if (id != 0)
311             parsedValue = CSSPrimitiveValue::createIdentifier(id);
312         else if (value->unit == CSSPrimitiveValue::CSS_STRING)
313             parsedValue = CSSPrimitiveValue::create(value->string, (CSSPrimitiveValue::UnitTypes) value->unit);
314         else if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
315             parsedValue = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit);
316         else if (value->unit >= CSSParserValue::Q_EMS)
317             parsedValue = CSSPrimitiveValue::createAllowingMarginQuirk(value->fValue, CSSPrimitiveValue::CSS_EMS);
318         if (isCalculation(value)) {
319             // FIXME calc() http://webkit.org/b/16662 : actually create a CSSPrimitiveValue here, ie
320             // parsedValue = CSSPrimitiveValue::create(m_parsedCalculation.release());
321             m_parsedCalculation.release();
322             parsedValue = 0;
323         }
324         m_valueList->next();
325     }
326     if (!parsedValue || (m_valueList->current() && !inShorthand()))
327         return false;
328
329     addProperty(propId, parsedValue.release(), important);
330     return true;
331 }
332
333 PassRefPtr<CSSValue> BisonCSSParser::parseSVGStrokeDasharray()
334 {
335     RefPtrWillBeRawPtr<CSSValueList> ret = CSSValueList::createCommaSeparated();
336     CSSParserValue* value = m_valueList->current();
337     bool valid_primitive = true;
338     while (value) {
339         valid_primitive = validUnit(value, FLength | FPercent | FNonNeg, SVGAttributeMode);
340         if (!valid_primitive)
341             break;
342         if (value->id != 0)
343             ret->append(CSSPrimitiveValue::createIdentifier(value->id));
344         else if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
345             ret->append(CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit));
346         value = m_valueList->next();
347         if (value && value->unit == CSSParserValue::Operator && value->iValue == ',')
348             value = m_valueList->next();
349     }
350     if (!valid_primitive)
351         return 0;
352     return ret.release();
353 }
354
355 PassRefPtr<CSSValue> BisonCSSParser::parseSVGPaint()
356 {
357     RGBA32 c = Color::transparent;
358     if (!parseColorFromValue(m_valueList->current(), c))
359         return SVGPaint::createUnknown();
360     return SVGPaint::createColor(Color(c));
361 }
362
363 PassRefPtr<CSSValue> BisonCSSParser::parseSVGColor()
364 {
365     RGBA32 c = Color::transparent;
366     if (!parseColorFromValue(m_valueList->current(), c))
367         return 0;
368     return SVGColor::createFromColor(Color(c));
369 }
370
371 // normal | [ fill || stroke || markers ]
372 PassRefPtr<CSSValue> BisonCSSParser::parsePaintOrder() const
373 {
374     if (m_valueList->size() > 3)
375         return 0;
376
377     CSSParserValue* value = m_valueList->current();
378     if (!value)
379         return 0;
380
381     RefPtrWillBeRawPtr<CSSValueList> parsedValues = CSSValueList::createSpaceSeparated();
382
383     // The default paint-order is: Fill, Stroke, Markers.
384     bool seenFill = false,
385          seenStroke = false,
386          seenMarkers = false;
387
388     do {
389         switch (value->id) {
390         case CSSValueNormal:
391             // normal inside [fill || stroke || markers] not valid
392             return 0;
393         case CSSValueFill:
394             if (seenFill)
395                 return 0;
396
397             seenFill = true;
398             break;
399         case CSSValueStroke:
400             if (seenStroke)
401                 return 0;
402
403             seenStroke = true;
404             break;
405         case CSSValueMarkers:
406             if (seenMarkers)
407                 return 0;
408
409             seenMarkers = true;
410             break;
411         default:
412             return 0;
413         }
414
415         parsedValues->append(CSSPrimitiveValue::createIdentifier(value->id));
416     } while ((value = m_valueList->next()));
417
418     // fill out the rest of the paint order
419     if (!seenFill)
420         parsedValues->append(CSSPrimitiveValue::createIdentifier(CSSValueFill));
421     if (!seenStroke)
422         parsedValues->append(CSSPrimitiveValue::createIdentifier(CSSValueStroke));
423     if (!seenMarkers)
424         parsedValues->append(CSSPrimitiveValue::createIdentifier(CSSValueMarkers));
425
426     return parsedValues.release();
427 }
428
429 }