1 /*
2     Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org>
3                   2004, 2005, 2007 Rob Buis <buis@kde.org>
4     Copyright (C) 2005, 2006 Apple Computer, Inc.
5 
6     This file is part of the KDE project
7 
8     This library is free software; you can redistribute it and/or
9     modify it under the terms of the GNU Library General Public
10     License as published by the Free Software Foundation; either
11     version 2 of the License, or (at your option) any later version.
12 
13     This library is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16     Library General Public License for more details.
17 
18     You should have received a copy of the GNU Library General Public License
19     along with this library; see the file COPYING.LIB.  If not, write to
20     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21     Boston, MA 02110-1301, USA.
22 */
23 
24 #include "cssparser.h"
25 #include "cssproperties.h"
26 #include "cssvalues.h"
27 
28 #include "css/css_valueimpl.h"
29 #include "css/css_svgvalueimpl.h"
30 
31 using namespace std;
32 
33 namespace DOM
34 {
35 
parseSVGValue(int propId,bool important)36 bool CSSParser::parseSVGValue(int propId, bool important)
37 {
38     Value *value = valueList->current();
39     if (!value) {
40         return false;
41     }
42 
43     int id = value->id;
44 
45     bool valid_primitive = false;
46     CSSValueImpl *parsedValue = nullptr;
47 
48     switch (propId) {
49     /* The comment to the right defines all valid value of these
50      * properties as defined in SVG 1.1, Appendix N. Property index */
51     case CSS_PROP_ALIGNMENT_BASELINE:
52         // auto | baseline | before-edge | text-before-edge | middle |
53         // central | after-edge | text-after-edge | ideographic | alphabetic |
54         // hanging | mathematical | inherit
55         if (id == CSS_VAL_AUTO || id == CSS_VAL_BASELINE || id == CSS_VAL_MIDDLE ||
56                 (id >= CSS_VAL_BEFORE_EDGE && id <= CSS_VAL_MATHEMATICAL)) {
57             valid_primitive = true;
58         }
59         break;
60 
61     case CSS_PROP_BASELINE_SHIFT:
62         // baseline | super | sub | <percentage> | <length> | inherit
63         if (id == CSS_VAL_BASELINE || id == CSS_VAL_SUB || id >= CSS_VAL_SUPER) {
64             valid_primitive = true;
65         } else {
66             valid_primitive = validUnit(value, FLength | FPercent, false);
67         }
68         break;
69 
70     case CSS_PROP_DOMINANT_BASELINE:
71         // auto | use-script | no-change | reset-size | ideographic |
72         // alphabetic | hanging | mathematical | central | middle |
73         // text-after-edge | text-before-edge | inherit
74         if (id == CSS_VAL_AUTO || id == CSS_VAL_MIDDLE ||
75                 (id >= CSS_VAL_USE_SCRIPT && id <= CSS_VAL_RESET_SIZE) ||
76                 (id >= CSS_VAL_CENTRAL && id <= CSS_VAL_MATHEMATICAL)) {
77             valid_primitive = true;
78         }
79         break;
80 
81     case CSS_PROP_ENABLE_BACKGROUND:
82         // accumulate | new [x] [y] [width] [height] | inherit
83         if (id == CSS_VAL_ACCUMULATE) { // ### TODO: new
84             valid_primitive = true;
85         }
86         break;
87 
88     case CSS_PROP_MARKER_START:
89     case CSS_PROP_MARKER_MID:
90     case CSS_PROP_MARKER_END:
91     case CSS_PROP_MASK:
92         if (id == CSS_VAL_NONE) {
93             valid_primitive = true;
94         } else if (value->unit == CSSPrimitiveValue::CSS_URI) {
95             parsedValue = new CSSPrimitiveValueImpl(domString(value->string), CSSPrimitiveValue::CSS_URI);
96             if (parsedValue) {
97                 valueList->next();
98             }
99         }
100         break;
101 
102     case CSS_PROP_CLIP_RULE:            // nonzero | evenodd | inherit
103     case CSS_PROP_FILL_RULE:
104         if (id == CSS_VAL_NONZERO || id == CSS_VAL_EVENODD) {
105             valid_primitive = true;
106         }
107         break;
108 
109     case CSS_PROP_STROKE_MITERLIMIT:   // <miterlimit> | inherit
110         valid_primitive = validUnit(value, FNumber | FNonNeg, false);
111         break;
112 
113     case CSS_PROP_STROKE_LINEJOIN:   // miter | round | bevel | inherit
114         if (id == CSS_VAL_MITER || id == CSS_VAL_ROUND || id == CSS_VAL_BEVEL) {
115             valid_primitive = true;
116         }
117         break;
118 
119     case CSS_PROP_STROKE_LINECAP:    // butt | round | square | inherit
120         if (id == CSS_VAL_BUTT || id == CSS_VAL_ROUND || id == CSS_VAL_SQUARE) {
121             valid_primitive = true;
122         }
123         break;
124 
125     case CSS_PROP_STROKE_OPACITY:   // <opacity-value> | inherit
126     case CSS_PROP_FILL_OPACITY:
127     case CSS_PROP_STOP_OPACITY:
128     case CSS_PROP_FLOOD_OPACITY:
129         valid_primitive = (!id && validUnit(value, FNumber | FPercent, false));
130         break;
131 
132     case CSS_PROP_SHAPE_RENDERING:
133         // auto | optimizeSpeed | crispEdges | geometricPrecision | inherit
134         if (id == CSS_VAL_AUTO || id == CSS_VAL_OPTIMIZESPEED ||
135                 id == CSS_VAL_CRISPEDGES || id == CSS_VAL_GEOMETRICPRECISION) {
136             valid_primitive = true;
137         }
138         break;
139 
140     case CSS_PROP_TEXT_RENDERING:   // auto | optimizeSpeed | optimizeLegibility | geometricPrecision | inherit
141         if (id == CSS_VAL_AUTO || id == CSS_VAL_OPTIMIZESPEED || id == CSS_VAL_OPTIMIZELEGIBILITY ||
142                 id == CSS_VAL_GEOMETRICPRECISION) {
143             valid_primitive = true;
144         }
145         break;
146 
147     case CSS_PROP_IMAGE_RENDERING:  // auto | optimizeSpeed |
148     case CSS_PROP_COLOR_RENDERING:  // optimizeQuality | inherit
149         if (id == CSS_VAL_AUTO || id == CSS_VAL_OPTIMIZESPEED ||
150                 id == CSS_VAL_OPTIMIZEQUALITY) {
151             valid_primitive = true;
152         }
153         break;
154 
155     case CSS_PROP_COLOR_PROFILE: // auto | sRGB | <name> | <uri> inherit
156         if (id == CSS_VAL_AUTO || id == CSS_VAL_SRGB) {
157             valid_primitive = true;
158         }
159         break;
160 
161     case CSS_PROP_COLOR_INTERPOLATION:   // auto | sRGB | linearRGB | inherit
162     case CSS_PROP_COLOR_INTERPOLATION_FILTERS:
163         if (id == CSS_VAL_AUTO || id == CSS_VAL_SRGB || id == CSS_VAL_LINEARRGB) {
164             valid_primitive = true;
165         }
166         break;
167 
168     case CSS_PROP_POINTER_EVENTS:
169         // visiblePainted | visibleFill | visibleStroke | visible |
170         // painted | fill | stroke | all | none |  inherit
171         if (id == CSS_VAL_VISIBLE || id == CSS_VAL_NONE ||
172                 (id >= CSS_VAL_VISIBLEPAINTED && id <= CSS_VAL_ALL)) {
173             valid_primitive = true;
174         }
175         break;
176 
177     case CSS_PROP_TEXT_ANCHOR:    // start | middle | end | inherit
178         if (id == CSS_VAL_START || id == CSS_VAL_MIDDLE || id == CSS_VAL_END) {
179             valid_primitive = true;
180         }
181         break;
182 
183     case CSS_PROP_GLYPH_ORIENTATION_VERTICAL: // auto | <angle> | inherit
184         if (id == CSS_VAL_AUTO) {
185             valid_primitive = true;
186             break;
187         }
188     /* fallthrough intentional */
189     case CSS_PROP_GLYPH_ORIENTATION_HORIZONTAL: // <angle> (restricted to _deg_ per SVG 1.1 spec) | inherit
190         if (value->unit == CSSPrimitiveValue::CSS_DEG || value->unit == CSSPrimitiveValue::CSS_NUMBER) {
191             parsedValue = new CSSPrimitiveValueImpl(value->fValue, CSSPrimitiveValue::CSS_DEG);
192 
193             if (parsedValue) {
194                 valueList->next();
195             }
196         }
197         break;
198 
199     case CSS_PROP_FILL:                 // <paint> | inherit
200     case CSS_PROP_STROKE: {             // <paint> | inherit
201         if (id == CSS_VAL_NONE) {
202             parsedValue = new SVGPaintImpl(SVGPaintImpl::SVG_PAINTTYPE_NONE);
203         } else if (id == CSS_VAL_CURRENTCOLOR) {
204             parsedValue = new SVGPaintImpl(SVGPaintImpl::SVG_PAINTTYPE_CURRENTCOLOR);
205         } else if (value->unit == CSSPrimitiveValue::CSS_URI) {
206             CSSPrimitiveValueImpl *val;
207             if (valueList->next() && (val = parseColorFromValue(valueList->current()/*, c, true*/))) {
208                 parsedValue = new SVGPaintImpl(domString(value->string), val->getRGBColorValue());
209                 delete val;
210             } else {
211                 parsedValue = new SVGPaintImpl(SVGPaintImpl::SVG_PAINTTYPE_URI, domString(value->string));
212             }
213         } else {
214             parsedValue = parseSVGPaint();
215         }
216 
217         if (parsedValue) {
218             valueList->next();
219         }
220     }
221     break;
222 
223     /*case CSS_PROP_Color:                // <color> | inherit
224         if ((id >= CSS_VAL_Aqua && id <= CSS_VAL_Windowtext) ||
225            (id >= CSS_VAL_Aliceblue && id <= CSS_VAL_Yellowgreen))
226             parsedValue = new SVGColor(value->string);
227         else
228             parsedValue = parseSVGColor();
229 
230         if (parsedValue)
231             valueList->next();
232         break;*/
233 
234     case CSS_PROP_STOP_COLOR: // TODO : icccolor
235     case CSS_PROP_FLOOD_COLOR:
236     case CSS_PROP_LIGHTING_COLOR:
237         if ((id >= CSS_VAL_AQUA && id <= CSS_VAL_WINDOWTEXT)/* ||
238            (id >= CSS_VAL_Aliceblue && id <= CSS_VAL_Yellowgreen)*/) {
239             parsedValue = new SVGColorImpl(domString(value->string));
240         } else if (id == CSS_VAL_CURRENTCOLOR) {
241             parsedValue = new SVGColorImpl(SVGColorImpl::SVG_COLORTYPE_CURRENTCOLOR);
242         } else { // TODO : svgcolor (iccColor)
243             parsedValue = parseSVGColor();
244         }
245 
246         if (parsedValue) {
247             valueList->next();
248         }
249 
250         break;
251 
252     case CSS_PROP_WRITING_MODE:
253         // lr-tb | rl_tb | tb-rl | lr | rl | tb | inherit
254         if (id >= CSS_VAL_LR_TB && id <= CSS_VAL_TB) {
255             valid_primitive = true;
256         }
257         break;
258 
259     case CSS_PROP_STROKE_WIDTH:         // <length> | inherit
260     case CSS_PROP_STROKE_DASHOFFSET:
261         valid_primitive = validUnit(value, FLength | FPercent, false);
262         break;
263 
264     case CSS_PROP_STROKE_DASHARRAY:     // none | <dasharray> | inherit
265         if (id == CSS_VAL_NONE) {
266             valid_primitive = true;
267         } else {
268             parsedValue = parseSVGStrokeDasharray();
269         }
270 
271         break;
272 
273     case CSS_PROP_KERNING:              // auto | normal | <length> | inherit
274         if (id == CSS_VAL_AUTO || id == CSS_VAL_NORMAL) {
275             valid_primitive = true;
276         } else {
277             valid_primitive = validUnit(value, FLength, false);
278         }
279         break;
280 
281     case CSS_PROP_CLIP_PATH:    // <uri> | none | inherit
282     case CSS_PROP_FILTER:
283         if (id == CSS_VAL_NONE) {
284             valid_primitive = true;
285         } else if (value->unit == CSSPrimitiveValue::CSS_URI) {
286             parsedValue = new CSSPrimitiveValueImpl(domString(value->string), (CSSPrimitiveValue::UnitTypes) value->unit);
287             if (parsedValue) {
288                 valueList->next();
289             }
290         }
291         break;
292 
293     /* shorthand properties */
294     case CSS_PROP_MARKER: {
295         const int properties[3] = { CSS_PROP_MARKER_START, CSS_PROP_MARKER_MID,
296                                     CSS_PROP_MARKER_END
297                                   };
298         return parseShortHand(propId, properties, 3, important);
299 
300     }
301     default:
302         // If you crash here, it's because you added a css property and are not handling it
303         // in either this switch statement or the one in CSSParser::parseValue
304         //ASSERT_WITH_MESSAGE(0, "unimplemented propertyID: %d", propId);
305         //return false;
306         break;
307     }
308 
309     if (valid_primitive) {
310         if (id != 0) {
311             parsedValue = new CSSPrimitiveValueImpl(id);
312         } else if (value->unit == CSSPrimitiveValue::CSS_STRING) {
313             parsedValue = new CSSPrimitiveValueImpl(domString(value->string), (CSSPrimitiveValue::UnitTypes)value->unit);
314         } else if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ) {
315             parsedValue = new CSSPrimitiveValueImpl(value->fValue, (CSSPrimitiveValue::UnitTypes)value->unit);
316         } else if (value->unit >= Value::Q_EMS) {
317             parsedValue = new CSSQuirkPrimitiveValueImpl(value->fValue, CSSPrimitiveValue::CSS_EMS);
318         }
319         valueList->next();
320     }
321     if (!parsedValue || (valueList->current() && !inShorthand())) {
322         delete parsedValue;
323         return false;
324     }
325 
326     addProperty(propId, parsedValue, important);
327     return true;
328 }
329 
parseSVGStrokeDasharray()330 CSSValueImpl *CSSParser::parseSVGStrokeDasharray()
331 {
332     CSSValueListImpl *ret = new CSSValueListImpl(CSSValueListImpl::Comma);
333     Value *value = valueList->current();
334     bool valid_primitive = true;
335     while (value) {
336         valid_primitive = validUnit(value, FLength | FPercent | FNonNeg, false);
337         if (!valid_primitive) {
338             break;
339         }
340         if (value->id != 0) {
341             ret->append(new CSSPrimitiveValueImpl(value->id));
342         } else if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ) {
343             ret->append(new CSSPrimitiveValueImpl(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit));
344         }
345         value = valueList->next();
346         if (value && value->unit == Value::Operator && value->iValue == ',') {
347             value = valueList->next();
348         }
349     }
350     if (!valid_primitive) {
351         delete ret;
352         ret = nullptr;
353     }
354 
355     return ret;
356 }
357 
parseSVGPaint()358 CSSValueImpl *CSSParser::parseSVGPaint()
359 {
360     CSSPrimitiveValueImpl *val;
361 
362     if (!(val = parseColorFromValue(valueList->current()/*, c, true*/))) {
363         return new SVGPaintImpl();
364     }
365 
366     SVGPaintImpl *paint = new SVGPaintImpl(QColor(val->getRGBColorValue()));
367     delete val;
368     return paint;
369 }
370 
parseSVGColor()371 CSSValueImpl *CSSParser::parseSVGColor()
372 {
373     CSSPrimitiveValueImpl *val;
374     if (!(val = parseColorFromValue(valueList->current()/*, c, true*/))) {
375         return nullptr;
376     }
377     SVGColorImpl *color = new SVGColorImpl(QColor(val->getRGBColorValue()));
378     delete val;
379     return color;
380 }
381 
382 }
383 
384