blob: 06a5c79287745e9d8ccc0dd4105d8ea2f51b0660 [file] [log] [blame]
/*
* Copyright (C) 2003 Lars Knoll (knoll@kde.org)
* Copyright (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com)
* Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved.
* Copyright (C) 2007 Nicholas Shanks <webkit@nickshanks.com>
* Copyright (C) 2008 Eric Seidel <eric@webkit.org>
* Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
* Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved.
* Copyright (C) 2012 Intel Corporation. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "config.h"
#include "core/css/CSSParser.h"
#include "CSSValueKeywords.h"
#include "RuntimeEnabledFeatures.h"
#include "StylePropertyShorthand.h"
#include "core/css/CSSArrayFunctionValue.h"
#include "core/css/CSSAspectRatioValue.h"
#include "core/css/CSSBasicShapes.h"
#include "core/css/CSSBorderImage.h"
#include "core/css/CSSCanvasValue.h"
#include "core/css/CSSCrossfadeValue.h"
#include "core/css/CSSCursorImageValue.h"
#include "core/css/CSSFontFaceSrcValue.h"
#include "core/css/CSSFontFeatureValue.h"
#include "core/css/CSSFunctionValue.h"
#include "core/css/CSSGradientValue.h"
#include "core/css/CSSGridTemplateValue.h"
#include "core/css/CSSImageSetValue.h"
#include "core/css/CSSImageValue.h"
#include "core/css/CSSInheritedValue.h"
#include "core/css/CSSInitialValue.h"
#include "core/css/CSSKeyframeRule.h"
#include "core/css/CSSKeyframesRule.h"
#include "core/css/CSSLineBoxContainValue.h"
#include "core/css/CSSMixFunctionValue.h"
#include "core/css/CSSPrimitiveValue.h"
#include "core/css/CSSPropertySourceData.h"
#include "core/css/CSSReflectValue.h"
#include "core/css/CSSSVGDocumentValue.h"
#include "core/css/CSSSelector.h"
#include "core/css/CSSShaderValue.h"
#include "core/css/CSSShadowValue.h"
#include "core/css/CSSStyleSheet.h"
#include "core/css/CSSTimingFunctionValue.h"
#include "core/css/CSSTransformValue.h"
#include "core/css/CSSUnicodeRangeValue.h"
#include "core/css/CSSValueList.h"
#include "core/css/CSSValuePool.h"
#include "core/css/CSSVariableValue.h"
#include "core/css/Counter.h"
#include "core/css/HashTools.h"
#include "core/css/MediaList.h"
#include "core/css/MediaQueryExp.h"
#include "core/css/Pair.h"
#include "core/css/Rect.h"
#include "core/css/StylePropertySet.h"
#include "core/css/StyleRule.h"
#include "core/css/StyleRuleImport.h"
#include "core/css/StyleSheetContents.h"
#include "core/dom/Document.h"
#include "core/html/parser/HTMLParserIdioms.h"
#include "core/inspector/InspectorInstrumentation.h"
#include "core/page/PageConsole.h"
#include "core/page/Settings.h"
#include "core/rendering/RenderTheme.h"
#include "core/svg/SVGParserUtilities.h"
#include "platform/FloatConversion.h"
#include "wtf/BitArray.h"
#include "wtf/HexNumber.h"
#include "wtf/text/StringBuffer.h"
#include "wtf/text/StringBuilder.h"
#include "wtf/text/StringImpl.h"
#include "wtf/text/TextEncoding.h"
#include <limits.h>
#define YYDEBUG 0
#if YYDEBUG > 0
extern int cssyydebug;
#endif
extern int cssyyparse(WebCore::CSSParser*);
using namespace std;
using namespace WTF;
namespace WebCore {
static const unsigned INVALID_NUM_PARSED_PROPERTIES = UINT_MAX;
static const double MAX_SCALE = 1000000;
template <unsigned N>
static bool equal(const CSSParserString& a, const char (&b)[N])
{
unsigned length = N - 1; // Ignore the trailing null character
if (a.length() != length)
return false;
return a.is8Bit() ? WTF::equal(a.characters8(), reinterpret_cast<const LChar*>(b), length) : WTF::equal(a.characters16(), reinterpret_cast<const LChar*>(b), length);
}
template <unsigned N>
static bool equalIgnoringCase(const CSSParserString& a, const char (&b)[N])
{
unsigned length = N - 1; // Ignore the trailing null character
if (a.length() != length)
return false;
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 bool hasPrefix(const char* string, unsigned length, const char* prefix)
{
for (unsigned i = 0; i < length; ++i) {
if (!prefix[i])
return true;
if (string[i] != prefix[i])
return false;
}
return false;
}
static PassRefPtr<CSSPrimitiveValue> createPrimitiveValuePair(PassRefPtr<CSSPrimitiveValue> first, PassRefPtr<CSSPrimitiveValue> second, Pair::IdenticalValuesPolicy identicalValuesPolicy = Pair::DropIdenticalValues)
{
return cssValuePool().createValue(Pair::create(first, second, identicalValuesPolicy));
}
class AnimationParseContext {
public:
AnimationParseContext()
: m_animationPropertyKeywordAllowed(true)
, m_firstAnimationCommitted(false)
, m_hasSeenAnimationPropertyKeyword(false)
{
}
void commitFirstAnimation()
{
m_firstAnimationCommitted = true;
}
bool hasCommittedFirstAnimation() const
{
return m_firstAnimationCommitted;
}
void commitAnimationPropertyKeyword()
{
m_animationPropertyKeywordAllowed = false;
}
bool animationPropertyKeywordAllowed() const
{
return m_animationPropertyKeywordAllowed;
}
bool hasSeenAnimationPropertyKeyword() const
{
return m_hasSeenAnimationPropertyKeyword;
}
void sawAnimationPropertyKeyword()
{
m_hasSeenAnimationPropertyKeyword = true;
}
private:
bool m_animationPropertyKeywordAllowed;
bool m_firstAnimationCommitted;
bool m_hasSeenAnimationPropertyKeyword;
};
const CSSParserContext& strictCSSParserContext()
{
DEFINE_STATIC_LOCAL(CSSParserContext, strictContext, (HTMLStandardMode));
return strictContext;
}
CSSParserContext::CSSParserContext(CSSParserMode mode, const KURL& baseURL)
: baseURL(baseURL)
, mode(mode)
, isHTMLDocument(false)
, needsSiteSpecificQuirks(false)
, useLegacyBackgroundSizeShorthandBehavior(false)
{
}
CSSParserContext::CSSParserContext(const Document& document, const KURL& baseURL, const String& charset)
: baseURL(baseURL.isNull() ? document.baseURL() : baseURL)
, charset(charset)
, mode(document.inQuirksMode() ? HTMLQuirksMode : HTMLStandardMode)
, isHTMLDocument(document.isHTMLDocument())
, needsSiteSpecificQuirks(document.settings() ? document.settings()->needsSiteSpecificQuirks() : false)
, useLegacyBackgroundSizeShorthandBehavior(document.settings() ? document.settings()->useLegacyBackgroundSizeShorthandBehavior() : false)
{
}
bool operator==(const CSSParserContext& a, const CSSParserContext& b)
{
return a.baseURL == b.baseURL
&& a.charset == b.charset
&& a.mode == b.mode
&& a.isHTMLDocument == b.isHTMLDocument
&& a.needsSiteSpecificQuirks == b.needsSiteSpecificQuirks
&& a.useLegacyBackgroundSizeShorthandBehavior == b.useLegacyBackgroundSizeShorthandBehavior;
}
CSSParser::CSSParser(const CSSParserContext& context, UseCounter* counter)
: m_context(context)
, m_important(false)
, m_id(CSSPropertyInvalid)
, m_styleSheet(0)
, m_supportsCondition(false)
, m_selectorListForParseSelector(0)
, m_numParsedPropertiesBeforeMarginBox(INVALID_NUM_PARSED_PROPERTIES)
, m_inParseShorthand(0)
, m_currentShorthand(CSSPropertyInvalid)
, m_implicitShorthand(false)
, m_hasFontFaceOnlyValues(false)
, m_hadSyntacticallyValidCSSRule(false)
, m_logErrors(false)
, m_ignoreErrors(false)
, m_inFilterRule(false)
, m_defaultNamespace(starAtom)
, m_parsedTextPrefixLength(0)
, m_parsedTextSuffixLength(0)
, m_sourceDataHandler(0)
, m_parsingMode(NormalMode)
, m_is8BitSource(false)
, m_currentCharacter8(0)
, m_currentCharacter16(0)
, m_source(0)
, m_length(0)
, m_token(0)
, m_lineNumber(0)
, m_tokenStartLineNumber(0)
, m_ruleHeaderType(CSSRuleSourceData::UNKNOWN_RULE)
, m_allowImportRules(true)
, m_allowNamespaceDeclarations(true)
, m_inViewport(false)
, m_useCounter(counter)
{
#if YYDEBUG > 0
cssyydebug = 1;
#endif
m_tokenStart.ptr8 = 0;
CSSPropertySourceData::init();
}
CSSParser::~CSSParser()
{
clearProperties();
deleteAllValues(m_floatingSelectors);
deleteAllValues(m_floatingSelectorVectors);
deleteAllValues(m_floatingValueLists);
deleteAllValues(m_floatingFunctions);
}
AtomicString CSSParserString::atomicSubstring(unsigned position, unsigned length) const
{
ASSERT(m_length >= position + length);
if (is8Bit())
return AtomicString(characters8() + position, length);
return AtomicString(characters16() + position, length);
}
void CSSParserString::trimTrailingWhitespace()
{
if (is8Bit()) {
while (m_length > 0 && isHTMLSpace<LChar>(m_data.characters8[m_length - 1]))
--m_length;
} else {
while (m_length > 0 && isHTMLSpace<UChar>(m_data.characters16[m_length - 1]))
--m_length;
}
}
void CSSParser::setupParser(const char* prefix, unsigned prefixLength, const String& string, const char* suffix, unsigned suffixLength)
{
m_parsedTextPrefixLength = prefixLength;
m_parsedTextSuffixLength = suffixLength;
unsigned stringLength = string.length();
unsigned length = stringLength + m_parsedTextPrefixLength + m_parsedTextSuffixLength + 1;
m_length = length;
if (!stringLength || string.is8Bit()) {
m_dataStart8 = adoptArrayPtr(new LChar[length]);
for (unsigned i = 0; i < m_parsedTextPrefixLength; i++)
m_dataStart8[i] = prefix[i];
if (stringLength)
memcpy(m_dataStart8.get() + m_parsedTextPrefixLength, string.characters8(), stringLength * sizeof(LChar));
unsigned start = m_parsedTextPrefixLength + stringLength;
unsigned end = start + suffixLength;
for (unsigned i = start; i < end; i++)
m_dataStart8[i] = suffix[i - start];
m_dataStart8[length - 1] = 0;
m_is8BitSource = true;
m_currentCharacter8 = m_dataStart8.get();
m_currentCharacter16 = 0;
setTokenStart<LChar>(m_currentCharacter8);
m_lexFunc = &CSSParser::realLex<LChar>;
return;
}
m_dataStart16 = adoptArrayPtr(new UChar[length]);
for (unsigned i = 0; i < m_parsedTextPrefixLength; i++)
m_dataStart16[i] = prefix[i];
ASSERT(stringLength);
memcpy(m_dataStart16.get() + m_parsedTextPrefixLength, string.characters16(), stringLength * sizeof(UChar));
unsigned start = m_parsedTextPrefixLength + stringLength;
unsigned end = start + suffixLength;
for (unsigned i = start; i < end; i++)
m_dataStart16[i] = suffix[i - start];
m_dataStart16[length - 1] = 0;
m_is8BitSource = false;
m_currentCharacter8 = 0;
m_currentCharacter16 = m_dataStart16.get();
setTokenStart<UChar>(m_currentCharacter16);
m_lexFunc = &CSSParser::realLex<UChar>;
}
void CSSParser::parseSheet(StyleSheetContents* sheet, const String& string, const TextPosition& startPosition, SourceDataHandler* sourceDataHandler, bool logErrors)
{
setStyleSheet(sheet);
m_defaultNamespace = starAtom; // Reset the default namespace.
m_sourceDataHandler = sourceDataHandler;
m_logErrors = logErrors && sheet->singleOwnerDocument() && !sheet->baseURL().isEmpty() && sheet->singleOwnerDocument()->page();
m_ignoreErrors = false;
m_lineNumber = 0;
m_startPosition = startPosition;
m_source = &string;
setupParser("", string, "");
cssyyparse(this);
sheet->shrinkToFit();
m_source = 0;
m_sourceDataHandler = 0;
m_rule = 0;
m_lineEndings.clear();
m_ignoreErrors = false;
m_logErrors = false;
}
PassRefPtr<StyleRuleBase> CSSParser::parseRule(StyleSheetContents* sheet, const String& string)
{
setStyleSheet(sheet);
m_allowNamespaceDeclarations = false;
setupParser("@-internal-rule ", string, "");
cssyyparse(this);
return m_rule.release();
}
PassRefPtr<StyleKeyframe> CSSParser::parseKeyframeRule(StyleSheetContents* sheet, const String& string)
{
setStyleSheet(sheet);
setupParser("@-internal-keyframe-rule ", string, "");
cssyyparse(this);
return m_keyframe.release();
}
PassOwnPtr<Vector<double> > CSSParser::parseKeyframeKeyList(const String& string)
{
setupParser("@-internal-keyframe-key-list ", string, "");
cssyyparse(this);
ASSERT(m_valueList);
return StyleKeyframe::createKeyList(m_valueList.get());
}
bool CSSParser::parseSupportsCondition(const String& string)
{
m_supportsCondition = false;
setupParser("@-internal-supports-condition ", string, "");
cssyyparse(this);
return m_supportsCondition;
}
static inline bool isColorPropertyID(CSSPropertyID propertyId)
{
switch (propertyId) {
case CSSPropertyColor:
case CSSPropertyBackgroundColor:
case CSSPropertyBorderBottomColor:
case CSSPropertyBorderLeftColor:
case CSSPropertyBorderRightColor:
case CSSPropertyBorderTopColor:
case CSSPropertyOutlineColor:
case CSSPropertyTextLineThroughColor:
case CSSPropertyTextOverlineColor:
case CSSPropertyTextUnderlineColor:
case CSSPropertyWebkitBorderAfterColor:
case CSSPropertyWebkitBorderBeforeColor:
case CSSPropertyWebkitBorderEndColor:
case CSSPropertyWebkitBorderStartColor:
case CSSPropertyWebkitColumnRuleColor:
case CSSPropertyWebkitTextEmphasisColor:
case CSSPropertyWebkitTextFillColor:
case CSSPropertyWebkitTextStrokeColor:
return true;
case CSSPropertyTextDecorationColor:
return RuntimeEnabledFeatures::css3TextDecorationsEnabled();
default:
return false;
}
}
static bool parseColorValue(MutableStylePropertySet* declaration, CSSPropertyID propertyId, const String& string, bool important, CSSParserMode cssParserMode)
{
ASSERT(!string.isEmpty());
bool quirksMode = isQuirksModeBehavior(cssParserMode);
if (!isColorPropertyID(propertyId))
return false;
CSSParserString cssString;
cssString.init(string);
CSSValueID valueID = cssValueKeywordID(cssString);
bool validPrimitive = false;
if (valueID == CSSValueWebkitText) {
validPrimitive = true;
} else if (valueID == CSSValueCurrentcolor) {
validPrimitive = true;
} else if ((valueID >= CSSValueAqua && valueID <= CSSValueWindowtext) || valueID == CSSValueMenu
|| (quirksMode && valueID >= CSSValueWebkitFocusRingColor && valueID < CSSValueWebkitText)) {
validPrimitive = true;
}
if (validPrimitive) {
RefPtr<CSSValue> value = cssValuePool().createIdentifierValue(valueID);
declaration->addParsedProperty(CSSProperty(propertyId, value.release(), important));
return true;
}
RGBA32 color;
if (!CSSParser::fastParseColor(color, string, !quirksMode && string[0] != '#'))
return false;
RefPtr<CSSValue> value = cssValuePool().createColorValue(color);
declaration->addParsedProperty(CSSProperty(propertyId, value.release(), important));
return true;
}
static inline bool isSimpleLengthPropertyID(CSSPropertyID propertyId, bool& acceptsNegativeNumbers)
{
switch (propertyId) {
case CSSPropertyFontSize:
case CSSPropertyHeight:
case CSSPropertyWidth:
case CSSPropertyMinHeight:
case CSSPropertyMinWidth:
case CSSPropertyPaddingBottom:
case CSSPropertyPaddingLeft:
case CSSPropertyPaddingRight:
case CSSPropertyPaddingTop:
case CSSPropertyWebkitLogicalWidth:
case CSSPropertyWebkitLogicalHeight:
case CSSPropertyWebkitMinLogicalWidth:
case CSSPropertyWebkitMinLogicalHeight:
case CSSPropertyWebkitPaddingAfter:
case CSSPropertyWebkitPaddingBefore:
case CSSPropertyWebkitPaddingEnd:
case CSSPropertyWebkitPaddingStart:
acceptsNegativeNumbers = false;
return true;
case CSSPropertyShapeMargin:
case CSSPropertyShapePadding:
acceptsNegativeNumbers = false;
return RuntimeEnabledFeatures::cssShapesEnabled();
case CSSPropertyBottom:
case CSSPropertyLeft:
case CSSPropertyMarginBottom:
case CSSPropertyMarginLeft:
case CSSPropertyMarginRight:
case CSSPropertyMarginTop:
case CSSPropertyRight:
case CSSPropertyTop:
case CSSPropertyWebkitMarginAfter:
case CSSPropertyWebkitMarginBefore:
case CSSPropertyWebkitMarginEnd:
case CSSPropertyWebkitMarginStart:
acceptsNegativeNumbers = true;
return true;
default:
return false;
}
}
template <typename CharacterType>
static inline bool parseSimpleLength(const CharacterType* characters, unsigned& length, CSSPrimitiveValue::UnitTypes& unit, double& number)
{
if (length > 2 && (characters[length - 2] | 0x20) == 'p' && (characters[length - 1] | 0x20) == 'x') {
length -= 2;
unit = CSSPrimitiveValue::CSS_PX;
} else if (length > 1 && characters[length - 1] == '%') {
length -= 1;
unit = CSSPrimitiveValue::CSS_PERCENTAGE;
}
// We rely on charactersToDouble for validation as well. The function
// will set "ok" to "false" if the entire passed-in character range does
// not represent a double.
bool ok;
number = charactersToDouble(characters, length, &ok);
return ok;
}
static bool parseSimpleLengthValue(MutableStylePropertySet* declaration, CSSPropertyID propertyId, const String& string, bool important, CSSParserMode cssParserMode)
{
ASSERT(!string.isEmpty());
bool acceptsNegativeNumbers;
// In @viewport, width and height are shorthands, not simple length values.
if (isCSSViewportParsingEnabledForMode(cssParserMode) || !isSimpleLengthPropertyID(propertyId, acceptsNegativeNumbers))
return false;
unsigned length = string.length();
double number;
CSSPrimitiveValue::UnitTypes unit = CSSPrimitiveValue::CSS_NUMBER;
if (string.is8Bit()) {
if (!parseSimpleLength(string.characters8(), length, unit, number))
return false;
} else {
if (!parseSimpleLength(string.characters16(), length, unit, number))
return false;
}
if (unit == CSSPrimitiveValue::CSS_NUMBER) {
bool quirksMode = isQuirksModeBehavior(cssParserMode);
if (number && !quirksMode)
return false;
unit = CSSPrimitiveValue::CSS_PX;
}
if (number < 0 && !acceptsNegativeNumbers)
return false;
RefPtr<CSSValue> value = cssValuePool().createValue(number, unit);
declaration->addParsedProperty(CSSProperty(propertyId, value.release(), important));
return true;
}
static inline bool isValidKeywordPropertyAndValue(CSSPropertyID propertyId, int valueID, const CSSParserContext& parserContext)
{
if (!valueID)
return false;
switch (propertyId) {
case CSSPropertyBorderCollapse: // collapse | separate | inherit
if (valueID == CSSValueCollapse || valueID == CSSValueSeparate)
return true;
break;
case CSSPropertyBorderTopStyle: // <border-style> | inherit
case CSSPropertyBorderRightStyle: // Defined as: none | hidden | dotted | dashed |
case CSSPropertyBorderBottomStyle: // solid | double | groove | ridge | inset | outset
case CSSPropertyBorderLeftStyle:
case CSSPropertyWebkitBorderAfterStyle:
case CSSPropertyWebkitBorderBeforeStyle:
case CSSPropertyWebkitBorderEndStyle:
case CSSPropertyWebkitBorderStartStyle:
case CSSPropertyWebkitColumnRuleStyle:
if (valueID >= CSSValueNone && valueID <= CSSValueDouble)
return true;
break;
case CSSPropertyBoxSizing:
if (valueID == CSSValueBorderBox || valueID == CSSValueContentBox)
return true;
break;
case CSSPropertyCaptionSide: // top | bottom | left | right | inherit
if (valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueTop || valueID == CSSValueBottom)
return true;
break;
case CSSPropertyClear: // none | left | right | both | inherit
if (valueID == CSSValueNone || valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueBoth)
return true;
break;
case CSSPropertyDirection: // ltr | rtl | inherit
if (valueID == CSSValueLtr || valueID == CSSValueRtl)
return true;
break;
case CSSPropertyDisplay:
// inline | block | list-item | run-in | inline-block | table |
// inline-table | table-row-group | table-header-group | table-footer-group | table-row |
// table-column-group | table-column | table-cell | table-caption | -webkit-box | -webkit-inline-box | none | inherit
// flex | inline-flex | -webkit-flex | -webkit-inline-flex | grid | inline-grid | lazy-block
if ((valueID >= CSSValueInline && valueID <= CSSValueInlineFlex) || valueID == CSSValueWebkitFlex || valueID == CSSValueWebkitInlineFlex || valueID == CSSValueNone)
return true;
if (valueID == CSSValueGrid || valueID == CSSValueInlineGrid)
return RuntimeEnabledFeatures::cssGridLayoutEnabled();
break;
case CSSPropertyEmptyCells: // show | hide | inherit
if (valueID == CSSValueShow || valueID == CSSValueHide)
return true;
break;
case CSSPropertyFloat: // left | right | none | center (for buggy CSS, maps to none)
if (valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueNone || valueID == CSSValueCenter)
return true;
break;
case CSSPropertyFontStyle: // normal | italic | oblique | inherit
if (valueID == CSSValueNormal || valueID == CSSValueItalic || valueID == CSSValueOblique)
return true;
break;
case CSSPropertyImageRendering: // auto | optimizeContrast
if (valueID == CSSValueAuto || valueID == CSSValueWebkitOptimizeContrast)
return true;
break;
case CSSPropertyIsolation: // auto | isolate
if (valueID == CSSValueAuto || valueID == CSSValueIsolate)
return RuntimeEnabledFeatures::cssCompositingEnabled();
break;
case CSSPropertyListStylePosition: // inside | outside | inherit
if (valueID == CSSValueInside || valueID == CSSValueOutside)
return true;
break;
case CSSPropertyListStyleType:
// See section CSS_PROP_LIST_STYLE_TYPE of file CSSValueKeywords.in
// for the list of supported list-style-types.
if ((valueID >= CSSValueDisc && valueID <= CSSValueKatakanaIroha) || valueID == CSSValueNone)
return true;
break;
case CSSPropertyObjectFit:
if (RuntimeEnabledFeatures::objectFitPositionEnabled()) {
if (valueID == CSSValueFill || valueID == CSSValueContain || valueID == CSSValueCover || valueID == CSSValueNone || valueID == CSSValueScaleDown)
return true;
}
break;
case CSSPropertyOutlineStyle: // (<border-style> except hidden) | auto | inherit
if (valueID == CSSValueAuto || valueID == CSSValueNone || (valueID >= CSSValueInset && valueID <= CSSValueDouble))
return true;
break;
case CSSPropertyOverflowWrap: // normal | break-word
case CSSPropertyWordWrap:
if (valueID == CSSValueNormal || valueID == CSSValueBreakWord)
return true;
break;
case CSSPropertyOverflowX: // visible | hidden | scroll | auto | overlay | inherit
if (valueID == CSSValueVisible || valueID == CSSValueHidden || valueID == CSSValueScroll || valueID == CSSValueAuto || valueID == CSSValueOverlay)
return true;
break;
case CSSPropertyOverflowY: // visible | hidden | scroll | auto | overlay | inherit | -webkit-paged-x | -webkit-paged-y
if (valueID == CSSValueVisible || valueID == CSSValueHidden || valueID == CSSValueScroll || valueID == CSSValueAuto || valueID == CSSValueOverlay || valueID == CSSValueWebkitPagedX || valueID == CSSValueWebkitPagedY)
return true;
break;
case CSSPropertyPageBreakAfter: // auto | always | avoid | left | right | inherit
case CSSPropertyPageBreakBefore:
case CSSPropertyWebkitColumnBreakAfter:
case CSSPropertyWebkitColumnBreakBefore:
if (valueID == CSSValueAuto || valueID == CSSValueAlways || valueID == CSSValueAvoid || valueID == CSSValueLeft || valueID == CSSValueRight)
return true;
break;
case CSSPropertyPageBreakInside: // avoid | auto | inherit
case CSSPropertyWebkitColumnBreakInside:
if (valueID == CSSValueAuto || valueID == CSSValueAvoid)
return true;
break;
case CSSPropertyPointerEvents:
// none | visiblePainted | visibleFill | visibleStroke | visible |
// painted | fill | stroke | auto | all | inherit
if (valueID == CSSValueVisible || valueID == CSSValueNone || valueID == CSSValueAll || valueID == CSSValueAuto || (valueID >= CSSValueVisiblepainted && valueID <= CSSValueStroke))
return true;
break;
case CSSPropertyPosition: // static | relative | absolute | fixed | sticky | inherit
if (valueID == CSSValueStatic || valueID == CSSValueRelative || valueID == CSSValueAbsolute || valueID == CSSValueFixed
|| (RuntimeEnabledFeatures::cssStickyPositionEnabled() && valueID == CSSValueSticky))
return true;
break;
case CSSPropertyResize: // none | both | horizontal | vertical | auto
if (valueID == CSSValueNone || valueID == CSSValueBoth || valueID == CSSValueHorizontal || valueID == CSSValueVertical || valueID == CSSValueAuto)
return true;
break;
case CSSPropertySpeak: // none | normal | spell-out | digits | literal-punctuation | no-punctuation | inherit
if (valueID == CSSValueNone || valueID == CSSValueNormal || valueID == CSSValueSpellOut || valueID == CSSValueDigits || valueID == CSSValueLiteralPunctuation || valueID == CSSValueNoPunctuation)
return true;
break;
case CSSPropertyTableLayout: // auto | fixed | inherit
if (valueID == CSSValueAuto || valueID == CSSValueFixed)
return true;
break;
case CSSPropertyTextAlignLast:
// auto | start | end | left | right | center | justify
if (RuntimeEnabledFeatures::css3TextEnabled()
&& ((valueID >= CSSValueLeft && valueID <= CSSValueJustify) || valueID == CSSValueStart || valueID == CSSValueEnd || valueID == CSSValueAuto))
return true;
break;
case CSSPropertyTextJustify:
// auto | none | inter-word | distribute
if (RuntimeEnabledFeatures::css3TextEnabled()
&& (valueID == CSSValueInterWord || valueID == CSSValueDistribute || valueID == CSSValueAuto || valueID == CSSValueNone))
return true;
break;
case CSSPropertyTextLineThroughMode:
case CSSPropertyTextOverlineMode:
case CSSPropertyTextUnderlineMode:
if (valueID == CSSValueContinuous || valueID == CSSValueSkipWhiteSpace)
return true;
break;
case CSSPropertyTextLineThroughStyle:
case CSSPropertyTextOverlineStyle:
case CSSPropertyTextUnderlineStyle:
if (valueID == CSSValueNone || valueID == CSSValueSolid || valueID == CSSValueDouble || valueID == CSSValueDashed || valueID == CSSValueDotDash || valueID == CSSValueDotDotDash || valueID == CSSValueWave)
return true;
break;
case CSSPropertyTextOverflow: // clip | ellipsis
if (valueID == CSSValueClip || valueID == CSSValueEllipsis)
return true;
break;
case CSSPropertyTextRendering: // auto | optimizeSpeed | optimizeLegibility | geometricPrecision
if (valueID == CSSValueAuto || valueID == CSSValueOptimizespeed || valueID == CSSValueOptimizelegibility || valueID == CSSValueGeometricprecision)
return true;
break;
case CSSPropertyTextTransform: // capitalize | uppercase | lowercase | none | inherit
if ((valueID >= CSSValueCapitalize && valueID <= CSSValueLowercase) || valueID == CSSValueNone)
return true;
break;
case CSSPropertyTouchAction: // auto | none
if (RuntimeEnabledFeatures::cssTouchActionEnabled() && (valueID == CSSValueAuto || valueID == CSSValueNone))
return true;
break;
case CSSPropertyTouchActionDelay: // none | script
if (RuntimeEnabledFeatures::cssTouchActionEnabled() && (valueID == CSSValueScript || valueID == CSSValueNone))
return true;
break;
case CSSPropertyVisibility: // visible | hidden | collapse | inherit
if (valueID == CSSValueVisible || valueID == CSSValueHidden || valueID == CSSValueCollapse)
return true;
break;
case CSSPropertyWebkitAppearance:
if ((valueID >= CSSValueCheckbox && valueID <= CSSValueTextarea) || valueID == CSSValueNone)
return true;
break;
case CSSPropertyWebkitBackfaceVisibility:
if (valueID == CSSValueVisible || valueID == CSSValueHidden)
return true;
break;
case CSSPropertyMixBlendMode:
if (RuntimeEnabledFeatures::cssCompositingEnabled() && (valueID == CSSValueNormal || valueID == CSSValueMultiply || valueID == CSSValueScreen
|| valueID == CSSValueOverlay || valueID == CSSValueDarken || valueID == CSSValueLighten || valueID == CSSValueColorDodge
|| valueID == CSSValueColorBurn || valueID == CSSValueHardLight || valueID == CSSValueSoftLight || valueID == CSSValueDifference
|| valueID == CSSValueExclusion || valueID == CSSValueHue || valueID == CSSValueSaturation || valueID == CSSValueColor
|| valueID == CSSValueLuminosity))
return true;
break;
case CSSPropertyWebkitBorderFit:
if (valueID == CSSValueBorder || valueID == CSSValueLines)
return true;
break;
case CSSPropertyWebkitBoxAlign:
if (valueID == CSSValueStretch || valueID == CSSValueStart || valueID == CSSValueEnd || valueID == CSSValueCenter || valueID == CSSValueBaseline)
return true;
break;
case CSSPropertyWebkitBoxDecorationBreak:
if (valueID == CSSValueClone || valueID == CSSValueSlice)
return true;
break;
case CSSPropertyWebkitBoxDirection:
if (valueID == CSSValueNormal || valueID == CSSValueReverse)
return true;
break;
case CSSPropertyWebkitBoxLines:
if (valueID == CSSValueSingle || valueID == CSSValueMultiple)
return true;
break;
case CSSPropertyWebkitBoxOrient:
if (valueID == CSSValueHorizontal || valueID == CSSValueVertical || valueID == CSSValueInlineAxis || valueID == CSSValueBlockAxis)
return true;
break;
case CSSPropertyWebkitBoxPack:
if (valueID == CSSValueStart || valueID == CSSValueEnd || valueID == CSSValueCenter || valueID == CSSValueJustify)
return true;
break;
case CSSPropertyInternalCallback:
// This property is only injected programmatically, not parsed from stylesheets.
return false;
case CSSPropertyColumnFill:
if (RuntimeEnabledFeatures::regionBasedColumnsEnabled()) {
if (valueID == CSSValueAuto || valueID == CSSValueBalance)
return true;
}
break;
case CSSPropertyAlignContent:
if (valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueSpaceBetween || valueID == CSSValueSpaceAround || valueID == CSSValueStretch)
return true;
break;
case CSSPropertyAlignItems:
if (valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueBaseline || valueID == CSSValueStretch)
return true;
break;
case CSSPropertyAlignSelf:
if (valueID == CSSValueAuto || valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueBaseline || valueID == CSSValueStretch)
return true;
break;
case CSSPropertyFlexDirection:
if (valueID == CSSValueRow || valueID == CSSValueRowReverse || valueID == CSSValueColumn || valueID == CSSValueColumnReverse)
return true;
break;
case CSSPropertyFlexWrap:
if (valueID == CSSValueNowrap || valueID == CSSValueWrap || valueID == CSSValueWrapReverse)
return true;
break;
case CSSPropertyJustifyContent:
if (valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueSpaceBetween || valueID == CSSValueSpaceAround)
return true;
break;
case CSSPropertyWebkitFontKerning:
if (valueID == CSSValueAuto || valueID == CSSValueNormal || valueID == CSSValueNone)
return true;
break;
case CSSPropertyWebkitFontSmoothing:
if (valueID == CSSValueAuto || valueID == CSSValueNone || valueID == CSSValueAntialiased || valueID == CSSValueSubpixelAntialiased)
return true;
break;
case CSSPropertyGridAutoFlow:
if (valueID == CSSValueNone || valueID == CSSValueRow || valueID == CSSValueColumn)
return RuntimeEnabledFeatures::cssGridLayoutEnabled();
break;
case CSSPropertyWebkitLineAlign:
if (valueID == CSSValueNone || valueID == CSSValueEdges)
return true;
break;
case CSSPropertyWebkitLineBreak: // auto | loose | normal | strict | after-white-space
if (valueID == CSSValueAuto || valueID == CSSValueLoose || valueID == CSSValueNormal || valueID == CSSValueStrict || valueID == CSSValueAfterWhiteSpace)
return true;
break;
case CSSPropertyWebkitLineSnap:
if (valueID == CSSValueNone || valueID == CSSValueBaseline || valueID == CSSValueContain)
return true;
break;
case CSSPropertyWebkitMarginAfterCollapse:
case CSSPropertyWebkitMarginBeforeCollapse:
case CSSPropertyWebkitMarginBottomCollapse:
case CSSPropertyWebkitMarginTopCollapse:
if (valueID == CSSValueCollapse || valueID == CSSValueSeparate || valueID == CSSValueDiscard)
return true;
break;
case CSSPropertyInternalMarqueeDirection:
if (valueID == CSSValueForwards || valueID == CSSValueBackwards || valueID == CSSValueAhead || valueID == CSSValueReverse || valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueDown
|| valueID == CSSValueUp || valueID == CSSValueAuto)
return true;
break;
case CSSPropertyInternalMarqueeStyle:
if (valueID == CSSValueNone || valueID == CSSValueSlide || valueID == CSSValueScroll || valueID == CSSValueAlternate)
return true;
break;
case CSSPropertyWebkitPrintColorAdjust:
if (valueID == CSSValueExact || valueID == CSSValueEconomy)
return true;
break;
case CSSPropertyWebkitRegionBreakAfter:
case CSSPropertyWebkitRegionBreakBefore:
if (RuntimeEnabledFeatures::cssRegionsEnabled() && (valueID == CSSValueAuto || valueID == CSSValueAlways || valueID == CSSValueAvoid || valueID == CSSValueLeft || valueID == CSSValueRight))
return true;
break;
case CSSPropertyWebkitRegionBreakInside:
if (RuntimeEnabledFeatures::cssRegionsEnabled() && (valueID == CSSValueAuto || valueID == CSSValueAvoid))
return true;
break;
case CSSPropertyWebkitRegionFragment:
if (RuntimeEnabledFeatures::cssRegionsEnabled() && (valueID == CSSValueAuto || valueID == CSSValueBreak))
return true;
break;
case CSSPropertyWebkitRtlOrdering:
if (valueID == CSSValueLogical || valueID == CSSValueVisual)
return true;
break;
case CSSPropertyWebkitRubyPosition:
if (valueID == CSSValueBefore || valueID == CSSValueAfter)
return true;
break;
case CSSPropertyWebkitTextCombine:
if (valueID == CSSValueNone || valueID == CSSValueHorizontal)
return true;
break;
case CSSPropertyWebkitTextEmphasisPosition:
if (valueID == CSSValueOver || valueID == CSSValueUnder)
return true;
break;
case CSSPropertyWebkitTextSecurity:
// disc | circle | square | none | inherit
if (valueID == CSSValueDisc || valueID == CSSValueCircle || valueID == CSSValueSquare || valueID == CSSValueNone)
return true;
break;
case CSSPropertyWebkitTransformStyle:
if (valueID == CSSValueFlat || valueID == CSSValuePreserve3d)
return true;
break;
case CSSPropertyWebkitUserDrag: // auto | none | element
if (valueID == CSSValueAuto || valueID == CSSValueNone || valueID == CSSValueElement)
return true;
break;
case CSSPropertyWebkitUserModify: // read-only | read-write
if (valueID == CSSValueReadOnly || valueID == CSSValueReadWrite || valueID == CSSValueReadWritePlaintextOnly)
return true;
break;
case CSSPropertyWebkitUserSelect: // auto | none | text | all
if (valueID == CSSValueAuto || valueID == CSSValueNone || valueID == CSSValueText || valueID == CSSValueAll)
return true;
break;
case CSSPropertyWebkitWrapFlow:
if (!RuntimeEnabledFeatures::cssExclusionsEnabled())
return false;
if (valueID == CSSValueAuto || valueID == CSSValueBoth || valueID == CSSValueStart || valueID == CSSValueEnd || valueID == CSSValueMaximum || valueID == CSSValueClear)
return true;
break;
case CSSPropertyWebkitWrapThrough:
if (!RuntimeEnabledFeatures::cssExclusionsEnabled())
return false;
if (valueID == CSSValueWrap || valueID == CSSValueNone)
return true;
break;
case CSSPropertyWebkitWritingMode:
if (valueID >= CSSValueHorizontalTb && valueID <= CSSValueHorizontalBt)
return true;
break;
case CSSPropertyWhiteSpace: // normal | pre | nowrap | inherit
if (valueID == CSSValueNormal || valueID == CSSValuePre || valueID == CSSValuePreWrap || valueID == CSSValuePreLine || valueID == CSSValueNowrap)
return true;
break;
case CSSPropertyWordBreak: // normal | break-all | break-word (this is a custom extension)
if (valueID == CSSValueNormal || valueID == CSSValueBreakAll || valueID == CSSValueBreakWord)
return true;
break;
default:
ASSERT_NOT_REACHED();
return false;
}
return false;
}
static inline bool isKeywordPropertyID(CSSPropertyID propertyId)
{
switch (propertyId) {
case CSSPropertyMixBlendMode:
case CSSPropertyIsolation:
return RuntimeEnabledFeatures::cssCompositingEnabled();
case CSSPropertyBorderBottomStyle:
case CSSPropertyBorderCollapse:
case CSSPropertyBorderLeftStyle:
case CSSPropertyBorderRightStyle:
case CSSPropertyBorderTopStyle:
case CSSPropertyBoxSizing:
case CSSPropertyCaptionSide:
case CSSPropertyClear:
case CSSPropertyDirection:
case CSSPropertyDisplay:
case CSSPropertyEmptyCells:
case CSSPropertyFloat:
case CSSPropertyFontStyle:
case CSSPropertyImageRendering:
case CSSPropertyListStylePosition:
case CSSPropertyListStyleType:
case CSSPropertyObjectFit:
case CSSPropertyOutlineStyle:
case CSSPropertyOverflowWrap:
case CSSPropertyOverflowX:
case CSSPropertyOverflowY:
case CSSPropertyPageBreakAfter:
case CSSPropertyPageBreakBefore:
case CSSPropertyPageBreakInside:
case CSSPropertyPointerEvents:
case CSSPropertyPosition:
case CSSPropertyResize:
case CSSPropertySpeak:
case CSSPropertyTableLayout:
case CSSPropertyTextAlignLast:
case CSSPropertyTextJustify:
case CSSPropertyTextLineThroughMode:
case CSSPropertyTextLineThroughStyle:
case CSSPropertyTextOverflow:
case CSSPropertyTextOverlineMode:
case CSSPropertyTextOverlineStyle:
case CSSPropertyTextRendering:
case CSSPropertyTextTransform:
case CSSPropertyTextUnderlineMode:
case CSSPropertyTextUnderlineStyle:
case CSSPropertyTouchAction:
case CSSPropertyTouchActionDelay:
case CSSPropertyVisibility:
case CSSPropertyWebkitAppearance:
case CSSPropertyWebkitBackfaceVisibility:
case CSSPropertyWebkitBorderAfterStyle:
case CSSPropertyWebkitBorderBeforeStyle:
case CSSPropertyWebkitBorderEndStyle:
case CSSPropertyWebkitBorderFit:
case CSSPropertyWebkitBorderStartStyle:
case CSSPropertyWebkitBoxAlign:
case CSSPropertyWebkitBoxDecorationBreak:
case CSSPropertyWebkitBoxDirection:
case CSSPropertyWebkitBoxLines:
case CSSPropertyWebkitBoxOrient:
case CSSPropertyWebkitBoxPack:
case CSSPropertyInternalCallback:
case CSSPropertyWebkitColumnBreakAfter:
case CSSPropertyWebkitColumnBreakBefore:
case CSSPropertyWebkitColumnBreakInside:
case CSSPropertyColumnFill:
case CSSPropertyWebkitColumnRuleStyle:
case CSSPropertyAlignContent:
case CSSPropertyAlignItems:
case CSSPropertyAlignSelf:
case CSSPropertyFlexDirection:
case CSSPropertyFlexWrap:
case CSSPropertyJustifyContent:
case CSSPropertyWebkitFontKerning:
case CSSPropertyWebkitFontSmoothing:
case CSSPropertyGridAutoFlow:
case CSSPropertyWebkitLineAlign:
case CSSPropertyWebkitLineBreak:
case CSSPropertyWebkitLineSnap:
case CSSPropertyWebkitMarginAfterCollapse:
case CSSPropertyWebkitMarginBeforeCollapse:
case CSSPropertyWebkitMarginBottomCollapse:
case CSSPropertyWebkitMarginTopCollapse:
case CSSPropertyInternalMarqueeDirection:
case CSSPropertyInternalMarqueeStyle:
case CSSPropertyWebkitPrintColorAdjust:
case CSSPropertyWebkitRegionBreakAfter:
case CSSPropertyWebkitRegionBreakBefore:
case CSSPropertyWebkitRegionBreakInside:
case CSSPropertyWebkitRegionFragment:
case CSSPropertyWebkitRtlOrdering:
case CSSPropertyWebkitRubyPosition:
case CSSPropertyWebkitTextCombine:
case CSSPropertyWebkitTextEmphasisPosition:
case CSSPropertyWebkitTextSecurity:
case CSSPropertyWebkitTransformStyle:
case CSSPropertyWebkitUserDrag:
case CSSPropertyWebkitUserModify:
case CSSPropertyWebkitUserSelect:
case CSSPropertyWebkitWrapFlow:
case CSSPropertyWebkitWrapThrough:
case CSSPropertyWebkitWritingMode:
case CSSPropertyWhiteSpace:
case CSSPropertyWordBreak:
case CSSPropertyWordWrap:
return true;
default:
return false;
}
}
static bool parseKeywordValue(MutableStylePropertySet* declaration, CSSPropertyID propertyId, const String& string, bool important, const CSSParserContext& parserContext)
{
ASSERT(!string.isEmpty());
if (!isKeywordPropertyID(propertyId)) {
// All properties accept the values of "initial" and "inherit".
String lowerCaseString = string.lower();
if (lowerCaseString != "initial" && lowerCaseString != "inherit")
return false;
// Parse initial/inherit shorthands using the CSSParser.
if (shorthandForProperty(propertyId).length())
return false;
}
CSSParserString cssString;
cssString.init(string);
CSSValueID valueID = cssValueKeywordID(cssString);
if (!valueID)
return false;
RefPtr<CSSValue> value;
if (valueID == CSSValueInherit)
value = cssValuePool().createInheritedValue();
else if (valueID == CSSValueInitial)
value = cssValuePool().createExplicitInitialValue();
else if (isValidKeywordPropertyAndValue(propertyId, valueID, parserContext))
value = cssValuePool().createIdentifierValue(valueID);
else
return false;
declaration->addParsedProperty(CSSProperty(propertyId, value.release(), important));
return true;
}
template <typename CharacterType>
static bool parseTransformArguments(CSSTransformValue* transformValue, CharacterType* characters, unsigned length, unsigned start, unsigned expectedCount)
{
while (expectedCount) {
size_t end = WTF::find(characters, length, expectedCount == 1 ? ')' : ',', start);
if (end == kNotFound || (expectedCount == 1 && end != length - 1))
return false;
unsigned argumentLength = end - start;
CSSPrimitiveValue::UnitTypes unit = CSSPrimitiveValue::CSS_NUMBER;
double number;
if (!parseSimpleLength(characters + start, argumentLength, unit, number))
return false;
if (unit != CSSPrimitiveValue::CSS_PX && (number || unit != CSSPrimitiveValue::CSS_NUMBER))
return false;
transformValue->append(cssValuePool().createValue(number, unit));
start = end + 1;
--expectedCount;
}
return true;
}
static bool parseTranslateTransformValue(MutableStylePropertySet* properties, CSSPropertyID propertyID, const String& string, bool important)
{
if (propertyID != CSSPropertyWebkitTransform)
return false;
static const unsigned shortestValidTransformStringLength = 12;
static const unsigned likelyMultipartTransformStringLengthCutoff = 32;
if (string.length() < shortestValidTransformStringLength || string.length() > likelyMultipartTransformStringLengthCutoff)
return false;
if (!string.startsWith("translate", false))
return false;
UChar c9 = toASCIILower(string[9]);
UChar c10 = toASCIILower(string[10]);
CSSTransformValue::TransformOperationType transformType;
unsigned expectedArgumentCount = 1;
unsigned argumentStart = 11;
if (c9 == 'x' && c10 == '(')
transformType = CSSTransformValue::TranslateXTransformOperation;
else if (c9 == 'y' && c10 == '(')
transformType = CSSTransformValue::TranslateYTransformOperation;
else if (c9 == 'z' && c10 == '(')
transformType = CSSTransformValue::TranslateZTransformOperation;
else if (c9 == '(') {
transformType = CSSTransformValue::TranslateTransformOperation;
expectedArgumentCount = 2;
argumentStart = 10;
} else if (c9 == '3' && c10 == 'd' && string[11] == '(') {
transformType = CSSTransformValue::Translate3DTransformOperation;
expectedArgumentCount = 3;
argumentStart = 12;
} else
return false;
RefPtr<CSSTransformValue> transformValue = CSSTransformValue::create(transformType);
bool success;
if (string.is8Bit())
success = parseTransformArguments(transformValue.get(), string.characters8(), string.length(), argumentStart, expectedArgumentCount);
else
success = parseTransformArguments(transformValue.get(), string.characters16(), string.length(), argumentStart, expectedArgumentCount);
if (!success)
return false;
RefPtr<CSSValueList> result = CSSValueList::createSpaceSeparated();
result->append(transformValue.release());
properties->addParsedProperty(CSSProperty(CSSPropertyWebkitTransform, result.release(), important));
return true;
}
PassRefPtr<CSSValueList> CSSParser::parseFontFaceValue(const AtomicString& string)
{
if (string.isEmpty())
return 0;
RefPtr<MutableStylePropertySet> dummyStyle = MutableStylePropertySet::create();
if (!parseValue(dummyStyle.get(), CSSPropertyFontFamily, string, false, HTMLQuirksMode, 0))
return 0;
RefPtr<CSSValue> fontFamily = dummyStyle->getPropertyCSSValue(CSSPropertyFontFamily);
if (!fontFamily->isValueList())
return 0;
return toCSSValueList(dummyStyle->getPropertyCSSValue(CSSPropertyFontFamily).get());
}
bool CSSParser::parseValue(MutableStylePropertySet* declaration, CSSPropertyID propertyID, const String& string, bool important, const Document& document)
{
ASSERT(!string.isEmpty());
CSSParserContext context(document);
if (parseSimpleLengthValue(declaration, propertyID, string, important, context.mode))
return true;
if (parseColorValue(declaration, propertyID, string, important, context.mode))
return true;
if (parseKeywordValue(declaration, propertyID, string, important, context))
return true;
CSSParser parser(context, UseCounter::getFrom(&document));
return parser.parseValue(declaration, propertyID, string, important, static_cast<StyleSheetContents*>(0));
}
bool CSSParser::parseValue(MutableStylePropertySet* declaration, CSSPropertyID propertyID, const String& string, bool important, CSSParserMode cssParserMode, StyleSheetContents* contextStyleSheet)
{
ASSERT(!string.isEmpty());
if (parseSimpleLengthValue(declaration, propertyID, string, important, cssParserMode))
return true;
if (parseColorValue(declaration, propertyID, string, important, cssParserMode))
return true;
CSSParserContext context(cssParserMode);
if (contextStyleSheet) {
context = contextStyleSheet->parserContext();
context.mode = cssParserMode;
}
if (parseKeywordValue(declaration, propertyID, string, important, context))
return true;
if (parseTranslateTransformValue(declaration, propertyID, string, important))
return true;
CSSParser parser(context);
return parser.parseValue(declaration, propertyID, string, important, contextStyleSheet);
}
bool CSSParser::parseValue(MutableStylePropertySet* declaration, CSSPropertyID propertyID, const String& string, bool important, StyleSheetContents* contextStyleSheet)
{
// FIXME: Check RuntimeCSSEnabled::isPropertyEnabled or isValueEnabledForProperty.
if (m_useCounter)
m_useCounter->count(m_context, propertyID);
setStyleSheet(contextStyleSheet);
setupParser("@-internal-value ", string, "");
m_id = propertyID;
m_important = important;
{
StyleDeclarationScope scope(this, declaration);
cssyyparse(this);
}
m_rule = 0;
m_id = CSSPropertyInvalid;
bool ok = false;
if (m_hasFontFaceOnlyValues)
deleteFontFaceOnlyValues();
if (!m_parsedProperties.isEmpty()) {
ok = true;
declaration->addParsedProperties(m_parsedProperties);
clearProperties();
}
return ok;
}
// The color will only be changed when string contains a valid CSS color, so callers
// can set it to a default color and ignore the boolean result.
bool CSSParser::parseColor(RGBA32& color, const String& string, bool strict)
{
// First try creating a color specified by name, rgba(), rgb() or "#" syntax.
if (fastParseColor(color, string, strict))
return true;
CSSParser parser(HTMLStandardMode);
// In case the fast-path parser didn't understand the color, try the full parser.
if (!parser.parseColor(string))
return false;
CSSValue* value = parser.m_parsedProperties.first().value();
if (!value->isPrimitiveValue())
return false;
CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
if (!primitiveValue->isRGBColor())
return false;
color = primitiveValue->getRGBA32Value();
return true;
}
bool CSSParser::parseColor(const String& string)
{
setupParser("@-internal-decls color:", string, "");
cssyyparse(this);
m_rule = 0;
return !m_parsedProperties.isEmpty() && m_parsedProperties.first().id() == CSSPropertyColor;
}
bool CSSParser::parseSystemColor(RGBA32& color, const String& string, Document* document)
{
if (!document || !document->page())
return false;
CSSParserString cssColor;
cssColor.init(string);
CSSValueID id = cssValueKeywordID(cssColor);
if (id <= 0)
return false;
color = RenderTheme::theme().systemColor(id).rgb();
return true;
}
void CSSParser::parseSelector(const String& string, CSSSelectorList& selectorList)
{
m_selectorListForParseSelector = &selectorList;
setupParser("@-internal-selector ", string, "");
cssyyparse(this);
m_selectorListForParseSelector = 0;
}
PassRefPtr<ImmutableStylePropertySet> CSSParser::parseInlineStyleDeclaration(const String& string, Element* element)
{
Document& document = element->document();
CSSParserContext context = document.elementSheet()->contents()->parserContext();
context.mode = (element->isHTMLElement() && !document.inQuirksMode()) ? HTMLStandardMode : HTMLQuirksMode;
return CSSParser(context, UseCounter::getFrom(&document)).parseDeclaration(string, document.elementSheet()->contents());
}
PassRefPtr<ImmutableStylePropertySet> CSSParser::parseDeclaration(const String& string, StyleSheetContents* contextStyleSheet)
{
setStyleSheet(contextStyleSheet);
setupParser("@-internal-decls ", string, "");
cssyyparse(this);
m_rule = 0;
if (m_hasFontFaceOnlyValues)
deleteFontFaceOnlyValues();
RefPtr<ImmutableStylePropertySet> style = createStylePropertySet();
clearProperties();
return style.release();
}
bool CSSParser::parseDeclaration(MutableStylePropertySet* declaration, const String& string, SourceDataHandler* sourceDataHandler, StyleSheetContents* contextStyleSheet)
{
setStyleSheet(contextStyleSheet);
m_sourceDataHandler = sourceDataHandler;
setupParser("@-internal-decls ", string, "");
if (m_sourceDataHandler) {
m_sourceDataHandler->startRuleHeader(CSSRuleSourceData::STYLE_RULE, 0);
m_sourceDataHandler->endRuleHeader(1);
m_sourceDataHandler->startRuleBody(0);
}
{
StyleDeclarationScope scope(this, declaration);
cssyyparse(this);
}
m_rule = 0;
bool ok = false;
if (m_hasFontFaceOnlyValues)
deleteFontFaceOnlyValues();
if (!m_parsedProperties.isEmpty()) {
ok = true;
declaration->addParsedProperties(m_parsedProperties);
clearProperties();
}
if (m_sourceDataHandler)
m_sourceDataHandler->endRuleBody(string.length(), false);
m_sourceDataHandler = 0;
return ok;
}
PassRefPtr<MediaQuerySet> CSSParser::parseMediaQueryList(const String& string)
{
ASSERT(!m_mediaList);
// can't use { because tokenizer state switches from mediaquery to initial state when it sees { token.
// instead insert one " " (which is caught by maybe_space in CSSGrammar.y)
setupParser("@-internal-medialist ", string, "");
cssyyparse(this);
ASSERT(m_mediaList);
return m_mediaList.release();
}
static inline void filterProperties(bool important, const CSSParser::ParsedPropertyVector& input, Vector<CSSProperty, 256>& output, size_t& unusedEntries, BitArray<numCSSProperties>& seenProperties, HashSet<AtomicString>& seenVariables)
{
// Add properties in reverse order so that highest priority definitions are reached first. Duplicate definitions can then be ignored when found.
for (int i = input.size() - 1; i >= 0; --i) {
const CSSProperty& property = input[i];
if (property.isImportant() != important)
continue;
if (property.id() == CSSPropertyVariable) {
const AtomicString& name = toCSSVariableValue(property.value())->name();
if (!seenVariables.add(name).isNewEntry)
continue;
output[--unusedEntries] = property;
continue;
}
const unsigned propertyIDIndex = property.id() - firstCSSProperty;
if (seenProperties.get(propertyIDIndex))
continue;
seenProperties.set(propertyIDIndex);
output[--unusedEntries] = property;
}
}
PassRefPtr<ImmutableStylePropertySet> CSSParser::createStylePropertySet()
{
BitArray<numCSSProperties> seenProperties;
size_t unusedEntries = m_parsedProperties.size();
Vector<CSSProperty, 256> results(unusedEntries);
// Important properties have higher priority, so add them first. Duplicate definitions can then be ignored when found.
HashSet<AtomicString> seenVariables;
filterProperties(true, m_parsedProperties, results, unusedEntries, seenProperties, seenVariables);
filterProperties(false, m_parsedProperties, results, unusedEntries, seenProperties, seenVariables);
if (unusedEntries)
results.remove(0, unusedEntries);
CSSParserMode mode = inViewport() ? CSSViewportRuleMode : m_context.mode;
return ImmutableStylePropertySet::create(results.data(), results.size(), mode);
}
void CSSParser::addPropertyWithPrefixingVariant(CSSPropertyID propId, PassRefPtr<CSSValue> value, bool important, bool implicit)
{
RefPtr<CSSValue> val = value.get();
addProperty(propId, value, important, implicit);
CSSPropertyID prefixingVariant = prefixingVariantForPropertyId(propId);
if (prefixingVariant == propId)
return;
if (m_currentShorthand) {
// We can't use ShorthandScope here as we can already be inside one (e.g we are parsing CSSTransition).
m_currentShorthand = prefixingVariantForPropertyId(m_currentShorthand);
addProperty(prefixingVariant, val.release(), important, implicit);
m_currentShorthand = prefixingVariantForPropertyId(m_currentShorthand);
} else {
addProperty(prefixingVariant, val.release(), important, implicit);
}
}
void CSSParser::addProperty(CSSPropertyID propId, PassRefPtr<CSSValue> value, bool important, bool implicit)
{
CSSPrimitiveValue* primitiveValue = value->isPrimitiveValue() ? toCSSPrimitiveValue(value.get()) : 0;
// This property doesn't belong to a shorthand or is a CSS variable (which will be resolved later).
if (!m_currentShorthand || (primitiveValue && primitiveValue->isVariableName())) {
m_parsedProperties.append(CSSProperty(propId, value, important, false, CSSPropertyInvalid, m_implicitShorthand || implicit));
return;
}
const Vector<StylePropertyShorthand> shorthands = matchingShorthandsForLonghand(propId);
// The longhand does not belong to multiple shorthands.
if (shorthands.size() == 1)
m_parsedProperties.append(CSSProperty(propId, value, important, true, CSSPropertyInvalid, m_implicitShorthand || implicit));
else
m_parsedProperties.append(CSSProperty(propId, value, important, true, indexOfShorthandForLonghand(m_currentShorthand, shorthands), m_implicitShorthand || implicit));
}
void CSSParser::rollbackLastProperties(int num)
{
ASSERT(num >= 0);
ASSERT(m_parsedProperties.size() >= static_cast<unsigned>(num));
m_parsedProperties.shrink(m_parsedProperties.size() - num);
}
void CSSParser::clearProperties()
{
m_parsedProperties.clear();
m_numParsedPropertiesBeforeMarginBox = INVALID_NUM_PARSED_PROPERTIES;
m_hasFontFaceOnlyValues = false;
}
KURL CSSParser::completeURL(const CSSParserContext& context, const String& url)
{
if (url.isNull())
return KURL();
if (context.charset.isEmpty())
return KURL(context.baseURL, url);
return KURL(context.baseURL, url, context.charset);
}
KURL CSSParser::completeURL(const String& url) const
{
return completeURL(m_context, url);
}
bool CSSParser::validCalculationUnit(CSSParserValue* value, Units unitflags, ReleaseParsedCalcValueCondition releaseCalc)
{
bool mustBeNonNegative = unitflags & FNonNeg;
if (!parseCalculation(value, mustBeNonNegative ? ValueRangeNonNegative : ValueRangeAll))
return false;
bool b = false;
switch (m_parsedCalculation->category()) {
case CalcLength:
b = (unitflags & FLength);
break;
case CalcPercent:
b = (unitflags & FPercent);
if (b && mustBeNonNegative && m_parsedCalculation->isNegative())
b = false;
break;
case CalcNumber:
b = (unitflags & FNumber);
if (!b && (unitflags & FInteger) && m_parsedCalculation->isInt())
b = true;
if (b && mustBeNonNegative && m_parsedCalculation->isNegative())
b = false;
break;
case CalcPercentLength:
b = (unitflags & FPercent) && (unitflags & FLength);
break;
case CalcPercentNumber:
b = (unitflags & FPercent) && (unitflags & FNumber);
break;
case CalcVariable:
b = true;
break;
case CalcOther:
break;
}
if (!b || releaseCalc == ReleaseParsedCalcValue)
m_parsedCalculation.release();
return b;
}
inline bool CSSParser::shouldAcceptUnitLessValues(CSSParserValue* value, Units unitflags, CSSParserMode cssParserMode)
{
// Quirks mode and presentation attributes accept unit less values.
return (unitflags & (FLength | FAngle | FTime)) && (!value->fValue || isUnitLessLengthParsingEnabledForMode(cssParserMode));
}
bool CSSParser::validUnit(CSSParserValue* value, Units unitflags, CSSParserMode cssParserMode, ReleaseParsedCalcValueCondition releaseCalc)
{
if (isCalculation(value))
return validCalculationUnit(value, unitflags, releaseCalc);
bool b = false;
switch (value->unit) {
case CSSPrimitiveValue::CSS_VARIABLE_NAME:
// Variables are checked at the point they are dereferenced because unit type is not available here.
b = true;
break;
case CSSPrimitiveValue::CSS_NUMBER:
b = (unitflags & FNumber);
if (!b && shouldAcceptUnitLessValues(value, unitflags, cssParserMode)) {
value->unit = (unitflags & FLength) ? CSSPrimitiveValue::CSS_PX :
((unitflags & FAngle) ? CSSPrimitiveValue::CSS_DEG : CSSPrimitiveValue::CSS_MS);
b = true;
}
if (!b && (unitflags & FInteger) && value->isInt)
b = true;
if (!b && (unitflags & FPositiveInteger) && value->isInt && value->fValue > 0)
b = true;
break;
case CSSPrimitiveValue::CSS_PERCENTAGE:
b = (unitflags & FPercent);
break;
case CSSParserValue::Q_EMS:
case CSSPrimitiveValue::CSS_EMS:
case CSSPrimitiveValue::CSS_REMS:
case CSSPrimitiveValue::CSS_CHS:
case CSSPrimitiveValue::CSS_EXS:
case CSSPrimitiveValue::CSS_PX:
case CSSPrimitiveValue::CSS_CM:
case CSSPrimitiveValue::CSS_MM:
case CSSPrimitiveValue::CSS_IN:
case CSSPrimitiveValue::CSS_PT:
case CSSPrimitiveValue::CSS_PC:
case CSSPrimitiveValue::CSS_VW:
case CSSPrimitiveValue::CSS_VH:
case CSSPrimitiveValue::CSS_VMIN:
case CSSPrimitiveValue::CSS_VMAX:
b = (unitflags & FLength);
break;
case CSSPrimitiveValue::CSS_MS:
case CSSPrimitiveValue::CSS_S:
b = (unitflags & FTime);
break;
case CSSPrimitiveValue::CSS_DEG:
case CSSPrimitiveValue::CSS_RAD:
case CSSPrimitiveValue::CSS_GRAD:
case CSSPrimitiveValue::CSS_TURN:
b = (unitflags & FAngle);
break;
case CSSPrimitiveValue::CSS_DPPX:
case CSSPrimitiveValue::CSS_DPI:
case CSSPrimitiveValue::CSS_DPCM:
b = (unitflags & FResolution);
break;
case CSSPrimitiveValue::CSS_HZ:
case CSSPrimitiveValue::CSS_KHZ:
case CSSPrimitiveValue::CSS_DIMENSION:
default:
break;
}
if (b && unitflags & FNonNeg && value->fValue < 0)
b = false;
return b;
}
inline PassRefPtr<CSSPrimitiveValue> CSSParser::createPrimitiveNumericValue(CSSParserValue* value)
{
if (value->unit == CSSPrimitiveValue::CSS_VARIABLE_NAME)
return createPrimitiveVariableNameValue(value);
if (m_parsedCalculation) {
ASSERT(isCalculation(value));
return CSSPrimitiveValue::create(m_parsedCalculation.release());
}
ASSERT((value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
|| (value->unit >= CSSPrimitiveValue::CSS_TURN && value->unit <= CSSPrimitiveValue::CSS_CHS)
|| (value->unit >= CSSPrimitiveValue::CSS_VW && value->unit <= CSSPrimitiveValue::CSS_VMAX)
|| (value->unit >= CSSPrimitiveValue::CSS_DPPX && value->unit <= CSSPrimitiveValue::CSS_DPCM));
return cssValuePool().createValue(value->fValue, static_cast<CSSPrimitiveValue::UnitTypes>(value->unit));
}
inline PassRefPtr<CSSPrimitiveValue> CSSParser::createPrimitiveStringValue(CSSParserValue* value)
{
ASSERT(value->unit == CSSPrimitiveValue::CSS_STRING || value->unit == CSSPrimitiveValue::CSS_IDENT);
return cssValuePool().createValue(value->string, CSSPrimitiveValue::CSS_STRING);
}
inline PassRefPtr<CSSPrimitiveValue> CSSParser::createPrimitiveVariableNameValue(CSSParserValue* value)
{
ASSERT(value->unit == CSSPrimitiveValue::CSS_VARIABLE_NAME);
return CSSPrimitiveValue::create(value->string, CSSPrimitiveValue::CSS_VARIABLE_NAME);
}
static inline bool isComma(CSSParserValue* value)
{
return value && value->unit == CSSParserValue::Operator && value->iValue == ',';
}
static inline bool isForwardSlashOperator(CSSParserValue* value)
{
ASSERT(value);
return value->unit == CSSParserValue::Operator && value->iValue == '/';
}
bool CSSParser::validWidthOrHeight(CSSParserValue* value)
{
int id = value->id;
if (id == CSSValueIntrinsic || id == CSSValueMinIntrinsic || id == CSSValueWebkitMinContent || id == CSSValueWebkitMaxContent || id == CSSValueWebkitFillAvailable || id == CSSValueWebkitFitContent)
return true;
return !id && validUnit(value, FLength | FPercent | FNonNeg);
}
inline PassRefPtr<CSSPrimitiveValue> CSSParser::parseValidPrimitive(CSSValueID identifier, CSSParserValue* value)
{
if (identifier)
return cssValuePool().createIdentifierValue(identifier);
if (value->unit == CSSPrimitiveValue::CSS_STRING)
return createPrimitiveStringValue(value);
if (value->unit >= CSSPrimitiveValue::CSS_NUMBER && value->unit <= CSSPrimitiveValue::CSS_KHZ)
return createPrimitiveNumericValue(value);
if (value->unit >= CSSPrimitiveValue::CSS_TURN && value->unit <= CSSPrimitiveValue::CSS_CHS)
return createPrimitiveNumericValue(value);
if (value->unit >= CSSPrimitiveValue::CSS_VW && value->unit <= CSSPrimitiveValue::CSS_VMAX)
return createPrimitiveNumericValue(value);
if (value->unit >= CSSPrimitiveValue::CSS_DPPX && value->unit <= CSSPrimitiveValue::CSS_DPCM)
return createPrimitiveNumericValue(value);
if (value->unit == CSSPrimitiveValue::CSS_VARIABLE_NAME)
return createPrimitiveVariableNameValue(value);
if (value->unit >= CSSParserValue::Q_EMS)
return CSSPrimitiveValue::createAllowingMarginQuirk(value->fValue, CSSPrimitiveValue::CSS_EMS);
if (isCalculation(value))
return CSSPrimitiveValue::create(m_parsedCalculation.release());
return 0;
}
void CSSParser::addExpandedPropertyForValue(CSSPropertyID propId, PassRefPtr<CSSValue> prpValue, bool important)
{
const StylePropertyShorthand& shorthand = shorthandForProperty(propId);
unsigned shorthandLength = shorthand.length();
if (!shorthandLength) {
addProperty(propId, prpValue, important);
return;
}
RefPtr<CSSValue> value = prpValue;
ShorthandScope scope(this, propId);
const CSSPropertyID* longhands = shorthand.properties();
for (unsigned i = 0; i < shorthandLength; ++i)
addProperty(longhands[i], value, important);
}
void CSSParser::setCurrentProperty(CSSPropertyID propId)
{
m_id = propId;
}
bool CSSParser::parseValue(CSSPropertyID propId, bool important)
{
if (!isInternalPropertyAndValueParsingEnabledForMode(m_context.mode) && isInternalProperty(propId))
return false;
// We don't count the UA style sheet in our statistics.
if (m_useCounter)
m_useCounter->count(m_context, propId);
if (!m_valueList)
return false;
CSSParserValue* value = m_valueList->current();
if (!value)
return false;
if (inViewport()) {
// Allow @viewport rules from UA stylesheets even if the feature is disabled.
if (!RuntimeEnabledFeatures::cssViewportEnabled() && !isUASheetBehavior(m_context.mode))
return false;
return parseViewportProperty(propId, important);
}
// Note: m_parsedCalculation is used to pass the calc value to validUnit and then cleared at the end of this function.
// FIXME: This is to avoid having to pass parsedCalc to all validUnit callers.
ASSERT(!m_parsedCalculation);
CSSValueID id = value->id;
int num = inShorthand() ? 1 : m_valueList->size();
if (id == CSSValueInherit) {
if (num != 1)
return false;
addExpandedPropertyForValue(propId, cssValuePool().createInheritedValue(), important);
return true;
}
else if (id == CSSValueInitial) {
if (num != 1)
return false;
addExpandedPropertyForValue(propId, cssValuePool().createExplicitInitialValue(), important);
return true;
}
if (!id && value->unit == CSSPrimitiveValue::CSS_VARIABLE_NAME && num == 1) {
addProperty(propId, createPrimitiveVariableNameValue(value), important);
m_valueList->next();
return true;
}
ASSERT(propId != CSSPropertyVariable);
if (isKeywordPropertyID(propId)) {
if (!isValidKeywordPropertyAndValue(propId, id, m_context))
return false;
if (m_valueList->next() && !inShorthand())
return false;
addProperty(propId, cssValuePool().createIdentifierValue(id), important);
return true;
}
bool validPrimitive = false;
RefPtr<CSSValue> parsedValue;
switch (propId) {
case CSSPropertySize: // <length>{1,2} | auto | [ <page-size> || [ portrait | landscape] ]
return parseSize(propId, important);
case CSSPropertyQuotes: // [<string> <string>]+ | none | inherit
if (id)
validPrimitive = true;
else
return parseQuotes(propId, important);
break;
case CSSPropertyUnicodeBidi: // normal | embed | bidi-override | isolate | isolate-override | plaintext | inherit
if (id == CSSValueNormal
|| id == CSSValueEmbed
|| id == CSSValueBidiOverride
|| id == CSSValueWebkitIsolate
|| id == CSSValueWebkitIsolateOverride
|| id == CSSValueWebkitPlaintext)
validPrimitive = true;
break;
case CSSPropertyContent: // [ <string> | <uri> | <counter> | attr(X) | open-quote |
// close-quote | no-open-quote | no-close-quote ]+ | inherit
return parseContent(propId, important);
case CSSPropertyClip: // <shape> | auto | inherit
if (id == CSSValueAuto)
validPrimitive = true;
else if (value->unit == CSSParserValue::Function)
return parseClipShape(propId, important);
break;
/* Start of supported CSS properties with validation. This is needed for parseShorthand to work
* correctly and allows optimization in WebCore::applyRule(..)
*/
case CSSPropertyOverflow: {
ShorthandScope scope(this, propId);
if (num != 1 || !parseValue(CSSPropertyOverflowY, important))
return false;
RefPtr<CSSValue> overflowXValue;
// FIXME: -webkit-paged-x or -webkit-paged-y only apply to overflow-y. If this value has been
// set using the shorthand, then for now overflow-x will default to auto, but once we implement
// pagination controls, it should default to hidden. If the overflow-y value is anything but
// paged-x or paged-y, then overflow-x and overflow-y should have the same value.
if (id == CSSValueWebkitPagedX || id == CSSValueWebkitPagedY)
overflowXValue = cssValuePool().createIdentifierValue(CSSValueAuto);
else
overflowXValue = m_parsedProperties.last().value();
addProperty(CSSPropertyOverflowX, overflowXValue.release(), important);
return true;
}
case CSSPropertyTextAlign:
// left | right | center | justify | -webkit-left | -webkit-right | -webkit-center | -webkit-match-parent
// | start | end | <string> | inherit | -webkit-auto (converted to start)
if ((id >= CSSValueWebkitAuto && id <= CSSValueWebkitMatchParent) || id == CSSValueStart || id == CSSValueEnd
|| value->unit == CSSPrimitiveValue::CSS_STRING)
validPrimitive = true;
break;
case CSSPropertyFontWeight: { // normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | inherit
if (m_valueList->size() != 1)
return false;
return parseFontWeight(important);
}
case CSSPropertyBorderSpacing: {
if (num == 1) {
ShorthandScope scope(this, CSSPropertyBorderSpacing);
if (!parseValue(CSSPropertyWebkitBorderHorizontalSpacing, important))
return false;
CSSValue* value = m_parsedProperties.last().value();
addProperty(CSSPropertyWebkitBorderVerticalSpacing, value, important);
return true;
}
else if (num == 2) {
ShorthandScope scope(this, CSSPropertyBorderSpacing);
if (!parseValue(CSSPropertyWebkitBorderHorizontalSpacing, important) || !parseValue(CSSPropertyWebkitBorderVerticalSpacing, important))
return false;
return true;
}
return false;
}
case CSSPropertyWebkitBorderHorizontalSpacing:
case CSSPropertyWebkitBorderVerticalSpacing:
validPrimitive = validUnit(value, FLength | FNonNeg);
break;
case CSSPropertyOutlineColor: // <color> | invert | inherit
// Outline color has "invert" as additional keyword.
// Also, we want to allow the special focus color even in HTML Standard parsing mode.
if (id == CSSValueInvert || id == CSSValueWebkitFocusRingColor) {
validPrimitive = true;
break;
}
/* nobreak */
case CSSPropertyBackgroundColor: // <color> | inherit
case CSSPropertyBorderTopColor: // <color> | inherit
case CSSPropertyBorderRightColor:
case CSSPropertyBorderBottomColor:
case CSSPropertyBorderLeftColor:
case CSSPropertyWebkitBorderStartColor:
case CSSPropertyWebkitBorderEndColor:
case CSSPropertyWebkitBorderBeforeColor:
case CSSPropertyWebkitBorderAfterColor:
case CSSPropertyColor: // <color> | inherit
case CSSPropertyTextDecorationColor: // CSS3 text decoration colors
case CSSPropertyTextLineThroughColor:
case CSSPropertyTextUnderlineColor:
case CSSPropertyTextOverlineColor:
case CSSPropertyWebkitColumnRuleColor:
case CSSPropertyWebkitTextEmphasisColor:
case CSSPropertyWebkitTextFillColor:
case CSSPropertyWebkitTextStrokeColor:
if (propId == CSSPropertyTextDecorationColor
&& !RuntimeEnabledFeatures::css3TextDecorationsEnabled())
return false;
if ((id >= CSSValueAqua && id <= CSSValueWebkitText) || id == CSSValueMenu) {
validPrimitive = isValueAllowedInMode(id, m_context.mode);
} else {
parsedValue = parseColor();
if (parsedValue)
m_valueList->next();
}
break;
case CSSPropertyCursor: {
// Grammar defined by CSS3 UI and modified by CSS4 images:
// [ [<image> [<x> <y>]?,]*
// [ auto | crosshair | default | pointer | progress | move | e-resize | ne-resize |
// nw-resize | n-resize | se-resize | sw-resize | s-resize | w-resize | ew-resize |
// ns-resize | nesw-resize | nwse-resize | col-resize | row-resize | text | wait | help |
// vertical-text | cell | context-menu | alias | copy | no-drop | not-allowed | -webkit-zoom-in
// -webkit-zoom-out | all-scroll | -webkit-grab | -webkit-grabbing ] ] | inherit
RefPtr<CSSValueList> list;
while (value) {
RefPtr<CSSValue> image = 0;
if (value->unit == CSSPrimitiveValue::CSS_URI) {
String uri = value->string;
if (!uri.isNull())
image = CSSImageValue::create(completeURL(uri));
} else if (value->unit == CSSParserValue::Function && equalIgnoringCase(value->function->name, "-webkit-image-set(")) {
image = parseImageSet(m_valueList.get());
if (!image)
break;
} else
break;
Vector<int> coords;
value = m_valueList->next();
while (value && value->unit == CSSPrimitiveValue::CSS_NUMBER) {
coords.append(int(value->fValue));
value = m_valueList->next();
}
bool hasHotSpot = false;
IntPoint hotSpot(-1, -1);
int nrcoords = coords.size();
if (nrcoords > 0 && nrcoords != 2)
return false;
if (nrcoords == 2) {
hasHotSpot = true;
hotSpot = IntPoint(coords[0], coords[1]);
}
if (!list)
list = CSSValueList::createCommaSeparated();
if (image)
list->append(CSSCursorImageValue::create(image, hasHotSpot, hotSpot));
if (!value || !(value->unit == CSSParserValue::Operator && value->iValue == ','))
return false;
value = m_valueList->next(); // comma
}
if (list) {
if (!value)
return false;
if (inQuirksMode() && value->id == CSSValueHand) // MSIE 5 compatibility :/
list->append(cssValuePool().createIdentifierValue(CSSValuePointer));
else if ((value->id >= CSSValueAuto && value->id <= CSSValueWebkitGrabbing) || value->id == CSSValueCopy || value->id == CSSValueNone)
list->append(cssValuePool().createIdentifierValue(value->id));
m_valueList->next();
parsedValue = list.release();
break;
} else if (value) {
id = value->id;
if (inQuirksMode() && value->id == CSSValueHand) { // MSIE 5 compatibility :/
id = CSSValuePointer;
validPrimitive = true;
} else if ((value->id >= CSSValueAuto && value->id <= CSSValueWebkitGrabbing) || value->id == CSSValueCopy || value->id == CSSValueNone)
validPrimitive = true;
} else {
ASSERT_NOT_REACHED();
return false;
}
break;
}
case CSSPropertyBackgroundBlendMode:
case CSSPropertyBackgroundAttachment:
case CSSPropertyBackgroundClip:
case CSSPropertyWebkitBackgroundClip:
case CSSPropertyWebkitBackgroundComposite:
case CSSPropertyBackgroundImage:
case CSSPropertyBackgroundOrigin:
case CSSPropertyMaskSourceType:
case CSSPropertyWebkitBackgroundOrigin:
case CSSPropertyBackgroundPosition:
case CSSPropertyBackgroundPositionX:
case CSSPropertyBackgroundPositionY:
case CSSPropertyBackgroundSize:
case CSSPropertyWebkitBackgroundSize:
case CSSPropertyBackgroundRepeat:
case CSSPropertyBackgroundRepeatX:
case CSSPropertyBackgroundRepeatY:
case CSSPropertyWebkitMaskClip:
case CSSPropertyWebkitMaskComposite:
case CSSPropertyWebkitMaskImage:
case CSSPropertyWebkitMaskOrigin:
case CSSPropertyWebkitMaskPosition:
case CSSPropertyWebkitMaskPositionX:
case CSSPropertyWebkitMaskPositionY:
case CSSPropertyWebkitMaskSize:
case CSSPropertyWebkitMaskRepeat:
case CSSPropertyWebkitMaskRepeatX:
case CSSPropertyWebkitMaskRepeatY:
{
RefPtr<CSSValue> val1;
RefPtr<CSSValue> val2;
CSSPropertyID propId1, propId2;
bool result = false;
if (parseFillProperty(propId, propId1, propId2, val1, val2)) {
OwnPtr<ShorthandScope> shorthandScope;
if (propId == CSSPropertyBackgroundPosition ||
propId == CSSPropertyBackgroundRepeat ||
propId == CSSPropertyWebkitMaskPosition ||
propId == CSSPropertyWebkitMaskRepeat) {
shorthandScope = adoptPtr(new ShorthandScope(this, propId));
}
addProperty(propId1, val1.release(), important);
if (val2)
addProperty(propId2, val2.release(), important);
result = true;
}
m_implicitShorthand = false;
return result;
}
case CSSPropertyObjectPosition:
return RuntimeEnabledFeatures::objectFitPositionEnabled() && parseObjectPosition(important);
case CSSPropertyListStyleImage: // <uri> | none | inherit
case CSSPropertyBorderImageSource:
case CSSPropertyWebkitMaskBoxImageSource:
if (id == CSSValueNone) {
parsedValue = cssValuePool().createIdentifierValue(CSSValueNone);
m_valueList->next();
} else if (value->unit == CSSPrimitiveValue::CSS_URI) {
parsedValue = CSSImageValue::create(completeURL(value->string));
m_valueList->next();
} else if (isGeneratedImageValue(value)) {
if (parseGeneratedImage(m_valueList.get(), parsedValue))
m_valueList->next();
else
return false;
}
else if (value->unit == CSSParserValue::Function && equalIgnoringCase(value->function->name, "-webkit-image-set(")) {
parsedValue = parseImageSet(m_valueList.get());
if (!parsedValue)
return false;
m_valueList->next();
}
break;
case CSSPropertyWebkitTextStrokeWidth:
case CSSPropertyOutlineWidth: // <border-width> | inherit
case CSSPropertyBorderTopWidth: //// <border-width> | inherit
case CSSPropertyBorderRightWidth: // Which is defined as
case CSSPropertyBorderBottomWidth: // thin | medium | thick | <length>
case CSSPropertyBorderLeftWidth:
case CSSPropertyWebkitBorderStartWidth:
case CSSPropertyWebkitBorderEndWidth:
case CSSPropertyWebkitBorderBeforeWidth:
case CSSPropertyWebkitBorderAfterWidth:
case CSSPropertyWebkitColumnRuleWidth:
if (id == CSSValueThin || id == CSSValueMedium || id == CSSValueThick)
validPrimitive = true;
else
validPrimitive = validUnit(value, FLength | FNonNeg);
break;
case CSSPropertyLetterSpacing: // normal | <length> | inherit
case CSSPropertyWordSpacing: // normal | <length> | inherit
if (id == CSSValueNormal)
validPrimitive = true;
else
validPrimitive = validUnit(value, FLength);
break;
case CSSPropertyTextIndent:
parsedValue = parseTextIndent();
break;
case CSSPropertyPaddingTop: //// <padding-width> | inherit
case CSSPropertyPaddingRight: // Which is defined as
case CSSPropertyPaddingBottom: // <length> | <percentage>
case CSSPropertyPaddingLeft: ////
case CSSPropertyWebkitPaddingStart:
case CSSPropertyWebkitPaddingEnd:
case CSSPropertyWebkitPaddingBefore:
case CSSPropertyWebkitPaddingAfter:
validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg));
break;
case CSSPropertyMaxWidth:
case CSSPropertyWebkitMaxLogicalWidth:
case CSSPropertyMaxHeight:
case CSSPropertyWebkitMaxLogicalHeight:
validPrimitive = (id == CSSValueNone || validWidthOrHeight(value));
break;
case CSSPropertyMinWidth:
case CSSPropertyWebkitMinLogicalWidth:
case CSSPropertyMinHeight:
case CSSPropertyWebkitMinLogicalHeight:
validPrimitive = validWidthOrHeight(value);
break;
case CSSPropertyWidth:
case CSSPropertyWebkitLogicalWidth:
case CSSPropertyHeight:
case CSSPropertyWebkitLogicalHeight:
validPrimitive = (id == CSSValueAuto || validWidthOrHeight(value));
break;
case CSSPropertyFontSize:
return parseFontSize(important);
case CSSPropertyFontVariant: // normal | small-caps | inherit
return parseFontVariant(important);
case CSSPropertyVerticalAlign:
// baseline | sub | super | top | text-top | middle | bottom | text-bottom |
// <percentage> | <length> | inherit
if (id >= CSSValueBaseline && id <= CSSValueWebkitBaselineMiddle)
validPrimitive = true;
else
validPrimitive = (!id && validUnit(value, FLength | FPercent));
break;
case CSSPropertyBottom: // <length> | <percentage> | auto | inherit
case CSSPropertyLeft: // <length> | <percentage> | auto | inherit
case CSSPropertyRight: // <length> | <percentage> | auto | inherit
case CSSPropertyTop: // <length> | <percentage> | auto | inherit
case CSSPropertyMarginTop: //// <margin-width> | inherit
case CSSPropertyMarginRight: // Which is defined as
case CSSPropertyMarginBottom: // <length> | <percentage> | auto | inherit
case CSSPropertyMarginLeft: ////
case CSSPropertyWebkitMarginStart:
case CSSPropertyWebkitMarginEnd:
case CSSPropertyWebkitMarginBefore:
case CSSPropertyWebkitMarginAfter:
if (id == CSSValueAuto)
validPrimitive = true;
else
validPrimitive = (!id && validUnit(value, FLength | FPercent));
break;
case CSSPropertyZIndex: // auto | <integer> | inherit
if (id == CSSValueAuto) {
validPrimitive = true;
break;
}
/* nobreak */
case CSSPropertyOrphans: // <integer> | inherit | auto (We've added support for auto for backwards compatibility)
case CSSPropertyWidows: // <integer> | inherit | auto (Ditto)
if (id == CSSValueAuto)
validPrimitive = true;
else
validPrimitive = (!id && validUnit(value, FInteger, HTMLQuirksMode));
break;
case CSSPropertyLineHeight:
return parseLineHeight(important);
case CSSPropertyCounterIncrement: // [ <identifier> <integer>? ]+ | none | inherit
if (id != CSSValueNone)
return parseCounter(propId, 1, important);
validPrimitive = true;
break;
case CSSPropertyCounterReset: // [ <identifier> <integer>? ]+ | none | inherit
if (id != CSSValueNone)
return parseCounter(propId, 0, important);
validPrimitive = true;
break;
case CSSPropertyFontFamily:
// [[ <family-name> | <generic-family> ],]* [<family-name> | <generic-family>] | inherit
{
parsedValue = parseFontFamily();
break;
}
case CSSPropertyTextDecoration:
// Fall through 'text-decoration-line' parsing if CSS 3 Text Decoration
// is disabled to match CSS 2.1 rules for parsing 'text-decoration'.
if (RuntimeEnabledFeatures::css3TextDecorationsEnabled()) {
// [ <text-decoration-line> || <text-decoration-style> || <text-decoration-color> ] | inherit
return parseShorthand(CSSPropertyTextDecoration, textDecorationShorthand(), important);
}
case CSSPropertyWebkitTextDecorationsInEffect:
case CSSPropertyTextDecorationLine:
// none | [ underline || overline || line-through || blink ] | inherit
return parseTextDecoration(propId, important);
case CSSPropertyTextDecorationStyle:
// solid | double | dotted | dashed | wavy
if (RuntimeEnabledFeatures::css3TextDecorationsEnabled()
&& (id == CSSValueSolid || id == CSSValueDouble || id == CSSValueDotted || id == CSSValueDashed || id == CSSValueWavy))
validPrimitive = true;
break;
#if ENABLE(CSS3_TEXT)
case CSSPropertyWebkitTextUnderlinePosition:
// auto | alphabetic | under
return parseTextUnderlinePosition(important);
#endif // CSS3_TEXT
case CSSPropertyZoom: // normal | reset | document | <number> | <percentage> | inherit
if (id == CSSValueNormal || id == CSSValueReset || id == CSSValueDocument)
validPrimitive = true;
else
validPrimitive = (!id && validUnit(value, FNumber | FPercent | FNonNeg, HTMLStandardMode));
break;
case CSSPropertySrc: // Only used within @font-face and @-webkit-filter, so cannot use inherit | initial or be !important. This is a list of urls or local references.
if (m_inFilterRule)
return parseFilterRuleSrc();
return parseFontFaceSrc();
case CSSPropertyUnicodeRange:
return parseFontFaceUnicodeRange();
/* CSS3 properties */
case CSSPropertyBorderImage: {
RefPtr<CSSValue> result;
return parseBorderImage(propId, result, important);
}
case CSSPropertyWebkitBorderImage:
case CSSPropertyWebkitMaskBoxImage: {
RefPtr<CSSValue> result;
if (parseBorderImage(propId, result)) {
addProperty(propId, result, important);
return true;
}
break;
}
case CSSPropertyBorderImageOutset:
case CSSPropertyWebkitMaskBoxImageOutset: {
RefPtr<CSSPrimitiveValue> result;
if (parseBorderImageOutset(result)) {
addProperty(propId, result, important);
return true;
}
break;
}
case CSSPropertyBorderImageRepeat:
case CSSPropertyWebkitMaskBoxImageRepeat: {
RefPtr<CSSValue> result;
if (parseBorderImageRepeat(result)) {
addProperty(propId, result, important);
return true;
}
break;
}
case CSSPropertyBorderImageSlice:
case CSSPropertyWebkitMaskBoxImageSlice: {
RefPtr<CSSBorderImageSliceValue> result;
if (parseBorderImageSlice(propId, result)) {
addProperty(propId, result, important);
return true;
}
break;
}
case CSSPropertyBorderImageWidth:
case CSSPropertyWebkitMaskBoxImageWidth: {
RefPtr<CSSPrimitiveValue> result;
if (parseBorderImageWidth(result)) {
addProperty(propId, result, important);
return true;
}
break;
}
case CSSPropertyBorderTopRightRadius:
case CSSPropertyBorderTopLeftRadius:
case CSSPropertyBorderBottomLeftRadius:
case CSSPropertyBorderBottomRightRadius: {
if (num != 1 && num != 2)
return false;
validPrimitive = validUnit(value, FLength | FPercent | FNonNeg);
if (!validPrimitive)
return false;
RefPtr<CSSPrimitiveValue> parsedValue1 = createPrimitiveNumericValue(value);
RefPtr<CSSPrimitiveValue> parsedValue2;
if (num == 2) {
value = m_valueList->next();
validPrimitive = validUnit(value, FLength | FPercent | FNonNeg);
if (!validPrimitive)
return false;
parsedValue2 = createPrimitiveNumericValue(value);
} else
parsedValue2 = parsedValue1;
addProperty(propId, createPrimitiveValuePair(parsedValue1.release(), parsedValue2.release()), important);
return true;
}
case CSSPropertyTabSize:
validPrimitive = validUnit(value, FInteger | FNonNeg);
break;
case CSSPropertyWebkitAspectRatio:
return parseAspectRatio(important);
case CSSPropertyBorderRadius:
case CSSPropertyWebkitBorderRadius:
return parseBorderRadius(propId, important);
case CSSPropertyOutlineOffset:
validPrimitive = validUnit(value, FLength | FPercent);
break;
case CSSPropertyTextShadow: // CSS2 property, dropped in CSS2.1, back in CSS3, so treat as CSS3
case CSSPropertyBoxShadow:
case CSSPropertyWebkitBoxShadow:
if (id == CSSValueNone)
validPrimitive = true;
else {
RefPtr<CSSValueList> shadowValueList = parseShadow(m_valueList.get(), propId);
if (shadowValueList) {
addProperty(propId, shadowValueList.release(), important);
m_valueList->next();
return true;
}
return false;
}
break;
case CSSPropertyWebkitBoxReflect:
if (id == CSSValueNone)
validPrimitive = true;
else
return parseReflect(propId, important);
break;
case CSSPropertyOpacity:
validPrimitive = validUnit(value, FNumber);
break;
case CSSPropertyWebkitBoxFlex:
validPrimitive = validUnit(value, FNumber);
break;
case CSSPropertyWebkitBoxFlexGroup:
validPrimitive = validUnit(value, FInteger | FNonNeg, HTMLStandardMode);
break;
case CSSPropertyWebkitBoxOrdinalGroup:
validPrimitive = validUnit(value, FInteger | FNonNeg, HTMLStandardMode) && value->fValue;
break;
case CSSPropertyWebkitFilter:
if (id == CSSValueNone)
validPrimitive = true;
else {
RefPtr<CSSValue> val = parseFilter();
if (val) {
addProperty(propId, val, important);
return true;
}
return false;
}
break;
case CSSPropertyMixBlendMode:
case CSSPropertyIsolation:
if (!RuntimeEnabledFeatures::cssCompositingEnabled())
return false;
validPrimitive = true;
break;
case CSSPropertyFlex: {
ShorthandScope scope(this, propId);
if (id == CSSValueNone) {
addProperty(CSSPropertyFlexGrow, cssValuePool().createValue(0, CSSPrimitiveValue::CSS_NUMBER), important);
addProperty(CSSPropertyFlexShrink, cssValuePool().createValue(0, CSSPrimitiveValue::CSS_NUMBER), important);
addProperty(CSSPropertyFlexBasis, cssValuePool().createIdentifierValue(CSSValueAuto), important);
return true;
}
return parseFlex(m_valueList.get(), important);
}
case CSSPropertyFlexBasis:
// FIXME: Support intrinsic dimensions too.
if (id == CSSValueAuto)
validPrimitive = true;
else
validPrimitive = (!id && validUnit(value, FLength | FPercent | FNonNeg));
break;
case CSSPropertyFlexGrow:
case CSSPropertyFlexShrink:
validPrimitive = validUnit(value, FNumber | FNonNeg);
break;
case CSSPropertyOrder:
if (validUnit(value, FInteger, HTMLStandardMode)) {
if (value->unit != CSSPrimitiveValue::CSS_VARIABLE_NAME) {
// We restrict the smallest value to int min + 2 because we use int min and int min + 1 as special values in a hash set.
parsedValue = cssValuePool().createValue(max(static_cast<double>(std::numeric_limits<int>::min() + 2), value->fValue),
static_cast<CSSPrimitiveValue::UnitTypes>(value->unit));
m_valueList->next();
} else {
validPrimitive = true;
}
}
break;
case CSSPropertyInternalMarqueeIncrement:
if (id == CSSValueSmall || id == CSSValueLarge || id == CSSValueMedium)
validPrimitive = true;
else
validPrimitive = validUnit(value, FLength | FPercent);
break;
case CSSPropertyInternalMarqueeRepetition:
if (id == CSSValueInfinite)
validPrimitive = true;
else
validPrimitive = validUnit(value, FInteger | FNonNeg);
break;
case CSSPropertyInternalMarqueeSpeed:
if (id == CSSValueNormal || id == CSSValueSlow || id == CSSValueFast)
validPrimitive = true;
else
validPrimitive = validUnit(value, FTime | FInteger | FNonNeg);
break;
case CSSPropertyWebkitFlowInto:
if (!RuntimeEnabledFeatures::cssRegionsEnabled())
return false;
return parseFlowThread(propId, important);
case CSSPropertyWebkitFlowFrom:
if (!RuntimeEnabledFeatures::cssRegionsEnabled())
return false;
return parseRegionThread(propId, important);
case CSSPropertyWebkitTransform:
if (id == CSSValueNone)