// FIXME: Way too many!
#include "core/CSSValueKeywords.h"
#include "core/StylePropertyShorthand.h"
-#include "core/css/CSSAspectRatioValue.h"
#include "core/css/CSSBasicShapes.h"
#include "core/css/CSSBorderImage.h"
#include "core/css/CSSCanvasValue.h"
+#include "core/css/CSSContentDistributionValue.h"
#include "core/css/CSSCrossfadeValue.h"
#include "core/css/CSSCursorImageValue.h"
#include "core/css/CSSFontFaceSrcValue.h"
#include "core/css/CSSKeyframesRule.h"
#include "core/css/CSSLineBoxContainValue.h"
#include "core/css/CSSPrimitiveValue.h"
+#include "core/css/CSSPrimitiveValueMappings.h"
#include "core/css/CSSPropertyMetadata.h"
#include "core/css/CSSPropertySourceData.h"
#include "core/css/CSSReflectValue.h"
#include "core/css/HashTools.h"
#include "core/css/Pair.h"
#include "core/css/Rect.h"
+#include "core/css/parser/CSSParserFastPaths.h"
#include "core/css/parser/CSSParserIdioms.h"
#include "core/css/parser/CSSParserValues.h"
#include "core/frame/UseCounter.h"
#include "core/html/parser/HTMLParserIdioms.h"
#include "core/inspector/InspectorInstrumentation.h"
#include "core/rendering/RenderTheme.h"
+#include "core/rendering/style/GridCoordinate.h"
#include "platform/FloatConversion.h"
#include "platform/RuntimeEnabledFeatures.h"
#include "wtf/BitArray.h"
return a.is8Bit() ? WTF::equalIgnoringCase(b, a.characters8(), length) : WTF::equalIgnoringCase(b, a.characters16(), length);
}
-template <unsigned N>
-static bool equalIgnoringCase(CSSParserValue* value, const char (&b)[N])
-{
- ASSERT(value->unit == CSSPrimitiveValue::CSS_IDENT || value->unit == CSSPrimitiveValue::CSS_STRING);
- return equalIgnoringCase(value->string, b);
-}
-
static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> createPrimitiveValuePair(PassRefPtrWillBeRawPtr<CSSPrimitiveValue> first, PassRefPtrWillBeRawPtr<CSSPrimitiveValue> second, Pair::IdenticalValuesPolicy identicalValuesPolicy = Pair::DropIdenticalValues)
{
return cssValuePool().createValue(Pair::create(first, second, identicalValuesPolicy));
CSSParserValueList* valueList, const CSSParserContext& context, bool inViewport,
WillBeHeapVector<CSSProperty, 256>& parsedProperties, CSSRuleSourceData::Type ruleType)
{
+ int parsedPropertiesSize = parsedProperties.size();
+
CSSPropertyParser parser(valueList, context, inViewport, parsedProperties, ruleType);
- return parser.parseValue(property, important);
+ bool parseSuccess = parser.parseValue(property, important);
+
+ // This doesn't count UA style sheets
+ if (parseSuccess && context.useCounter())
+ context.useCounter()->count(context, property);
+
+ if (!parseSuccess)
+ parser.rollbackLastProperties(parsedProperties.size() - parsedPropertiesSize);
+
+ return parseSuccess;
}
void CSSPropertyParser::addPropertyWithPrefixingVariant(CSSPropertyID propId, PassRefPtrWillBeRawPtr<CSSValue> value, bool important, bool implicit)
if (val->unit != CSSParserValue::Function)
return false;
- return equalIgnoringCase(val->function->name, "-webkit-gradient")
- || equalIgnoringCase(val->function->name, "-webkit-linear-gradient")
- || equalIgnoringCase(val->function->name, "linear-gradient")
- || equalIgnoringCase(val->function->name, "-webkit-repeating-linear-gradient")
- || equalIgnoringCase(val->function->name, "repeating-linear-gradient")
- || equalIgnoringCase(val->function->name, "-webkit-radial-gradient")
- || equalIgnoringCase(val->function->name, "radial-gradient")
- || equalIgnoringCase(val->function->name, "-webkit-repeating-radial-gradient")
- || equalIgnoringCase(val->function->name, "repeating-radial-gradient")
- || equalIgnoringCase(val->function->name, "-webkit-canvas")
- || equalIgnoringCase(val->function->name, "-webkit-cross-fade");
+ CSSValueID id = val->function->id;
+ return id == CSSValueLinearGradient
+ || id == CSSValueRadialGradient
+ || id == CSSValueRepeatingLinearGradient
+ || id == CSSValueRepeatingRadialGradient
+ || id == CSSValueWebkitLinearGradient
+ || id == CSSValueWebkitRadialGradient
+ || id == CSSValueWebkitRepeatingLinearGradient
+ || id == CSSValueWebkitRepeatingRadialGradient
+ || id == CSSValueWebkitGradient
+ || id == CSSValueWebkitCanvas
+ || id == CSSValueWebkitCrossFade;
}
bool CSSPropertyParser::validWidthOrHeight(CSSParserValue* value)
if (!isInternalPropertyAndValueParsingEnabledForMode(m_context.mode()) && isInternalProperty(propId))
return false;
- // We don't count the UA style sheet in our statistics.
- if (m_context.useCounter())
- m_context.useCounter()->count(m_context, propId);
-
if (!m_valueList)
return false;
return true;
}
- if (isKeywordPropertyID(propId)) {
- if (!isValidKeywordPropertyAndValue(propId, id, m_context))
+ if (CSSParserFastPaths::isKeywordPropertyID(propId)) {
+ if (!CSSParserFastPaths::isValidKeywordPropertyAndValue(propId, id))
return false;
if (m_valueList->next() && !inShorthand())
return false;
String uri = value->string;
if (!uri.isNull())
image = createCSSImageValueWithReferrer(uri, completeURL(uri));
- } else if (value->unit == CSSParserValue::Function && equalIgnoringCase(value->function->name, "-webkit-image-set")) {
+ } else if (value->unit == CSSParserValue::Function && value->function->id == CSSValueWebkitImageSet) {
image = parseImageSet(m_valueList);
if (!image)
break;
m_valueList->next();
else
return false;
- }
- else if (value->unit == CSSParserValue::Function && equalIgnoringCase(value->function->name, "-webkit-image-set")) {
+ } else if (value->unit == CSSParserValue::Function && value->function->id == CSSValueWebkitImageSet) {
parsedValue = parseImageSet(m_valueList);
if (!parsedValue)
return false;
case CSSPropertyTabSize:
validPrimitive = validUnit(value, FInteger | FNonNeg);
break;
- case CSSPropertyWebkitAspectRatio:
- parsedValue = parseAspectRatio();
- break;
case CSSPropertyBorderRadius:
case CSSPropertyWebkitBorderRadius:
return parseBorderRadius(propId, important);
case CSSPropertyOrder:
validPrimitive = validUnit(value, FInteger);
break;
- case CSSPropertyInternalMarqueeIncrement:
- validPrimitive = validUnit(value, FLength | FPercent);
- break;
- case CSSPropertyInternalMarqueeRepetition:
- if (id == CSSValueInfinite)
- validPrimitive = true;
- else
- validPrimitive = validUnit(value, FInteger | FNonNeg);
- break;
- case CSSPropertyInternalMarqueeSpeed:
- validPrimitive = validUnit(value, FInteger | FNonNeg);
- break;
case CSSPropertyTransform:
case CSSPropertyWebkitTransform:
if (id == CSSValueNone)
return false;
}
break;
- case CSSPropertyTransformOrigin: {
+ case CSSPropertyTransformOrigin:
+ case CSSPropertyWebkitTransformOrigin: {
RefPtrWillBeRawPtr<CSSValueList> list = parseTransformOrigin();
if (!list)
return false;
case CSSPropertyWebkitTransformOriginZ:
validPrimitive = validUnit(value, FLength);
break;
- case CSSPropertyWebkitTransformOrigin:
- return parseWebkitTransformOriginShorthand(important);
case CSSPropertyPerspective:
if (id == CSSValueNone) {
validPrimitive = true;
return false;
}
+ case CSSPropertyJustifyContent:
+ parsedValue = parseContentDistributionOverflowPosition();
+ break;
case CSSPropertyJustifySelf:
ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled());
return parseItemPositionOverflowPosition(propId, important);
case CSSPropertyFont:
// [ [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]?
// 'font-family' ] | caption | icon | menu | message-box | small-caption | status-bar | inherit
- if (id >= CSSValueCaption && id <= CSSValueStatusBar)
- validPrimitive = true;
- else
- return parseFont(important);
- break;
+ if (num == 1 && id >= CSSValueCaption && id <= CSSValueStatusBar) {
+ parseSystemFont(important);
+ return true;
+ }
+ return parseFont(important);
case CSSPropertyListStyle:
return parseShorthand(propId, listStyleShorthand(), important);
case CSSPropertyWebkitColumns:
// [ <string> | attr(X) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit
bool CSSPropertyParser::parseContent(CSSPropertyID propId, bool important)
{
- RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createCommaSeparated();
+ RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createSpaceSeparated();
while (CSSParserValue* val = m_valueList->current()) {
RefPtrWillBeRawPtr<CSSValue> parsedValue = nullptr;
CSSParserValueList* args = val->function->args.get();
if (!args)
return false;
- if (equalIgnoringCase(val->function->name, "attr")) {
+ if (val->function->id == CSSValueAttr) {
parsedValue = parseAttr(args);
if (!parsedValue)
return false;
- } else if (equalIgnoringCase(val->function->name, "counter")) {
+ } else if (val->function->id == CSSValueCounter) {
parsedValue = parseCounterContent(args, false);
if (!parsedValue)
return false;
- } else if (equalIgnoringCase(val->function->name, "counters")) {
+ } else if (val->function->id == CSSValueCounters) {
parsedValue = parseCounterContent(args, true);
if (!parsedValue)
return false;
- } else if (equalIgnoringCase(val->function->name, "-webkit-image-set")) {
+ } else if (val->function->id == CSSValueWebkitImageSet) {
parsedValue = parseImageSet(m_valueList);
if (!parsedValue)
return false;
if (isGeneratedImageValue(valueList->current()))
return parseGeneratedImage(valueList, value);
- if (valueList->current()->unit == CSSParserValue::Function && equalIgnoringCase(valueList->current()->function->name, "-webkit-image-set")) {
+ if (valueList->current()->unit == CSSParserValue::Function && valueList->current()->function->id == CSSValueWebkitImageSet) {
value = parseImageSet(m_valueList);
if (value)
return true;
PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationName()
{
CSSParserValue* value = m_valueList->current();
+ // FIXME: Strings are not valid as per spec
if (value->unit == CSSPrimitiveValue::CSS_STRING || value->unit == CSSPrimitiveValue::CSS_IDENT) {
- if (value->id == CSSValueNone || (value->unit == CSSPrimitiveValue::CSS_STRING && equalIgnoringCase(value, "none"))) {
+ if (value->unit == CSSPrimitiveValue::CSS_STRING && m_context.useCounter())
+ m_context.useCounter()->count(UseCounter::QuotedAnimationName);
+ if (value->id == CSSValueNone || (value->unit == CSSPrimitiveValue::CSS_STRING && equalIgnoringCase(value->string, "none")))
return cssValuePool().createIdentifierValue(CSSValueNone);
- } else {
- return createPrimitiveStringValue(value);
- }
+ return createPrimitiveStringValue(value);
}
return nullptr;
}
return createPrimitiveStringValue(value);
}
-bool CSSPropertyParser::parseWebkitTransformOriginShorthand(bool important)
-{
- RefPtrWillBeRawPtr<CSSValue> originX = nullptr;
- RefPtrWillBeRawPtr<CSSValue> originY = nullptr;
- RefPtrWillBeRawPtr<CSSValue> originZ = nullptr;
-
- parse2ValuesFillPosition(m_valueList, originX, originY);
-
- if (m_valueList->current()) {
- if (!validUnit(m_valueList->current(), FLength))
- return false;
- originZ = createPrimitiveNumericValue(m_valueList->current());
- m_valueList->next();
- } else {
- originZ = cssValuePool().createImplicitInitialValue();
- }
-
- addProperty(CSSPropertyWebkitTransformOriginX, originX.release(), important);
- addProperty(CSSPropertyWebkitTransformOriginY, originY.release(), important);
- addProperty(CSSPropertyWebkitTransformOriginZ, originZ.release(), important);
-
- return true;
-}
-
bool CSSPropertyParser::parseCubicBezierTimingFunctionValue(CSSParserValueList*& args, double& result)
{
CSSParserValue* v = args->current();
CSSParserValueList* args = value->function->args.get();
- if (equalIgnoringCase(value->function->name, "steps")) {
+ if (value->function->id == CSSValueSteps) {
// For steps, 1 or 2 params must be specified (comma-separated)
if (!args || (args->size() != 1 && args->size() != 3))
return nullptr;
CSSParserValue* v = args->current();
if (!validUnit(v, FInteger))
return nullptr;
- numSteps = clampToInteger(v->fValue);
+ numSteps = clampTo<int>(v->fValue);
if (numSteps < 1)
return nullptr;
return CSSStepsTimingFunctionValue::create(numSteps, stepAtPosition);
}
- if (equalIgnoringCase(value->function->name, "cubic-bezier")) {
+ if (value->function->id == CSSValueCubicBezier) {
// For cubic bezier, 4 values must be specified.
if (!args || args->size() != 7)
return nullptr;
while (CSSParserValue* currentValue = m_valueList->current()) {
if (isForwardSlashOperator(currentValue))
break;
- if (currentValue->unit == CSSParserValue::Function && equalIgnoringCase(currentValue->function->name, "repeat")) {
+ if (currentValue->unit == CSSParserValue::Function && currentValue->function->id == CSSValueRepeat) {
if (!parseGridTrackRepeatFunction(*values))
return nullptr;
seenTrackSizeOrRepeatFunction = true;
if (!arguments || arguments->size() < 3 || !validUnit(arguments->valueAt(0), FPositiveInteger) || !isComma(arguments->valueAt(1)))
return false;
- ASSERT_WITH_SECURITY_IMPLICATION(arguments->valueAt(0)->fValue > 0);
- size_t repetitions = arguments->valueAt(0)->fValue;
-
- // The spec allows us to clamp the number of repetitions: http://www.w3.org/TR/css-grid-1/#repeat-notation
- const size_t maxRepetitions = 10000;
- repetitions = std::min(repetitions, maxRepetitions);
+ ASSERT(arguments->valueAt(0)->fValue > 0);
+ size_t repetitions = clampTo<size_t>(arguments->valueAt(0)->fValue, 0, kGridMaxTracks);
RefPtrWillBeRawPtr<CSSValueList> repeatedValues = CSSValueList::createSpaceSeparated();
arguments->next(); // Skip the repetition count.
if (currentValue && currentValue->unit == CSSParserValue::ValueList)
parseGridLineNames(*arguments, *repeatedValues);
- bool seenTrackSize = false;
+ size_t numberOfTracks = 0;
while (arguments->current()) {
RefPtrWillBeRawPtr<CSSValue> trackSize = parseGridTrackSize(*arguments);
if (!trackSize)
return false;
repeatedValues->append(trackSize);
- seenTrackSize = true;
+ ++numberOfTracks;
// This takes care of any trailing <ident>* in the grammar.
currentValue = arguments->current();
}
// We should have found at least one <track-size> or else it is not a valid <track-list>.
- if (!seenTrackSize)
+ if (!numberOfTracks)
return false;
+ // We clamp the number of repetitions to a multiple of the repeat() track list's size, while staying below the max
+ // grid size.
+ repetitions = std::min(repetitions, kGridMaxTracks / numberOfTracks);
+
for (size_t i = 0; i < repetitions; ++i) {
for (size_t j = 0; j < repeatedValues->length(); ++j)
list.append(repeatedValues->item(j));
if (currentValue->id == CSSValueAuto)
return cssValuePool().createIdentifierValue(CSSValueAuto);
- if (currentValue->unit == CSSParserValue::Function && equalIgnoringCase(currentValue->function->name, "minmax")) {
+ if (currentValue->unit == CSSParserValue::Function && currentValue->function->id == CSSValueMinmax) {
// The spec defines the following grammar: minmax( <track-breadth> , <track-breadth> )
CSSParserValueList* arguments = currentValue->function->args.get();
if (!arguments || arguments->size() != 3 || !isComma(arguments->valueAt(1)))
CSSParserValue* value = m_valueList->current();
CSSParserValueList* args = value->function->args.get();
- if (!equalIgnoringCase(value->function->name, "rect") || !args)
+ if (value->function->id != CSSValueRect || !args)
return false;
// rect(t, r, b, l) || rect(t r b l)
return shape;
}
+static bool isContentDistributionKeyword(CSSValueID id)
+{
+ return id == CSSValueSpaceBetween || id == CSSValueSpaceAround
+ || id == CSSValueSpaceEvenly || id == CSSValueStretch;
+}
+
+static bool isContentPositionKeyword(CSSValueID id)
+{
+ return id == CSSValueStart || id == CSSValueEnd || id == CSSValueCenter
+ || id == CSSValueFlexStart || id == CSSValueFlexEnd
+ || id == CSSValueLeft || id == CSSValueRight;
+}
+
static bool isBaselinePositionKeyword(CSSValueID id)
{
return id == CSSValueBaseline || id == CSSValueLastBaseline;
}
+static bool isAlignmentOverflowKeyword(CSSValueID id)
+{
+ return id == CSSValueTrue || id == CSSValueSafe;
+}
+
static bool isItemPositionKeyword(CSSValueID id)
{
return id == CSSValueStart || id == CSSValueEnd || id == CSSValueCenter
return !m_valueList->next();
}
+PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseContentDistributionOverflowPosition()
+{
+ // auto | <baseline-position> | [ <content-distribution>? && <content-position>? ]! && <overflow-position>?
+ // <baseline-position> = baseline | last-baseline;
+ // <content-distribution> = space-between | space-around | space-evenly | stretch;
+ // <content-position> = center | start | end | flex-start | flex-end | left | right;
+ // <overflow-position> = true | safe
+
+ // auto | <baseline-position>
+ CSSParserValue* value = m_valueList->current();
+ if (value->id == CSSValueAuto || isBaselinePositionKeyword(value->id)) {
+ m_valueList->next();
+ return CSSContentDistributionValue::create(CSSValueInvalid, value->id, CSSValueInvalid);
+ }
+
+ CSSValueID distribution = CSSValueInvalid;
+ CSSValueID position = CSSValueInvalid;
+ CSSValueID overflow = CSSValueInvalid;
+ if (isAlignmentOverflowKeyword(value->id)) {
+ overflow = value->id;
+ value = m_valueList->next();
+ }
+ if (value && isContentDistributionKeyword(value->id)) {
+ distribution = value->id;
+ value = m_valueList->next();
+ }
+ if (value && isContentPositionKeyword(value->id)) {
+ position = value->id;
+ value = m_valueList->next();
+ }
+ if (value) {
+ if (overflow != CSSValueInvalid || !isAlignmentOverflowKeyword(value->id))
+ return nullptr;
+ overflow = value->id;
+ }
+
+ // The grammar states that we should have at least <content-distribution> or
+ // <content-position> ([ <content-distribution>? && <content-position>? ]!).
+ if (m_valueList->next() || (position == CSSValueInvalid && distribution == CSSValueInvalid))
+ return nullptr;
+
+ return CSSContentDistributionValue::create(distribution, position, overflow);
+}
+
bool CSSPropertyParser::parseItemPositionOverflowPosition(CSSPropertyID propId, bool important)
{
// auto | stretch | <baseline-position> | [<item-position> && <overflow-position>? ]
position = cssValuePool().createIdentifierValue(value->id);
value = m_valueList->next();
if (value) {
- if (value->id == CSSValueTrue || value->id == CSSValueSafe)
+ if (isAlignmentOverflowKeyword(value->id))
overflowAlignmentKeyword = cssValuePool().createIdentifierValue(value->id);
else
return false;
}
- } else if (value->id == CSSValueTrue || value->id == CSSValueSafe) {
+ } else if (isAlignmentOverflowKeyword(value->id)) {
overflowAlignmentKeyword = cssValuePool().createIdentifierValue(value->id);
value = m_valueList->next();
if (value && isItemPositionKeyword(value->id))
return nullptr;
RefPtrWillBeRawPtr<CSSBasicShape> shape = nullptr;
- if (equalIgnoringCase(value->function->name, "circle"))
+ if (value->function->id == CSSValueCircle)
shape = parseBasicShapeCircle(args);
- else if (equalIgnoringCase(value->function->name, "ellipse"))
+ else if (value->function->id == CSSValueEllipse)
shape = parseBasicShapeEllipse(args);
- else if (equalIgnoringCase(value->function->name, "polygon"))
+ else if (value->function->id == CSSValuePolygon)
shape = parseBasicShapePolygon(args);
- else if (equalIgnoringCase(value->function->name, "inset"))
+ else if (value->function->id == CSSValueInset)
shape = parseBasicShapeInset(args);
if (!shape)
bool fontStretchParsed = false;
CSSParserValue* value = m_valueList->current();
for (; value; value = m_valueList->next()) {
- if (!fontStyleParsed && isValidKeywordPropertyAndValue(CSSPropertyFontStyle, value->id, m_context)) {
+ if (!fontStyleParsed && CSSParserFastPaths::isValidKeywordPropertyAndValue(CSSPropertyFontStyle, value->id)) {
addProperty(CSSPropertyFontStyle, cssValuePool().createIdentifierValue(value->id), important);
fontStyleParsed = true;
} else if (!fontVariantParsed && (value->id == CSSValueNormal || value->id == CSSValueSmallCaps)) {
fontVariantParsed = true;
} else if (!fontWeightParsed && parseFontWeight(important)) {
fontWeightParsed = true;
- } else if (!fontStretchParsed && isValidKeywordPropertyAndValue(CSSPropertyFontStretch, value->id, m_context)) {
+ } else if (!fontStretchParsed && CSSParserFastPaths::isValidKeywordPropertyAndValue(CSSPropertyFontStretch, value->id)) {
addProperty(CSSPropertyFontStretch, cssValuePool().createIdentifierValue(value->id), important);
fontStretchParsed = true;
} else {
return true;
}
+void CSSPropertyParser::parseSystemFont(bool important)
+{
+ ASSERT(m_valueList->size() == 1);
+ CSSValueID systemFontID = m_valueList->valueAt(0)->id;
+ ASSERT(systemFontID >= CSSValueCaption && systemFontID <= CSSValueStatusBar);
+ m_valueList->next();
+
+ FontStyle fontStyle = FontStyleNormal;
+ FontWeight fontWeight = FontWeightNormal;
+ float fontSize = 0;
+ AtomicString fontFamily;
+ RenderTheme::theme().systemFont(systemFontID, fontStyle, fontWeight, fontSize, fontFamily);
+
+ ShorthandScope scope(this, CSSPropertyFont);
+ addProperty(CSSPropertyFontStyle, cssValuePool().createIdentifierValue(fontStyle == FontStyleItalic ? CSSValueItalic : CSSValueNormal), important);
+ addProperty(CSSPropertyFontWeight, cssValuePool().createValue(fontWeight), important);
+ addProperty(CSSPropertyFontSize, cssValuePool().createValue(fontSize, CSSPrimitiveValue::CSS_PX), important);
+ RefPtrWillBeRawPtr<CSSValueList> fontFamilyList = CSSValueList::createCommaSeparated();
+ fontFamilyList->append(cssValuePool().createFontFamilyValue(fontFamily));
+ addProperty(CSSPropertyFontFamily, fontFamilyList.release(), important);
+ addProperty(CSSPropertyFontVariant, cssValuePool().createIdentifierValue(CSSValueNormal), important);
+ addProperty(CSSPropertyLineHeight, cssValuePool().createIdentifierValue(CSSValueNormal), important);
+}
+
class FontFamilyValueBuilder {
DISALLOW_ALLOCATION();
public:
return true;
}
- if (value->unit != CSSParserValue::Function || !equalIgnoringCase(value->function->name, "format"))
+ if (value->unit != CSSParserValue::Function || value->function->id != CSSValueFormat)
return false;
// FIXME: http://www.w3.org/TR/2011/WD-css3-fonts-20111004/ says that format() contains a comma-separated list of strings,
if (value->unit == CSSPrimitiveValue::CSS_URI) {
if (!parseFontFaceSrcURI(values.get()))
return nullptr;
- } else if (value->unit == CSSParserValue::Function && equalIgnoringCase(value->function->name, "local")) {
+ } else if (value->unit == CSSParserValue::Function && value->function->id == CSSValueLocal) {
if (!parseFontFaceSrcLocal(values.get()))
return nullptr;
} else {
bool CSSPropertyParser::isCalculation(CSSParserValue* value)
{
return (value->unit == CSSParserValue::Function)
- && (equalIgnoringCase(value->function->name, "calc")
- || equalIgnoringCase(value->function->name, "-webkit-calc"));
+ && (value->function->id == CSSValueCalc
+ || value->function->id == CSSValueWebkitCalc);
}
inline int CSSPropertyParser::colorIntFromValue(CSSParserValue* v)
} else if (value->unit == CSSParserValue::Function &&
value->function->args != 0 &&
value->function->args->size() == 5 /* rgb + two commas */ &&
- equalIgnoringCase(value->function->name, "rgb")) {
+ value->function->id == CSSValueRgb) {
int colorValues[3];
if (!parseColorParameters(value, colorValues, false))
return false;
if (value->unit == CSSParserValue::Function &&
value->function->args != 0 &&
value->function->args->size() == 7 /* rgba + three commas */ &&
- equalIgnoringCase(value->function->name, "rgba")) {
+ value->function->id == CSSValueRgba) {
int colorValues[4];
if (!parseColorParameters(value, colorValues, true))
return false;
} else if (value->unit == CSSParserValue::Function &&
value->function->args != 0 &&
value->function->args->size() == 5 /* hsl + two commas */ &&
- equalIgnoringCase(value->function->name, "hsl")) {
+ value->function->id == CSSValueHsl) {
double colorValues[3];
if (!parseHSLParameters(value, colorValues, false))
return false;
} else if (value->unit == CSSParserValue::Function &&
value->function->args != 0 &&
value->function->args->size() == 7 /* hsla + three commas */ &&
- equalIgnoringCase(value->function->name, "hsla")) {
+ value->function->id == CSSValueHsla) {
double colorValues[4];
if (!parseHSLParameters(value, colorValues, true))
return false;
if (!flexBasis)
flexBasis = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_PERCENTAGE);
- addProperty(CSSPropertyFlexGrow, cssValuePool().createValue(clampToFloat(flexGrow), CSSPrimitiveValue::CSS_NUMBER), important);
- addProperty(CSSPropertyFlexShrink, cssValuePool().createValue(clampToFloat(flexShrink), CSSPrimitiveValue::CSS_NUMBER), important);
+ addProperty(CSSPropertyFlexGrow, cssValuePool().createValue(clampTo<float>(flexGrow), CSSPrimitiveValue::CSS_NUMBER), important);
+ addProperty(CSSPropertyFlexShrink, cssValuePool().createValue(clampTo<float>(flexShrink), CSSPrimitiveValue::CSS_NUMBER), important);
addProperty(CSSPropertyFlexBasis, flexBasis, important);
return true;
}
context.commitImage(value.release());
else
return false;
- } else if (val->unit == CSSParserValue::Function && equalIgnoringCase(val->function->name, "-webkit-image-set")) {
+ } else if (val->unit == CSSParserValue::Function && val->function->id == CSSValueWebkitImageSet) {
RefPtrWillBeRawPtr<CSSValue> value = parser.parseImageSet(parser.m_valueList);
if (value)
context.commitImage(value.release());
return true;
}
-PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAspectRatio()
-{
- unsigned num = m_valueList->size();
- if (num == 1 && m_valueList->valueAt(0)->id == CSSValueNone) {
- m_valueList->next();
- return cssValuePool().createIdentifierValue(CSSValueNone);
- }
-
- if (num != 3)
- return nullptr;
-
- CSSParserValue* lvalue = m_valueList->current();
- CSSParserValue* op = m_valueList->next();
- CSSParserValue* rvalue = m_valueList->next();
- m_valueList->next();
-
- if (!isForwardSlashOperator(op))
- return nullptr;
-
- if (!validUnit(lvalue, FNumber | FNonNeg) || !validUnit(rvalue, FNumber | FNonNeg))
- return nullptr;
-
- if (!lvalue->fValue || !rvalue->fValue)
- return nullptr;
-
- return CSSAspectRatioValue::create(narrowPrecisionToFloat(lvalue->fValue), narrowPrecisionToFloat(rvalue->fValue));
-}
-
PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseCounter(int defaultValue)
{
RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createCommaSeparated();
val = m_valueList->current();
int i = defaultValue;
if (val && validUnit(val, FInteger)) {
- i = clampToInteger(val->fValue);
+ i = clampTo<int>(val->fValue);
m_valueList->next();
}
if (a->unit != CSSParserValue::Function)
return false;
- if (!equalIgnoringCase(a->function->name, "from") &&
- !equalIgnoringCase(a->function->name, "to") &&
- !equalIgnoringCase(a->function->name, "color-stop"))
+ if (a->function->id != CSSValueFrom
+ && a->function->id != CSSValueTo
+ && a->function->id != CSSValueColorStop)
return false;
CSSParserValueList* args = a->function->args.get();
if (!args)
return false;
- if (equalIgnoringCase(a->function->name, "from")
- || equalIgnoringCase(a->function->name, "to")) {
+ if (a->function->id == CSSValueFrom || a->function->id == CSSValueTo) {
// The "from" and "to" stops expect 1 argument.
if (args->size() != 1)
return false;
- if (equalIgnoringCase(a->function->name, "from"))
+ if (a->function->id == CSSValueFrom)
stop.m_position = cssValuePool().createValue(0, CSSPrimitiveValue::CSS_NUMBER);
else
stop.m_position = cssValuePool().createValue(1, CSSPrimitiveValue::CSS_NUMBER);
}
// The "color-stop" function expects 3 arguments.
- if (equalIgnoringCase(a->function->name, "color-stop")) {
+ if (a->function->id == CSSValueColorStop) {
if (args->size() != 3)
return false;
return false;
if (a->id == CSSValueLinear)
gradientType = CSSDeprecatedLinearGradient;
- else if (equalIgnoringCase(a, "radial"))
+ else if (a->id == CSSValueRadial)
gradientType = CSSDeprecatedRadialGradient;
else
return false;
{
RefPtrWillBeRawPtr<CSSLinearGradientValue> result = CSSLinearGradientValue::create(repeating, CSSLinearGradient);
- CSSParserValueList* args = valueList->current()->function->args.get();
+ CSSParserFunction* function = valueList->current()->function;
+ CSSParserValueList* args = function->args.get();
if (!args || !args->size())
return false;
args->next();
expectComma = true;
- } else if (a->unit == CSSPrimitiveValue::CSS_IDENT && equalIgnoringCase(a, "to")) {
+ } else if (a->unit == CSSPrimitiveValue::CSS_IDENT && a->id == CSSValueTo) {
// to [ [left | right] || [top | bottom] ]
a = args->next();
if (!a)
CSSParserValue* a = valueList->current();
// Now look for color stops.
+ // <color-stop-list> = [ <color-stop> , <color-hint>? ]# , <color-stop>
+ bool supportsColorHints = gradient->gradientType() == CSSLinearGradient
+ || gradient->gradientType() == CSSRadialGradient;
+
+ // The first color stop cannot be a color hint.
+ bool previousStopWasColorHint = true;
while (a) {
// Look for the comma before the next stop.
if (expectComma) {
}
// <color-stop> = <color> [ <percentage> | <length> ]?
+ // <color-hint> = <length> | <percentage>
CSSGradientColorStop stop;
stop.m_color = parseGradientColorOrKeyword(this, a);
- if (!stop.m_color)
+
+ // Two hints in a row are not allowed.
+ if (!stop.m_color && (!supportsColorHints || previousStopWasColorHint))
return false;
+ previousStopWasColorHint = !stop.m_color;
+
+ if (stop.m_color)
+ a = valueList->next();
- a = valueList->next();
if (a) {
if (validUnit(a, FLength | FPercent)) {
stop.m_position = createPrimitiveNumericValue(a);
}
}
+ if (!stop.m_color && !stop.m_position)
+ return false;
+
gradient->addStop(stop);
expectComma = true;
}
+ // The last color stop cannot be a color hint.
+ if (previousStopWasColorHint)
+ return false;
+
// Must have 2 or more stops to be valid.
return gradient->stopCount() >= 2;
}
if (val->unit != CSSParserValue::Function)
return false;
- if (equalIgnoringCase(val->function->name, "-webkit-gradient")) {
+ if (val->function->id == CSSValueWebkitGradient) {
// FIXME: This should send a deprecation message.
if (m_context.useCounter())
m_context.useCounter()->count(UseCounter::DeprecatedWebKitGradient);
return parseDeprecatedGradient(valueList, value);
}
- if (equalIgnoringCase(val->function->name, "-webkit-linear-gradient")) {
+ if (val->function->id == CSSValueWebkitLinearGradient) {
// FIXME: This should send a deprecation message.
if (m_context.useCounter())
m_context.useCounter()->count(UseCounter::DeprecatedWebKitLinearGradient);
return parseDeprecatedLinearGradient(valueList, value, NonRepeating);
}
- if (equalIgnoringCase(val->function->name, "linear-gradient"))
+ if (val->function->id == CSSValueLinearGradient)
return parseLinearGradient(valueList, value, NonRepeating);
- if (equalIgnoringCase(val->function->name, "-webkit-repeating-linear-gradient")) {
+ if (val->function->id == CSSValueWebkitRepeatingLinearGradient) {
// FIXME: This should send a deprecation message.
if (m_context.useCounter())
m_context.useCounter()->count(UseCounter::DeprecatedWebKitRepeatingLinearGradient);
return parseDeprecatedLinearGradient(valueList, value, Repeating);
}
- if (equalIgnoringCase(val->function->name, "repeating-linear-gradient"))
+ if (val->function->id == CSSValueRepeatingLinearGradient)
return parseLinearGradient(valueList, value, Repeating);
- if (equalIgnoringCase(val->function->name, "-webkit-radial-gradient")) {
+ if (val->function->id == CSSValueWebkitRadialGradient) {
// FIXME: This should send a deprecation message.
if (m_context.useCounter())
m_context.useCounter()->count(UseCounter::DeprecatedWebKitRadialGradient);
return parseDeprecatedRadialGradient(valueList, value, NonRepeating);
}
- if (equalIgnoringCase(val->function->name, "radial-gradient"))
+ if (val->function->id == CSSValueRadialGradient)
return parseRadialGradient(valueList, value, NonRepeating);
- if (equalIgnoringCase(val->function->name, "-webkit-repeating-radial-gradient")) {
+ if (val->function->id == CSSValueWebkitRepeatingRadialGradient) {
if (m_context.useCounter())
m_context.useCounter()->count(UseCounter::DeprecatedWebKitRepeatingRadialGradient);
return parseDeprecatedRadialGradient(valueList, value, Repeating);
}
- if (equalIgnoringCase(val->function->name, "repeating-radial-gradient"))
+ if (val->function->id == CSSValueRepeatingRadialGradient)
return parseRadialGradient(valueList, value, Repeating);
- if (equalIgnoringCase(val->function->name, "-webkit-canvas"))
+ if (val->function->id == CSSValueWebkitCanvas)
return parseCanvas(valueList, value);
- if (equalIgnoringCase(val->function->name, "-webkit-cross-fade"))
+ if (val->function->id == CSSValueWebkitCrossFade)
return parseCrossfade(valueList, value);
return false;
return values.release();
}
-static void filterInfoForName(const CSSParserString& name, CSSFilterValue::FilterOperationType& filterType, unsigned& maximumArgumentCount)
-{
- if (equalIgnoringCase(name, "grayscale"))
- filterType = CSSFilterValue::GrayscaleFilterOperation;
- else if (equalIgnoringCase(name, "sepia"))
- filterType = CSSFilterValue::SepiaFilterOperation;
- else if (equalIgnoringCase(name, "saturate"))
- filterType = CSSFilterValue::SaturateFilterOperation;
- else if (equalIgnoringCase(name, "hue-rotate"))
- filterType = CSSFilterValue::HueRotateFilterOperation;
- else if (equalIgnoringCase(name, "invert"))
- filterType = CSSFilterValue::InvertFilterOperation;
- else if (equalIgnoringCase(name, "opacity"))
- filterType = CSSFilterValue::OpacityFilterOperation;
- else if (equalIgnoringCase(name, "brightness"))
- filterType = CSSFilterValue::BrightnessFilterOperation;
- else if (equalIgnoringCase(name, "contrast"))
- filterType = CSSFilterValue::ContrastFilterOperation;
- else if (equalIgnoringCase(name, "blur"))
- filterType = CSSFilterValue::BlurFilterOperation;
- else if (equalIgnoringCase(name, "drop-shadow")) {
- filterType = CSSFilterValue::DropShadowFilterOperation;
+static CSSFilterValue::FilterOperationType filterInfoForId(CSSValueID id, unsigned& maximumArgumentCount)
+{
+ if (id == CSSValueGrayscale)
+ return CSSFilterValue::GrayscaleFilterOperation;
+ if (id == CSSValueSepia)
+ return CSSFilterValue::SepiaFilterOperation;
+ if (id == CSSValueSaturate)
+ return CSSFilterValue::SaturateFilterOperation;
+ if (id == CSSValueHueRotate)
+ return CSSFilterValue::HueRotateFilterOperation;
+ if (id == CSSValueInvert)
+ return CSSFilterValue::InvertFilterOperation;
+ if (id == CSSValueOpacity)
+ return CSSFilterValue::OpacityFilterOperation;
+ if (id == CSSValueBrightness)
+ return CSSFilterValue::BrightnessFilterOperation;
+ if (id == CSSValueContrast)
+ return CSSFilterValue::ContrastFilterOperation;
+ if (id == CSSValueBlur)
+ return CSSFilterValue::BlurFilterOperation;
+ if (id == CSSValueDropShadow) {
maximumArgumentCount = 4; // x-offset, y-offset, blur-radius, color -- spread and inset style not allowed.
+ return CSSFilterValue::DropShadowFilterOperation;
}
+ return CSSFilterValue::UnknownFilterOperation;
}
PassRefPtrWillBeRawPtr<CSSFilterValue> CSSPropertyParser::parseBuiltinFilterArguments(CSSParserValueList* args, CSSFilterValue::FilterOperationType filterType)
list->append(referenceFilterValue);
referenceFilterValue->append(CSSSVGDocumentValue::create(value->string));
} else {
- const CSSParserString name = value->function->name;
unsigned maximumArgumentCount = 1;
- filterInfoForName(name, filterType, maximumArgumentCount);
+ filterType = filterInfoForId(value->function->id, maximumArgumentCount);
if (filterType == CSSFilterValue::UnknownFilterOperation)
return nullptr;
value = m_valueList->next();
if (value) {
if (value->unit == CSSPrimitiveValue::CSS_NUMBER && value->isInt && value->fValue >= 0) {
- tagValue = clampToInteger(value->fValue);
+ tagValue = clampTo<int>(value->fValue);
if (tagValue < 0)
return false;
m_valueList->next();
return false;
ASSERT(!m_parsedCalculation);
- m_parsedCalculation = CSSCalcValue::create(value->function->name, args, range);
+ m_parsedCalculation = CSSCalcValue::create(args, range);
if (!m_parsedCalculation)
return false;
return string.is8Bit() ? cssValueKeywordID(string.characters8(), length) : cssValueKeywordID(string.characters16(), length);
}
+// FIXME: This has nothing to do with parsing properties
bool isValidNthToken(const CSSParserString& token)
{
// The tokenizer checks for the construct of an+b.
return parsedValues.release();
}
+class TransformOperationInfo {
+public:
+ TransformOperationInfo(CSSValueID id)
+ : m_type(CSSTransformValue::UnknownTransformOperation)
+ , m_argCount(1)
+ , m_allowSingleArgument(false)
+ , m_unit(CSSPropertyParser::FUnknown)
+ {
+ switch (id) {
+ case CSSValueSkew:
+ m_unit = CSSPropertyParser::FAngle;
+ m_type = CSSTransformValue::SkewTransformOperation;
+ m_allowSingleArgument = true;
+ m_argCount = 3;
+ break;
+ case CSSValueScale:
+ m_unit = CSSPropertyParser::FNumber;
+ m_type = CSSTransformValue::ScaleTransformOperation;
+ m_allowSingleArgument = true;
+ m_argCount = 3;
+ break;
+ case CSSValueSkewx:
+ m_unit = CSSPropertyParser::FAngle;
+ m_type = CSSTransformValue::SkewXTransformOperation;
+ break;
+ case CSSValueSkewy:
+ m_unit = CSSPropertyParser::FAngle;
+ m_type = CSSTransformValue::SkewYTransformOperation;
+ break;
+ case CSSValueMatrix:
+ m_unit = CSSPropertyParser::FNumber;
+ m_type = CSSTransformValue::MatrixTransformOperation;
+ m_argCount = 11;
+ break;
+ case CSSValueRotate:
+ m_unit = CSSPropertyParser::FAngle;
+ m_type = CSSTransformValue::RotateTransformOperation;
+ break;
+ case CSSValueScalex:
+ m_unit = CSSPropertyParser::FNumber;
+ m_type = CSSTransformValue::ScaleXTransformOperation;
+ break;
+ case CSSValueScaley:
+ m_unit = CSSPropertyParser::FNumber;
+ m_type = CSSTransformValue::ScaleYTransformOperation;
+ break;
+ case CSSValueScalez:
+ m_unit = CSSPropertyParser::FNumber;
+ m_type = CSSTransformValue::ScaleZTransformOperation;
+ break;
+ case CSSValueScale3d:
+ m_unit = CSSPropertyParser::FNumber;
+ m_type = CSSTransformValue::Scale3DTransformOperation;
+ m_argCount = 5;
+ break;
+ case CSSValueRotatex:
+ m_unit = CSSPropertyParser::FAngle;
+ m_type = CSSTransformValue::RotateXTransformOperation;
+ break;
+ case CSSValueRotatey:
+ m_unit = CSSPropertyParser::FAngle;
+ m_type = CSSTransformValue::RotateYTransformOperation;
+ break;
+ case CSSValueRotatez:
+ m_unit = CSSPropertyParser::FAngle;
+ m_type = CSSTransformValue::RotateZTransformOperation;
+ break;
+ case CSSValueMatrix3d:
+ m_unit = CSSPropertyParser::FNumber;
+ m_type = CSSTransformValue::Matrix3DTransformOperation;
+ m_argCount = 31;
+ break;
+ case CSSValueRotate3d:
+ m_unit = CSSPropertyParser::FNumber;
+ m_type = CSSTransformValue::Rotate3DTransformOperation;
+ m_argCount = 7;
+ break;
+ case CSSValueTranslate:
+ m_unit = CSSPropertyParser::FLength | CSSPropertyParser::FPercent;
+ m_type = CSSTransformValue::TranslateTransformOperation;
+ m_allowSingleArgument = true;
+ m_argCount = 3;
+ break;
+ case CSSValueTranslatex:
+ m_unit = CSSPropertyParser::FLength | CSSPropertyParser::FPercent;
+ m_type = CSSTransformValue::TranslateXTransformOperation;
+ break;
+ case CSSValueTranslatey:
+ m_unit = CSSPropertyParser::FLength | CSSPropertyParser::FPercent;
+ m_type = CSSTransformValue::TranslateYTransformOperation;
+ break;
+ case CSSValueTranslatez:
+ m_unit = CSSPropertyParser::FLength | CSSPropertyParser::FPercent;
+ m_type = CSSTransformValue::TranslateZTransformOperation;
+ break;
+ case CSSValuePerspective:
+ m_unit = CSSPropertyParser::FNumber;
+ m_type = CSSTransformValue::PerspectiveTransformOperation;
+ break;
+ case CSSValueTranslate3d:
+ m_unit = CSSPropertyParser::FLength | CSSPropertyParser::FPercent;
+ m_type = CSSTransformValue::Translate3DTransformOperation;
+ m_argCount = 5;
+ break;
+ default:
+ m_type = CSSTransformValue::UnknownTransformOperation;
+ break;
+ }
+ }
+
+ CSSTransformValue::TransformOperationType type() const { return m_type; }
+ unsigned argCount() const { return m_argCount; }
+ CSSPropertyParser::Units unit() const { return m_unit; }
+
+ bool unknown() const { return m_type == CSSTransformValue::UnknownTransformOperation; }
+ bool hasCorrectArgCount(unsigned argCount) { return m_argCount == argCount || (m_allowSingleArgument && argCount == 1); }
+
+private:
+ CSSTransformValue::TransformOperationType m_type;
+ unsigned m_argCount;
+ bool m_allowSingleArgument;
+ CSSPropertyParser::Units m_unit;
+};
+
+PassRefPtrWillBeRawPtr<CSSValueList> CSSPropertyParser::parseTransform(CSSPropertyID propId)
+{
+ if (!m_valueList)
+ return nullptr;
+
+ RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
+ for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
+ RefPtrWillBeRawPtr<CSSValue> parsedTransformValue = parseTransformValue(propId, value);
+ if (!parsedTransformValue)
+ return nullptr;
+
+ list->append(parsedTransformValue.release());
+ }
+
+ return list.release();
+}
+
+PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseTransformValue(CSSPropertyID propId, CSSParserValue *value)
+{
+ if (value->unit != CSSParserValue::Function || !value->function)
+ return nullptr;
+
+ // Every primitive requires at least one argument.
+ CSSParserValueList* args = value->function->args.get();
+ if (!args)
+ return nullptr;
+
+ // See if the specified primitive is one we understand.
+ TransformOperationInfo info(value->function->id);
+ if (info.unknown())
+ return nullptr;
+
+ if (!info.hasCorrectArgCount(args->size()))
+ return nullptr;
+
+ // The transform is a list of functional primitives that specify transform operations.
+ // We collect a list of CSSTransformValues, where each value specifies a single operation.
+
+ // Create the new CSSTransformValue for this operation and add it to our list.
+ RefPtrWillBeRawPtr<CSSTransformValue> transformValue = CSSTransformValue::create(info.type());
+
+ // Snag our values.
+ CSSParserValue* a = args->current();
+ unsigned argNumber = 0;
+ while (a) {
+ CSSPropertyParser::Units unit = info.unit();
+
+ if (info.type() == CSSTransformValue::Rotate3DTransformOperation && argNumber == 3) {
+ // 4th param of rotate3d() is an angle rather than a bare number, validate it as such
+ if (!validUnit(a, FAngle, HTMLStandardMode))
+ return nullptr;
+ } else if (info.type() == CSSTransformValue::Translate3DTransformOperation && argNumber == 2) {
+ // 3rd param of translate3d() cannot be a percentage
+ if (!validUnit(a, FLength, HTMLStandardMode))
+ return nullptr;
+ } else if (info.type() == CSSTransformValue::TranslateZTransformOperation && !argNumber) {
+ // 1st param of translateZ() cannot be a percentage
+ if (!validUnit(a, FLength, HTMLStandardMode))
+ return nullptr;
+ } else if (info.type() == CSSTransformValue::PerspectiveTransformOperation && !argNumber) {
+ // 1st param of perspective() must be a non-negative number (deprecated) or length.
+ if ((propId == CSSPropertyWebkitTransform && !validUnit(a, FNumber | FLength | FNonNeg, HTMLStandardMode))
+ || (propId == CSSPropertyTransform && !validUnit(a, FLength | FNonNeg, HTMLStandardMode)))
+ return nullptr;
+ } else if (!validUnit(a, unit, HTMLStandardMode)) {
+ return nullptr;
+ }
+
+ // Add the value to the current transform operation.
+ transformValue->append(createPrimitiveNumericValue(a));
+
+ a = args->next();
+ if (!a)
+ break;
+ if (a->unit != CSSParserValue::Operator || a->iValue != ',')
+ return nullptr;
+ a = args->next();
+
+ argNumber++;
+ }
+
+ return transformValue.release();
+}
+
} // namespace blink