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 #include "CSSPropertyNames.h" 26 #include "CSSValueKeywords.h" 27 #include "core/css/CSSParser.h" 28 #include "core/css/CSSValueList.h" 29 #include "core/rendering/RenderTheme.h" 30 #include "core/svg/SVGPaint.h" 31 32 using namespace std; 33 34 namespace WebCore { 35 36 static bool isSystemColor(int id) 37 { 38 return (id >= CSSValueActiveborder && id <= CSSValueWindowtext) || id == CSSValueMenu; 39 } 40 41 bool CSSParser::parseSVGValue(CSSPropertyID propId, bool important) 42 { 43 CSSParserValue* value = m_valueList->current(); 44 if (!value) 45 return false; 46 47 CSSValueID 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, SVGAttributeMode); 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, SVGAttributeMode); 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, SVGAttributeMode)); 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 CSSPropertyBufferedRendering: // auto | dynamic | static 144 if (id == CSSValueAuto || id == CSSValueDynamic || id == CSSValueStatic) 145 valid_primitive = true; 146 break; 147 148 case CSSPropertyColorProfile: // auto | sRGB | <name> | <uri> inherit 149 if (id == CSSValueAuto || id == CSSValueSrgb) 150 valid_primitive = true; 151 break; 152 153 case CSSPropertyColorInterpolation: // auto | sRGB | linearRGB | inherit 154 case CSSPropertyColorInterpolationFilters: 155 if (id == CSSValueAuto || id == CSSValueSrgb || id == CSSValueLinearrgb) 156 valid_primitive = true; 157 break; 158 159 /* Start of supported CSS properties with validation. This is needed for parseShortHand to work 160 * correctly and allows optimization in applyRule(..) 161 */ 162 163 case CSSPropertyTextAnchor: // start | middle | end | inherit 164 if (id == CSSValueStart || id == CSSValueMiddle || id == CSSValueEnd) 165 valid_primitive = true; 166 break; 167 168 case CSSPropertyGlyphOrientationVertical: // auto | <angle> | inherit 169 if (id == CSSValueAuto) { 170 valid_primitive = true; 171 break; 172 } 173 /* fallthrough intentional */ 174 case CSSPropertyGlyphOrientationHorizontal: // <angle> (restricted to _deg_ per SVG 1.1 spec) | inherit 175 if (value->unit == CSSPrimitiveValue::CSS_DEG || value->unit == CSSPrimitiveValue::CSS_NUMBER) { 176 parsedValue = CSSPrimitiveValue::create(value->fValue, CSSPrimitiveValue::CSS_DEG); 177 178 if (parsedValue) 179 m_valueList->next(); 180 } 181 break; 182 183 case CSSPropertyFill: // <paint> | inherit 184 case CSSPropertyStroke: // <paint> | inherit 185 { 186 if (id == CSSValueNone) 187 parsedValue = SVGPaint::createNone(); 188 else if (id == CSSValueCurrentcolor) 189 parsedValue = SVGPaint::createCurrentColor(); 190 else if (isSystemColor(id)) 191 parsedValue = SVGPaint::createColor(RenderTheme::defaultTheme()->systemColor(id)); 192 else if (value->unit == CSSPrimitiveValue::CSS_URI) { 193 RGBA32 c = Color::transparent; 194 if (m_valueList->next()) { 195 if (parseColorFromValue(m_valueList->current(), c)) 196 parsedValue = SVGPaint::createURIAndColor(value->string, c); 197 else if (m_valueList->current()->id == CSSValueNone) 198 parsedValue = SVGPaint::createURIAndNone(value->string); 199 } 200 if (!parsedValue) 201 parsedValue = SVGPaint::createURI(value->string); 202 } else 203 parsedValue = parseSVGPaint(); 204 205 if (parsedValue) 206 m_valueList->next(); 207 } 208 break; 209 210 case CSSPropertyStopColor: // TODO : icccolor 211 case CSSPropertyFloodColor: 212 case CSSPropertyLightingColor: 213 if (isSystemColor(id)) 214 parsedValue = SVGColor::createFromColor(RenderTheme::defaultTheme()->systemColor(id)); 215 else if ((id >= CSSValueAqua && id <= CSSValueTransparent) || 216 (id >= CSSValueAliceblue && id <= CSSValueYellowgreen) || id == CSSValueGrey) 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, SVGAttributeMode); 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, SVGAttributeMode); 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 CSSPropertyMaskType: // luminance | alpha | inherit 269 if (id == CSSValueLuminance || id == CSSValueAlpha) 270 valid_primitive = true; 271 break; 272 273 /* shorthand properties */ 274 case CSSPropertyMarker: 275 { 276 ShorthandScope scope(this, propId); 277 CSSParser::ImplicitScope implicitScope(this, PropertyImplicit); 278 if (!parseValue(CSSPropertyMarkerStart, important)) 279 return false; 280 if (m_valueList->current()) { 281 rollbackLastProperties(1); 282 return false; 283 } 284 CSSValue* value = m_parsedProperties.last().value(); 285 addProperty(CSSPropertyMarkerMid, value, important); 286 addProperty(CSSPropertyMarkerEnd, value, important); 287 return true; 288 } 289 default: 290 // If you crash here, it's because you added a css property and are not handling it 291 // in either this switch statement or the one in CSSParser::parseValue 292 ASSERT_WITH_MESSAGE(0, "unimplemented propertyID: %d", propId); 293 return false; 294 } 295 296 if (valid_primitive) { 297 if (id != 0) 298 parsedValue = CSSPrimitiveValue::createIdentifier(id); 299 else if (value->unit == CSSPrimitiveValue::CSS_STRING) 300 parsedValue = CSSPrimitiveValue::create(value->string, (CSSPrimitiveValue::UnitTypes) value->unit); 301 else if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ) 302 parsedValue = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit); 303 else if (value->unit >= CSSParserValue::Q_EMS) 304 parsedValue = CSSPrimitiveValue::createAllowingMarginQuirk(value->fValue, CSSPrimitiveValue::CSS_EMS); 305 if (isCalculation(value)) { 306 // FIXME calc() http://webkit.org/b/16662 : actually create a CSSPrimitiveValue here, ie 307 // parsedValue = CSSPrimitiveValue::create(m_parsedCalculation.release()); 308 m_parsedCalculation.release(); 309 parsedValue = 0; 310 } 311 m_valueList->next(); 312 } 313 if (!parsedValue || (m_valueList->current() && !inShorthand())) 314 return false; 315 316 addProperty(propId, parsedValue.release(), important); 317 return true; 318 } 319 320 PassRefPtr<CSSValue> CSSParser::parseSVGStrokeDasharray() 321 { 322 RefPtr<CSSValueList> ret = CSSValueList::createCommaSeparated(); 323 CSSParserValue* value = m_valueList->current(); 324 bool valid_primitive = true; 325 while (value) { 326 valid_primitive = validUnit(value, FLength | FPercent | FNonNeg, SVGAttributeMode); 327 if (!valid_primitive) 328 break; 329 if (value->id != 0) 330 ret->append(CSSPrimitiveValue::createIdentifier(value->id)); 331 else if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ) 332 ret->append(CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit)); 333 value = m_valueList->next(); 334 if (value && value->unit == CSSParserValue::Operator && value->iValue == ',') 335 value = m_valueList->next(); 336 } 337 if (!valid_primitive) 338 return 0; 339 return ret.release(); 340 } 341 342 PassRefPtr<CSSValue> CSSParser::parseSVGPaint() 343 { 344 RGBA32 c = Color::transparent; 345 if (!parseColorFromValue(m_valueList->current(), c)) 346 return SVGPaint::createUnknown(); 347 return SVGPaint::createColor(Color(c)); 348 } 349 350 PassRefPtr<CSSValue> CSSParser::parseSVGColor() 351 { 352 RGBA32 c = Color::transparent; 353 if (!parseColorFromValue(m_valueList->current(), c)) 354 return 0; 355 return SVGColor::createFromColor(Color(c)); 356 } 357 358 } 359