4993 RefPtr<CSSRadialGradientValue> result = CSSRadialGradientValue::create();
4994
4995 // Walk the arguments.
4996 CSSParserValueList* args = m_valueList->current()->function->args.get();
4997 if (!args || !args->size())
4998 return false;
4999
5000 CSSParserValue* a = args->current();
5001 if (!a)
5002 return false;
5003
5004 bool expectComma = false;
5005
5006 // Optional background-position
5007 RefPtr<CSSValue> centerX;
5008 RefPtr<CSSValue> centerY;
5009 // parseFillPosition advances the args next pointer.
5010 parseFillPosition(args, centerX, centerY);
5011 a = args->current();
5012
5013 if (centerX || centerY) {
5014 // Comma
5015 if (a->unit != CSSParserValue::Operator || a->iValue != ',')
5016 return false;
5017
5018 a = args->next();
5019 if (!a)
5020 return false;
5021 }
5022
5023 ASSERT(!centerX || centerX->isPrimitiveValue());
5024 ASSERT(!centerY || centerY->isPrimitiveValue());
5025
5026 result->setFirstX(static_cast<CSSPrimitiveValue*>(centerX.get()));
5027 result->setSecondX(static_cast<CSSPrimitiveValue*>(centerX.get()));
5028 // CSS3 radial gradients always share the same start and end point.
5029 result->setFirstY(static_cast<CSSPrimitiveValue*>(centerY.get()));
5030 result->setSecondY(static_cast<CSSPrimitiveValue*>(centerY.get()));
5031
5032 RefPtr<CSSPrimitiveValue> shapeValue;
5033 RefPtr<CSSPrimitiveValue> sizeValue;
5034
5035 // Optional shape and/or size in any order.
5036 for (int i = 0; i < 2; ++i) {
5037 if (a->unit != CSSPrimitiveValue::CSS_IDENT)
5038 break;
5039
5040 bool foundValue = false;
5041 switch (a->id) {
5042 case CSSValueCircle:
5043 case CSSValueEllipse:
5044 shapeValue = CSSPrimitiveValue::createIdentifier(a->id);
5045 foundValue = true;
5046 break;
5047 case CSSValueClosestSide:
5048 case CSSValueClosestCorner:
5049 case CSSValueFarthestSide:
5050 case CSSValueFarthestCorner:
5051 case CSSValueContain:
5052 case CSSValueCover:
5053 sizeValue = CSSPrimitiveValue::createIdentifier(a->id);
5054 foundValue = true;
5055 break;
5056 }
5057
5058 if (foundValue) {
5059 a = args->next();
5060 if (!a)
5061 return false;
5062
5063 expectComma = true;
5064 }
5065 }
5066
5067 result->setShape(shapeValue);
5068 result->setSizingBehavior(sizeValue);
5069
5070 // Or, two lengths or percentages
5071 RefPtr<CSSPrimitiveValue> horizontalSize;
5072 RefPtr<CSSPrimitiveValue> verticalSize;
5073
5074 if (!shapeValue && !sizeValue) {
5075 if (validUnit(a, FLength | FPercent, m_strict)) {
5076 horizontalSize = CSSPrimitiveValue::create(a->fValue, (CSSPrimitiveValue::UnitTypes) a->unit);
5077 a = args->next();
5078 if (!a)
5079 return false;
5080
5081 expectComma = true;
5082 }
5083
5084 if (validUnit(a, FLength | FPercent, m_strict)) {
5085 verticalSize = CSSPrimitiveValue::create(a->fValue, (CSSPrimitiveValue::UnitTypes) a->unit);
5086
5087 a = args->next();
5088 if (!a)
5089 return false;
5090 expectComma = true;
5091 }
5092 }
5093
5094 // Must have neither or both.
5095 if (!horizontalSize != !verticalSize)
5096 return false;
5097
5098 result->setEndHorizontalSize(horizontalSize);
5099 result->setEndVerticalSize(verticalSize);
5100
5101 // Now look for 0 or more color stops.
5102 while (a) {
5103 // Look for the comma before the next stop.
5104 if (expectComma) {
5105 if (a->unit != CSSParserValue::Operator || a->iValue != ',')
5106 return false;
5107
5108 a = args->next();
5109 if (!a)
5110 return false;
5111 }
5112
5113 // <color-stop> = <color> [ <percentage> | <length> ]?
5114 CSSGradientColorStop stop;
5115 stop.m_color = parseGradientColorOrKeyword(this, a);
5116 if (!stop.m_color)
5117 return false;
5118
5119 a = args->next();
5120 if (a) {
5121 if (validUnit(a, FLength | FPercent, m_strict)) {
5122 stop.m_position = CSSPrimitiveValue::create(a->fValue, (CSSPrimitiveValue::UnitTypes)a->unit);
5123 a = args->next();
5124 }
5125 }
5126
5127 result->addStop(stop);
5128 expectComma = true;
5129 }
5130
5131 Vector<CSSGradientColorStop>& stops = result->stops();
5132 if (stops.isEmpty())
5133 return false;
5134
5135 gradient = result.release();
5136 return true;