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