diff options
author | Simon Hausmann <simon.hausmann@nokia.com> | 2012-09-10 19:10:20 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2012-09-10 19:10:20 +0200 |
commit | 284837daa07b29d6a63a748544a90b1f5842ac5c (patch) | |
tree | ecd258180bde91fe741e0cfd2638beb3c6da7e8e /Source/WebCore/css/CSSParser.cpp | |
parent | 2e2ba8ff45915f40ed3e014101269c175f2a89a0 (diff) | |
download | qtwebkit-284837daa07b29d6a63a748544a90b1f5842ac5c.tar.gz |
Imported WebKit commit 68645295d2e3e09af2c942f092556f06aa5f8b0d (http://svn.webkit.org/repository/webkit/trunk@128073)
New snapshot
Diffstat (limited to 'Source/WebCore/css/CSSParser.cpp')
-rw-r--r-- | Source/WebCore/css/CSSParser.cpp | 1235 |
1 files changed, 772 insertions, 463 deletions
diff --git a/Source/WebCore/css/CSSParser.cpp b/Source/WebCore/css/CSSParser.cpp index 7a5ea37d3..28ce13157 100644 --- a/Source/WebCore/css/CSSParser.cpp +++ b/Source/WebCore/css/CSSParser.cpp @@ -27,6 +27,7 @@ #include "CSSParser.h" #include "CSSAspectRatioValue.h" +#include "CSSBasicShapes.h" #include "CSSBorderImage.h" #include "CSSCanvasValue.h" #include "CSSCrossfadeValue.h" @@ -56,7 +57,6 @@ #if ENABLE(CSS_VARIABLES) #include "CSSVariableValue.h" #endif -#include "CSSWrapShapes.h" #include "Counter.h" #include "Document.h" #include "FloatConversion.h" @@ -91,6 +91,7 @@ #include <wtf/dtoa.h> #include <wtf/text/StringBuffer.h> #include <wtf/text/StringBuilder.h> +#include <wtf/text/StringImpl.h> #if ENABLE(CSS_IMAGE_SET) #include "CSSImageSetValue.h" @@ -104,6 +105,7 @@ #endif #if ENABLE(CSS_SHADERS) +#include "WebKitCSSArrayFunctionValue.h" #include "WebKitCSSMixFunctionValue.h" #include "WebKitCSSShaderValue.h" #endif @@ -155,27 +157,24 @@ namespace WebCore { static const unsigned INVALID_NUM_PARSED_PROPERTIES = UINT_MAX; static const double MAX_SCALE = 1000000; -static bool equal(const CSSParserString& a, const char* b) +template <unsigned N> +static bool equal(const CSSParserString& a, const char (&b)[N]) { - for (int i = 0; i < a.length; ++i) { - if (!b[i]) - return false; - if (a.characters[i] != b[i]) - return false; - } - return !b[a.length]; + 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); } -static bool equalIgnoringCase(const CSSParserString& a, const char* b) +template <unsigned N> +static bool equalIgnoringCase(const CSSParserString& a, const char (&b)[N]) { - for (int i = 0; i < a.length; ++i) { - if (!b[i]) - return false; - ASSERT(!isASCIIUpper(b[i])); - if (toASCIILower(a.characters[i]) != b[i]) - return false; - } - return !b[a.length]; + 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); } static bool hasPrefix(const char* string, unsigned length, const char* prefix) @@ -260,8 +259,10 @@ CSSParser::CSSParser(const CSSParserContext& context) , m_propertyRange(UINT_MAX, UINT_MAX) , m_ruleSourceDataResult(0) , m_parsingMode(NormalMode) - , m_currentCharacter(0) - , m_tokenStart(0) + , m_is8BitSource(false) + , m_currentCharacter8(0) + , m_currentCharacter16(0) + , m_length(0) , m_token(0) , m_lineNumber(0) , m_lastSelectorLineNumber(0) @@ -272,6 +273,7 @@ CSSParser::CSSParser(const CSSParserContext& context) #if YYDEBUG > 0 cssyydebug = 1; #endif + m_tokenStart.ptr8 = 0; CSSPropertySourceData::init(); } @@ -285,7 +287,8 @@ CSSParser::~CSSParser() deleteAllValues(m_floatingFunctions); } -void CSSParserString::lower() +template <typename CharacterType> +ALWAYS_INLINE static void makeLower(CharacterType* characters, unsigned length) { // FIXME: If we need Unicode lowercasing here, then we probably want the real kind // that can potentially change the length of the string rather than the character @@ -294,33 +297,73 @@ void CSSParserString::lower() if (charactersAreAllASCII(characters, length)) { // Fast case for all-ASCII. - for (int i = 0; i < length; i++) + for (unsigned i = 0; i < length; i++) characters[i] = toASCIILower(characters[i]); } else { - for (int i = 0; i < length; i++) + for (unsigned i = 0; i < length; i++) characters[i] = Unicode::toLower(characters[i]); } } +void CSSParserString::lower() +{ + if (is8Bit()) { + makeLower(characters8(), length()); + return; + } + + makeLower(characters16(), length()); +} + void CSSParser::setupParser(const char* prefix, const String& string, const char* suffix) { m_parsedTextPrefixLength = strlen(prefix); - int length = string.length() + m_parsedTextPrefixLength + strlen(suffix) + 1; + unsigned stringLength = string.length(); + unsigned length = stringLength + m_parsedTextPrefixLength + strlen(suffix) + 1; + + 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 + strlen(suffix); + 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_length = length; + m_lexFunc = &CSSParser::realLex<LChar>; + return; + } - m_dataStart = adoptArrayPtr(new UChar[length]); + m_dataStart16 = adoptArrayPtr(new UChar[length]); for (unsigned i = 0; i < m_parsedTextPrefixLength; i++) - m_dataStart[i] = prefix[i]; + m_dataStart16[i] = prefix[i]; - memcpy(m_dataStart.get() + m_parsedTextPrefixLength, string.characters(), string.length() * sizeof(UChar)); + memcpy(m_dataStart16.get() + m_parsedTextPrefixLength, string.characters(), stringLength * sizeof(UChar)); - unsigned start = m_parsedTextPrefixLength + string.length(); + unsigned start = m_parsedTextPrefixLength + stringLength; unsigned end = start + strlen(suffix); for (unsigned i = start; i < end; i++) - m_dataStart[i] = suffix[i - start]; + m_dataStart16[i] = suffix[i - start]; - m_dataStart[length - 1] = 0; + m_dataStart16[length - 1] = 0; - m_currentCharacter = m_tokenStart = m_dataStart.get(); + m_is8BitSource = false; + m_currentCharacter8 = 0; + m_currentCharacter16 = m_dataStart16.get(); + setTokenStart<UChar>(m_currentCharacter16); + m_length = length; + m_lexFunc = &CSSParser::realLex<UChar>; } void CSSParser::parseSheet(StyleSheetContents* sheet, const String& string, int startLineNumber, RuleSourceDataList* ruleSourceDataResult) @@ -390,8 +433,7 @@ static bool parseColorValue(StylePropertySet* declaration, CSSPropertyID propert if (!isColorPropertyID(propertyId)) return false; CSSParserString cssString; - cssString.characters = const_cast<UChar*>(string.characters()); - cssString.length = string.length(); + cssString.init(string); int valueID = cssValueKeywordID(cssString); bool validPrimitive = false; if (valueID == CSSValueWebkitText) @@ -464,8 +506,8 @@ static inline bool isSimpleLengthPropertyID(CSSPropertyID propertyId, bool& acce } } -template <typename CharType> -static inline bool parseSimpleLength(const CharType* characters, unsigned& length, CSSPrimitiveValue::UnitTypes& unit, double& number) +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; @@ -558,12 +600,8 @@ static inline bool isValidKeywordPropertyAndValue(CSSPropertyID propertyId, int // 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 // -webkit-flex | -webkit-inline-flex | -webkit-grid | -webkit-inline-grid - if ((valueID >= CSSValueInline && valueID <= CSSValueWebkitInlineBox) || valueID == CSSValueNone) + if ((valueID >= CSSValueInline && valueID <= CSSValueWebkitInlineFlex) || valueID == CSSValueNone) return true; -#if ENABLE(CSS3_FLEXBOX) - if (valueID == CSSValueWebkitFlex || valueID == CSSValueWebkitInlineFlex) - return true; -#endif if (parserContext.isCSSGridLayoutEnabled && (valueID == CSSValueWebkitGrid || valueID == CSSValueWebkitInlineGrid)) return true; break; @@ -598,6 +636,11 @@ static inline bool isValidKeywordPropertyAndValue(CSSPropertyID propertyId, int 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 | marquee | overlay | inherit if (valueID == CSSValueVisible || valueID == CSSValueHidden || valueID == CSSValueScroll || valueID == CSSValueAuto || valueID == CSSValueOverlay || valueID == CSSValueWebkitMarquee) return true; @@ -723,7 +766,6 @@ static inline bool isValidKeywordPropertyAndValue(CSSPropertyID propertyId, int if (valueID == CSSValueSrgb || valueID == CSSValueDefault) return true; break; -#if ENABLE(CSS3_FLEXBOX) case CSSPropertyWebkitAlignContent: if (valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueSpaceBetween || valueID == CSSValueSpaceAround || valueID == CSSValueStretch) return true; @@ -748,7 +790,6 @@ static inline bool isValidKeywordPropertyAndValue(CSSPropertyID propertyId, int if (valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueSpaceBetween || valueID == CSSValueSpaceAround) return true; break; -#endif case CSSPropertyWebkitFontKerning: if (valueID == CSSValueAuto || valueID == CSSValueNormal || valueID == CSSValueNone) return true; @@ -881,10 +922,6 @@ static inline bool isValidKeywordPropertyAndValue(CSSPropertyID propertyId, int if (valueID == CSSValueNormal || valueID == CSSValueBreakAll || valueID == CSSValueBreakWord) return true; break; - case CSSPropertyWordWrap: // normal | break-word - if (valueID == CSSValueNormal || valueID == CSSValueBreakWord) - return true; - break; default: ASSERT_NOT_REACHED(); return false; @@ -912,6 +949,7 @@ static inline bool isKeywordPropertyID(CSSPropertyID propertyId) case CSSPropertyListStylePosition: case CSSPropertyListStyleType: case CSSPropertyOutlineStyle: + case CSSPropertyOverflowWrap: case CSSPropertyOverflowX: case CSSPropertyOverflowY: case CSSPropertyPageBreakAfter: @@ -955,14 +993,12 @@ static inline bool isKeywordPropertyID(CSSPropertyID propertyId) case CSSPropertyWebkitColumnBreakBefore: case CSSPropertyWebkitColumnBreakInside: case CSSPropertyWebkitColumnRuleStyle: -#if ENABLE(CSS3_FLEXBOX) case CSSPropertyWebkitAlignContent: case CSSPropertyWebkitAlignItems: case CSSPropertyWebkitAlignSelf: case CSSPropertyWebkitFlexDirection: case CSSPropertyWebkitFlexWrap: case CSSPropertyWebkitJustifyContent: -#endif case CSSPropertyWebkitFontKerning: case CSSPropertyWebkitFontSmoothing: case CSSPropertyWebkitHyphens: @@ -1017,8 +1053,7 @@ static bool parseKeywordValue(StylePropertySet* declaration, CSSPropertyID prope return false; CSSParserString cssString; - cssString.characters = const_cast<UChar*>(string.characters()); - cssString.length = string.length(); + cssString.init(string); int valueID = cssValueKeywordID(cssString); if (!valueID) @@ -1038,8 +1073,8 @@ static bool parseKeywordValue(StylePropertySet* declaration, CSSPropertyID prope return true; } -template <typename CharType> -static bool parseTransformArguments(WebKitCSSTransformValue* transformValue, CharType* characters, unsigned length, unsigned start, unsigned expectedCount) +template <typename CharacterType> +static bool parseTransformArguments(WebKitCSSTransformValue* transformValue, CharacterType* characters, unsigned length, unsigned start, unsigned expectedCount) { while (expectedCount) { size_t end = WTF::find(characters, length, expectedCount == 1 ? ')' : ',', start); @@ -1222,8 +1257,7 @@ bool CSSParser::parseSystemColor(RGBA32& color, const String& string, Document* return false; CSSParserString cssColor; - cssColor.characters = const_cast<UChar*>(string.characters()); - cssColor.length = string.length(); + cssColor.init(string); int id = cssValueKeywordID(cssColor); if (id <= 0) return false; @@ -1443,6 +1477,11 @@ bool CSSParser::validCalculationUnit(CSSParserValue* value, Units unitflags) case CalcPercentNumber: b = (unitflags & FPercent) && (unitflags & FNumber); break; +#if ENABLE(CSS_VARIABLES) + case CalcVariable: + b = true; + break; +#endif case CalcOther: break; } @@ -2304,7 +2343,6 @@ bool CSSParser::parseValue(CSSPropertyID propId, bool important) validPrimitive = true; break; #endif -#if ENABLE(CSS3_FLEXBOX) case CSSPropertyWebkitFlex: { ShorthandScope scope(this, propId); if (id == CSSValueNone) { @@ -2334,7 +2372,6 @@ bool CSSParser::parseValue(CSSPropertyID propId, bool important) m_valueList->next(); } break; -#endif case CSSPropertyWebkitMarquee: return parseShorthand(propId, webkitMarqueeShorthand(), important); case CSSPropertyWebkitMarqueeIncrement: @@ -2656,10 +2693,8 @@ bool CSSParser::parseValue(CSSPropertyID propId, bool important) case CSSPropertyPadding: // <padding-width>{1,4} | inherit return parse4Values(propId, paddingShorthand().properties(), important); -#if ENABLE(CSS3_FLEXBOX) case CSSPropertyWebkitFlexFlow: return parseShorthand(propId, webkitFlexFlowShorthand(), important); -#endif case CSSPropertyFont: // [ [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]? // 'font-family' ] | caption | icon | menu | message-box | small-caption | status-bar | inherit @@ -2721,6 +2756,12 @@ bool CSSParser::parseValue(CSSPropertyID propId, bool important) else return parseFontVariantLigatures(important); break; + case CSSPropertyWebkitClipPath: + if (id == CSSValueNone) + validPrimitive = true; + else if (value->unit == CSSParserValue::Function) + return parseBasicShape(propId, important); + break; #if ENABLE(CSS_EXCLUSIONS) case CSSPropertyWebkitShapeInside: case CSSPropertyWebkitShapeOutside: @@ -2729,7 +2770,7 @@ bool CSSParser::parseValue(CSSPropertyID propId, bool important) if (id == CSSValueAuto) validPrimitive = true; else if (value->unit == CSSParserValue::Function) - return parseExclusionShape((propId == CSSPropertyWebkitShapeInside), important); + return parseBasicShape(propId, important); break; case CSSPropertyWebkitWrapMargin: case CSSPropertyWebkitWrapPadding: @@ -2768,6 +2809,7 @@ bool CSSParser::parseValue(CSSPropertyID propId, bool important) case CSSPropertyListStylePosition: case CSSPropertyListStyleType: case CSSPropertyOutlineStyle: + case CSSPropertyOverflowWrap: case CSSPropertyOverflowX: case CSSPropertyOverflowY: case CSSPropertyPageBreakAfter: @@ -2811,14 +2853,12 @@ bool CSSParser::parseValue(CSSPropertyID propId, bool important) case CSSPropertyWebkitColumnBreakBefore: case CSSPropertyWebkitColumnBreakInside: case CSSPropertyWebkitColumnRuleStyle: -#if ENABLE(CSS3_FLEXBOX) case CSSPropertyWebkitAlignContent: case CSSPropertyWebkitAlignItems: case CSSPropertyWebkitAlignSelf: case CSSPropertyWebkitFlexDirection: case CSSPropertyWebkitFlexWrap: case CSSPropertyWebkitJustifyContent: -#endif case CSSPropertyWebkitFontKerning: case CSSPropertyWebkitFontSmoothing: case CSSPropertyWebkitHyphens: @@ -3065,8 +3105,8 @@ void CSSParser::storeVariableDeclaration(const CSSParserString& name, PassOwnPtr if (!value) return; - ASSERT(name.length > 12); - AtomicString variableName = String(name.characters + 12, name.length - 12); + ASSERT(name.length() > 12); + AtomicString variableName = name.is8Bit() ? AtomicString(name.characters8() + 12, name.length() - 12) : AtomicString(name.characters16() + 12, name.length() - 12); StringBuilder builder; for (unsigned i = 0, size = value->size(); i < size; i++) { @@ -4307,7 +4347,7 @@ bool CSSParser::parseDashboardRegions(CSSPropertyID propId, bool important) } bool validFunctionName = false; #if ENABLE(DASHBOARD_SUPPORT) - static const char* const dashboardRegionFunctionName = "dashboard-region("; + static const char dashboardRegionFunctionName[] = "dashboard-region("; if (equalIgnoringCase(value->function->name, dashboardRegionFunctionName)) { validFunctionName = true; #if ENABLE(DASHBOARD_SUPPORT) && ENABLE(WIDGET_REGION) @@ -4317,7 +4357,7 @@ bool CSSParser::parseDashboardRegions(CSSPropertyID propId, bool important) } #endif #if ENABLE(WIDGET_REGION) - static const char* const widgetRegionFunctionName = "region("; + static const char widgetRegionFunctionName[] = "region("; if (equalIgnoringCase(value->function->name, widgetRegionFunctionName)) { validFunctionName = true; #if ENABLE(DASHBOARD_SUPPORT) && ENABLE(WIDGET_REGION) @@ -4515,9 +4555,7 @@ bool CSSParser::parseClipShape(CSSPropertyID propId, bool important) return false; } -#if ENABLE(CSS_EXCLUSIONS) - -PassRefPtr<CSSWrapShape> CSSParser::parseExclusionShapeRectangle(CSSParserValueList* args) +PassRefPtr<CSSBasicShape> CSSParser::parseBasicShapeRectangle(CSSParserValueList* args) { ASSERT(args); @@ -4525,7 +4563,7 @@ PassRefPtr<CSSWrapShape> CSSParser::parseExclusionShapeRectangle(CSSParserValueL if (args->size() != 7 && args->size() != 9 && args->size() != 11) return 0; - RefPtr<CSSWrapShapeRectangle> shape = CSSWrapShapeRectangle::create(); + RefPtr<CSSBasicShapeRectangle> shape = CSSBasicShapeRectangle::create(); unsigned argumentNumber = 0; CSSParserValue* argument = args->current(); @@ -4575,7 +4613,7 @@ PassRefPtr<CSSWrapShape> CSSParser::parseExclusionShapeRectangle(CSSParserValueL return shape; } -PassRefPtr<CSSWrapShape> CSSParser::parseExclusionShapeCircle(CSSParserValueList* args) +PassRefPtr<CSSBasicShape> CSSParser::parseBasicShapeCircle(CSSParserValueList* args) { ASSERT(args); @@ -4583,7 +4621,7 @@ PassRefPtr<CSSWrapShape> CSSParser::parseExclusionShapeCircle(CSSParserValueList if (args->size() != 5) return 0; - RefPtr<CSSWrapShapeCircle> shape = CSSWrapShapeCircle::create(); + RefPtr<CSSBasicShapeCircle> shape = CSSBasicShapeCircle::create(); unsigned argumentNumber = 0; CSSParserValue* argument = args->current(); @@ -4625,7 +4663,7 @@ PassRefPtr<CSSWrapShape> CSSParser::parseExclusionShapeCircle(CSSParserValueList return shape; } -PassRefPtr<CSSWrapShape> CSSParser::parseExclusionShapeEllipse(CSSParserValueList* args) +PassRefPtr<CSSBasicShape> CSSParser::parseBasicShapeEllipse(CSSParserValueList* args) { ASSERT(args); @@ -4633,7 +4671,7 @@ PassRefPtr<CSSWrapShape> CSSParser::parseExclusionShapeEllipse(CSSParserValueLis if (args->size() != 7) return 0; - RefPtr<CSSWrapShapeEllipse> shape = CSSWrapShapeEllipse::create(); + RefPtr<CSSBasicShapeEllipse> shape = CSSBasicShapeEllipse::create(); unsigned argumentNumber = 0; CSSParserValue* argument = args->current(); while (argument) { @@ -4676,7 +4714,7 @@ PassRefPtr<CSSWrapShape> CSSParser::parseExclusionShapeEllipse(CSSParserValueLis return shape; } -PassRefPtr<CSSWrapShape> CSSParser::parseExclusionShapePolygon(CSSParserValueList* args) +PassRefPtr<CSSBasicShape> CSSParser::parseBasicShapePolygon(CSSParserValueList* args) { ASSERT(args); @@ -4684,7 +4722,7 @@ PassRefPtr<CSSWrapShape> CSSParser::parseExclusionShapePolygon(CSSParserValueLis if (!size) return 0; - RefPtr<CSSWrapShapePolygon> shape = CSSWrapShapePolygon::create(); + RefPtr<CSSBasicShapePolygon> shape = CSSBasicShapePolygon::create(); CSSParserValue* argument = args->current(); if (argument->id == CSSValueEvenodd || argument->id == CSSValueNonzero) { @@ -4727,36 +4765,33 @@ PassRefPtr<CSSWrapShape> CSSParser::parseExclusionShapePolygon(CSSParserValueLis return shape; } -bool CSSParser::parseExclusionShape(bool shapeInside, bool important) +bool CSSParser::parseBasicShape(CSSPropertyID propId, bool important) { CSSParserValue* value = m_valueList->current(); + ASSERT(value->unit == CSSParserValue::Function); CSSParserValueList* args = value->function->args.get(); if (!args) return false; - RefPtr<CSSWrapShape> shape; - + RefPtr<CSSBasicShape> shape; if (equalIgnoringCase(value->function->name, "rectangle(")) - shape = parseExclusionShapeRectangle(args); + shape = parseBasicShapeRectangle(args); else if (equalIgnoringCase(value->function->name, "circle(")) - shape = parseExclusionShapeCircle(args); + shape = parseBasicShapeCircle(args); else if (equalIgnoringCase(value->function->name, "ellipse(")) - shape = parseExclusionShapeEllipse(args); + shape = parseBasicShapeEllipse(args); else if (equalIgnoringCase(value->function->name, "polygon(")) - shape = parseExclusionShapePolygon(args); + shape = parseBasicShapePolygon(args); - if (shape) { - addProperty(shapeInside ? CSSPropertyWebkitShapeInside : CSSPropertyWebkitShapeOutside, cssValuePool().createValue(shape.release()), important); - m_valueList->next(); - return true; - } + if (!shape) + return false; - return false; + addProperty(propId, cssValuePool().createValue(shape.release()), important); + m_valueList->next(); + return true; } -#endif - // [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]? 'font-family' bool CSSParser::parseFont(bool important) { @@ -4843,7 +4878,13 @@ public: { if (!m_builder.isEmpty()) m_builder.append(' '); - m_builder.append(string.characters, string.length); + + if (string.is8Bit()) { + m_builder.append(string.characters8(), string.length()); + return; + } + + m_builder.append(string.characters16(), string.length()); } void commit() @@ -5196,7 +5237,8 @@ bool CSSParser::parseFontFaceUnicodeRange() // Returns the number of characters which form a valid double // and are terminated by the given terminator character -static int checkForValidDouble(const UChar* string, const UChar* end, const char terminator) +template <typename CharacterType> +static int checkForValidDouble(const CharacterType* string, const CharacterType* end, const char terminator) { int length = end - string; if (length < 1) @@ -5226,7 +5268,8 @@ static int checkForValidDouble(const UChar* string, const UChar* end, const char // Returns the number of characters consumed for parsing a valid double // terminated by the given terminator character -static int parseDouble(const UChar* string, const UChar* end, const char terminator, double& value) +template <typename CharacterType> +static int parseDouble(const CharacterType* string, const CharacterType* end, const char terminator, double& value) { int length = checkForValidDouble(string, end, terminator); if (!length) @@ -5260,9 +5303,10 @@ static int parseDouble(const UChar* string, const UChar* end, const char termina return length; } -static bool parseColorIntOrPercentage(const UChar*& string, const UChar* end, const char terminator, CSSPrimitiveValue::UnitTypes& expect, int& value) +template <typename CharacterType> +static bool parseColorIntOrPercentage(const CharacterType*& string, const CharacterType* end, const char terminator, CSSPrimitiveValue::UnitTypes& expect, int& value) { - const UChar* current = string; + const CharacterType* current = string; double localValue = 0; bool negative = false; while (current != end && isHTMLSpace(*current)) @@ -5327,7 +5371,8 @@ static bool parseColorIntOrPercentage(const UChar*& string, const UChar* end, co return true; } -static inline bool isTenthAlpha(const UChar* string, const int length) +template <typename CharacterType> +static inline bool isTenthAlpha(const CharacterType* string, const int length) { // "0.X" if (length == 3 && string[0] == '0' && string[1] == '.' && isASCIIDigit(string[2])) @@ -5340,7 +5385,8 @@ static inline bool isTenthAlpha(const UChar* string, const int length) return false; } -static inline bool parseAlphaValue(const UChar*& string, const UChar* end, const char terminator, int& value) +template <typename CharacterType> +static inline bool parseAlphaValue(const CharacterType*& string, const CharacterType* end, const char terminator, int& value) { while (string != end && isHTMLSpace(*string)) string++; @@ -5391,7 +5437,8 @@ static inline bool parseAlphaValue(const UChar*& string, const UChar* end, const return true; } -static inline bool mightBeRGBA(const UChar* characters, unsigned length) +template <typename CharacterType> +static inline bool mightBeRGBA(const CharacterType* characters, unsigned length) { if (length < 5) return false; @@ -5402,7 +5449,8 @@ static inline bool mightBeRGBA(const UChar* characters, unsigned length) && isASCIIAlphaCaselessEqual(characters[3], 'a'); } -static inline bool mightBeRGB(const UChar* characters, unsigned length) +template <typename CharacterType> +static inline bool mightBeRGB(const CharacterType* characters, unsigned length) { if (length < 4) return false; @@ -5412,14 +5460,13 @@ static inline bool mightBeRGB(const UChar* characters, unsigned length) && isASCIIAlphaCaselessEqual(characters[2], 'b'); } -bool CSSParser::fastParseColor(RGBA32& rgb, const String& name, bool strict) +template <typename CharacterType> +static inline bool fastParseColorInternal(RGBA32& rgb, const CharacterType* characters, unsigned length , bool strict) { - const UChar* characters = name.characters(); - unsigned length = name.length(); CSSPrimitiveValue::UnitTypes expect = CSSPrimitiveValue::CSS_UNKNOWN; - + if (!strict && length >= 3) { - if (name[0] == '#') { + if (characters[0] == '#') { if (Color::parseHexColor(characters + 1, length - 1, rgb)) return true; } else { @@ -5430,13 +5477,13 @@ bool CSSParser::fastParseColor(RGBA32& rgb, const String& name, bool strict) // Try rgba() syntax. if (mightBeRGBA(characters, length)) { - const UChar* current = characters + 5; - const UChar* end = characters + length; + const CharacterType* current = characters + 5; + const CharacterType* end = characters + length; int red; int green; int blue; int alpha; - + if (!parseColorIntOrPercentage(current, end, ',', expect, red)) return false; if (!parseColorIntOrPercentage(current, end, ',', expect, green)) @@ -5453,8 +5500,8 @@ bool CSSParser::fastParseColor(RGBA32& rgb, const String& name, bool strict) // Try rgb() syntax. if (mightBeRGB(characters, length)) { - const UChar* current = characters + 4; - const UChar* end = characters + length; + const CharacterType* current = characters + 4; + const CharacterType* end = characters + length; int red; int green; int blue; @@ -5470,6 +5517,25 @@ bool CSSParser::fastParseColor(RGBA32& rgb, const String& name, bool strict) return true; } + return false; +} + +bool CSSParser::fastParseColor(RGBA32& rgb, const String& name, bool strict) +{ + unsigned length = name.length(); + bool parseResult; + + if (!length) + return false; + + if (name.is8Bit()) + parseResult = fastParseColorInternal(rgb, name.characters8(), length, strict); + else + parseResult = fastParseColorInternal(rgb, name.characters(), length, strict); + + if (parseResult) + return true; + // Try named colors. Color tc; tc.setNamedColor(name); @@ -5478,6 +5544,7 @@ bool CSSParser::fastParseColor(RGBA32& rgb, const String& name, bool strict) return true; } return false; + } inline double CSSParser::parsedDouble(CSSParserValue *v, ReleaseParsedCalcValueCondition releaseCalc) @@ -5891,8 +5958,6 @@ bool CSSParser::parseReflect(CSSPropertyID propId, bool important) return true; } -#if ENABLE(CSS3_FLEXBOX) - bool CSSParser::parseFlex(CSSParserValueList* args, bool important) { if (!args || !args->size() || args->size() > 3) @@ -5937,8 +6002,6 @@ bool CSSParser::parseFlex(CSSParserValueList* args, bool important) return true; } -#endif - struct BorderImageParseContext { BorderImageParseContext() : m_canAdvance(false) @@ -7180,9 +7243,16 @@ PassRefPtr<CSSValue> CSSParser::parseImageSet(CSSParserValueList* valueList) double imageScaleFactor = 0; const String& string = arg->string; - const UChar* current = string.characters(); - const UChar* end = current + string.length(); - parseDouble(current, end, 'x', imageScaleFactor); + unsigned length = string.length(); + if (!length) + return 0; + if (string.is8Bit()) { + const LChar* start = string.characters8(); + parseDouble(start, start + length, 'x', imageScaleFactor); + } else { + const UChar* start = string.characters(); + parseDouble(start, start + length, 'x', imageScaleFactor); + } if (imageScaleFactor <= 0) return 0; imageSet->append(cssValuePool().createValue(imageScaleFactor, CSSPrimitiveValue::CSS_NUMBER)); @@ -7207,10 +7277,10 @@ PassRefPtr<CSSValue> CSSParser::parseImageSet(CSSParserValueList* valueList) class TransformOperationInfo { public: TransformOperationInfo(const CSSParserString& name) - : m_type(WebKitCSSTransformValue::UnknownTransformOperation) - , m_argCount(1) - , m_allowSingleArgument(false) - , m_unit(CSSParser::FUnknown) + : m_type(WebKitCSSTransformValue::UnknownTransformOperation) + , m_argCount(1) + , m_allowSingleArgument(false) + , m_unit(CSSParser::FUnknown) { if (equalIgnoringCase(name, "scale(") || equalIgnoringCase(name, "scalex(") || equalIgnoringCase(name, "scaley(") || equalIgnoringCase(name, "scalez(")) { m_unit = CSSParser::FNumber; @@ -7437,6 +7507,41 @@ static bool acceptCommaOperator(CSSParserValueList* argsList) return true; } +PassRefPtr<WebKitCSSArrayFunctionValue> CSSParser::parseCustomFilterArrayFunction(CSSParserValue* value) +{ + ASSERT(value->unit == CSSParserValue::Function && value->function); + + if (!equalIgnoringCase(value->function->name, "array(")) + return 0; + + CSSParserValueList* arrayArgsParserValueList = value->function->args.get(); + if (!arrayArgsParserValueList || !arrayArgsParserValueList->size()) + return 0; + + // array() values are comma separated. + RefPtr<WebKitCSSArrayFunctionValue> arrayFunction = WebKitCSSArrayFunctionValue::create(); + while (true) { + // We parse pairs <Value, Comma> at each step. + CSSParserValue* currentParserValue = arrayArgsParserValueList->current(); + if (!currentParserValue || !validUnit(currentParserValue, FNumber, CSSStrictMode)) + return 0; + + RefPtr<CSSValue> arrayValue = cssValuePool().createValue(currentParserValue->fValue, CSSPrimitiveValue::CSS_NUMBER); + arrayFunction->append(arrayValue.release()); + + CSSParserValue* nextParserValue = arrayArgsParserValueList->next(); + if (!nextParserValue) + break; + + if (!isComma(nextParserValue)) + return 0; + + arrayArgsParserValueList->next(); + } + + return arrayFunction; +} + PassRefPtr<WebKitCSSMixFunctionValue> CSSParser::parseMixFunction(CSSParserValue* value) { ASSERT(value->unit == CSSParserValue::Function && value->function); @@ -7445,6 +7550,9 @@ PassRefPtr<WebKitCSSMixFunctionValue> CSSParser::parseMixFunction(CSSParserValue return 0; CSSParserValueList* argsList = value->function->args.get(); + if (!argsList) + return 0; + unsigned numArgs = argsList->size(); if (numArgs < 1 || numArgs > 3) return 0; @@ -7602,13 +7710,19 @@ PassRefPtr<WebKitCSSFilterValue> CSSParser::parseCustomFilter(CSSParserValue* va RefPtr<CSSValue> parameterValue; - if (arg->unit == CSSParserValue::Function && arg->function) + if (arg->unit == CSSParserValue::Function && arg->function) { // TODO: Implement other parameters types parsing. // textures: https://bugs.webkit.org/show_bug.cgi?id=71442 // mat2, mat3, mat4: https://bugs.webkit.org/show_bug.cgi?id=71444 - // array: https://bugs.webkit.org/show_bug.cgi?id=94226 // 3d-transform shall be the last to be checked - parameterValue = parseCustomFilterTransform(argsList); + if (equalIgnoringCase(arg->function->name, "array(")) { + parameterValue = parseCustomFilterArrayFunction(arg); + // This parsing step only consumes function arguments, + // argsList is therefore moved forward explicitely. + argsList->next(); + } else + parameterValue = parseCustomFilterTransform(argsList); + } else { RefPtr<CSSValueList> paramValueList = CSSValueList::createSpaceSeparated(); while ((arg = argsList->current())) { @@ -8143,17 +8257,17 @@ bool CSSParser::parseLineBoxContain(bool important) bool CSSParser::parseFontFeatureTag(CSSValueList* settings) { // Feature tag name consists of 4-letter characters. - static const int tagNameLength = 4; + static const unsigned tagNameLength = 4; CSSParserValue* value = m_valueList->current(); // Feature tag name comes first if (value->unit != CSSPrimitiveValue::CSS_STRING) return false; - if (value->string.length != tagNameLength) + if (value->string.length() != tagNameLength) return false; - for (int i = 0; i < tagNameLength; ++i) { + for (unsigned i = 0; i < tagNameLength; ++i) { // Limits the range of characters to 0x20-0x7E, following the tag name rules defiend in the OpenType specification. - UChar character = value->string.characters[i]; + UChar character = value->string[i]; if (character < 0x20 || character > 0x7E) return false; } @@ -8434,30 +8548,35 @@ static const CharacterType typesOfASCIICharacters[128] = { // Utility functions for the CSS tokenizer. -static inline bool isCSSLetter(UChar character) +template <typename CharacterType> +static inline bool isCSSLetter(CharacterType character) { return character >= 128 || typesOfASCIICharacters[character] <= CharacterDash; } -static inline bool isCSSEscape(UChar character) +template <typename CharacterType> +static inline bool isCSSEscape(CharacterType character) { return character >= ' ' && character != 127; } -static inline bool isURILetter(UChar character) +template <typename CharacterType> +static inline bool isURILetter(CharacterType character) { return (character >= '*' && character != 127) || (character >= '#' && character <= '&') || character == '!'; } -static inline bool isIdentifierStartAfterDash(UChar* currentCharacter) +template <typename CharacterType> +static inline bool isIdentifierStartAfterDash(CharacterType* currentCharacter) { return isASCIIAlpha(currentCharacter[0]) || currentCharacter[0] == '_' || currentCharacter[0] >= 128 || (currentCharacter[0] == '\\' && isCSSEscape(currentCharacter[1])); } -static inline bool isEqualToCSSIdentifier(UChar* cssString, const char* constantString) +template <typename CharacterType> +static inline bool isEqualToCSSIdentifier(CharacterType* cssString, const char* constantString) { - // Compare an UChar memory data with a zero terminated string. + // Compare an character memory data with a zero terminated string. do { // The input must be part of an identifier if constantChar or constString // contains '-'. Otherwise toASCIILowerUnchecked('\r') would be equal to '-'. @@ -8469,7 +8588,8 @@ static inline bool isEqualToCSSIdentifier(UChar* cssString, const char* constant return true; } -static UChar* checkAndSkipEscape(UChar* currentCharacter) +template <typename CharacterType> +static CharacterType* checkAndSkipEscape(CharacterType* currentCharacter) { // Returns with 0, if escape check is failed. Otherwise // it returns with the following character. @@ -8494,7 +8614,8 @@ static UChar* checkAndSkipEscape(UChar* currentCharacter) return currentCharacter + 1; } -static inline UChar* skipWhiteSpace(UChar* currentCharacter) +template <typename CharacterType> +static inline CharacterType* skipWhiteSpace(CharacterType* currentCharacter) { while (isHTMLSpace(*currentCharacter)) ++currentCharacter; @@ -8503,13 +8624,55 @@ static inline UChar* skipWhiteSpace(UChar* currentCharacter) // Main CSS tokenizer functions. +template <> +LChar* CSSParserString::characters<LChar>() const { return characters8(); } + +template <> +UChar* CSSParserString::characters<UChar>() const { return characters16(); } + +template <> +inline LChar*& CSSParser::currentCharacter<LChar>() +{ + return m_currentCharacter8; +} + +template <> +inline UChar*& CSSParser::currentCharacter<UChar>() +{ + return m_currentCharacter16; +} + +UChar*& CSSParser::currentCharacter16() +{ + if (!m_currentCharacter16) { + m_dataStart16 = adoptArrayPtr(new UChar[m_length]); + m_currentCharacter16 = m_dataStart16.get(); + } + + return m_currentCharacter16; +} + +template <> +inline LChar* CSSParser::tokenStart<LChar>() +{ + return m_tokenStart.ptr8; +} + +template <> +inline UChar* CSSParser::tokenStart<UChar>() +{ + return m_tokenStart.ptr16; +} + +template <typename CharacterType> inline bool CSSParser::isIdentifierStart() { // Check whether an identifier is started. - return isIdentifierStartAfterDash((*m_currentCharacter != '-') ? m_currentCharacter : m_currentCharacter + 1); + return isIdentifierStartAfterDash((*currentCharacter<CharacterType>() != '-') ? currentCharacter<CharacterType>() : currentCharacter<CharacterType>() + 1); } -inline UChar* CSSParser::checkAndSkipString(UChar* currentCharacter, UChar quote) +template <typename CharacterType> +inline CharacterType* CSSParser::checkAndSkipString(CharacterType* currentCharacter, int quote) { // Returns with 0, if string check is failed. Otherwise // it returns with the following character. This is necessary @@ -8543,101 +8706,194 @@ inline UChar* CSSParser::checkAndSkipString(UChar* currentCharacter, UChar quote } } -void CSSParser::parseEscape(UChar*& result) +template <typename CharacterType> +unsigned CSSParser::parseEscape(CharacterType*& src) { - ASSERT(*m_currentCharacter == '\\' && isCSSEscape(m_currentCharacter[1])); + ASSERT(*src == '\\' && isCSSEscape(src[1])); + + unsigned unicode = 0; + + ++src; + if (isASCIIHexDigit(*src)) { - ++m_currentCharacter; - if (isASCIIHexDigit(*m_currentCharacter)) { - unsigned unicode = 0; int length = 6; do { - unicode = (unicode << 4) + toASCIIHexValue(*m_currentCharacter++); - } while (--length && isASCIIHexDigit(*m_currentCharacter)); + unicode = (unicode << 4) + toASCIIHexValue(*src++); + } while (--length && isASCIIHexDigit(*src)); // Characters above 0x10ffff are not handled. if (unicode > 0x10ffff) unicode = 0xfffd; // Optional space after the escape sequence. - if (isHTMLSpace(*m_currentCharacter)) - ++m_currentCharacter; + if (isHTMLSpace(*src)) + ++src; - // Replace unicode with a surrogate pairs when it is bigger than 0xffff - if (U16_LENGTH(unicode) == 2) { - *result++ = U16_LEAD(unicode); - *result = U16_TRAIL(unicode); - } else - *result = unicode; + return unicode; + } + + return *currentCharacter<CharacterType>()++; +} + +template <> +inline void CSSParser::UnicodeToChars<LChar>(LChar*& result, unsigned unicode) +{ + ASSERT(unicode <= 0xff); + *result = unicode; + + ++result; +} + +template <> +inline void CSSParser::UnicodeToChars<UChar>(UChar*& result, unsigned unicode) +{ + // Replace unicode with a surrogate pairs when it is bigger than 0xffff + if (U16_LENGTH(unicode) == 2) { + *result++ = U16_LEAD(unicode); + *result = U16_TRAIL(unicode); } else - *result = *m_currentCharacter++; + *result = unicode; + ++result; } -inline void CSSParser::parseIdentifier(UChar*& result, bool& hasEscape) +template <typename SrcCharacterType, typename DestCharacterType> +inline bool CSSParser::parseIdentifierInternal(SrcCharacterType*& src, DestCharacterType*& result, bool& hasEscape) { - // If a valid identifier start is found, we can safely - // parse the identifier until the next invalid character. - ASSERT(isIdentifierStart()); hasEscape = false; do { - if (LIKELY(*m_currentCharacter != '\\')) - *result++ = *m_currentCharacter++; + if (LIKELY(*src != '\\')) + *result++ = *src++; else { hasEscape = true; - parseEscape(result); + SrcCharacterType* savedEscapeStart = src; + unsigned unicode = parseEscape<SrcCharacterType>(src); + if (unicode > 0xff && sizeof(DestCharacterType) == 1) { + src = savedEscapeStart; + return false; + } + UnicodeToChars(result, unicode); } - } while (isCSSLetter(m_currentCharacter[0]) || (m_currentCharacter[0] == '\\' && isCSSEscape(m_currentCharacter[1]))); + } while (isCSSLetter(src[0]) || (src[0] == '\\' && isCSSEscape(src[1]))); + + return true; +} + +template <typename CharacterType> +inline void CSSParser::parseIdentifier(CharacterType*& result, CSSParserString& resultString, bool& hasEscape) +{ + // If a valid identifier start is found, we can safely + // parse the identifier until the next invalid character. + ASSERT(isIdentifierStart<CharacterType>()); + + CharacterType* start = currentCharacter<CharacterType>(); + if (UNLIKELY(!parseIdentifierInternal(currentCharacter<CharacterType>(), result, hasEscape))) { + // Found an escape we couldn't handle with 8 bits, copy what has been recognized and continue + ASSERT(is8BitSource()); + UChar*& result16 = currentCharacter16(); + UChar* start16 = result16; + int i = 0; + for (; i < result - start; i++) + result16[i] = start[i]; + + result16 += i; + + parseIdentifierInternal(currentCharacter<CharacterType>(), result16, hasEscape); + + resultString.init(start16, result16 - start16); + + return; + } + + resultString.init(start, result - start); } -inline void CSSParser::parseString(UChar*& result, UChar quote) +template <typename SrcCharacterType, typename DestCharacterType> +inline bool CSSParser::parseStringInternal(SrcCharacterType*& src, DestCharacterType*& result, UChar quote) { while (true) { - if (UNLIKELY(*m_currentCharacter == quote)) { + if (UNLIKELY(*src == quote)) { // String parsing is done. - ++m_currentCharacter; - return; + ++src; + return true; } - if (UNLIKELY(!*m_currentCharacter)) { + if (UNLIKELY(!*src)) { // String parsing is done, but don't advance pointer if at the end of input. - return; + return true; } - ASSERT(*m_currentCharacter > '\r' || (*m_currentCharacter < '\n' && *m_currentCharacter) || *m_currentCharacter == '\v'); + ASSERT(*src > '\r' || (*src < '\n' && *src) || *src == '\v'); - if (LIKELY(m_currentCharacter[0] != '\\')) - *result++ = *m_currentCharacter++; - else if (m_currentCharacter[1] == '\n' || m_currentCharacter[1] == '\f') - m_currentCharacter += 2; - else if (m_currentCharacter[1] == '\r') - m_currentCharacter += m_currentCharacter[2] == '\n' ? 3 : 2; - else - parseEscape(result); + if (LIKELY(src[0] != '\\')) + *result++ = *src++; + else if (src[1] == '\n' || src[1] == '\f') + src += 2; + else if (src[1] == '\r') + src += src[2] == '\n' ? 3 : 2; + else { + SrcCharacterType* savedEscapeStart = src; + unsigned unicode = parseEscape<SrcCharacterType>(src); + if (unicode > 0xff && sizeof(DestCharacterType) == 1) { + src = savedEscapeStart; + return false; + } + UnicodeToChars(result, unicode); + } + } + + return true; +} + +template <typename CharacterType> +inline void CSSParser::parseString(CharacterType*& result, CSSParserString& resultString, UChar quote) +{ + CharacterType* start = currentCharacter<CharacterType>(); + + if (UNLIKELY(!parseStringInternal(currentCharacter<CharacterType>(), result, quote))) { + // Found an escape we couldn't handle with 8 bits, copy what has been recognized and continue + ASSERT(is8BitSource()); + UChar*& result16 = currentCharacter16(); + UChar* start16 = result16; + int i = 0; + for (; i < result - start; i++) + result16[i] = start[i]; + + result16 += i; + + parseStringInternal(currentCharacter<CharacterType>(), result16, quote); + + resultString.init(start16, result16 - start16); + return; } + + resultString.init(start, result - start); } -inline void CSSParser::parseURI(UChar*& start, UChar*& result) +template <typename CharacterType> +inline bool CSSParser::parseURIInternal(CharacterType*& start, CharacterType*& result) { - UChar* uriStart = skipWhiteSpace(m_currentCharacter); + CharacterType* uriStart = skipWhiteSpace(currentCharacter<CharacterType>()); + CharacterType* savedResult = result; if (*uriStart == '"' || *uriStart == '\'') { - UChar quote = *uriStart; + CharacterType quote = *uriStart; ++uriStart; - UChar* stringEnd = checkAndSkipString(uriStart, quote); + CharacterType* stringEnd = checkAndSkipString(uriStart, quote); if (!stringEnd) - return; + return true; stringEnd = skipWhiteSpace(stringEnd); if (*stringEnd != ')') - return; + return true; - start = result = m_currentCharacter = uriStart; - parseString(result, quote); + start = result = currentCharacter<CharacterType>() = uriStart; + if (!parseStringInternal(currentCharacter<CharacterType>(), result, quote)) + return false; - m_currentCharacter = stringEnd + 1; + currentCharacter<CharacterType>() = stringEnd + 1; m_token = URI; } else { - UChar* stringEnd = uriStart; + CharacterType* stringEnd = uriStart; while (isURILetter(*stringEnd)) { if (*stringEnd != '\\') @@ -8645,99 +8901,124 @@ inline void CSSParser::parseURI(UChar*& start, UChar*& result) else { stringEnd = checkAndSkipEscape(stringEnd); if (!stringEnd) - return; + return true; } } stringEnd = skipWhiteSpace(stringEnd); if (*stringEnd != ')') - return; + return true; - start = result = m_currentCharacter = uriStart; - while (isURILetter(*m_currentCharacter)) { - if (LIKELY(*m_currentCharacter != '\\')) - *result++ = *m_currentCharacter++; - else - parseEscape(result); + start = result = currentCharacter<CharacterType>() = uriStart; + while (isURILetter(*currentCharacter<CharacterType>())) { + if (LIKELY(*currentCharacter<CharacterType>() != '\\')) + *result++ = *currentCharacter<CharacterType>()++; + else { + unsigned unicode = parseEscape<CharacterType>(currentCharacter<CharacterType>()); + if (unicode > 0xff && sizeof(CharacterType) == 1) { + result = savedResult; + return false; + } + UnicodeToChars(result, unicode); + } } - m_currentCharacter = stringEnd + 1; + currentCharacter<CharacterType>() = stringEnd + 1; m_token = URI; } + + return true; +} + +template <typename CharacterType> +inline void CSSParser::parseURI(CSSParserString& string) +{ + CharacterType* uriStart = string.characters<CharacterType>(); + CharacterType* result = uriStart + string.length(); + bool parseResult = parseURIInternal(uriStart, result); + + // parseIdentifier() parsed and created the string, therefore there shouldn't be any unhandled escapses. + ASSERT_UNUSED(parseResult, parseResult); + + string.init(uriStart, result - uriStart); } +template <typename CharacterType> inline bool CSSParser::parseUnicodeRange() { - UChar* currentCharacter = m_currentCharacter + 1; + CharacterType* character = currentCharacter<CharacterType>() + 1; int length = 6; - ASSERT(*m_currentCharacter == '+'); + ASSERT(*currentCharacter<CharacterType>() == '+'); - while (isASCIIHexDigit(*currentCharacter) && length) { - ++currentCharacter; + while (isASCIIHexDigit(*character) && length) { + ++character; --length; } - if (length && *currentCharacter == '?') { + if (length && *character == '?') { // At most 5 hex digit followed by a question mark. do { - ++currentCharacter; + ++character; --length; - } while (*currentCharacter == '?' && length); - m_currentCharacter = currentCharacter; + } while (*character == '?' && length); + currentCharacter<CharacterType>() = character; return true; } if (length < 6) { // At least one hex digit. - if (currentCharacter[0] == '-' && isASCIIHexDigit(currentCharacter[1])) { + if (character[0] == '-' && isASCIIHexDigit(character[1])) { // Followed by a dash and a hex digit. - ++currentCharacter; + ++character; length = 6; do { - ++currentCharacter; - } while (--length && isASCIIHexDigit(*currentCharacter)); + ++character; + } while (--length && isASCIIHexDigit(*character)); } - m_currentCharacter = currentCharacter; + currentCharacter<CharacterType>() = character; return true; } return false; } +template <typename CharacterType> bool CSSParser::parseNthChild() { - UChar* currentCharacter = m_currentCharacter; + CharacterType* character = currentCharacter<CharacterType>(); - while (isASCIIDigit(*currentCharacter)) - ++currentCharacter; - if (isASCIIAlphaCaselessEqual(*currentCharacter, 'n')) { - m_currentCharacter = currentCharacter + 1; + while (isASCIIDigit(*character)) + ++character; + if (isASCIIAlphaCaselessEqual(*character, 'n')) { + currentCharacter<CharacterType>() = character + 1; return true; } return false; } +template <typename CharacterType> bool CSSParser::parseNthChildExtra() { - UChar* currentCharacter = skipWhiteSpace(m_currentCharacter); - if (*currentCharacter != '+' && *currentCharacter != '-') + CharacterType* character = skipWhiteSpace(currentCharacter<CharacterType>()); + if (*character != '+' && *character != '-') return false; - currentCharacter = skipWhiteSpace(currentCharacter + 1); - if (!isASCIIDigit(*currentCharacter)) + character = skipWhiteSpace(character + 1); + if (!isASCIIDigit(*character)) return false; do { - ++currentCharacter; - } while (isASCIIDigit(*currentCharacter)); + ++character; + } while (isASCIIDigit(*character)); - m_currentCharacter = currentCharacter; + currentCharacter<CharacterType>() = character; return true; } +template <typename CharacterType> inline void CSSParser::detectFunctionTypeToken(int length) { ASSERT(length > 0); - UChar* name = m_tokenStart; + CharacterType* name = tokenStart<CharacterType>(); switch (length) { case 3: @@ -8769,10 +9050,11 @@ inline void CSSParser::detectFunctionTypeToken(int length) } } +template <typename CharacterType> inline void CSSParser::detectMediaQueryToken(int length) { ASSERT(m_parsingMode == MediaQueryMode); - UChar* name = m_tokenStart; + CharacterType* name = tokenStart<CharacterType>(); if (length == 3) { if (isASCIIAlphaCaselessEqual(name[0], 'a') && isASCIIAlphaCaselessEqual(name[1], 'n') && isASCIIAlphaCaselessEqual(name[2], 'd')) @@ -8786,7 +9068,8 @@ inline void CSSParser::detectMediaQueryToken(int length) } } -inline void CSSParser::detectNumberToken(UChar* type, int length) +template <typename CharacterType> +inline void CSSParser::detectNumberToken(CharacterType* type, int length) { ASSERT(length > 0); @@ -8903,9 +9186,10 @@ inline void CSSParser::detectNumberToken(UChar* type, int length) } } +template <typename CharacterType> inline void CSSParser::detectDashToken(int length) { - UChar* name = m_tokenStart; + CharacterType* name = tokenStart<CharacterType>(); if (length == 11) { if (isASCIIAlphaCaselessEqual(name[10], 'y') && isEqualToCSSIdentifier(name + 1, "webkit-an")) @@ -8922,9 +9206,10 @@ inline void CSSParser::detectDashToken(int length) m_token = CALCFUNCTION; } +template <typename CharacterType> inline void CSSParser::detectAtToken(int length, bool hasEscape) { - UChar* name = m_tokenStart; + CharacterType* name = tokenStart<CharacterType>(); ASSERT(name[0] == '@' && length >= 2); // charset, font-face, import, media, namespace, page, @@ -9110,81 +9395,80 @@ inline void CSSParser::detectAtToken(int length, bool hasEscape) } } -int CSSParser::lex(void* yylvalWithoutType) +template <typename SrcCharacterType> +int CSSParser::realLex(void* yylvalWithoutType) { YYSTYPE* yylval = static_cast<YYSTYPE*>(yylvalWithoutType); // Write pointer for the next character. - UChar* result; + SrcCharacterType* result; + CSSParserString resultString; bool hasEscape; // The input buffer is terminated by a \0 character, so // it is safe to read one character ahead of a known non-null. - #ifndef NDEBUG // In debug we check with an ASSERT that the length is > 0 for string types. - yylval->string.characters = 0; - yylval->string.length = 0; + yylval->string.clear(); #endif restartAfterComment: - m_tokenStart = result = m_currentCharacter; - m_token = *m_currentCharacter; - ++m_currentCharacter; + result = currentCharacter<SrcCharacterType>(); + setTokenStart(result); + m_token = *currentCharacter<SrcCharacterType>(); + ++currentCharacter<SrcCharacterType>(); switch ((m_token <= 127) ? typesOfASCIICharacters[m_token] : CharacterIdentifierStart) { case CharacterCaselessU: - if (UNLIKELY(*m_currentCharacter == '+')) - if (parseUnicodeRange()) { + if (UNLIKELY(*currentCharacter<SrcCharacterType>() == '+')) + if (parseUnicodeRange<SrcCharacterType>()) { m_token = UNICODERANGE; - yylval->string.characters = m_tokenStart; - yylval->string.length = m_currentCharacter - m_tokenStart; + yylval->string.init(tokenStart<SrcCharacterType>(), currentCharacter<SrcCharacterType>() - tokenStart<SrcCharacterType>()); break; } // Fall through to CharacterIdentifierStart. case CharacterIdentifierStart: - --m_currentCharacter; - parseIdentifier(result, hasEscape); + --currentCharacter<SrcCharacterType>(); + parseIdentifier(result, yylval->string, hasEscape); m_token = IDENT; - yylval->string.characters = m_tokenStart; - yylval->string.length = result - m_tokenStart; - - if (UNLIKELY(*m_currentCharacter == '(')) { + if (UNLIKELY(*currentCharacter<SrcCharacterType>() == '(')) { m_token = FUNCTION; if (!hasEscape) - detectFunctionTypeToken(result - m_tokenStart); - ++m_currentCharacter; + detectFunctionTypeToken<SrcCharacterType>(result - tokenStart<SrcCharacterType>()); + ++currentCharacter<SrcCharacterType>(); ++result; - ++yylval->string.length; + ++yylval->string.m_length; if (token() == URI) { m_token = FUNCTION; // Check whether it is really an URI. - parseURI(yylval->string.characters, result); - yylval->string.length = result - yylval->string.characters; + if (yylval->string.is8Bit()) + parseURI<LChar>(yylval->string); + else + parseURI<UChar>(yylval->string); } } else if (UNLIKELY(m_parsingMode != NormalMode) && !hasEscape) { if (m_parsingMode == MediaQueryMode) - detectMediaQueryToken(result - m_tokenStart); - else if (m_parsingMode == NthChildMode && isASCIIAlphaCaselessEqual(m_tokenStart[0], 'n')) { - if (result - m_tokenStart == 1) { + detectMediaQueryToken<SrcCharacterType>(result - tokenStart<SrcCharacterType>()); + else if (m_parsingMode == NthChildMode && isASCIIAlphaCaselessEqual(tokenStart<SrcCharacterType>()[0], 'n')) { + if (result - tokenStart<SrcCharacterType>() == 1) { // String "n" is IDENT but "n+1" is NTH. - if (parseNthChildExtra()) { + if (parseNthChildExtra<SrcCharacterType>()) { m_token = NTH; - yylval->string.length = m_currentCharacter - m_tokenStart; + yylval->string.m_length = currentCharacter<SrcCharacterType>() - tokenStart<SrcCharacterType>(); } - } else if (result - m_tokenStart >= 2 && m_tokenStart[1] == '-') { + } else if (result - tokenStart<SrcCharacterType>() >= 2 && tokenStart<SrcCharacterType>()[1] == '-') { // String "n-" is IDENT but "n-1" is NTH. - // Set m_currentCharacter to '-' to continue parsing. - UChar* nextCharacter = result; - m_currentCharacter = m_tokenStart + 1; - if (parseNthChildExtra()) { + // Set currentCharacter to '-' to continue parsing. + SrcCharacterType* nextCharacter = result; + currentCharacter<SrcCharacterType>() = tokenStart<SrcCharacterType>() + 1; + if (parseNthChildExtra<SrcCharacterType>()) { m_token = NTH; - yylval->string.length = m_currentCharacter - m_tokenStart; + yylval->string.setLength(currentCharacter<SrcCharacterType>() - tokenStart<SrcCharacterType>()); } else { - // Revert the change to m_currentCharacter if unsuccessful. - m_currentCharacter = nextCharacter; + // Revert the change to currentCharacter if unsuccessful. + currentCharacter<SrcCharacterType>() = nextCharacter; } } } @@ -9192,7 +9476,7 @@ restartAfterComment: break; case CharacterDot: - if (!isASCIIDigit(m_currentCharacter[0])) + if (!isASCIIDigit(currentCharacter<SrcCharacterType>()[0])) break; // Fall through to CharacterNumber. @@ -9200,23 +9484,22 @@ restartAfterComment: bool dotSeen = (m_token == '.'); while (true) { - if (!isASCIIDigit(m_currentCharacter[0])) { + if (!isASCIIDigit(currentCharacter<SrcCharacterType>()[0])) { // Only one dot is allowed for a number, // and it must be followed by a digit. - if (m_currentCharacter[0] != '.' || dotSeen || !isASCIIDigit(m_currentCharacter[1])) + if (currentCharacter<SrcCharacterType>()[0] != '.' || dotSeen || !isASCIIDigit(currentCharacter<SrcCharacterType>()[1])) break; dotSeen = true; } - ++m_currentCharacter; + ++currentCharacter<SrcCharacterType>(); } - if (UNLIKELY(m_parsingMode == NthChildMode) && !dotSeen && isASCIIAlphaCaselessEqual(*m_currentCharacter, 'n')) { + if (UNLIKELY(m_parsingMode == NthChildMode) && !dotSeen && isASCIIAlphaCaselessEqual(*currentCharacter<SrcCharacterType>(), 'n')) { // "[0-9]+n" is always an NthChild. - ++m_currentCharacter; - parseNthChildExtra(); + ++currentCharacter<SrcCharacterType>(); + parseNthChildExtra<SrcCharacterType>(); m_token = NTH; - yylval->string.characters = m_tokenStart; - yylval->string.length = m_currentCharacter - m_tokenStart; + yylval->string.init(tokenStart<SrcCharacterType>(), currentCharacter<SrcCharacterType>() - tokenStart<SrcCharacterType>()); break; } @@ -9224,52 +9507,51 @@ restartAfterComment: // Use SVG parser for numbers on SVG presentation attributes. if (m_context.mode == SVGAttributeMode) { // We need to take care of units like 'em' or 'ex'. - UChar* currentCharacter = m_currentCharacter; - if (isASCIIAlphaCaselessEqual(*currentCharacter, 'e')) { - ASSERT(currentCharacter - m_tokenStart > 0); - ++currentCharacter; - if (*currentCharacter == '-' || *currentCharacter == '+' || isASCIIDigit(*currentCharacter)) { - ++currentCharacter; - while (isASCIIDigit(*currentCharacter)) - ++currentCharacter; + SrcCharacterType* character = currentCharacter<SrcCharacterType>(); + if (isASCIIAlphaCaselessEqual(*character, 'e')) { + ASSERT(character - tokenStart<SrcCharacterType>() > 0); + ++character; + if (*character == '-' || *character == '+' || isASCIIDigit(*character)) { + ++character; + while (isASCIIDigit(*character)) + ++character; // Use FLOATTOKEN if the string contains exponents. dotSeen = true; - m_currentCharacter = currentCharacter; + currentCharacter<SrcCharacterType>() = character; } } - if (!parseSVGNumber(m_tokenStart, currentCharacter - m_tokenStart, yylval->number)) + if (!parseSVGNumber(tokenStart<SrcCharacterType>(), character - tokenStart<SrcCharacterType>(), yylval->number)) break; } else #endif - yylval->number = charactersToDouble(m_tokenStart, m_currentCharacter - m_tokenStart); + yylval->number = charactersToDouble(tokenStart<SrcCharacterType>(), currentCharacter<SrcCharacterType>() - tokenStart<SrcCharacterType>()); // Type of the function. - if (isIdentifierStart()) { - UChar* type = m_currentCharacter; - result = m_currentCharacter; + if (isIdentifierStart<SrcCharacterType>()) { + SrcCharacterType* type = currentCharacter<SrcCharacterType>(); + result = currentCharacter<SrcCharacterType>(); - parseIdentifier(result, hasEscape); - if (*m_currentCharacter == '+') { + parseIdentifier(result, resultString, hasEscape); + if (*currentCharacter<SrcCharacterType>() == '+') { // Any identifier followed by a '+' sign is an invalid dimension. - ++m_currentCharacter; + ++currentCharacter<SrcCharacterType>(); m_token = INVALIDDIMEN; } else { m_token = DIMEN; if (!hasEscape) - detectNumberToken(type, m_currentCharacter - type); + detectNumberToken(type, currentCharacter<SrcCharacterType>() - type); if (m_token == DIMEN) { // The decoded number is overwritten, but this is intentional. - yylval->string.characters = m_tokenStart; - yylval->string.length = m_currentCharacter - m_tokenStart; + yylval->string.init(tokenStart<SrcCharacterType>(), currentCharacter<SrcCharacterType>() - tokenStart<SrcCharacterType>()); } } - } else if (*m_currentCharacter == '%') { + } else if (*currentCharacter<SrcCharacterType>() == '%') { // Although the CSS grammar says {num}% we follow // webkit at the moment which uses {num}%+. do { - ++m_currentCharacter; - } while (*m_currentCharacter == '%'); + ++currentCharacter<SrcCharacterType>(); + } while (*currentCharacter<SrcCharacterType>() == '%'); m_token = PERCENTAGE; } else m_token = dotSeen ? FLOATTOKEN : INTEGER; @@ -9277,55 +9559,54 @@ restartAfterComment: } case CharacterDash: - if (isIdentifierStartAfterDash(m_currentCharacter)) { - --m_currentCharacter; - parseIdentifier(result, hasEscape); + if (isIdentifierStartAfterDash(currentCharacter<SrcCharacterType>())) { + --currentCharacter<SrcCharacterType>(); + parseIdentifier(result, resultString, hasEscape); m_token = IDENT; #if ENABLE(CSS_VARIABLES) - if (cssVariablesEnabled() && isEqualToCSSIdentifier(m_tokenStart + 1, "webkit-var") && m_tokenStart[11] == '-' && isIdentifierStartAfterDash(m_tokenStart + 12)) + if (cssVariablesEnabled() && isEqualToCSSIdentifier(tokenStart<SrcCharacterType>() + 1, "webkit-var") && tokenStart<SrcCharacterType>()[11] == '-' && isIdentifierStartAfterDash(tokenStart<SrcCharacterType>() + 12)) m_token = VAR_DEFINITION; else #endif - if (*m_currentCharacter == '(') { + if (*currentCharacter<SrcCharacterType>() == '(') { m_token = FUNCTION; if (!hasEscape) - detectDashToken(result - m_tokenStart); - ++m_currentCharacter; + detectDashToken<SrcCharacterType>(result - tokenStart<SrcCharacterType>()); + ++currentCharacter<SrcCharacterType>(); ++result; - } else if (UNLIKELY(m_parsingMode == NthChildMode) && !hasEscape && isASCIIAlphaCaselessEqual(m_tokenStart[1], 'n')) { - if (result - m_tokenStart == 2) { + } else if (UNLIKELY(m_parsingMode == NthChildMode) && !hasEscape && isASCIIAlphaCaselessEqual(tokenStart<SrcCharacterType>()[1], 'n')) { + if (result - tokenStart<SrcCharacterType>() == 2) { // String "-n" is IDENT but "-n+1" is NTH. - if (parseNthChildExtra()) { + if (parseNthChildExtra<SrcCharacterType>()) { m_token = NTH; - result = m_currentCharacter; + result = currentCharacter<SrcCharacterType>(); } - } else if (result - m_tokenStart >= 3 && m_tokenStart[2] == '-') { + } else if (result - tokenStart<SrcCharacterType>() >= 3 && tokenStart<SrcCharacterType>()[2] == '-') { // String "-n-" is IDENT but "-n-1" is NTH. - // Set m_currentCharacter to second '-' of '-n-' to continue parsing. - UChar* nextCharacter = result; - m_currentCharacter = m_tokenStart + 2; - if (parseNthChildExtra()) { + // Set currentCharacter to second '-' of '-n-' to continue parsing. + SrcCharacterType* nextCharacter = result; + currentCharacter<SrcCharacterType>() = tokenStart<SrcCharacterType>() + 2; + if (parseNthChildExtra<SrcCharacterType>()) { m_token = NTH; - result = m_currentCharacter; + result = currentCharacter<SrcCharacterType>(); } else { - // Revert the change to m_currentCharacter if unsuccessful. - m_currentCharacter = nextCharacter; + // Revert the change to currentCharacter if unsuccessful. + currentCharacter<SrcCharacterType>() = nextCharacter; } } } - yylval->string.characters = m_tokenStart; - yylval->string.length = result - m_tokenStart; - } else if (m_currentCharacter[0] == '-' && m_currentCharacter[1] == '>') { - m_currentCharacter += 2; + resultString.setLength(result - tokenStart<SrcCharacterType>()); + yylval->string = resultString; + } else if (currentCharacter<SrcCharacterType>()[0] == '-' && currentCharacter<SrcCharacterType>()[1] == '>') { + currentCharacter<SrcCharacterType>() += 2; m_token = SGML_CD; } else if (UNLIKELY(m_parsingMode == NthChildMode)) { // "-[0-9]+n" is always an NthChild. - if (parseNthChild()) { - parseNthChildExtra(); + if (parseNthChild<SrcCharacterType>()) { + parseNthChildExtra<SrcCharacterType>(); m_token = NTH; - yylval->string.characters = m_tokenStart; - yylval->string.length = m_currentCharacter - m_tokenStart; + yylval->string.init(tokenStart<SrcCharacterType>(), currentCharacter<SrcCharacterType>() - tokenStart<SrcCharacterType>()); } } break; @@ -9336,18 +9617,18 @@ restartAfterComment: case CharacterNull: // Do not advance pointer at the end of input. - --m_currentCharacter; + --currentCharacter<SrcCharacterType>(); break; case CharacterWhiteSpace: m_token = WHITESPACE; // Might start with a '\n'. - --m_currentCharacter; + --currentCharacter<SrcCharacterType>(); do { - if (*m_currentCharacter == '\n') + if (*currentCharacter<SrcCharacterType>() == '\n') ++m_lineNumber; - ++m_currentCharacter; - } while (*m_currentCharacter <= ' ' && (typesOfASCIICharacters[*m_currentCharacter] == CharacterWhiteSpace)); + ++currentCharacter<SrcCharacterType>(); + } while (*currentCharacter<SrcCharacterType>() <= ' ' && (typesOfASCIICharacters[*currentCharacter<SrcCharacterType>()] == CharacterWhiteSpace)); break; case CharacterEndMediaQuery: @@ -9361,42 +9642,39 @@ restartAfterComment: break; case CharacterQuote: - if (checkAndSkipString(m_currentCharacter, m_token)) { + if (checkAndSkipString(currentCharacter<SrcCharacterType>(), m_token)) { ++result; - parseString(result, m_token); + parseString<SrcCharacterType>(result, yylval->string, m_token); m_token = STRING; - yylval->string.characters = m_tokenStart + 1; - yylval->string.length = result - (m_tokenStart + 1); } break; case CharacterExclamationMark: { - UChar* start = skipWhiteSpace(m_currentCharacter); + SrcCharacterType* start = skipWhiteSpace(currentCharacter<SrcCharacterType>()); if (isEqualToCSSIdentifier(start, "important")) { m_token = IMPORTANT_SYM; - m_currentCharacter = start + 9; + currentCharacter<SrcCharacterType>() = start + 9; } break; } case CharacterHashmark: { - UChar* start = m_currentCharacter; - result = m_currentCharacter; + SrcCharacterType* start = currentCharacter<SrcCharacterType>(); + result = currentCharacter<SrcCharacterType>(); - if (isASCIIDigit(*m_currentCharacter)) { + if (isASCIIDigit(*currentCharacter<SrcCharacterType>())) { // This must be a valid hex number token. do { - ++m_currentCharacter; - } while (isASCIIHexDigit(*m_currentCharacter)); + ++currentCharacter<SrcCharacterType>(); + } while (isASCIIHexDigit(*currentCharacter<SrcCharacterType>())); m_token = HEX; - yylval->string.characters = start; - yylval->string.length = m_currentCharacter - start; - } else if (isIdentifierStart()) { + yylval->string.init(start, currentCharacter<SrcCharacterType>() - start); + } else if (isIdentifierStart<SrcCharacterType>()) { m_token = IDSEL; - parseIdentifier(result, hasEscape); + parseIdentifier(result, yylval->string, hasEscape); if (!hasEscape) { // Check whether the identifier is also a valid hex number. - UChar* current = start; + SrcCharacterType* current = start; m_token = HEX; do { if (!isASCIIHexDigit(*current)) { @@ -9406,41 +9684,39 @@ restartAfterComment: ++current; } while (current < result); } - yylval->string.characters = start; - yylval->string.length = result - start; } break; } case CharacterSlash: // Ignore comments. They are not even considered as white spaces. - if (*m_currentCharacter == '*') { - ++m_currentCharacter; - while (m_currentCharacter[0] != '*' || m_currentCharacter[1] != '/') { - if (*m_currentCharacter == '\n') + if (*currentCharacter<SrcCharacterType>() == '*') { + ++currentCharacter<SrcCharacterType>(); + while (currentCharacter<SrcCharacterType>()[0] != '*' || currentCharacter<SrcCharacterType>()[1] != '/') { + if (*currentCharacter<SrcCharacterType>() == '\n') ++m_lineNumber; - if (*m_currentCharacter == '\0') { + if (*currentCharacter<SrcCharacterType>() == '\0') { // Unterminated comments are simply ignored. - m_currentCharacter -= 2; + currentCharacter<SrcCharacterType>() -= 2; break; } - ++m_currentCharacter; + ++currentCharacter<SrcCharacterType>(); } - m_currentCharacter += 2; + currentCharacter<SrcCharacterType>() += 2; goto restartAfterComment; } break; case CharacterDollar: - if (*m_currentCharacter == '=') { - ++m_currentCharacter; + if (*currentCharacter<SrcCharacterType>() == '=') { + ++currentCharacter<SrcCharacterType>(); m_token = ENDSWITH; } break; case CharacterAsterisk: - if (*m_currentCharacter == '=') { - ++m_currentCharacter; + if (*currentCharacter<SrcCharacterType>() == '=') { + ++currentCharacter<SrcCharacterType>(); m_token = CONTAINS; } break; @@ -9448,58 +9724,55 @@ restartAfterComment: case CharacterPlus: if (UNLIKELY(m_parsingMode == NthChildMode)) { // Simplest case. "+[0-9]*n" is always NthChild. - if (parseNthChild()) { - parseNthChildExtra(); + if (parseNthChild<SrcCharacterType>()) { + parseNthChildExtra<SrcCharacterType>(); m_token = NTH; - yylval->string.characters = m_tokenStart; - yylval->string.length = m_currentCharacter - m_tokenStart; + yylval->string.init(tokenStart<SrcCharacterType>(), currentCharacter<SrcCharacterType>() - tokenStart<SrcCharacterType>()); } } break; case CharacterLess: - if (m_currentCharacter[0] == '!' && m_currentCharacter[1] == '-' && m_currentCharacter[2] == '-') { - m_currentCharacter += 3; + if (currentCharacter<SrcCharacterType>()[0] == '!' && currentCharacter<SrcCharacterType>()[1] == '-' && currentCharacter<SrcCharacterType>()[2] == '-') { + currentCharacter<SrcCharacterType>() += 3; m_token = SGML_CD; } break; case CharacterAt: - if (isIdentifierStart()) { + if (isIdentifierStart<SrcCharacterType>()) { m_token = ATKEYWORD; ++result; - parseIdentifier(result, hasEscape); - detectAtToken(result - m_tokenStart, hasEscape); + parseIdentifier(result, resultString, hasEscape); + detectAtToken<SrcCharacterType>(result - tokenStart<SrcCharacterType>(), hasEscape); } break; case CharacterBackSlash: - if (isCSSEscape(*m_currentCharacter)) { - --m_currentCharacter; - parseIdentifier(result, hasEscape); + if (isCSSEscape(*currentCharacter<SrcCharacterType>())) { + --currentCharacter<SrcCharacterType>(); + parseIdentifier(result, yylval->string, hasEscape); m_token = IDENT; - yylval->string.characters = m_tokenStart; - yylval->string.length = result - m_tokenStart; } break; case CharacterXor: - if (*m_currentCharacter == '=') { - ++m_currentCharacter; + if (*currentCharacter<SrcCharacterType>() == '=') { + ++currentCharacter<SrcCharacterType>(); m_token = BEGINSWITH; } break; case CharacterVerticalBar: - if (*m_currentCharacter == '=') { - ++m_currentCharacter; + if (*currentCharacter<SrcCharacterType>() == '=') { + ++currentCharacter<SrcCharacterType>(); m_token = DASHMATCH; } break; case CharacterTilde: - if (*m_currentCharacter == '=') { - ++m_currentCharacter; + if (*currentCharacter<SrcCharacterType>() == '=') { + ++currentCharacter<SrcCharacterType>(); m_token = INCLUDES; } break; @@ -9509,36 +9782,6 @@ restartAfterComment: break; } -#ifndef NDEBUG - switch (token()) { - case STRING: - ASSERT(yylval->string.characters == m_tokenStart + 1); - break; - - case IDENT: - case NTH: - case DIMEN: - case UNICODERANGE: - case FUNCTION: - case ANYFUNCTION: - case NOTFUNCTION: - case CALCFUNCTION: - case MINFUNCTION: - case MAXFUNCTION: - ASSERT(yylval->string.characters == m_tokenStart && yylval->string.length > 0); - break; - - case URI: - ASSERT(yylval->string.characters && yylval->string.characters != m_tokenStart); - break; - - case HEX: - case IDSEL: - ASSERT(yylval->string.characters == m_tokenStart + 1 && yylval->string.length > 0); - break; - } -#endif - return token(); } @@ -9945,17 +10188,17 @@ void CSSParser::deleteFontFaceOnlyValues() StyleKeyframe* CSSParser::createKeyframe(CSSParserValueList* keys) { // Create a key string from the passed keys - String keyString; + StringBuilder keyString; for (unsigned i = 0; i < keys->size(); ++i) { float key = static_cast<float>(keys->valueAt(i)->fValue); if (i != 0) - keyString += ","; - keyString += String::number(key); - keyString += "%"; + keyString.append(','); + keyString.append(String::number(key)); + keyString.append('%'); } RefPtr<StyleKeyframe> keyframe = StyleKeyframe::create(); - keyframe->setKeyText(keyString); + keyframe->setKeyText(keyString.toString()); keyframe->setProperties(createStylePropertySet()); clearProperties(); @@ -9981,17 +10224,15 @@ void CSSParser::updateLastMediaLine(MediaQuerySet* media) media->setLastLine(m_lineNumber); } -void CSSParser::fixUnparsedPropertyRanges(CSSRuleSourceData* ruleData) +template <typename CharacterType> +static inline void fixUnparsedProperties(const CharacterType* characters, CSSRuleSourceData* ruleData) { - if (!ruleData->styleSourceData) - return; Vector<CSSPropertySourceData>& propertyData = ruleData->styleSourceData->propertyData; unsigned size = propertyData.size(); if (!size) return; unsigned styleStart = ruleData->ruleBodyRange.start; - const UChar* characters = m_dataStart.get() + m_parsedTextPrefixLength; CSSPropertySourceData* nextData = &(propertyData.at(0)); for (unsigned i = 0; i < size; ++i) { CSSPropertySourceData* currentData = nextData; @@ -10028,36 +10269,60 @@ void CSSParser::fixUnparsedPropertyRanges(CSSRuleSourceData* ruleData) } } +void CSSParser::fixUnparsedPropertyRanges(CSSRuleSourceData* ruleData) +{ + if (!ruleData->styleSourceData) + return; + + if (is8BitSource()) { + fixUnparsedProperties<LChar>(m_dataStart8.get() + m_parsedTextPrefixLength, ruleData); + return; + } + + fixUnparsedProperties<UChar>(m_dataStart16.get() + m_parsedTextPrefixLength, ruleData); +} + void CSSParser::markRuleHeaderStart(CSSRuleSourceData::Type ruleType) { if (!isExtractingSourceData()) return; RefPtr<CSSRuleSourceData> data = CSSRuleSourceData::create(ruleType); - data->ruleHeaderRange.start = m_tokenStart - m_dataStart.get(); + data->ruleHeaderRange.start = tokenStartOffset(); m_currentRuleDataStack->append(data.release()); } -void CSSParser::markRuleHeaderEnd() +template <typename CharacterType> +inline void CSSParser::setRuleHeaderEnd(const CharacterType* dataStart) { - if (!isExtractingSourceData()) - return; - ASSERT(!m_currentRuleDataStack->isEmpty()); - UChar* listEnd = m_tokenStart; - while (listEnd > m_dataStart.get() + 1) { + CharacterType* listEnd = tokenStart<CharacterType>(); + while (listEnd > dataStart + 1) { if (isHTMLSpace(*(listEnd - 1))) --listEnd; else break; } - m_currentRuleDataStack->last()->ruleHeaderRange.end = listEnd - m_dataStart.get(); + + m_currentRuleDataStack->last()->ruleHeaderRange.end = listEnd - dataStart; +} + +void CSSParser::markRuleHeaderEnd() +{ + if (!isExtractingSourceData()) + return; + ASSERT(!m_currentRuleDataStack->isEmpty()); + + if (is8BitSource()) + setRuleHeaderEnd<LChar>(m_dataStart8.get()); + else + setRuleHeaderEnd<UChar>(m_dataStart16.get()); } void CSSParser::markRuleBodyStart() { if (!isExtractingSourceData()) return; - unsigned offset = m_tokenStart - m_dataStart.get(); - if (*m_tokenStart == '{') + unsigned offset = tokenStartOffset(); + if (tokenStartChar() == '{') ++offset; // Skip the rule body opening brace. ASSERT(!m_currentRuleDataStack->isEmpty()); m_currentRuleDataStack->last()->ruleBodyRange.start = offset; @@ -10066,7 +10331,7 @@ void CSSParser::markRuleBodyStart() void CSSParser::markRuleBodyEnd() { // Precondition: (!isExtractingSourceData()) - unsigned offset = m_tokenStart - m_dataStart.get(); + unsigned offset = tokenStartOffset(); ASSERT(!m_currentRuleDataStack->isEmpty()); m_currentRuleDataStack->last()->ruleBodyRange.end = offset; } @@ -10078,7 +10343,7 @@ void CSSParser::markPropertyStart() if (m_currentRuleDataStack->isEmpty() || !m_currentRuleDataStack->last()->styleSourceData) return; - m_propertyRange.start = m_tokenStart - m_dataStart.get(); + m_propertyRange.start = tokenStartOffset(); } void CSSParser::markPropertyEnd(bool isImportantFound, bool isPropertyParsed) @@ -10088,8 +10353,8 @@ void CSSParser::markPropertyEnd(bool isImportantFound, bool isPropertyParsed) if (m_currentRuleDataStack->isEmpty() || !m_currentRuleDataStack->last()->styleSourceData) return; - unsigned offset = m_tokenStart - m_dataStart.get(); - if (*m_tokenStart == ';') // Include semicolon into the property text. + unsigned offset = tokenStartOffset(); + if (tokenStartChar() == ';') // Include semicolon into the property text. ++offset; m_propertyRange.end = offset; if (m_propertyRange.start != UINT_MAX && !m_currentRuleDataStack->isEmpty()) { @@ -10097,7 +10362,11 @@ void CSSParser::markPropertyEnd(bool isImportantFound, bool isPropertyParsed) const unsigned start = m_propertyRange.start; const unsigned end = m_propertyRange.end; ASSERT(start < end); - String propertyString = String(m_dataStart.get() + start, end - start).stripWhiteSpace(); + String propertyString; + if (is8BitSource()) + propertyString = String(m_dataStart8.get() + start, end - start).stripWhiteSpace(); + else + propertyString = String(m_dataStart16.get() + start, end - start).stripWhiteSpace(); if (propertyString.endsWith(';')) propertyString = propertyString.left(propertyString.length() - 1); size_t colonIndex = propertyString.find(':'); @@ -10113,17 +10382,13 @@ void CSSParser::markPropertyEnd(bool isImportantFound, bool isPropertyParsed) resetPropertyRange(); } -static CSSPropertyID cssPropertyID(const UChar* propertyName, unsigned length) +template <typename CharacterType> +static CSSPropertyID cssPropertyID(const CharacterType* propertyName, unsigned length) { - if (!length) - return CSSPropertyInvalid; - if (length > maxCSSPropertyNameLength) - return CSSPropertyInvalid; - char buffer[maxCSSPropertyNameLength + 1 + 1]; // 1 to turn "apple"/"khtml" into "webkit", 1 for null character for (unsigned i = 0; i != length; ++i) { - UChar c = propertyName[i]; + CharacterType c = propertyName[i]; if (c == 0 || c >= 0x7F) return CSSPropertyInvalid; // illegal character buffer[i] = toASCIILower(c); @@ -10161,12 +10426,26 @@ static CSSPropertyID cssPropertyID(const UChar* propertyName, unsigned length) CSSPropertyID cssPropertyID(const String& string) { - return cssPropertyID(string.characters(), string.length()); + unsigned length = string.length(); + + if (!length) + return CSSPropertyInvalid; + if (length > maxCSSPropertyNameLength) + return CSSPropertyInvalid; + + return string.is8Bit() ? cssPropertyID(string.characters8(), length) : cssPropertyID(string.characters(), length); } CSSPropertyID cssPropertyID(const CSSParserString& string) { - return cssPropertyID(string.characters, string.length); + unsigned length = string.length(); + + if (!length) + return CSSPropertyInvalid; + if (length > maxCSSPropertyNameLength) + return CSSPropertyInvalid; + + return string.is8Bit() ? cssPropertyID(string.characters8(), length) : cssPropertyID(string.characters16(), length); } #if PLATFORM(IOS) @@ -10181,18 +10460,13 @@ void cssPropertyNameIOSAliasing(const char* propertyName, const char*& propertyN } #endif -int cssValueKeywordID(const CSSParserString& string) +template <typename CharacterType> +static int cssValueKeywordID(const CharacterType* valueKeyword, unsigned length) { - unsigned length = string.length; - if (!length) - return 0; - if (length > maxCSSValueKeywordLength) - return 0; - char buffer[maxCSSValueKeywordLength + 1 + 1]; // 1 to turn "apple"/"khtml" into "webkit", 1 for null character for (unsigned i = 0; i != length; ++i) { - UChar c = string.characters[i]; + CharacterType c = valueKeyword[i]; if (c == 0 || c >= 0x7F) return 0; // illegal character buffer[i] = WTF::toASCIILower(c); @@ -10213,38 +10487,60 @@ int cssValueKeywordID(const CSSParserString& string) return hashTableEntry ? hashTableEntry->id : 0; } -// "ident" from the CSS tokenizer, minus backslash-escape sequences -static bool isCSSTokenizerIdentifier(const String& string) +int cssValueKeywordID(const CSSParserString& string) +{ + unsigned length = string.length(); + if (!length) + return 0; + if (length > maxCSSValueKeywordLength) + return 0; + + return string.is8Bit() ? cssValueKeywordID(string.characters8(), length) : cssValueKeywordID(string.characters16(), length); +} + +template <typename CharacterType> +static inline bool isCSSTokenizerIdentifier(const CharacterType* characters, unsigned length) { - const UChar* p = string.characters(); - const UChar* end = p + string.length(); + const CharacterType* end = characters + length; // -? - if (p != end && p[0] == '-') - ++p; + if (characters != end && characters[0] == '-') + ++characters; // {nmstart} - if (p == end || !(p[0] == '_' || p[0] >= 128 || isASCIIAlpha(p[0]))) + if (characters == end || !(characters[0] == '_' || characters[0] >= 128 || isASCIIAlpha(characters[0]))) return false; - ++p; + ++characters; // {nmchar}* - for (; p != end; ++p) { - if (!(p[0] == '_' || p[0] == '-' || p[0] >= 128 || isASCIIAlphanumeric(p[0]))) + for (; characters != end; ++characters) { + if (!(characters[0] == '_' || characters[0] == '-' || characters[0] >= 128 || isASCIIAlphanumeric(characters[0]))) return false; } return true; } -// "url" from the CSS tokenizer, minus backslash-escape sequences -static bool isCSSTokenizerURL(const String& string) +// "ident" from the CSS tokenizer, minus backslash-escape sequences +static bool isCSSTokenizerIdentifier(const String& string) { - const UChar* p = string.characters(); - const UChar* end = p + string.length(); + unsigned length = string.length(); - for (; p != end; ++p) { - UChar c = p[0]; + if (!length) + return false; + + if (string.is8Bit()) + return isCSSTokenizerIdentifier(string.characters8(), length); + return isCSSTokenizerIdentifier(string.characters(), length); +} + +template <typename CharacterType> +static inline bool isCSSTokenizerURL(const CharacterType* characters, unsigned length) +{ + const CharacterType* end = characters + length; + + for (; characters != end; ++characters) { + CharacterType c = characters[0]; switch (c) { case '!': case '#': @@ -10261,10 +10557,23 @@ static bool isCSSTokenizerURL(const String& string) return false; } } - + return true; } +// "url" from the CSS tokenizer, minus backslash-escape sequences +static bool isCSSTokenizerURL(const String& string) +{ + unsigned length = string.length(); + + if (!length) + return true; + + if (string.is8Bit()) + return isCSSTokenizerURL(string.characters8(), length); + return isCSSTokenizerURL(string.characters(), length); +} + // We use single quotes for now because markup.cpp uses double quotes. String quoteCSSString(const String& string) { |