Chromium Code Reviews| Index: Source/core/css/parser/CSSPropertyParser.cpp |
| diff --git a/Source/core/css/parser/CSSPropertyParser.cpp b/Source/core/css/parser/CSSPropertyParser.cpp |
| index 9f52c8fd6c92ffb915d29f0c53cbe011dd75e8c4..22d6ef2c4fd6b858946997c8183a51d056cad255 100644 |
| --- a/Source/core/css/parser/CSSPropertyParser.cpp |
| +++ b/Source/core/css/parser/CSSPropertyParser.cpp |
| @@ -26,6 +26,11 @@ |
| #include "config.h" |
| #include "core/css/parser/CSSPropertyParser.h" |
| +#include "RuntimeEnabledFeatures.h" |
| +#include "core/rendering/RenderTheme.h" |
| +#include "core/svg/SVGPaint.h" |
| + |
| +using namespace std; |
| namespace WebCore { |
| @@ -48,4 +53,394 @@ CSSPropertyParser::~CSSPropertyParser() |
| { |
| } |
| +static bool isSystemColor(int id) |
|
pdr.
2014/02/28 22:47:17
Can we now remove the version of this from BisonCS
|
| +{ |
| + return (id >= CSSValueActiveborder && id <= CSSValueWindowtext) || id == CSSValueMenu; |
| +} |
| + |
| +bool CSSPropertyParser::parseSVGValue(CSSPropertyID propId, bool important) |
| +{ |
| + CSSParserValue* value = m_valueList->current(); |
| + if (!value) |
| + return false; |
| + |
| + CSSValueID id = value->id; |
| + |
| + bool validPrimitive = false; |
| + RefPtrWillBeRawPtr<CSSValue> parsedValue; |
| + |
| + switch (propId) { |
| + /* The comment to the right defines all valid value of these |
| + * properties as defined in SVG 1.1, Appendix N. Property index */ |
| + case CSSPropertyAlignmentBaseline: |
| + // auto | baseline | before-edge | text-before-edge | middle | |
| + // central | after-edge | text-after-edge | ideographic | alphabetic | |
| + // hanging | mathematical | inherit |
| + if (id == CSSValueAuto || id == CSSValueBaseline || id == CSSValueMiddle |
| + || (id >= CSSValueBeforeEdge && id <= CSSValueMathematical)) |
| + validPrimitive = true; |
| + break; |
| + |
| + case CSSPropertyBaselineShift: |
| + // baseline | super | sub | <percentage> | <length> | inherit |
| + if (id == CSSValueBaseline || id == CSSValueSub |
| + || id >= CSSValueSuper) |
| + validPrimitive = true; |
| + else |
| + validPrimitive = validUnit(value, FLength | FPercent, SVGAttributeMode); |
| + break; |
| + |
| + case CSSPropertyDominantBaseline: |
| + // auto | use-script | no-change | reset-size | ideographic | |
| + // alphabetic | hanging | mathematical | central | middle | |
| + // text-after-edge | text-before-edge | inherit |
| + if (id == CSSValueAuto || id == CSSValueMiddle |
| + || (id >= CSSValueUseScript && id <= CSSValueResetSize) |
| + || (id >= CSSValueCentral && id <= CSSValueMathematical)) |
| + validPrimitive = true; |
| + break; |
| + |
| + case CSSPropertyEnableBackground: |
| + // accumulate | new [x] [y] [width] [height] | inherit |
| + if (id == CSSValueAccumulate) // TODO : new |
| + validPrimitive = true; |
| + break; |
| + |
| + case CSSPropertyMarkerStart: |
| + case CSSPropertyMarkerMid: |
| + case CSSPropertyMarkerEnd: |
| + case CSSPropertyMask: |
| + if (id == CSSValueNone) { |
| + validPrimitive = true; |
| + } else if (value->unit == CSSPrimitiveValue::CSS_URI) { |
| + parsedValue = CSSPrimitiveValue::create(value->string, CSSPrimitiveValue::CSS_URI); |
| + if (parsedValue) |
| + m_valueList->next(); |
| + } |
| + break; |
| + |
| + case CSSPropertyClipRule: // nonzero | evenodd | inherit |
| + case CSSPropertyFillRule: |
| + if (id == CSSValueNonzero || id == CSSValueEvenodd) |
| + validPrimitive = true; |
| + break; |
| + |
| + case CSSPropertyStrokeMiterlimit: // <miterlimit> | inherit |
| + validPrimitive = validUnit(value, FNumber | FNonNeg, SVGAttributeMode); |
| + break; |
| + |
| + case CSSPropertyStrokeLinejoin: // miter | round | bevel | inherit |
| + if (id == CSSValueMiter || id == CSSValueRound || id == CSSValueBevel) |
| + validPrimitive = true; |
| + break; |
| + |
| + case CSSPropertyStrokeLinecap: // butt | round | square | inherit |
| + if (id == CSSValueButt || id == CSSValueRound || id == CSSValueSquare) |
| + validPrimitive = true; |
| + break; |
| + |
| + case CSSPropertyStrokeOpacity: // <opacity-value> | inherit |
| + case CSSPropertyFillOpacity: |
| + case CSSPropertyStopOpacity: |
| + case CSSPropertyFloodOpacity: |
| + validPrimitive = (!id && validUnit(value, FNumber | FPercent, SVGAttributeMode)); |
| + break; |
| + |
| + case CSSPropertyShapeRendering: |
| + // auto | optimizeSpeed | crispEdges | geometricPrecision | inherit |
| + if (id == CSSValueAuto || id == CSSValueOptimizespeed |
| + || id == CSSValueCrispedges || id == CSSValueGeometricprecision) |
| + validPrimitive = true; |
| + break; |
| + |
| + case CSSPropertyImageRendering: // auto | optimizeSpeed | |
| + case CSSPropertyColorRendering: // optimizeQuality | inherit |
| + if (id == CSSValueAuto || id == CSSValueOptimizespeed |
| + || id == CSSValueOptimizequality) |
| + validPrimitive = true; |
| + break; |
| + |
| + case CSSPropertyBufferedRendering: // auto | dynamic | static |
| + if (id == CSSValueAuto || id == CSSValueDynamic || id == CSSValueStatic) |
| + validPrimitive = true; |
| + break; |
| + |
| + case CSSPropertyColorProfile: // auto | sRGB | <name> | <uri> inherit |
| + if (id == CSSValueAuto || id == CSSValueSrgb) |
| + validPrimitive = true; |
| + break; |
| + |
| + case CSSPropertyColorInterpolation: // auto | sRGB | linearRGB | inherit |
| + case CSSPropertyColorInterpolationFilters: |
| + if (id == CSSValueAuto || id == CSSValueSrgb || id == CSSValueLinearrgb) |
| + validPrimitive = true; |
| + break; |
| + |
| + /* Start of supported CSS properties with validation. This is needed for parseShortHand to work |
| + * correctly and allows optimization in applyRule(..) |
| + */ |
| + |
| + case CSSPropertyTextAnchor: // start | middle | end | inherit |
| + if (id == CSSValueStart || id == CSSValueMiddle || id == CSSValueEnd) |
| + validPrimitive = true; |
| + break; |
| + |
| + case CSSPropertyGlyphOrientationVertical: // auto | <angle> | inherit |
| + if (id == CSSValueAuto) { |
| + validPrimitive = true; |
| + break; |
| + } |
| + /* fallthrough intentional */ |
| + case CSSPropertyGlyphOrientationHorizontal: // <angle> (restricted to _deg_ per SVG 1.1 spec) | inherit |
| + if (value->unit == CSSPrimitiveValue::CSS_DEG || value->unit == CSSPrimitiveValue::CSS_NUMBER) { |
| + parsedValue = CSSPrimitiveValue::create(value->fValue, CSSPrimitiveValue::CSS_DEG); |
| + |
| + if (parsedValue) |
| + m_valueList->next(); |
| + } |
| + break; |
| + |
| + case CSSPropertyFill: // <paint> | inherit |
| + case CSSPropertyStroke: // <paint> | inherit |
| + { |
| + if (id == CSSValueNone) { |
| + parsedValue = SVGPaint::createNone(); |
| + } else if (id == CSSValueCurrentcolor) { |
| + parsedValue = SVGPaint::createCurrentColor(); |
| + } else if (isSystemColor(id)) { |
| + parsedValue = SVGPaint::createColor(RenderTheme::theme().systemColor(id)); |
| + } else if (value->unit == CSSPrimitiveValue::CSS_URI) { |
| + RGBA32 c = Color::transparent; |
| + if (m_valueList->next()) { |
| + if (parseColorFromValue(m_valueList->current(), c)) |
| + parsedValue = SVGPaint::createURIAndColor(value->string, c); |
| + else if (m_valueList->current()->id == CSSValueNone) |
| + parsedValue = SVGPaint::createURIAndNone(value->string); |
| + else if (m_valueList->current()->id == CSSValueCurrentcolor) |
| + parsedValue = SVGPaint::createURIAndCurrentColor(value->string); |
| + } |
| + if (!parsedValue) |
| + parsedValue = SVGPaint::createURI(value->string); |
| + } else { |
| + parsedValue = parseSVGPaint(); |
| + } |
| + |
| + if (parsedValue) |
| + m_valueList->next(); |
| + } |
| + break; |
| + |
| + case CSSPropertyStopColor: // TODO : icccolor |
| + case CSSPropertyFloodColor: |
| + case CSSPropertyLightingColor: |
| + if (isSystemColor(id)) |
| + parsedValue = SVGColor::createFromColor(RenderTheme::theme().systemColor(id)); |
| + else if ((id >= CSSValueAqua && id <= CSSValueTransparent) |
| + || (id >= CSSValueAliceblue && id <= CSSValueYellowgreen) || id == CSSValueGrey) |
| + parsedValue = SVGColor::createFromString(value->string); |
| + else if (id == CSSValueCurrentcolor) |
| + parsedValue = SVGColor::createCurrentColor(); |
| + else // TODO : svgcolor (iccColor) |
| + parsedValue = parseSVGColor(); |
| + |
| + if (parsedValue) |
| + m_valueList->next(); |
| + |
| + break; |
| + |
| + case CSSPropertyPaintOrder: |
| + if (!RuntimeEnabledFeatures::svgPaintOrderEnabled()) |
| + return false; |
| + |
| + if (m_valueList->size() == 1 && id == CSSValueNormal) |
| + validPrimitive = true; |
| + else if ((parsedValue = parsePaintOrder())) |
| + m_valueList->next(); |
| + break; |
| + |
| + case CSSPropertyVectorEffect: // none | non-scaling-stroke | inherit |
| + if (id == CSSValueNone || id == CSSValueNonScalingStroke) |
| + validPrimitive = true; |
| + break; |
| + |
| + case CSSPropertyWritingMode: |
| + // lr-tb | rl_tb | tb-rl | lr | rl | tb | inherit |
| + if (id == CSSValueLrTb || id == CSSValueRlTb || id == CSSValueTbRl || id == CSSValueLr || id == CSSValueRl || id == CSSValueTb) |
| + validPrimitive = true; |
| + break; |
| + |
| + case CSSPropertyStrokeWidth: // <length> | inherit |
| + case CSSPropertyStrokeDashoffset: |
| + validPrimitive = validUnit(value, FLength | FPercent, SVGAttributeMode); |
| + break; |
| + case CSSPropertyStrokeDasharray: // none | <dasharray> | inherit |
| + if (id == CSSValueNone) |
| + validPrimitive = true; |
| + else |
| + parsedValue = parseSVGStrokeDasharray(); |
| + |
| + break; |
| + |
| + case CSSPropertyKerning: // auto | normal | <length> | inherit |
| + if (id == CSSValueAuto || id == CSSValueNormal) |
| + validPrimitive = true; |
| + else |
| + validPrimitive = validUnit(value, FLength, SVGAttributeMode); |
| + break; |
| + |
| + case CSSPropertyClipPath: // <uri> | none | inherit |
| + case CSSPropertyFilter: |
| + if (id == CSSValueNone) { |
| + validPrimitive = true; |
| + } else if (value->unit == CSSPrimitiveValue::CSS_URI) { |
| + parsedValue = CSSPrimitiveValue::create(value->string, (CSSPrimitiveValue::UnitTypes) value->unit); |
| + if (parsedValue) |
| + m_valueList->next(); |
| + } |
| + break; |
| + case CSSPropertyMaskType: // luminance | alpha | inherit |
| + if (id == CSSValueLuminance || id == CSSValueAlpha) |
| + validPrimitive = true; |
| + break; |
| + |
| + /* shorthand properties */ |
| + case CSSPropertyMarker: { |
| + ShorthandScope scope(this, propId); |
| + CSSPropertyParser::ImplicitScope implicitScope(this, PropertyImplicit); |
| + if (!parseValue(CSSPropertyMarkerStart, important)) |
| + return false; |
| + if (m_valueList->current()) { |
| + rollbackLastProperties(1); |
| + return false; |
| + } |
| + CSSValue* value = m_parsedProperties.last().value(); |
| + addProperty(CSSPropertyMarkerMid, value, important); |
| + addProperty(CSSPropertyMarkerEnd, value, important); |
| + return true; |
| + } |
| + default: |
| + // If you crash here, it's because you added a css property and are not handling it |
| + // in either this switch statement or the one in CSSPropertyParser::parseValue |
| + ASSERT_WITH_MESSAGE(0, "unimplemented propertyID: %d", propId); |
| + return false; |
| + } |
| + |
| + if (validPrimitive) { |
| + if (id) |
| + parsedValue = CSSPrimitiveValue::createIdentifier(id); |
| + else if (value->unit == CSSPrimitiveValue::CSS_STRING) |
| + parsedValue = CSSPrimitiveValue::create(value->string, (CSSPrimitiveValue::UnitTypes) value->unit); |
| + else if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ) |
| + parsedValue = CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit); |
| + else if (value->unit >= CSSParserValue::Q_EMS) |
| + parsedValue = CSSPrimitiveValue::createAllowingMarginQuirk(value->fValue, CSSPrimitiveValue::CSS_EMS); |
| + if (isCalculation(value)) { |
| + // FIXME calc() http://webkit.org/b/16662 : actually create a CSSPrimitiveValue here, ie |
| + // parsedValue = CSSPrimitiveValue::create(m_parsedCalculation.release()); |
| + m_parsedCalculation.release(); |
| + parsedValue = nullptr; |
| + } |
| + m_valueList->next(); |
| + } |
| + if (!parsedValue || (m_valueList->current() && !inShorthand())) |
| + return false; |
| + |
| + addProperty(propId, parsedValue.release(), important); |
| + return true; |
| +} |
| + |
| +PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseSVGStrokeDasharray() |
| +{ |
| + RefPtrWillBeRawPtr<CSSValueList> ret = CSSValueList::createCommaSeparated(); |
| + CSSParserValue* value = m_valueList->current(); |
| + bool validPrimitive = true; |
| + while (value) { |
| + validPrimitive = validUnit(value, FLength | FPercent | FNonNeg, SVGAttributeMode); |
| + if (!validPrimitive) |
| + break; |
| + if (value->id) |
| + ret->append(CSSPrimitiveValue::createIdentifier(value->id)); |
| + else if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ) |
| + ret->append(CSSPrimitiveValue::create(value->fValue, (CSSPrimitiveValue::UnitTypes) value->unit)); |
| + value = m_valueList->next(); |
| + if (value && value->unit == CSSParserValue::Operator && value->iValue == ',') |
| + value = m_valueList->next(); |
| + } |
| + if (!validPrimitive) |
| + return nullptr; |
| + return ret.release(); |
| +} |
| + |
| +PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseSVGPaint() |
| +{ |
| + RGBA32 c = Color::transparent; |
| + if (!parseColorFromValue(m_valueList->current(), c)) |
| + return SVGPaint::createUnknown(); |
| + return SVGPaint::createColor(Color(c)); |
| +} |
| + |
| +PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseSVGColor() |
| +{ |
| + RGBA32 c = Color::transparent; |
| + if (!parseColorFromValue(m_valueList->current(), c)) |
| + return nullptr; |
| + return SVGColor::createFromColor(Color(c)); |
| +} |
| + |
| +// normal | [ fill || stroke || markers ] |
| +PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parsePaintOrder() const |
| +{ |
| + if (m_valueList->size() > 3) |
| + return nullptr; |
| + |
| + CSSParserValue* value = m_valueList->current(); |
| + if (!value) |
| + return nullptr; |
| + |
| + RefPtrWillBeRawPtr<CSSValueList> parsedValues = CSSValueList::createSpaceSeparated(); |
| + |
| + // The default paint-order is: Fill, Stroke, Markers. |
| + bool seenFill = false, seenStroke = false, seenMarkers = false; |
| + |
| + do { |
| + switch (value->id) { |
| + case CSSValueNormal: |
| + // normal inside [fill || stroke || markers] not valid |
| + return nullptr; |
| + case CSSValueFill: |
| + if (seenFill) |
| + return nullptr; |
| + |
| + seenFill = true; |
| + break; |
| + case CSSValueStroke: |
| + if (seenStroke) |
| + return nullptr; |
| + |
| + seenStroke = true; |
| + break; |
| + case CSSValueMarkers: |
| + if (seenMarkers) |
| + return nullptr; |
| + |
| + seenMarkers = true; |
| + break; |
| + default: |
| + return nullptr; |
| + } |
| + |
| + parsedValues->append(CSSPrimitiveValue::createIdentifier(value->id)); |
| + } while ((value = m_valueList->next())); |
| + |
| + // fill out the rest of the paint order |
| + if (!seenFill) |
| + parsedValues->append(CSSPrimitiveValue::createIdentifier(CSSValueFill)); |
| + if (!seenStroke) |
| + parsedValues->append(CSSPrimitiveValue::createIdentifier(CSSValueStroke)); |
| + if (!seenMarkers) |
| + parsedValues->append(CSSPrimitiveValue::createIdentifier(CSSValueMarkers)); |
| + |
| + return parsedValues.release(); |
| +} |
| + |
| } // namespace WebCore |