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