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