2 Copyright (C) 2004, 2005 Nikolas Zimmermann <wildfox@kde.org>
3 2004, 2005 Rob Buis <buis@kde.org>
4 Copyright (C) 2005, 2006 Apple Computer, Inc.
6 This file is part of the KDE project
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.
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.
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., 59 Temple Place - Suite 330,
21 Boston, MA 02111-1307, USA.
28 #include "CSSInheritedValue.h"
29 #include "CSSInitialValue.h"
30 #include "cssparser.h"
31 #include "CSSPropertyNames.h"
32 #include "CSSQuirkPrimitiveValue.h"
33 #include "CSSValueKeywords.h"
34 #include "CSSValueList.h"
35 #include "ksvgcssproperties.c"
36 #include "ksvgcssvalues.c"
42 bool CSSParser::parseSVGValue(int propId, bool important)
47 Value* value = valueList->current();
53 int num = inShorthand() ? 1 : valueList->size();
55 if (id == CSS_VAL_INHERIT) {
58 addProperty(propId, new CSSInheritedValue(), important);
60 } else if (id == CSS_VAL_INITIAL) {
63 addProperty(propId, new CSSInitialValue(), important);
67 bool valid_primitive = false;
68 CSSValue* parsedValue = 0;
72 /* The comment to the right defines all valid value of these
73 * properties as defined in SVG 1.1, Appendix N. Property index */
74 case SVGCSS_PROP_ALIGNMENT_BASELINE:
75 // auto | baseline | before-edge | text-before-edge | middle |
76 // central | after-edge | text-after-edge | ideographic | alphabetic |
77 // hanging | mathematical | inherit
78 if (id == CSS_VAL_AUTO || id == CSS_VAL_BASELINE || id == CSS_VAL_MIDDLE ||
79 (id >= SVGCSS_VAL_BEFORE_EDGE && id <= SVGCSS_VAL_MATHEMATICAL))
80 valid_primitive = true;
83 case SVGCSS_PROP_BASELINE_SHIFT:
84 // baseline | super | sub | <percentage> | <length> | inherit
85 if (id == CSS_VAL_BASELINE || id == CSS_VAL_SUB ||
87 valid_primitive = true;
89 valid_primitive = validUnit(value, FLength|FPercent, false);
92 case SVGCSS_PROP_DOMINANT_BASELINE:
93 // auto | use-script | no-change | reset-size | ideographic |
94 // alphabetic | hanging | mathematical | central | middle |
95 // text-after-edge | text-before-edge | inherit
96 if (id == CSS_VAL_AUTO || id == CSS_VAL_MIDDLE ||
97 (id >= SVGCSS_VAL_USE_SCRIPT && id <= SVGCSS_VAL_RESET_SIZE) ||
98 (id >= SVGCSS_VAL_CENTRAL && id <= SVGCSS_VAL_MATHEMATICAL))
99 valid_primitive = true;
102 case SVGCSS_PROP_ENABLE_BACKGROUND:
103 // accumulate | new [x] [y] [width] [height] | inherit
104 if (id == SVGCSS_VAL_ACCUMULATE) // TODO : new
105 valid_primitive = true;
108 case SVGCSS_PROP_MARKER_START:
109 case SVGCSS_PROP_MARKER_MID:
110 case SVGCSS_PROP_MARKER_END:
111 case SVGCSS_PROP_MASK:
112 if (id == CSS_VAL_NONE)
113 valid_primitive = true;
114 else if (value->unit == CSSPrimitiveValue::CSS_URI) {
115 parsedValue = new CSSPrimitiveValue(domString(value->string), CSSPrimitiveValue::CSS_URI);
121 case SVGCSS_PROP_CLIP_RULE: // nonzero | evenodd | inherit
122 case SVGCSS_PROP_FILL_RULE:
123 if (id == SVGCSS_VAL_NONZERO || id == SVGCSS_VAL_EVENODD)
124 valid_primitive = true;
127 case SVGCSS_PROP_STROKE_MITERLIMIT: // <miterlimit> | inherit
128 valid_primitive = validUnit(value, FInteger|FNonNeg, false);
131 case SVGCSS_PROP_STROKE_LINEJOIN: // miter | round | bevel | inherit
132 if (id == SVGCSS_VAL_MITER || id == CSS_VAL_ROUND || id == SVGCSS_VAL_BEVEL)
133 valid_primitive = true;
136 case SVGCSS_PROP_STROKE_LINECAP: // butt | round | square | inherit
137 if (id == SVGCSS_VAL_BUTT || id == CSS_VAL_ROUND || id == CSS_VAL_SQUARE)
138 valid_primitive = true;
141 case SVGCSS_PROP_STROKE_OPACITY: // <opacity-value> | inherit
142 case SVGCSS_PROP_FILL_OPACITY:
143 case SVGCSS_PROP_STOP_OPACITY:
144 case SVGCSS_PROP_FLOOD_OPACITY:
145 valid_primitive = (!id && validUnit(value, FNumber|FPercent, false));
148 case SVGCSS_PROP_SHAPE_RENDERING:
149 // auto | optimizeSpeed | crispEdges | geometricPrecision | inherit
150 if (id == CSS_VAL_AUTO || id == SVGCSS_VAL_OPTIMIZESPEED ||
151 id == SVGCSS_VAL_CRISPEDGES || id == SVGCSS_VAL_GEOMETRICPRECISION)
152 valid_primitive = true;
155 case SVGCSS_PROP_TEXT_RENDERING: // auto | optimizeSpeed | optimizeLegibility | geometricPrecision | inherit
156 if (id == CSS_VAL_AUTO || id == SVGCSS_VAL_OPTIMIZESPEED || id == SVGCSS_VAL_OPTIMIZELEGIBILITY ||
157 id == SVGCSS_VAL_GEOMETRICPRECISION)
158 valid_primitive = true;
161 case SVGCSS_PROP_IMAGE_RENDERING: // auto | optimizeSpeed |
162 case SVGCSS_PROP_COLOR_RENDERING: // optimizeQuality | inherit
163 if (id == CSS_VAL_AUTO || id == SVGCSS_VAL_OPTIMIZESPEED ||
164 id == SVGCSS_VAL_OPTIMIZEQUALITY)
165 valid_primitive = true;
168 case SVGCSS_PROP_COLOR_PROFILE: // auto | sRGB | <name> | <uri> inherit
169 if (id == CSS_VAL_AUTO || id == SVGCSS_VAL_SRGB)
170 valid_primitive = true;
173 case SVGCSS_PROP_COLOR_INTERPOLATION: // auto | sRGB | linearRGB | inherit
174 case SVGCSS_PROP_COLOR_INTERPOLATION_FILTERS:
175 if (id == CSS_VAL_AUTO || id == SVGCSS_VAL_SRGB || id == SVGCSS_VAL_LINEARRGB)
176 valid_primitive = true;
179 /* Start of supported CSS properties with validation. This is needed for parseShortHand to work
180 * correctly and allows optimization in applyRule(..)
183 case SVGCSS_PROP_POINTER_EVENTS:
184 // none | visiblePainted | visibleFill | visibleStroke | visible |
185 // painted | fill | stroke | none | all | inherit
186 if (id == CSS_VAL_VISIBLE || id == CSS_VAL_NONE ||
187 (id >= SVGCSS_VAL_VISIBLEPAINTED && id <= SVGCSS_VAL_ALL))
188 valid_primitive = true;
191 case SVGCSS_PROP_TEXT_ANCHOR: // start | middle | end | inherit
192 if (id == CSS_VAL_START || id == CSS_VAL_MIDDLE || id == CSS_VAL_END)
193 valid_primitive = true;
196 case SVGCSS_PROP_GLYPH_ORIENTATION_VERTICAL: // auto | <angle> | inherit
197 if (id == CSS_VAL_AUTO) {
198 valid_primitive = true;
201 /* fallthrough intentional */
202 case SVGCSS_PROP_GLYPH_ORIENTATION_HORIZONTAL: // <angle> | inherit
203 if (value->unit == CSSPrimitiveValue::CSS_DEG)
204 parsedValue = new CSSPrimitiveValue(value->fValue, CSSPrimitiveValue::CSS_DEG);
205 else if (value->unit == CSSPrimitiveValue::CSS_GRAD)
206 parsedValue = new CSSPrimitiveValue(value->fValue, CSSPrimitiveValue::CSS_GRAD);
207 else if (value->unit == CSSPrimitiveValue::CSS_RAD)
208 parsedValue = new CSSPrimitiveValue(value->fValue, CSSPrimitiveValue::CSS_RAD);
211 case SVGCSS_PROP_FILL: // <paint> | inherit
212 case SVGCSS_PROP_STROKE: // <paint> | inherit
214 if (id == CSS_VAL_NONE)
215 parsedValue = new SVGPaint(SVGPaint::SVG_PAINTTYPE_NONE);
216 else if (id == SVGCSS_VAL_CURRENTCOLOR)
217 parsedValue = new SVGPaint(SVGPaint::SVG_PAINTTYPE_CURRENTCOLOR);
218 else if (value->unit == CSSPrimitiveValue::CSS_URI)
219 parsedValue = new SVGPaint(SVGPaint::SVG_PAINTTYPE_URI, domString(value->string).impl());
221 parsedValue = parseSVGPaint();
228 case CSS_PROP_COLOR: // <color> | inherit
229 if ((id >= CSS_VAL_AQUA && id <= CSS_VAL_WINDOWTEXT) ||
230 (id >= SVGCSS_VAL_ALICEBLUE && id <= SVGCSS_VAL_YELLOWGREEN))
231 parsedValue = new SVGColor(domString(value->string).impl());
233 parsedValue = parseSVGColor();
239 case SVGCSS_PROP_STOP_COLOR: // TODO : icccolor
240 case SVGCSS_PROP_FLOOD_COLOR:
241 case SVGCSS_PROP_LIGHTING_COLOR:
242 if ((id >= CSS_VAL_AQUA && id <= CSS_VAL_WINDOWTEXT) ||
243 (id >= SVGCSS_VAL_ALICEBLUE && id <= SVGCSS_VAL_YELLOWGREEN))
244 parsedValue = new SVGColor(domString(value->string).impl());
245 else if (id == SVGCSS_VAL_CURRENTCOLOR)
246 parsedValue = new SVGColor(SVGColor::SVG_COLORTYPE_CURRENTCOLOR);
247 else // TODO : svgcolor (iccColor)
248 parsedValue = parseSVGColor();
255 case SVGCSS_PROP_WRITING_MODE:
256 // lr-tb | rl_tb | tb-rl | lr | rl | tb | inherit
257 if (id >= SVGCSS_VAL_LR_TB && id <= SVGCSS_VAL_TB)
258 valid_primitive = true;
261 case SVGCSS_PROP_STROKE_WIDTH: // <length> | inherit
262 case SVGCSS_PROP_STROKE_DASHOFFSET:
263 valid_primitive = validUnit(value, FLength | FPercent, false);
265 case SVGCSS_PROP_STROKE_DASHARRAY: // none | <dasharray> | inherit
266 if (id == CSS_VAL_NONE)
267 valid_primitive = true;
269 parsedValue = parseSVGStrokeDasharray();
273 case SVGCSS_PROP_KERNING: // auto | normal | <length> | inherit
274 if (id == CSS_VAL_AUTO)
275 valid_primitive = true;
277 valid_primitive = validUnit(value, FLength, false);
280 case SVGCSS_PROP_CLIP_PATH: // <uri> | none | inherit
281 case SVGCSS_PROP_FILTER:
282 if (id == CSS_VAL_NONE)
283 valid_primitive = true;
284 else if (value->unit == CSSPrimitiveValue::CSS_URI) {
285 parsedValue = new CSSPrimitiveValue(domString(value->string), (CSSPrimitiveValue::UnitTypes) value->unit);
291 /* shorthand properties */
292 case SVGCSS_PROP_MARKER:
294 const int properties[3] = { SVGCSS_PROP_MARKER_START,
295 SVGCSS_PROP_MARKER_MID,
296 SVGCSS_PROP_MARKER_END };
297 return parseShorthand(propId, properties, 3, important);
303 if (valid_primitive) {
305 parsedValue = new CSSPrimitiveValue(id);
306 else if (value->unit == CSSPrimitiveValue::CSS_STRING)
307 parsedValue = new CSSPrimitiveValue(domString(value->string), (CSSPrimitiveValue::UnitTypes) value->unit);
308 else if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
309 parsedValue = new CSSPrimitiveValue(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit);
310 else if (value->unit >= Value::Q_EMS)
311 parsedValue = new CSSQuirkPrimitiveValue(value->fValue, CSSPrimitiveValue::CSS_EMS);
315 if (!valueList->current() || inShorthand()) {
316 addProperty(propId, parsedValue, important);
324 CSSValue* CSSParser::parseSVGStrokeDasharray()
326 CSSValueList* ret = new CSSValueList;
327 Value* value = valueList->current();
328 bool valid_primitive = true;
329 while(valid_primitive && value) {
330 valid_primitive = validUnit(value, FLength | FPercent |FNonNeg, false);
332 ret->append(new CSSPrimitiveValue(value->id));
333 else if (value->unit == CSSPrimitiveValue::CSS_STRING)
334 ret->append(new CSSPrimitiveValue(domString(value->string), (CSSPrimitiveValue::UnitTypes) value->unit));
335 else if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
336 ret->append(new CSSPrimitiveValue(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit));
337 value = valueList->next();
338 if (value && value->unit == Value::Operator && value->iValue == ',')
339 value = valueList->next();
341 if (!valid_primitive) {
349 CSSValue* CSSParser::parseSVGPaint()
351 Value* value = valueList->current();
352 if (!strict && value->unit == CSSPrimitiveValue::CSS_NUMBER &&
353 value->fValue >= 0. && value->fValue < 1000000.) {
354 String str = String::sprintf("%06d", (int)(value->fValue+.5));
355 return new SVGPaint(SVGPaint::SVG_PAINTTYPE_RGBCOLOR, String(), str);
356 } else if (value->unit == CSSPrimitiveValue::CSS_RGBCOLOR) {
357 String str = "#" + domString(value->string);
358 return new SVGPaint(SVGPaint::SVG_PAINTTYPE_RGBCOLOR, String(), str);
359 } else if (value->unit == CSSPrimitiveValue::CSS_IDENT ||
360 (!strict && value->unit == CSSPrimitiveValue::CSS_DIMENSION))
361 return new SVGPaint(SVGPaint::SVG_PAINTTYPE_RGBCOLOR, String(), domString(value->string));
362 else if (value->unit == Value::Function && value->function->args != 0 &&
363 domString(value->function->name).lower() == "rgb(") {
364 ValueList* args = value->function->args;
365 Value* v = args->current();
366 if (!validUnit(v, FInteger|FPercent, true))
368 int r = (int) (v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256./100. : 1.));
370 if (v->unit != Value::Operator && v->iValue != ',')
373 if (!validUnit(v, FInteger|FPercent, true))
375 int g = (int) (v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256./100. : 1.));
377 if (v->unit != Value::Operator && v->iValue != ',')
380 if (!validUnit(v, FInteger|FPercent, true))
382 int b = (int) (v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256./100. : 1.));
383 r = max(0, min(255, r));
384 g = max(0, min(255, g));
385 b = max(0, min(255, b));
387 return new SVGPaint(SVGPaint::SVG_PAINTTYPE_RGBCOLOR, String(), String::sprintf("rgb(%d, %d, %d)", r, g, b).impl());
392 return new SVGPaint();
395 CSSValue* CSSParser::parseSVGColor()
397 Value* value = valueList->current();
398 if (!strict && value->unit == CSSPrimitiveValue::CSS_NUMBER && value->fValue >= 0. && value->fValue < 1000000.)
399 return new SVGColor(String::sprintf("%06d", (int)(value->fValue+.5)).impl());
400 else if (value->unit == CSSPrimitiveValue::CSS_RGBCOLOR) {
401 String str = "#" + domString(value->string);
402 return new SVGColor(str.impl());
403 } else if (value->unit == CSSPrimitiveValue::CSS_IDENT || (!strict && value->unit == CSSPrimitiveValue::CSS_DIMENSION))
404 return new SVGColor(domString(value->string).impl());
405 else if (value->unit == Value::Function && value->function->args != 0 && domString(value->function->name).lower() == "rgb(") {
406 ValueList* args = value->function->args;
407 Value* v = args->current();
408 if (!validUnit(v, FInteger|FPercent, true))
410 int r = (int) (v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256./100. : 1.));
412 if (v->unit != Value::Operator && v->iValue != ',')
415 if (!validUnit(v, FInteger|FPercent, true))
417 int g = (int) (v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256./100. : 1.));
419 if (v->unit != Value::Operator && v->iValue != ',')
422 if (!validUnit(v, FInteger|FPercent, true))
424 int b = (int) (v->fValue * (v->unit == CSSPrimitiveValue::CSS_PERCENTAGE ? 256./100. : 1.));
425 r = max(0, min(255, r));
426 g = max(0, min(255, g));
427 b = max(0, min(255, b));
429 return new SVGColor(String::sprintf("rgb(%d, %d, %d)", r, g, b).impl());
434 return new SVGPaint();
439 #endif // SVG_SUPPORT