Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 * Copyright (C) 2003 Lars Knoll (knoll@kde.org) | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 * Copyright (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com) | 3 // found in the LICENSE file. |
| 4 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved. | |
| 5 * Copyright (C) 2007 Nicholas Shanks <webkit@nickshanks.com> | |
| 6 * Copyright (C) 2008 Eric Seidel <eric@webkit.org> | |
| 7 * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmo bile.com/) | |
| 8 * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved. | |
| 9 * Copyright (C) 2012 Intel Corporation. All rights reserved. | |
| 10 * | |
| 11 * This library is free software; you can redistribute it and/or | |
| 12 * modify it under the terms of the GNU Library General Public | |
| 13 * License as published by the Free Software Foundation; either | |
| 14 * version 2 of the License, or (at your option) any later version. | |
| 15 * | |
| 16 * This library is distributed in the hope that it will be useful, | |
| 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 19 * Library General Public License for more details. | |
| 20 * | |
| 21 * You should have received a copy of the GNU Library General Public License | |
| 22 * along with this library; see the file COPYING.LIB. If not, write to | |
| 23 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | |
| 24 * Boston, MA 02110-1301, USA. | |
| 25 */ | |
| 26 | 4 |
| 27 #include "config.h" | 5 #include "config.h" |
| 28 #include "core/css/parser/CSSPropertyParser.h" | 6 #include "core/css/parser/CSSPropertyParser.h" |
| 29 | 7 |
| 30 #include "core/StylePropertyShorthand.h" | 8 #include "core/StylePropertyShorthand.h" |
| 31 #include "core/css/CSSBasicShapes.h" | |
| 32 #include "core/css/CSSBorderImage.h" | |
| 33 #include "core/css/CSSCanvasValue.h" | |
| 34 #include "core/css/CSSContentDistributionValue.h" | |
| 35 #include "core/css/CSSCounterValue.h" | |
| 36 #include "core/css/CSSCrossfadeValue.h" | |
| 37 #include "core/css/CSSCursorImageValue.h" | |
| 38 #include "core/css/CSSFontFaceSrcValue.h" | |
| 39 #include "core/css/CSSFontFeatureValue.h" | |
| 40 #include "core/css/CSSFunctionValue.h" | |
| 41 #include "core/css/CSSGridLineNamesValue.h" | |
| 42 #include "core/css/CSSImageSetValue.h" | |
| 43 #include "core/css/CSSImageValue.h" | |
| 44 #include "core/css/CSSPathValue.h" | |
| 45 #include "core/css/CSSPrimitiveValueMappings.h" | |
| 46 #include "core/css/CSSProperty.h" | |
| 47 #include "core/css/CSSPropertyMetadata.h" | |
| 48 #include "core/css/CSSQuadValue.h" | |
| 49 #include "core/css/CSSReflectValue.h" | |
| 50 #include "core/css/CSSSVGDocumentValue.h" | |
| 51 #include "core/css/CSSShadowValue.h" | |
| 52 #include "core/css/CSSTimingFunctionValue.h" | |
| 53 #include "core/css/CSSUnicodeRangeValue.h" | |
| 54 #include "core/css/CSSValuePair.h" | |
| 55 #include "core/css/CSSValuePool.h" | 9 #include "core/css/CSSValuePool.h" |
| 56 #include "core/css/HashTools.h" | 10 #include "core/css/CSSCalculationValue.h" |
| 57 #include "core/css/parser/CSSParserFastPaths.h" | 11 #include "core/css/parser/CSSParserFastPaths.h" |
| 58 #include "core/css/parser/CSSParserValues.h" | 12 #include "core/css/parser/CSSParserValues.h" |
| 59 #include "core/frame/UseCounter.h" | 13 #include "core/frame/UseCounter.h" |
| 60 #include "core/layout/LayoutTheme.h" | |
| 61 #include "core/style/GridCoordinate.h" | |
| 62 #include "core/svg/SVGPathUtilities.h" | |
| 63 #include "platform/RuntimeEnabledFeatures.h" | |
| 64 | 14 |
| 65 namespace blink { | 15 namespace blink { |
| 66 | 16 |
| 67 template <unsigned N> | 17 CSSPropertyParser::CSSPropertyParser(CSSParserValueList* valueList, const CSSPar serTokenRange& range, |
| 68 static bool equalIgnoringCase(const CSSParserString& a, const char (&b)[N]) | |
| 69 { | |
| 70 unsigned length = N - 1; // Ignore the trailing null character | |
| 71 if (a.length() != length) | |
| 72 return false; | |
| 73 | |
| 74 return a.is8Bit() ? WTF::equalIgnoringCase(b, a.characters8(), length) : WTF ::equalIgnoringCase(b, a.characters16(), length); | |
| 75 } | |
| 76 | |
| 77 CSSPropertyParser::CSSPropertyParser(CSSParserValueList* valueList, | |
| 78 const CSSParserContext& context, WillBeHeapVector<CSSProperty, 256>& parsedP roperties, | 18 const CSSParserContext& context, WillBeHeapVector<CSSProperty, 256>& parsedP roperties, |
| 79 StyleRule::Type ruleType) | 19 StyleRule::Type ruleType) |
| 80 : m_valueList(valueList) | 20 : m_valueList(valueList) |
| 21 , m_range(range) | |
| 81 , m_context(context) | 22 , m_context(context) |
| 82 , m_parsedProperties(parsedProperties) | 23 , m_parsedProperties(parsedProperties) |
| 83 , m_ruleType(ruleType) | 24 , m_ruleType(ruleType) |
| 84 , m_inParseShorthand(0) | 25 , m_inParseShorthand(0) |
| 85 , m_currentShorthand(CSSPropertyInvalid) | 26 , m_currentShorthand(CSSPropertyInvalid) |
| 86 , m_implicitShorthand(false) | 27 , m_implicitShorthand(false) |
| 87 { | 28 { |
| 88 } | 29 } |
| 89 | 30 |
| 90 bool CSSPropertyParser::parseValue(CSSPropertyID unresolvedProperty, bool import ant, | 31 bool CSSPropertyParser::parseValue(CSSPropertyID unresolvedProperty, bool import ant, |
| 91 CSSParserValueList* valueList, const CSSParserContext& context, | 32 const CSSParserTokenRange& range, const CSSParserContext& context, |
| 92 WillBeHeapVector<CSSProperty, 256>& parsedProperties, StyleRule::Type ruleTy pe) | 33 WillBeHeapVector<CSSProperty, 256>& parsedProperties, StyleRule::Type ruleTy pe) |
| 93 { | 34 { |
| 94 int parsedPropertiesSize = parsedProperties.size(); | 35 int parsedPropertiesSize = parsedProperties.size(); |
| 95 | 36 |
| 96 CSSPropertyParser parser(valueList, context, parsedProperties, ruleType); | 37 CSSParserValueList valueList(range); |
| 38 if (!valueList.size()) | |
| 39 return false; // Parser error | |
| 40 CSSPropertyParser parser(&valueList, range, context, parsedProperties, ruleT ype); | |
| 97 CSSPropertyID resolvedProperty = resolveCSSPropertyID(unresolvedProperty); | 41 CSSPropertyID resolvedProperty = resolveCSSPropertyID(unresolvedProperty); |
| 98 bool parseSuccess; | 42 bool parseSuccess; |
| 99 | 43 |
| 100 if (ruleType == StyleRule::Viewport) { | 44 if (ruleType == StyleRule::Viewport) { |
| 101 parseSuccess = (RuntimeEnabledFeatures::cssViewportEnabled() || isUAShee tBehavior(context.mode())) | 45 parseSuccess = (RuntimeEnabledFeatures::cssViewportEnabled() || isUAShee tBehavior(context.mode())) |
| 102 && parser.parseViewportProperty(resolvedProperty, important); | 46 && parser.parseViewportProperty(resolvedProperty, important); |
| 103 } else if (ruleType == StyleRule::FontFace) { | 47 } else if (ruleType == StyleRule::FontFace) { |
| 104 parseSuccess = parser.parseFontFaceDescriptor(resolvedProperty); | 48 parseSuccess = parser.parseFontFaceDescriptor(resolvedProperty); |
| 105 } else { | 49 } else { |
| 106 parseSuccess = parser.parseValue(unresolvedProperty, important); | 50 parseSuccess = parser.parseValue(unresolvedProperty, important); |
| 107 } | 51 } |
| 108 | 52 |
| 109 // This doesn't count UA style sheets | 53 // This doesn't count UA style sheets |
| 110 if (parseSuccess && context.useCounter()) | 54 if (parseSuccess && context.useCounter()) |
| 111 context.useCounter()->count(context, unresolvedProperty); | 55 context.useCounter()->count(context, unresolvedProperty); |
| 112 | 56 |
| 113 if (!parseSuccess) | 57 if (!parseSuccess) |
| 114 parser.rollbackLastProperties(parsedProperties.size() - parsedProperties Size); | 58 parser.rollbackLastProperties(parsedProperties.size() - parsedProperties Size); |
| 115 | 59 |
| 116 return parseSuccess; | 60 return parseSuccess; |
| 117 } | 61 } |
| 118 | 62 |
| 119 void CSSPropertyParser::addProperty(CSSPropertyID propId, PassRefPtrWillBeRawPtr <CSSValue> value, bool important, bool implicit) | 63 // Helper methods for consuming tokens starts here. |
| 64 static bool consumeCommaIncludingWhitespace(CSSParserTokenRange& valueList) | |
| 120 { | 65 { |
| 121 ASSERT(!isPropertyAlias(propId)); | 66 CSSParserToken value = valueList.peek(); |
| 67 if (value.type() != CommaToken) | |
| 68 return false; | |
| 69 valueList.consumeIncludingWhitespace(); | |
| 70 return true; | |
| 71 } | |
| 122 | 72 |
| 123 int shorthandIndex = 0; | 73 static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> consumeIdent(CSSParserTokenRang e& range) |
| 124 bool setFromShorthand = false; | 74 { |
| 75 ASSERT(range.peek().type() == IdentToken); | |
|
alancutter (OOO until 2018)
2015/09/11 07:53:49
Let's just return nullptr, that way we can avoid d
| |
| 76 return cssValuePool().createIdentifierValue(range.consumeIncludingWhitespace ().id()); | |
| 77 } | |
| 125 | 78 |
| 126 if (m_currentShorthand) { | 79 static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> consumeCustomIdent(CSSParserTok enRange& range) |
| 127 Vector<StylePropertyShorthand, 4> shorthands; | 80 { |
| 128 getMatchingShorthandsForLonghand(propId, &shorthands); | 81 ASSERT(range.peek().type() == IdentToken); |
| 129 // Viewport descriptors have width and height as shorthands, but it does n't | 82 return cssValuePool().createValue(range.consumeIncludingWhitespace().value() , CSSPrimitiveValue::UnitType::CustomIdentifier); |
| 130 // make sense for CSSProperties.in to consider them as such. The shortha nd | 83 } |
| 131 // index is only used by the inspector and doesn't affect viewport | |
| 132 // descriptors. | |
| 133 if (shorthands.isEmpty()) | |
| 134 ASSERT(m_currentShorthand == CSSPropertyWidth || m_currentShorthand == CSSPropertyHeight); | |
| 135 else | |
| 136 setFromShorthand = true; | |
| 137 | 84 |
| 138 if (shorthands.size() > 1) | 85 static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> consumeString(CSSParserTokenRan ge& range) |
| 139 shorthandIndex = indexOfShorthandForLonghand(m_currentShorthand, sho rthands); | 86 { |
| 87 ASSERT(range.peek().type() == StringToken); | |
| 88 return cssValuePool().createValue(range.consumeIncludingWhitespace().value() , CSSPrimitiveValue::UnitType::String); | |
| 89 } | |
| 90 | |
| 91 // Methods for consuming non-shorthand properties starts here. | |
| 92 static PassRefPtrWillBeRawPtr<CSSValue> consumeWillChange(CSSParserTokenRange& r ange) | |
| 93 { | |
| 94 RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createCommaSeparated (); | |
| 95 if (range.peek().id() == CSSValueAuto) { | |
| 96 values->append(consumeIdent(range)); | |
| 97 return values.release(); | |
| 140 } | 98 } |
| 141 | 99 |
| 142 m_parsedProperties.append(CSSProperty(propId, value, important, setFromShort hand, shorthandIndex, m_implicitShorthand || implicit)); | 100 // Every comma-separated list of identifiers is a valid will-change value, |
| 101 // unless the list includes an explicitly disallowed identifier. | |
| 102 while (true) { | |
| 103 if (range.peek().type() != IdentToken) | |
| 104 return nullptr; | |
| 105 CSSPropertyID unresolvedProperty = unresolvedCSSPropertyID(range.peek(). value()); | |
| 106 if (unresolvedProperty) { | |
| 107 ASSERT(CSSPropertyMetadata::isEnabledProperty(unresolvedProperty)); | |
| 108 // Now "all" is used by both CSSValue and CSSPropertyValue. | |
| 109 // Need to return nullptr when currentValue is CSSPropertyAll. | |
| 110 if (unresolvedProperty == CSSPropertyWillChange || unresolvedPropert y == CSSPropertyAll) | |
| 111 return nullptr; | |
| 112 values->append(cssValuePool().createIdentifierValue(unresolvedProper ty)); | |
| 113 range.consumeIncludingWhitespace(); | |
| 114 } else { | |
| 115 switch (range.peek().id()) { | |
| 116 case CSSValueNone: | |
| 117 case CSSValueAll: | |
| 118 case CSSValueAuto: | |
| 119 case CSSValueDefault: | |
| 120 case CSSValueInitial: | |
| 121 case CSSValueInherit: | |
| 122 return nullptr; | |
| 123 case CSSValueContents: | |
| 124 case CSSValueScrollPosition: | |
| 125 values->append(consumeIdent(range)); | |
| 126 break; | |
| 127 default: | |
| 128 range.consumeIncludingWhitespace(); | |
| 129 break; | |
| 130 } | |
| 131 } | |
| 132 | |
| 133 if (range.atEnd()) | |
| 134 break; | |
| 135 if (!consumeCommaIncludingWhitespace(range)) | |
| 136 return nullptr; | |
| 137 } | |
| 138 | |
| 139 return values.release(); | |
| 143 } | 140 } |
| 144 | 141 |
| 145 void CSSPropertyParser::rollbackLastProperties(int num) | 142 static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> consumePage(CSSParserTokenRange & range) |
| 146 { | 143 { |
| 147 ASSERT(num >= 0); | 144 const CSSParserToken& token = range.peek(); |
| 148 ASSERT(m_parsedProperties.size() >= static_cast<unsigned>(num)); | 145 if (token.id() == CSSValueAuto) |
| 149 m_parsedProperties.shrink(m_parsedProperties.size() - num); | 146 return consumeIdent(range); |
| 147 if (token.type() == IdentToken) | |
| 148 return consumeCustomIdent(range); | |
| 149 return nullptr; | |
| 150 } | 150 } |
| 151 | 151 |
| 152 KURL CSSPropertyParser::completeURL(const String& url) const | 152 // [ <string> <string> ]+ | none |
| 153 static PassRefPtrWillBeRawPtr<CSSValue> consumeQuotes(CSSParserTokenRange& range ) | |
| 153 { | 154 { |
| 154 return m_context.completeURL(url); | 155 if (range.peek().id() == CSSValueNone) |
| 156 return consumeIdent(range); | |
| 157 RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createSpaceSeparated (); | |
| 158 while (!range.atEnd()) { | |
| 159 if (range.peek().type() != StringToken) | |
| 160 return nullptr; | |
| 161 RefPtrWillBeRawPtr<CSSValue> parsedValue = consumeString(range); | |
| 162 values->append(parsedValue.release()); | |
| 163 } | |
| 164 if (values->length() && values->length() % 2 == 0) | |
| 165 return values.release(); | |
| 166 return nullptr; | |
| 155 } | 167 } |
| 156 | 168 |
| 157 bool CSSPropertyParser::validCalculationUnit(CSSParserValue* value, Units unitfl ags, ReleaseParsedCalcValueCondition releaseCalc) | 169 static PassRefPtrWillBeRawPtr<CSSValue> consumeWebkitHighlight(CSSParserTokenRan ge& range) |
| 158 { | 170 { |
| 159 bool mustBeNonNegative = unitflags & (FNonNeg | FPositiveInteger); | 171 if (range.peek().id() == CSSValueNone) |
| 160 | 172 return consumeIdent(range); |
| 161 if (!parseCalculation(value, mustBeNonNegative ? ValueRangeNonNegative : Val ueRangeAll)) | 173 if (range.peek().type() == StringToken) |
| 162 return false; | 174 return consumeString(range); |
| 163 | 175 return nullptr; |
| 164 bool b = false; | |
| 165 switch (m_parsedCalculation->category()) { | |
| 166 case CalcLength: | |
| 167 b = (unitflags & FLength); | |
| 168 break; | |
| 169 case CalcNumber: | |
| 170 b = (unitflags & FNumber); | |
| 171 if (!b && (unitflags & (FInteger | FPositiveInteger)) && m_parsedCalcula tion->isInt()) | |
| 172 b = true; | |
| 173 if (b && mustBeNonNegative && m_parsedCalculation->isNegative()) | |
| 174 b = false; | |
| 175 // Always resolve calc() to a UnitType::Number in the CSSParserValue if there are no non-numbers specified in the unitflags. | |
| 176 if (b && !(unitflags & ~(FInteger | FNumber | FPositiveInteger | FNonNeg ))) { | |
| 177 double number = m_parsedCalculation->doubleValue(); | |
| 178 if ((unitflags & FPositiveInteger) && number <= 0) { | |
| 179 b = false; | |
| 180 } else { | |
| 181 delete value->calcFunction; | |
| 182 value->setUnit(CSSPrimitiveValue::UnitType::Number); | |
| 183 value->fValue = number; | |
| 184 value->isInt = m_parsedCalculation->isInt(); | |
| 185 } | |
| 186 m_parsedCalculation.release(); | |
| 187 return b; | |
| 188 } | |
| 189 break; | |
| 190 case CalcPercent: | |
| 191 b = (unitflags & FPercent); | |
| 192 if (b && mustBeNonNegative && m_parsedCalculation->isNegative()) | |
| 193 b = false; | |
| 194 break; | |
| 195 case CalcPercentLength: | |
| 196 b = (unitflags & FPercent) && (unitflags & FLength); | |
| 197 break; | |
| 198 case CalcPercentNumber: | |
| 199 b = (unitflags & FPercent) && (unitflags & FNumber); | |
| 200 break; | |
| 201 case CalcAngle: | |
| 202 b = (unitflags & FAngle); | |
| 203 break; | |
| 204 case CalcTime: | |
| 205 b = (unitflags & FTime); | |
| 206 break; | |
| 207 case CalcFrequency: | |
| 208 b = (unitflags & FFrequency); | |
| 209 break; | |
| 210 case CalcOther: | |
| 211 break; | |
| 212 } | |
| 213 if (!b || releaseCalc == ReleaseParsedCalcValue) | |
| 214 m_parsedCalculation.release(); | |
| 215 return b; | |
| 216 } | 176 } |
| 217 | 177 |
| 218 inline bool CSSPropertyParser::shouldAcceptUnitLessValues(CSSParserValue* value, Units unitflags, CSSParserMode cssParserMode) | 178 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseSingleValue(CSSProperty ID propId) |
| 219 { | 179 { |
| 220 // Quirks mode for certain properties and presentation attributes accept uni t-less values for certain units. | 180 m_range.consumeWhitespace(); |
| 221 return (unitflags & (FLength | FAngle)) | 181 switch (propId) { |
| 222 && (!value->fValue // 0 can always be unitless. | 182 case CSSPropertyWillChange: |
| 223 || isUnitLessLengthParsingEnabledForMode(cssParserMode) // HTML and SVG attribute values can always be unitless. | 183 return consumeWillChange(m_range); |
| 224 || (cssParserMode == HTMLQuirksMode && (unitflags & FUnitlessQuirk)) ); | 184 case CSSPropertyPage: |
| 225 } | 185 return consumePage(m_range); |
| 226 | 186 case CSSPropertyQuotes: |
| 227 inline bool isCalculation(CSSParserValue* value) | 187 return consumeQuotes(m_range); |
| 228 { | 188 case CSSPropertyWebkitHighlight: |
| 229 return value->m_unit == CSSParserValue::CalcFunction; | 189 return consumeWebkitHighlight(m_range); |
| 230 } | |
| 231 | |
| 232 bool CSSPropertyParser::validUnit(CSSParserValue* value, Units unitflags, CSSPar serMode cssParserMode, ReleaseParsedCalcValueCondition releaseCalc) | |
| 233 { | |
| 234 if (isCalculation(value)) | |
| 235 return validCalculationUnit(value, unitflags, releaseCalc); | |
| 236 | |
| 237 if (unitflags & FNonNeg && value->fValue < 0) | |
| 238 return false; | |
| 239 switch (value->unit()) { | |
| 240 case CSSPrimitiveValue::UnitType::Number: | |
| 241 if (unitflags & FNumber) | |
| 242 return true; | |
| 243 if (shouldAcceptUnitLessValues(value, unitflags, cssParserMode)) { | |
| 244 value->setUnit((unitflags & FLength) ? CSSPrimitiveValue::UnitType:: Pixels : CSSPrimitiveValue::UnitType::Degrees); | |
| 245 return true; | |
| 246 } | |
| 247 if ((unitflags & FInteger) && value->isInt) | |
| 248 return true; | |
| 249 if ((unitflags & FPositiveInteger) && value->isInt && value->fValue > 0) | |
| 250 return true; | |
| 251 return false; | |
| 252 case CSSPrimitiveValue::UnitType::Percentage: | |
| 253 return unitflags & FPercent; | |
| 254 case CSSPrimitiveValue::UnitType::QuirkyEms: | |
| 255 if (cssParserMode != UASheetMode) | |
| 256 return false; | |
| 257 /* fallthrough intentional */ | |
| 258 case CSSPrimitiveValue::UnitType::Ems: | |
| 259 case CSSPrimitiveValue::UnitType::Rems: | |
| 260 case CSSPrimitiveValue::UnitType::Chs: | |
| 261 case CSSPrimitiveValue::UnitType::Exs: | |
| 262 case CSSPrimitiveValue::UnitType::Pixels: | |
| 263 case CSSPrimitiveValue::UnitType::Centimeters: | |
| 264 case CSSPrimitiveValue::UnitType::Millimeters: | |
| 265 case CSSPrimitiveValue::UnitType::Inches: | |
| 266 case CSSPrimitiveValue::UnitType::Points: | |
| 267 case CSSPrimitiveValue::UnitType::Picas: | |
| 268 case CSSPrimitiveValue::UnitType::ViewportWidth: | |
| 269 case CSSPrimitiveValue::UnitType::ViewportHeight: | |
| 270 case CSSPrimitiveValue::UnitType::ViewportMin: | |
| 271 case CSSPrimitiveValue::UnitType::ViewportMax: | |
| 272 return unitflags & FLength; | |
| 273 case CSSPrimitiveValue::UnitType::Milliseconds: | |
| 274 case CSSPrimitiveValue::UnitType::Seconds: | |
| 275 return unitflags & FTime; | |
| 276 case CSSPrimitiveValue::UnitType::Degrees: | |
| 277 case CSSPrimitiveValue::UnitType::Radians: | |
| 278 case CSSPrimitiveValue::UnitType::Gradians: | |
| 279 case CSSPrimitiveValue::UnitType::Turns: | |
| 280 return unitflags & FAngle; | |
| 281 case CSSPrimitiveValue::UnitType::DotsPerPixel: | |
| 282 case CSSPrimitiveValue::UnitType::DotsPerInch: | |
| 283 case CSSPrimitiveValue::UnitType::DotsPerCentimeter: | |
| 284 return unitflags & FResolution; | |
| 285 default: | 190 default: |
| 286 return false; | 191 return nullptr; |
| 287 } | 192 } |
| 288 } | 193 } |
| 289 | 194 |
| 290 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::createPrimitiveNume ricValue(CSSParserValue* value) | 195 bool CSSPropertyParser::parseShorthand(CSSPropertyID propId, bool important) |
| 291 { | 196 { |
| 292 if (m_parsedCalculation) { | 197 m_range.consumeWhitespace(); |
| 293 ASSERT(isCalculation(value)); | 198 switch (propId) { |
| 294 return CSSPrimitiveValue::create(m_parsedCalculation.release()); | 199 case CSSPropertyWebkitMarginCollapse: { |
| 295 } | 200 CSSValueID id = m_range.consumeIncludingWhitespace().id(); |
| 296 | 201 if (!CSSParserFastPaths::isValidKeywordPropertyAndValue(CSSPropertyWebki tMarginBeforeCollapse, id)) |
| 297 ASSERT((value->unit() >= CSSPrimitiveValue::UnitType::Number && value->unit( ) <= CSSPrimitiveValue::UnitType::Kilohertz) | 202 return false; |
| 298 || (value->unit() >= CSSPrimitiveValue::UnitType::Turns && value->unit() <= CSSPrimitiveValue::UnitType::Chs) | 203 RefPtrWillBeRawPtr<CSSValue> beforeCollapse = cssValuePool().createIdent ifierValue(id); |
| 299 || (value->unit() >= CSSPrimitiveValue::UnitType::ViewportWidth && value ->unit() <= CSSPrimitiveValue::UnitType::ViewportMax) | 204 addProperty(CSSPropertyWebkitMarginBeforeCollapse, beforeCollapse, impor tant); |
| 300 || (value->unit() >= CSSPrimitiveValue::UnitType::DotsPerPixel && value- >unit() <= CSSPrimitiveValue::UnitType::DotsPerCentimeter)); | 205 if (m_range.atEnd()) { |
| 301 return cssValuePool().createValue(value->fValue, value->unit()); | 206 addProperty(CSSPropertyWebkitMarginAfterCollapse, beforeCollapse, im portant); |
| 302 } | 207 return true; |
| 303 | |
| 304 inline PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::createPrimit iveStringValue(CSSParserValue* value) | |
| 305 { | |
| 306 ASSERT(value->unit() == CSSPrimitiveValue::UnitType::String || value->m_unit == CSSParserValue::Identifier); | |
| 307 return cssValuePool().createValue(value->string, CSSPrimitiveValue::UnitType ::String); | |
| 308 } | |
| 309 | |
| 310 inline PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::createPrimit iveCustomIdentValue(CSSParserValue* value) | |
| 311 { | |
| 312 ASSERT(value->unit() == CSSPrimitiveValue::UnitType::String || value->m_unit == CSSParserValue::Identifier); | |
| 313 return cssValuePool().createValue(value->string, CSSPrimitiveValue::UnitType ::CustomIdentifier); | |
| 314 } | |
| 315 | |
| 316 inline PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::createCSSImageValueWi thReferrer(const String& rawValue, const KURL& url) | |
| 317 { | |
| 318 RefPtrWillBeRawPtr<CSSValue> imageValue = CSSImageValue::create(rawValue, ur l); | |
| 319 toCSSImageValue(imageValue.get())->setReferrer(m_context.referrer()); | |
| 320 return imageValue; | |
| 321 } | |
| 322 | |
| 323 static inline bool isComma(CSSParserValue* value) | |
| 324 { | |
| 325 ASSERT(value); | |
| 326 return value->m_unit == CSSParserValue::Operator && value->iValue == ','; | |
| 327 } | |
| 328 | |
| 329 static bool consumeComma(CSSParserValueList* valueList) | |
| 330 { | |
| 331 CSSParserValue* value = valueList->current(); | |
| 332 if (!value || !isComma(value)) | |
| 333 return false; | |
| 334 valueList->next(); | |
| 335 return true; | |
| 336 } | |
| 337 | |
| 338 static inline bool isForwardSlashOperator(CSSParserValue* value) | |
| 339 { | |
| 340 ASSERT(value); | |
| 341 return value->m_unit == CSSParserValue::Operator && value->iValue == '/'; | |
| 342 } | |
| 343 | |
| 344 static bool isGeneratedImageValue(CSSParserValue* val) | |
| 345 { | |
| 346 if (val->m_unit != CSSParserValue::Function) | |
| 347 return false; | |
| 348 | |
| 349 CSSValueID id = val->function->id; | |
| 350 return id == CSSValueLinearGradient | |
| 351 || id == CSSValueRadialGradient | |
| 352 || id == CSSValueRepeatingLinearGradient | |
| 353 || id == CSSValueRepeatingRadialGradient | |
| 354 || id == CSSValueWebkitLinearGradient | |
| 355 || id == CSSValueWebkitRadialGradient | |
| 356 || id == CSSValueWebkitRepeatingLinearGradient | |
| 357 || id == CSSValueWebkitRepeatingRadialGradient | |
| 358 || id == CSSValueWebkitGradient | |
| 359 || id == CSSValueWebkitCanvas | |
| 360 || id == CSSValueWebkitCrossFade; | |
| 361 } | |
| 362 | |
| 363 bool CSSPropertyParser::validWidthOrHeight(CSSParserValue* value, Units unitless ) | |
| 364 { | |
| 365 int id = value->id; | |
| 366 if (id == CSSValueIntrinsic || id == CSSValueMinIntrinsic | |
| 367 || id == CSSValueWebkitMinContent || id == CSSValueWebkitMaxContent || i d == CSSValueWebkitFillAvailable || id == CSSValueWebkitFitContent | |
| 368 || id == CSSValueMinContent || id == CSSValueMaxContent || id == CSSValu eFitContent) { | |
| 369 if (m_context.useCounter()) { | |
| 370 switch (value->id) { | |
| 371 case CSSValueIntrinsic: | |
| 372 m_context.useCounter()->count(UseCounter::LegacyCSSValueIntrinsi c); | |
| 373 break; | |
| 374 case CSSValueMinIntrinsic: | |
| 375 m_context.useCounter()->count(UseCounter::LegacyCSSValueMinIntri nsic); | |
| 376 break; | |
| 377 case CSSValueWebkitMinContent: | |
| 378 m_context.useCounter()->count(UseCounter::CSSValuePrefixedMinCon tent); | |
| 379 break; | |
| 380 case CSSValueWebkitMaxContent: | |
| 381 m_context.useCounter()->count(UseCounter::CSSValuePrefixedMaxCon tent); | |
| 382 break; | |
| 383 case CSSValueWebkitFillAvailable: | |
| 384 m_context.useCounter()->count(UseCounter::CSSValuePrefixedFillAv ailable); | |
| 385 break; | |
| 386 case CSSValueWebkitFitContent: | |
| 387 m_context.useCounter()->count(UseCounter::CSSValuePrefixedFitCon tent); | |
| 388 break; | |
| 389 default: | |
| 390 break; | |
| 391 } | |
| 392 } | 208 } |
| 209 id = m_range.consumeIncludingWhitespace().id(); | |
| 210 if (!CSSParserFastPaths::isValidKeywordPropertyAndValue(CSSPropertyWebki tMarginAfterCollapse, id)) | |
| 211 return false; | |
| 212 addProperty(CSSPropertyWebkitMarginAfterCollapse, cssValuePool().createI dentifierValue(id), important); | |
| 393 return true; | 213 return true; |
| 394 } | 214 } |
| 395 return validUnit(value, FLength | FPercent | FNonNeg | unitless); | 215 case CSSPropertyOverflow: { |
| 396 } | 216 CSSValueID id = m_range.consumeIncludingWhitespace().id(); |
| 397 | 217 if (!CSSParserFastPaths::isValidKeywordPropertyAndValue(CSSPropertyOverf lowY, id)) |
| 398 inline PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::parseValidPr imitive(CSSValueID identifier, CSSParserValue* value) | |
| 399 { | |
| 400 if (identifier) | |
| 401 return cssValuePool().createIdentifierValue(identifier); | |
| 402 if (value->unit() >= CSSPrimitiveValue::UnitType::Number && value->unit() <= CSSPrimitiveValue::UnitType::Kilohertz) | |
| 403 return createPrimitiveNumericValue(value); | |
| 404 if (value->unit() >= CSSPrimitiveValue::UnitType::Turns && value->unit() <= CSSPrimitiveValue::UnitType::Chs) | |
| 405 return createPrimitiveNumericValue(value); | |
| 406 if (value->unit() >= CSSPrimitiveValue::UnitType::ViewportWidth && value->un it() <= CSSPrimitiveValue::UnitType::ViewportMax) | |
| 407 return createPrimitiveNumericValue(value); | |
| 408 if (value->unit() >= CSSPrimitiveValue::UnitType::DotsPerPixel && value->uni t() <= CSSPrimitiveValue::UnitType::DotsPerCentimeter) | |
| 409 return createPrimitiveNumericValue(value); | |
| 410 if (value->unit() == CSSPrimitiveValue::UnitType::QuirkyEms) | |
| 411 return CSSPrimitiveValue::create(value->fValue, CSSPrimitiveValue::UnitT ype::QuirkyEms); | |
| 412 if (isCalculation(value)) | |
| 413 return CSSPrimitiveValue::create(m_parsedCalculation.release()); | |
| 414 | |
| 415 return nullptr; | |
| 416 } | |
| 417 | |
| 418 void CSSPropertyParser::addExpandedPropertyForValue(CSSPropertyID propId, PassRe fPtrWillBeRawPtr<CSSValue> prpValue, bool important) | |
| 419 { | |
| 420 const StylePropertyShorthand& shorthand = shorthandForProperty(propId); | |
| 421 unsigned shorthandLength = shorthand.length(); | |
| 422 if (!shorthandLength) { | |
| 423 addProperty(propId, prpValue, important); | |
| 424 return; | |
| 425 } | |
| 426 | |
| 427 RefPtrWillBeRawPtr<CSSValue> value = prpValue; | |
| 428 ShorthandScope scope(this, propId); | |
| 429 const CSSPropertyID* longhands = shorthand.properties(); | |
| 430 for (unsigned i = 0; i < shorthandLength; ++i) | |
| 431 addProperty(longhands[i], value, important); | |
| 432 } | |
| 433 | |
| 434 bool CSSPropertyParser::parseValue(CSSPropertyID unresolvedProperty, bool import ant) | |
| 435 { | |
| 436 CSSPropertyID propId = resolveCSSPropertyID(unresolvedProperty); | |
| 437 | |
| 438 CSSParserValue* value = m_valueList->current(); | |
| 439 | |
| 440 // Note: m_parsedCalculation is used to pass the calc value to validUnit and then cleared at the end of this function. | |
| 441 // FIXME: This is to avoid having to pass parsedCalc to all validUnit caller s. | |
| 442 ASSERT(!m_parsedCalculation); | |
| 443 | |
| 444 CSSValueID id = value->id; | |
| 445 | |
| 446 if (id == CSSValueInherit) { | |
| 447 if (m_valueList->size() != 1) | |
| 448 return false; | 218 return false; |
| 449 addExpandedPropertyForValue(propId, cssValuePool().createInheritedValue( ), important); | 219 if (!m_range.atEnd()) |
| 450 return true; | |
| 451 } else if (id == CSSValueInitial) { | |
| 452 if (m_valueList->size() != 1) | |
| 453 return false; | 220 return false; |
| 454 addExpandedPropertyForValue(propId, cssValuePool().createExplicitInitial Value(), important); | 221 RefPtrWillBeRawPtr<CSSValue> overflowYValue = cssValuePool().createIdent ifierValue(id); |
| 455 return true; | |
| 456 } else if (id == CSSValueUnset) { | |
| 457 if (m_valueList->size() != 1) | |
| 458 return false; | |
| 459 addExpandedPropertyForValue(propId, cssValuePool().createUnsetValue(), i mportant); | |
| 460 return true; | |
| 461 } | |
| 462 | |
| 463 if (CSSParserFastPaths::isKeywordPropertyID(propId)) { | |
| 464 if (!CSSParserFastPaths::isValidKeywordPropertyAndValue(propId, id)) | |
| 465 return false; | |
| 466 if (m_valueList->next() && !inShorthand()) | |
| 467 return false; | |
| 468 addProperty(propId, cssValuePool().createIdentifierValue(id), important) ; | |
| 469 return true; | |
| 470 } | |
| 471 | |
| 472 bool validPrimitive = false; | |
| 473 Units unitless = FUnknown; | |
| 474 RefPtrWillBeRawPtr<CSSValue> parsedValue = nullptr; | |
| 475 | |
| 476 switch (propId) { | |
| 477 case CSSPropertySize: // <length>{1,2} | auto | [ <page-size> || [ portrait | landscape] ] | |
| 478 parsedValue = parseSize(); | |
| 479 break; | |
| 480 case CSSPropertyQuotes: // [<string> <string>]+ | none | |
| 481 if (id == CSSValueNone) | |
| 482 validPrimitive = true; | |
| 483 else | |
| 484 parsedValue = parseQuotes(); | |
| 485 break; | |
| 486 | |
| 487 case CSSPropertyContent: // [ <string> | <uri> | <counter> | at tr(X) | open-quote | | |
| 488 // close-quote | no-open-quote | no-close-quote ]+ | inherit | |
| 489 parsedValue = parseContent(); | |
| 490 break; | |
| 491 case CSSPropertyClip: // <shape> | auto | inherit | |
| 492 if (id == CSSValueAuto) | |
| 493 validPrimitive = true; | |
| 494 else if (value->m_unit == CSSParserValue::Function) | |
| 495 parsedValue = parseClipShape(); | |
| 496 break; | |
| 497 | |
| 498 /* Start of supported CSS properties with validation. This is needed for par seShorthand to work | |
| 499 * correctly and allows optimization in blink::applyRule(..) | |
| 500 */ | |
| 501 case CSSPropertyOverflow: { | |
| 502 ShorthandScope scope(this, propId); | |
| 503 if (!parseValue(CSSPropertyOverflowY, important) || m_valueList->current ()) | |
| 504 return false; | |
| 505 | 222 |
| 506 RefPtrWillBeRawPtr<CSSValue> overflowXValue = nullptr; | 223 RefPtrWillBeRawPtr<CSSValue> overflowXValue = nullptr; |
| 507 | 224 |
| 508 // FIXME: -webkit-paged-x or -webkit-paged-y only apply to overflow-y. I f this value has been | 225 // FIXME: -webkit-paged-x or -webkit-paged-y only apply to overflow-y. I f this value has been |
| 509 // set using the shorthand, then for now overflow-x will default to auto , but once we implement | 226 // set using the shorthand, then for now overflow-x will default to auto , but once we implement |
| 510 // pagination controls, it should default to hidden. If the overflow-y v alue is anything but | 227 // pagination controls, it should default to hidden. If the overflow-y v alue is anything but |
| 511 // paged-x or paged-y, then overflow-x and overflow-y should have the sa me value. | 228 // paged-x or paged-y, then overflow-x and overflow-y should have the sa me value. |
| 512 if (id == CSSValueWebkitPagedX || id == CSSValueWebkitPagedY) | 229 if (id == CSSValueWebkitPagedX || id == CSSValueWebkitPagedY) |
| 513 overflowXValue = cssValuePool().createIdentifierValue(CSSValueAuto); | 230 overflowXValue = cssValuePool().createIdentifierValue(CSSValueAuto); |
| 514 else | 231 else |
| 515 overflowXValue = m_parsedProperties.last().value(); | 232 overflowXValue = overflowYValue; |
| 516 addProperty(CSSPropertyOverflowX, overflowXValue.release(), important); | 233 addProperty(CSSPropertyOverflowX, overflowXValue.release(), important); |
| 234 addProperty(CSSPropertyOverflowY, overflowYValue.release(), important); | |
| 517 return true; | 235 return true; |
| 518 } | 236 } |
| 519 | 237 default: |
| 520 case CSSPropertyTextAlign: | |
| 521 // left | right | center | justify | -webkit-left | -webkit-right | -web kit-center | -webkit-match-parent | |
| 522 // | start | end | <string> | inherit | -webkit-auto (converted to start ) | |
| 523 // FIXME: <string> not supported right now | |
| 524 if ((id >= CSSValueWebkitAuto && id <= CSSValueWebkitMatchParent) || id == CSSValueStart || id == CSSValueEnd) { | |
| 525 validPrimitive = true; | |
| 526 } | |
| 527 break; | |
| 528 | |
| 529 case CSSPropertyFontWeight: // normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | inherit | |
| 530 return parseFontWeight(important) && !m_valueList->next(); | |
| 531 | |
| 532 case CSSPropertyBorderSpacing: { | |
| 533 ShorthandScope scope(this, CSSPropertyBorderSpacing); | |
| 534 if (!parseValue(CSSPropertyWebkitBorderHorizontalSpacing, important)) | |
| 535 return false; | |
| 536 if (!m_valueList->current()) { | |
| 537 CSSValue* value = m_parsedProperties.last().value(); | |
| 538 addProperty(CSSPropertyWebkitBorderVerticalSpacing, value, important ); | |
| 539 return true; | |
| 540 } | |
| 541 if (!parseValue(CSSPropertyWebkitBorderVerticalSpacing, important)) | |
| 542 return false; | |
| 543 return !m_valueList->current(); | |
| 544 } | |
| 545 case CSSPropertyWebkitBorderHorizontalSpacing: | |
| 546 case CSSPropertyWebkitBorderVerticalSpacing: | |
| 547 unitless = FLength | FNonNeg; | |
| 548 if (inShorthand() && m_currentShorthand == CSSPropertyBorderSpacing) | |
| 549 unitless = unitless | FUnitlessQuirk; | |
| 550 validPrimitive = validUnit(value, unitless); | |
| 551 break; | |
| 552 case CSSPropertyOutlineColor: // <color> | invert | inherit | |
| 553 // Outline color has "invert" as additional keyword. | |
| 554 // Also, we want to allow the special focus color even in HTML Standard parsing mode. | |
| 555 if (id == CSSValueInvert || id == CSSValueWebkitFocusRingColor) { | |
| 556 validPrimitive = true; | |
| 557 break; | |
| 558 } | |
| 559 /* nobreak */ | |
| 560 case CSSPropertyBackgroundColor: // <color> | inherit | |
| 561 case CSSPropertyBorderTopColor: // <color> | inherit | |
| 562 case CSSPropertyBorderRightColor: | |
| 563 case CSSPropertyBorderBottomColor: | |
| 564 case CSSPropertyBorderLeftColor: | |
| 565 case CSSPropertyWebkitBorderStartColor: | |
| 566 case CSSPropertyWebkitBorderEndColor: | |
| 567 case CSSPropertyWebkitBorderBeforeColor: | |
| 568 case CSSPropertyWebkitBorderAfterColor: | |
| 569 case CSSPropertyColor: // <color> | inherit | |
| 570 case CSSPropertyTextDecorationColor: // CSS3 text decoration colors | |
| 571 case CSSPropertyWebkitColumnRuleColor: | |
| 572 case CSSPropertyWebkitTextEmphasisColor: | |
| 573 case CSSPropertyWebkitTextFillColor: | |
| 574 case CSSPropertyWebkitTextStrokeColor: | |
| 575 ASSERT(propId != CSSPropertyTextDecorationColor || RuntimeEnabledFeature s::css3TextDecorationsEnabled()); | |
| 576 parsedValue = parseColor(m_valueList->current(), acceptQuirkyColors(prop Id)); | |
| 577 if (parsedValue) | |
| 578 m_valueList->next(); | |
| 579 break; | |
| 580 | |
| 581 case CSSPropertyCursor: { | |
| 582 // Grammar defined by CSS3 UI and modified by CSS4 images: | |
| 583 // [ [<image> [<x> <y>]?,]* | |
| 584 // [ auto | crosshair | default | pointer | progress | move | e-resize | ne-resize | | |
| 585 // nw-resize | n-resize | se-resize | sw-resize | s-resize | w-resize | ew-resize | | |
| 586 // ns-resize | nesw-resize | nwse-resize | col-resize | row-resize | tex t | wait | help | | |
| 587 // vertical-text | cell | context-menu | alias | copy | no-drop | not-al lowed | all-scroll | | |
| 588 // zoom-in | zoom-out | -webkit-grab | -webkit-grabbing | -webkit-zoom-i n | -webkit-zoom-out ] ] | inherit | |
| 589 RefPtrWillBeRawPtr<CSSValueList> list = nullptr; | |
| 590 while (value) { | |
| 591 RefPtrWillBeRawPtr<CSSValue> image = nullptr; | |
| 592 if (value->unit() == CSSPrimitiveValue::UnitType::URI) { | |
| 593 String uri = value->string; | |
| 594 if (!uri.isNull()) | |
| 595 image = createCSSImageValueWithReferrer(uri, completeURL(uri )); | |
| 596 } else if (value->m_unit == CSSParserValue::Function && value->funct ion->id == CSSValueWebkitImageSet) { | |
| 597 image = parseImageSet(m_valueList); | |
| 598 if (!image) | |
| 599 break; | |
| 600 } else | |
| 601 break; | |
| 602 | |
| 603 Vector<int> coords; | |
| 604 value = m_valueList->next(); | |
| 605 while (value && validUnit(value, FNumber)) { | |
| 606 coords.append(int(value->fValue)); | |
| 607 value = m_valueList->next(); | |
| 608 } | |
| 609 bool hotSpotSpecified = false; | |
| 610 IntPoint hotSpot(-1, -1); | |
| 611 int nrcoords = coords.size(); | |
| 612 if (nrcoords > 0 && nrcoords != 2) | |
| 613 return false; | |
| 614 if (nrcoords == 2) { | |
| 615 hotSpotSpecified = true; | |
| 616 hotSpot = IntPoint(coords[0], coords[1]); | |
| 617 } | |
| 618 | |
| 619 if (!list) | |
| 620 list = CSSValueList::createCommaSeparated(); | |
| 621 | |
| 622 if (image) | |
| 623 list->append(CSSCursorImageValue::create(image, hotSpotSpecified , hotSpot)); | |
| 624 | |
| 625 if (!consumeComma(m_valueList)) | |
| 626 return false; | |
| 627 value = m_valueList->current(); | |
| 628 } | |
| 629 if (value && m_context.useCounter()) { | |
| 630 if (value->id == CSSValueWebkitZoomIn) | |
| 631 m_context.useCounter()->count(UseCounter::PrefixedCursorZoomIn); | |
| 632 else if (value->id == CSSValueWebkitZoomOut) | |
| 633 m_context.useCounter()->count(UseCounter::PrefixedCursorZoomOut) ; | |
| 634 } | |
| 635 if (list) { | |
| 636 if (!value) | |
| 637 return false; | |
| 638 if (inQuirksMode() && value->id == CSSValueHand) // MSIE 5 compatibi lity :/ | |
| 639 list->append(cssValuePool().createIdentifierValue(CSSValuePointe r)); | |
| 640 else if ((value->id >= CSSValueAuto && value->id <= CSSValueWebkitZo omOut) || value->id == CSSValueCopy || value->id == CSSValueNone) | |
| 641 list->append(cssValuePool().createIdentifierValue(value->id)); | |
| 642 m_valueList->next(); | |
| 643 parsedValue = list.release(); | |
| 644 break; | |
| 645 } else if (value) { | |
| 646 id = value->id; | |
| 647 if (inQuirksMode() && value->id == CSSValueHand) { // MSIE 5 compati bility :/ | |
| 648 id = CSSValuePointer; | |
| 649 validPrimitive = true; | |
| 650 } else if ((value->id >= CSSValueAuto && value->id <= CSSValueWebkit ZoomOut) || value->id == CSSValueCopy || value->id == CSSValueNone) | |
| 651 validPrimitive = true; | |
| 652 } else { | |
| 653 ASSERT_NOT_REACHED(); | |
| 654 return false; | |
| 655 } | |
| 656 break; | |
| 657 } | |
| 658 case CSSPropertyImageOrientation: | |
| 659 if (RuntimeEnabledFeatures::imageOrientationEnabled()) | |
| 660 validPrimitive = value->id == CSSValueFromImage || (value->unit() != CSSPrimitiveValue::UnitType::Number && validUnit(value, FAngle) && value->fValu e == 0); | |
| 661 break; | |
| 662 | |
| 663 case CSSPropertyBackgroundBlendMode: | |
| 664 case CSSPropertyBackgroundAttachment: | |
| 665 case CSSPropertyBackgroundClip: | |
| 666 case CSSPropertyWebkitBackgroundClip: | |
| 667 case CSSPropertyWebkitBackgroundComposite: | |
| 668 case CSSPropertyBackgroundImage: | |
| 669 case CSSPropertyBackgroundOrigin: | |
| 670 case CSSPropertyMaskSourceType: | |
| 671 case CSSPropertyWebkitBackgroundOrigin: | |
| 672 case CSSPropertyBackgroundPosition: | |
| 673 case CSSPropertyBackgroundPositionX: | |
| 674 case CSSPropertyBackgroundPositionY: | |
| 675 case CSSPropertyBackgroundSize: | |
| 676 case CSSPropertyBackgroundRepeat: | |
| 677 case CSSPropertyWebkitMaskClip: | |
| 678 case CSSPropertyWebkitMaskComposite: | |
| 679 case CSSPropertyWebkitMaskImage: | |
| 680 case CSSPropertyWebkitMaskOrigin: | |
| 681 case CSSPropertyWebkitMaskPosition: | |
| 682 case CSSPropertyWebkitMaskPositionX: | |
| 683 case CSSPropertyWebkitMaskPositionY: | |
| 684 case CSSPropertyWebkitMaskSize: | |
| 685 case CSSPropertyWebkitMaskRepeat: | |
| 686 case CSSPropertyWebkitMaskRepeatX: | |
| 687 case CSSPropertyWebkitMaskRepeatY: | |
| 688 { | |
| 689 RefPtrWillBeRawPtr<CSSValue> val1 = nullptr; | |
| 690 RefPtrWillBeRawPtr<CSSValue> val2 = nullptr; | |
| 691 CSSPropertyID propId1, propId2; | |
| 692 bool result = false; | |
| 693 if (parseFillProperty(unresolvedProperty, propId1, propId2, val1, val2)) { | |
| 694 if (propId == CSSPropertyBackgroundPosition || | |
| 695 propId == CSSPropertyBackgroundRepeat || | |
| 696 propId == CSSPropertyWebkitMaskPosition || | |
| 697 propId == CSSPropertyWebkitMaskRepeat) { | |
| 698 ShorthandScope scope(this, propId); | |
| 699 addProperty(propId1, val1.release(), important); | |
| 700 if (val2) | |
| 701 addProperty(propId2, val2.release(), important); | |
| 702 } else { | |
| 703 addProperty(propId1, val1.release(), important); | |
| 704 if (val2) | |
| 705 addProperty(propId2, val2.release(), important); | |
| 706 } | |
| 707 result = true; | |
| 708 } | |
| 709 m_implicitShorthand = false; | |
| 710 return result; | |
| 711 } | |
| 712 case CSSPropertyObjectPosition: | |
| 713 parsedValue = parsePosition(m_valueList); | |
| 714 break; | |
| 715 case CSSPropertyListStyleImage: // <uri> | none | inherit | |
| 716 case CSSPropertyBorderImageSource: | |
| 717 case CSSPropertyWebkitMaskBoxImageSource: | |
| 718 if (id == CSSValueNone) { | |
| 719 parsedValue = cssValuePool().createIdentifierValue(CSSValueNone); | |
| 720 m_valueList->next(); | |
| 721 } else if (value->unit() == CSSPrimitiveValue::UnitType::URI) { | |
| 722 parsedValue = createCSSImageValueWithReferrer(value->string, complet eURL(value->string)); | |
| 723 m_valueList->next(); | |
| 724 } else if (isGeneratedImageValue(value)) { | |
| 725 if (parseGeneratedImage(m_valueList, parsedValue)) | |
| 726 m_valueList->next(); | |
| 727 else | |
| 728 return false; | |
| 729 } else if (value->m_unit == CSSParserValue::Function && value->function- >id == CSSValueWebkitImageSet) { | |
| 730 parsedValue = parseImageSet(m_valueList); | |
| 731 if (!parsedValue) | |
| 732 return false; | |
| 733 m_valueList->next(); | |
| 734 } | |
| 735 break; | |
| 736 | |
| 737 case CSSPropertyBorderTopWidth: //// <border-width> | inherit | |
| 738 case CSSPropertyBorderRightWidth: // Which is defined as | |
| 739 case CSSPropertyBorderBottomWidth: // thin | medium | thick | <length> | |
| 740 case CSSPropertyBorderLeftWidth: | |
| 741 if (!inShorthand() || m_currentShorthand == CSSPropertyBorderWidth) | |
| 742 unitless = FUnitlessQuirk; | |
| 743 // fall through | |
| 744 case CSSPropertyWebkitTextStrokeWidth: | |
| 745 case CSSPropertyOutlineWidth: // <border-width> | inherit | |
| 746 case CSSPropertyWebkitBorderStartWidth: | |
| 747 case CSSPropertyWebkitBorderEndWidth: | |
| 748 case CSSPropertyWebkitBorderBeforeWidth: | |
| 749 case CSSPropertyWebkitBorderAfterWidth: | |
| 750 case CSSPropertyWebkitColumnRuleWidth: | |
| 751 if (id == CSSValueThin || id == CSSValueMedium || id == CSSValueThick) | |
| 752 validPrimitive = true; | |
| 753 else | |
| 754 validPrimitive = validUnit(value, FLength | FNonNeg | unitless); | |
| 755 break; | |
| 756 | |
| 757 case CSSPropertyLetterSpacing: // normal | <length> | inherit | |
| 758 case CSSPropertyWordSpacing: // normal | <length> | inherit | |
| 759 if (id == CSSValueNormal) | |
| 760 validPrimitive = true; | |
| 761 else | |
| 762 validPrimitive = validUnit(value, FLength | FUnitlessQuirk); | |
| 763 break; | |
| 764 | |
| 765 case CSSPropertyTextIndent: | |
| 766 parsedValue = parseTextIndent(); | |
| 767 break; | |
| 768 | |
| 769 case CSSPropertyPaddingTop: //// <padding-width> | inherit | |
| 770 case CSSPropertyPaddingRight: // Which is defined as | |
| 771 case CSSPropertyPaddingBottom: // <length> | <percentage> | |
| 772 case CSSPropertyPaddingLeft: //// | |
| 773 unitless = FUnitlessQuirk; | |
| 774 // fall through | |
| 775 case CSSPropertyWebkitPaddingStart: | |
| 776 case CSSPropertyWebkitPaddingEnd: | |
| 777 case CSSPropertyWebkitPaddingBefore: | |
| 778 case CSSPropertyWebkitPaddingAfter: | |
| 779 validPrimitive = validUnit(value, FLength | FPercent | FNonNeg | unitles s); | |
| 780 break; | |
| 781 | |
| 782 case CSSPropertyMaxWidth: | |
| 783 case CSSPropertyMaxHeight: | |
| 784 unitless = FUnitlessQuirk; | |
| 785 // fall through | |
| 786 case CSSPropertyWebkitMaxLogicalWidth: | |
| 787 case CSSPropertyWebkitMaxLogicalHeight: | |
| 788 validPrimitive = (id == CSSValueNone || validWidthOrHeight(value, unitle ss)); | |
| 789 break; | |
| 790 | |
| 791 case CSSPropertyMinWidth: | |
| 792 case CSSPropertyMinHeight: | |
| 793 case CSSPropertyWidth: | |
| 794 case CSSPropertyHeight: | |
| 795 unitless = FUnitlessQuirk; | |
| 796 // fall through | |
| 797 case CSSPropertyWebkitMinLogicalWidth: | |
| 798 case CSSPropertyWebkitMinLogicalHeight: | |
| 799 case CSSPropertyWebkitLogicalWidth: | |
| 800 case CSSPropertyWebkitLogicalHeight: | |
| 801 validPrimitive = (id == CSSValueAuto || validWidthOrHeight(value, unitle ss)); | |
| 802 break; | |
| 803 | |
| 804 case CSSPropertyFontSize: | |
| 805 return parseFontSize(important); | |
| 806 | |
| 807 case CSSPropertyFontVariant: // normal | small-caps | inherit | |
| 808 return parseFontVariant(important); | |
| 809 | |
| 810 case CSSPropertyVerticalAlign: | |
| 811 // baseline | sub | super | top | text-top | middle | bottom | text-bott om | | |
| 812 // <percentage> | <length> | inherit | |
| 813 | |
| 814 if (id >= CSSValueBaseline && id <= CSSValueWebkitBaselineMiddle) | |
| 815 validPrimitive = true; | |
| 816 else | |
| 817 validPrimitive = validUnit(value, FLength | FPercent | FUnitlessQuir k); | |
| 818 break; | |
| 819 | |
| 820 case CSSPropertyBottom: // <length> | <percentage> | auto | in herit | |
| 821 case CSSPropertyLeft: // <length> | <percentage> | auto | in herit | |
| 822 case CSSPropertyRight: // <length> | <percentage> | auto | in herit | |
| 823 case CSSPropertyTop: // <length> | <percentage> | auto | in herit | |
| 824 case CSSPropertyMarginTop: //// <margin-width> | inherit | |
| 825 case CSSPropertyMarginRight: // Which is defined as | |
| 826 case CSSPropertyMarginBottom: // <length> | <percentage> | auto | i nherit | |
| 827 case CSSPropertyMarginLeft: //// | |
| 828 unitless = FUnitlessQuirk; | |
| 829 // fall through | |
| 830 case CSSPropertyWebkitMarginStart: | |
| 831 case CSSPropertyWebkitMarginEnd: | |
| 832 case CSSPropertyWebkitMarginBefore: | |
| 833 case CSSPropertyWebkitMarginAfter: | |
| 834 if (id == CSSValueAuto) | |
| 835 validPrimitive = true; | |
| 836 else | |
| 837 validPrimitive = validUnit(value, FLength | FPercent | unitless); | |
| 838 break; | |
| 839 | |
| 840 case CSSPropertyOrphans: // <integer> | inherit | auto (We've added support for auto for backwards compatibility) | |
| 841 case CSSPropertyWidows: // <integer> | inherit | auto (Ditto) | |
| 842 if (id == CSSValueAuto) | |
| 843 validPrimitive = true; | |
| 844 else | |
| 845 validPrimitive = validUnit(value, FPositiveInteger); | |
| 846 break; | |
| 847 | |
| 848 case CSSPropertyZIndex: // auto | <integer> | inherit | |
| 849 if (id == CSSValueAuto) { | |
| 850 validPrimitive = true; | |
| 851 } else if (validUnit(value, FInteger)) { | |
| 852 addProperty(propId, cssValuePool().createValue(value->fValue, CSSPri mitiveValue::UnitType::Integer), important); | |
| 853 return true; | |
| 854 } | |
| 855 break; | |
| 856 | |
| 857 case CSSPropertyLineHeight: | |
| 858 parsedValue = parseLineHeight(); | |
| 859 break; | |
| 860 case CSSPropertyCounterIncrement: | |
| 861 if (id == CSSValueNone) | |
| 862 validPrimitive = true; | |
| 863 else | |
| 864 parsedValue = parseCounter(1); | |
| 865 break; | |
| 866 case CSSPropertyCounterReset: | |
| 867 if (id == CSSValueNone) | |
| 868 validPrimitive = true; | |
| 869 else | |
| 870 parsedValue = parseCounter(0); | |
| 871 break; | |
| 872 case CSSPropertyFontFamily: | |
| 873 // [[ <family-name> | <generic-family> ],]* [<family-name> | <generic-fa mily>] | inherit | |
| 874 { | |
| 875 parsedValue = parseFontFamily(); | |
| 876 break; | |
| 877 } | |
| 878 | |
| 879 case CSSPropertyTextDecoration: | |
| 880 // Fall through 'text-decoration-line' parsing if CSS 3 Text Decoration | |
| 881 // is disabled to match CSS 2.1 rules for parsing 'text-decoration'. | |
| 882 if (RuntimeEnabledFeatures::css3TextDecorationsEnabled()) { | |
| 883 // [ <text-decoration-line> || <text-decoration-style> || <text-deco ration-color> ] | inherit | |
| 884 return parseShorthand(CSSPropertyTextDecoration, textDecorationShort hand(), important); | |
| 885 } | |
| 886 case CSSPropertyWebkitTextDecorationsInEffect: | |
| 887 case CSSPropertyTextDecorationLine: | |
| 888 // none | [ underline || overline || line-through || blink ] | inherit | |
| 889 parsedValue = parseTextDecoration(); | |
| 890 break; | |
| 891 | |
| 892 case CSSPropertyTextUnderlinePosition: | |
| 893 // auto | [ under || [ left | right ] ], but we only support auto | unde r for now | |
| 894 ASSERT(RuntimeEnabledFeatures::css3TextDecorationsEnabled()); | |
| 895 validPrimitive = (id == CSSValueAuto || id == CSSValueUnder); | |
| 896 break; | |
| 897 | |
| 898 case CSSPropertyZoom: // normal | reset | document | <number> | <pe rcentage> | inherit | |
| 899 if (id == CSSValueNormal || id == CSSValueReset || id == CSSValueDocumen t) | |
| 900 validPrimitive = true; | |
| 901 else | |
| 902 validPrimitive = validUnit(value, FNumber | FPercent | FNonNeg); | |
| 903 if (validPrimitive && m_context.useCounter() | |
| 904 && !(id == CSSValueNormal | |
| 905 || (value->unit() == CSSPrimitiveValue::UnitType::Number && valu e->fValue == 1) | |
| 906 || (value->unit() == CSSPrimitiveValue::UnitType::Percentage && value->fValue == 100))) | |
| 907 m_context.useCounter()->count(UseCounter::CSSZoomNotEqualToOne); | |
| 908 break; | |
| 909 | |
| 910 case CSSPropertySrc: | |
| 911 case CSSPropertyUnicodeRange: | |
| 912 /* @font-face only descriptors */ | |
| 913 break; | |
| 914 | |
| 915 /* CSS3 properties */ | |
| 916 | |
| 917 case CSSPropertyBorderImage: | |
| 918 case CSSPropertyWebkitMaskBoxImage: | |
| 919 return parseBorderImageShorthand(propId, important); | |
| 920 case CSSPropertyWebkitBorderImage: { | |
| 921 if (RefPtrWillBeRawPtr<CSSValue> result = parseBorderImage(propId)) { | |
| 922 addProperty(propId, result, important); | |
| 923 return true; | |
| 924 } | |
| 925 return false; | 238 return false; |
| 926 } | 239 } |
| 927 | |
| 928 case CSSPropertyBorderImageOutset: | |
| 929 case CSSPropertyWebkitMaskBoxImageOutset: { | |
| 930 RefPtrWillBeRawPtr<CSSQuadValue> result = nullptr; | |
| 931 if (parseBorderImageOutset(result)) { | |
| 932 addProperty(propId, result, important); | |
| 933 return true; | |
| 934 } | |
| 935 break; | |
| 936 } | |
| 937 case CSSPropertyBorderImageRepeat: | |
| 938 case CSSPropertyWebkitMaskBoxImageRepeat: { | |
| 939 RefPtrWillBeRawPtr<CSSValue> result = nullptr; | |
| 940 if (parseBorderImageRepeat(result)) { | |
| 941 addProperty(propId, result, important); | |
| 942 return true; | |
| 943 } | |
| 944 break; | |
| 945 } | |
| 946 case CSSPropertyBorderImageSlice: | |
| 947 case CSSPropertyWebkitMaskBoxImageSlice: { | |
| 948 RefPtrWillBeRawPtr<CSSBorderImageSliceValue> result = nullptr; | |
| 949 if (parseBorderImageSlice(propId, result)) { | |
| 950 addProperty(propId, result, important); | |
| 951 return true; | |
| 952 } | |
| 953 break; | |
| 954 } | |
| 955 case CSSPropertyBorderImageWidth: | |
| 956 case CSSPropertyWebkitMaskBoxImageWidth: { | |
| 957 RefPtrWillBeRawPtr<CSSQuadValue> result = nullptr; | |
| 958 if (parseBorderImageWidth(result)) { | |
| 959 addProperty(propId, result, important); | |
| 960 return true; | |
| 961 } | |
| 962 break; | |
| 963 } | |
| 964 case CSSPropertyBorderTopRightRadius: | |
| 965 case CSSPropertyBorderTopLeftRadius: | |
| 966 case CSSPropertyBorderBottomLeftRadius: | |
| 967 case CSSPropertyBorderBottomRightRadius: { | |
| 968 validPrimitive = validUnit(value, FLength | FPercent | FNonNeg); | |
| 969 if (!validPrimitive) | |
| 970 return false; | |
| 971 RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue1 = createPrimitiveNume ricValue(value); | |
| 972 RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue2 = nullptr; | |
| 973 value = m_valueList->next(); | |
| 974 if (value) { | |
| 975 validPrimitive = validUnit(value, FLength | FPercent | FNonNeg); | |
| 976 if (!validPrimitive) | |
| 977 return false; | |
| 978 parsedValue2 = createPrimitiveNumericValue(value); | |
| 979 } else | |
| 980 parsedValue2 = parsedValue1; | |
| 981 | |
| 982 if (m_valueList->next()) | |
| 983 return false; | |
| 984 addProperty(propId, CSSValuePair::create(parsedValue1.release(), parsedV alue2.release(), CSSValuePair::DropIdenticalValues), important); | |
| 985 return true; | |
| 986 } | |
| 987 case CSSPropertyTabSize: | |
| 988 // May be specified as a unit-less non-negative integer or length indica ting number of space characters. | |
| 989 validPrimitive = validUnit(value, FInteger | FLength | FNonNeg); | |
| 990 break; | |
| 991 case CSSPropertyBorderRadius: | |
| 992 case CSSPropertyAliasWebkitBorderRadius: | |
| 993 return parseBorderRadius(unresolvedProperty, important); | |
| 994 case CSSPropertyOutlineOffset: | |
| 995 validPrimitive = validUnit(value, FLength); | |
| 996 break; | |
| 997 case CSSPropertyTextShadow: // CSS2 property, dropped in CSS2.1, back in CSS 3, so treat as CSS3 | |
| 998 case CSSPropertyBoxShadow: | |
| 999 if (id == CSSValueNone) | |
| 1000 validPrimitive = true; | |
| 1001 else | |
| 1002 parsedValue = parseShadow(m_valueList, propId); | |
| 1003 break; | |
| 1004 case CSSPropertyWebkitBoxReflect: | |
| 1005 if (id == CSSValueNone) | |
| 1006 validPrimitive = true; | |
| 1007 else | |
| 1008 parsedValue = parseReflect(); | |
| 1009 break; | |
| 1010 case CSSPropertyFontSizeAdjust: // none | <number> | |
| 1011 ASSERT(RuntimeEnabledFeatures::cssFontSizeAdjustEnabled()); | |
| 1012 validPrimitive = (id == CSSValueNone) ? true : validUnit(value, FNumber | FNonNeg); | |
| 1013 break; | |
| 1014 case CSSPropertyOpacity: | |
| 1015 case CSSPropertyWebkitBoxFlex: | |
| 1016 validPrimitive = validUnit(value, FNumber); | |
| 1017 break; | |
| 1018 case CSSPropertyWebkitBoxFlexGroup: | |
| 1019 validPrimitive = validUnit(value, FInteger | FNonNeg); | |
| 1020 break; | |
| 1021 case CSSPropertyWebkitBoxOrdinalGroup: | |
| 1022 validPrimitive = validUnit(value, FInteger | FNonNeg) && value->fValue; | |
| 1023 break; | |
| 1024 case CSSPropertyWebkitFilter: | |
| 1025 case CSSPropertyBackdropFilter: | |
| 1026 if (id == CSSValueNone) | |
| 1027 validPrimitive = true; | |
| 1028 else { | |
| 1029 RefPtrWillBeRawPtr<CSSValue> val = parseFilter(); | |
| 1030 if (val) { | |
| 1031 addProperty(propId, val, important); | |
| 1032 return true; | |
| 1033 } | |
| 1034 return false; | |
| 1035 } | |
| 1036 break; | |
| 1037 case CSSPropertyFlex: { | |
| 1038 ShorthandScope scope(this, propId); | |
| 1039 if (id == CSSValueNone) { | |
| 1040 addProperty(CSSPropertyFlexGrow, cssValuePool().createValue(0, CSSPr imitiveValue::UnitType::Number), important); | |
| 1041 addProperty(CSSPropertyFlexShrink, cssValuePool().createValue(0, CSS PrimitiveValue::UnitType::Number), important); | |
| 1042 addProperty(CSSPropertyFlexBasis, cssValuePool().createIdentifierVal ue(CSSValueAuto), important); | |
| 1043 return true; | |
| 1044 } | |
| 1045 return parseFlex(m_valueList, important); | |
| 1046 } | |
| 1047 case CSSPropertyFlexBasis: | |
| 1048 // FIXME: Support intrinsic dimensions too. | |
| 1049 if (id == CSSValueAuto) | |
| 1050 validPrimitive = true; | |
| 1051 else | |
| 1052 validPrimitive = validUnit(value, FLength | FPercent | FNonNeg); | |
| 1053 break; | |
| 1054 case CSSPropertyFlexGrow: | |
| 1055 case CSSPropertyFlexShrink: | |
| 1056 validPrimitive = validUnit(value, FNumber | FNonNeg); | |
| 1057 break; | |
| 1058 case CSSPropertyOrder: | |
| 1059 validPrimitive = validUnit(value, FInteger); | |
| 1060 break; | |
| 1061 case CSSPropertyTransform: | |
| 1062 if (id == CSSValueNone) | |
| 1063 validPrimitive = true; | |
| 1064 else | |
| 1065 parsedValue = parseTransform(unresolvedProperty == CSSPropertyAliasW ebkitTransform); | |
| 1066 break; | |
| 1067 case CSSPropertyTransformOrigin: { | |
| 1068 RefPtrWillBeRawPtr<CSSValueList> list = parseTransformOrigin(); | |
| 1069 if (!list) | |
| 1070 return false; | |
| 1071 // These values are added to match gecko serialization. | |
| 1072 if (list->length() == 1) | |
| 1073 list->append(cssValuePool().createValue(50, CSSPrimitiveValue::UnitT ype::Percentage)); | |
| 1074 if (list->length() == 2) | |
| 1075 list->append(cssValuePool().createValue(0, CSSPrimitiveValue::UnitTy pe::Pixels)); | |
| 1076 addProperty(propId, list.release(), important); | |
| 1077 return true; | |
| 1078 } | |
| 1079 | |
| 1080 case CSSPropertyTranslate: { | |
| 1081 // translate : [ <length> | <percentage> ] [[ <length> | <percentage> ] <length>? ]? | |
| 1082 // defaults to 0 on all axis, note that the last value CANNOT be a perce ntage | |
| 1083 ASSERT(RuntimeEnabledFeatures::cssIndependentTransformPropertiesEnabled( )); | |
| 1084 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparat ed(); | |
| 1085 if (!validUnit(value, FLength | FPercent)) | |
| 1086 return false; | |
| 1087 | |
| 1088 list->append(createPrimitiveNumericValue(value)); | |
| 1089 value = m_valueList->next(); | |
| 1090 | |
| 1091 if (value) { | |
| 1092 if (!validUnit(value, FLength | FPercent)) | |
| 1093 return false; | |
| 1094 | |
| 1095 list->append(createPrimitiveNumericValue(value)); | |
| 1096 value = m_valueList->next(); | |
| 1097 | |
| 1098 if (value) { | |
| 1099 if (!validUnit(value, FLength)) | |
| 1100 return false; | |
| 1101 | |
| 1102 list->append(createPrimitiveNumericValue(value)); | |
| 1103 value = m_valueList->next(); | |
| 1104 } | |
| 1105 } | |
| 1106 | |
| 1107 parsedValue = list.release(); | |
| 1108 break; | |
| 1109 } | |
| 1110 | |
| 1111 case CSSPropertyRotate: { // rotate : <angle> <number>{3}? defaults to a 0 0 1 | |
| 1112 ASSERT(RuntimeEnabledFeatures::cssIndependentTransformPropertiesEnabled( )); | |
| 1113 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparat ed(); | |
| 1114 | |
| 1115 if (!validUnit(value, FAngle)) | |
| 1116 return false; | |
| 1117 list->append(createPrimitiveNumericValue(value)); | |
| 1118 value = m_valueList->next(); | |
| 1119 | |
| 1120 if (!value) { | |
| 1121 parsedValue = list.release(); | |
| 1122 break; | |
| 1123 } | |
| 1124 | |
| 1125 for (unsigned i = 0; i < 3; i++) { // 3 dimensions of rotation | |
| 1126 if (!value || !validUnit(value, FNumber)) | |
| 1127 return false; | |
| 1128 list->append(createPrimitiveNumericValue(value)); | |
| 1129 value = m_valueList->next(); | |
| 1130 } | |
| 1131 | |
| 1132 parsedValue = list.release(); | |
| 1133 break; | |
| 1134 } | |
| 1135 | |
| 1136 case CSSPropertyScale: { // scale: <number>{1,3}, default scale for all axis is 1 | |
| 1137 ASSERT(RuntimeEnabledFeatures::cssIndependentTransformPropertiesEnabled( )); | |
| 1138 RefPtrWillBeRawPtr<CSSValueList> scaleList = CSSValueList::createSpaceSe parated(); | |
| 1139 | |
| 1140 for (unsigned i = 0; value && i < 3; i++) { // up to 3 dimensions of sca le | |
| 1141 if (!validUnit(value, FNumber)) | |
| 1142 return false; | |
| 1143 scaleList->append(createPrimitiveNumericValue(value)); | |
| 1144 value = m_valueList->next(); | |
| 1145 } | |
| 1146 | |
| 1147 parsedValue = scaleList.release(); | |
| 1148 break; | |
| 1149 } | |
| 1150 | |
| 1151 case CSSPropertyWebkitPerspectiveOriginX: | |
| 1152 case CSSPropertyWebkitTransformOriginX: | |
| 1153 parsedValue = parseFillPositionX(m_valueList); | |
| 1154 if (parsedValue) | |
| 1155 m_valueList->next(); | |
| 1156 break; | |
| 1157 case CSSPropertyWebkitPerspectiveOriginY: | |
| 1158 case CSSPropertyWebkitTransformOriginY: | |
| 1159 parsedValue = parseFillPositionY(m_valueList); | |
| 1160 if (parsedValue) | |
| 1161 m_valueList->next(); | |
| 1162 break; | |
| 1163 case CSSPropertyWebkitTransformOriginZ: | |
| 1164 validPrimitive = validUnit(value, FLength); | |
| 1165 break; | |
| 1166 case CSSPropertyPerspective: | |
| 1167 if (id == CSSValueNone) { | |
| 1168 validPrimitive = true; | |
| 1169 } else if (validUnit(value, FLength) && (m_parsedCalculation || value->f Value > 0)) { | |
| 1170 validPrimitive = true; | |
| 1171 } else if (unresolvedProperty == CSSPropertyAliasWebkitPerspective && va lidUnit(value, FNumber) && value->fValue > 0) { | |
| 1172 value->setUnit(CSSPrimitiveValue::UnitType::Pixels); | |
| 1173 validPrimitive = true; | |
| 1174 } else { | |
| 1175 return false; | |
| 1176 } | |
| 1177 break; | |
| 1178 case CSSPropertyPerspectiveOrigin: { | |
| 1179 RefPtrWillBeRawPtr<CSSValueList> list = parseTransformOrigin(); | |
| 1180 if (!list || list->length() == 3) | |
| 1181 return false; | |
| 1182 // This values are added to match gecko serialization. | |
| 1183 if (list->length() == 1) | |
| 1184 list->append(cssValuePool().createValue(50, CSSPrimitiveValue::UnitT ype::Percentage)); | |
| 1185 addProperty(propId, list.release(), important); | |
| 1186 return true; | |
| 1187 } | |
| 1188 | |
| 1189 case CSSPropertyMotion: | |
| 1190 // <motion-path> && <motion-offset> && <motion-rotation> | |
| 1191 ASSERT(RuntimeEnabledFeatures::cssMotionPathEnabled()); | |
| 1192 return parseShorthand(propId, motionShorthand(), important); | |
| 1193 case CSSPropertyMotionPath: | |
| 1194 ASSERT(RuntimeEnabledFeatures::cssMotionPathEnabled()); | |
| 1195 if (id == CSSValueNone) | |
| 1196 validPrimitive = true; | |
| 1197 else | |
| 1198 parsedValue = parseMotionPath(); | |
| 1199 break; | |
| 1200 case CSSPropertyMotionOffset: | |
| 1201 ASSERT(RuntimeEnabledFeatures::cssMotionPathEnabled()); | |
| 1202 validPrimitive = validUnit(value, FLength | FPercent); | |
| 1203 break; | |
| 1204 case CSSPropertyMotionRotation: | |
| 1205 ASSERT(RuntimeEnabledFeatures::cssMotionPathEnabled()); | |
| 1206 parsedValue = parseMotionRotation(); | |
| 1207 break; | |
| 1208 | |
| 1209 case CSSPropertyAnimationDelay: | |
| 1210 case CSSPropertyAnimationDirection: | |
| 1211 case CSSPropertyAnimationDuration: | |
| 1212 case CSSPropertyAnimationFillMode: | |
| 1213 case CSSPropertyAnimationName: | |
| 1214 case CSSPropertyAnimationPlayState: | |
| 1215 case CSSPropertyAnimationIterationCount: | |
| 1216 case CSSPropertyAnimationTimingFunction: | |
| 1217 case CSSPropertyTransitionDelay: | |
| 1218 case CSSPropertyTransitionDuration: | |
| 1219 case CSSPropertyTransitionTimingFunction: | |
| 1220 case CSSPropertyTransitionProperty: | |
| 1221 parsedValue = parseAnimationPropertyList(propId, unresolvedProperty == C SSPropertyAliasWebkitAnimationName); | |
| 1222 break; | |
| 1223 | |
| 1224 case CSSPropertyJustifyContent: | |
| 1225 parsedValue = parseContentDistributionOverflowPosition(); | |
| 1226 break; | |
| 1227 case CSSPropertyJustifySelf: | |
| 1228 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled()); | |
| 1229 return parseItemPositionOverflowPosition(propId, important); | |
| 1230 case CSSPropertyJustifyItems: | |
| 1231 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled()); | |
| 1232 | |
| 1233 if (parseLegacyPosition(propId, important)) | |
| 1234 return true; | |
| 1235 | |
| 1236 m_valueList->setCurrentIndex(0); | |
| 1237 return parseItemPositionOverflowPosition(propId, important); | |
| 1238 case CSSPropertyGridAutoFlow: | |
| 1239 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled()); | |
| 1240 parsedValue = parseGridAutoFlow(*m_valueList); | |
| 1241 break; | |
| 1242 case CSSPropertyGridAutoColumns: | |
| 1243 case CSSPropertyGridAutoRows: | |
| 1244 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled()); | |
| 1245 parsedValue = parseGridTrackSize(*m_valueList); | |
| 1246 break; | |
| 1247 | |
| 1248 case CSSPropertyGridTemplateColumns: | |
| 1249 case CSSPropertyGridTemplateRows: | |
| 1250 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled()); | |
| 1251 parsedValue = parseGridTrackList(); | |
| 1252 break; | |
| 1253 | |
| 1254 case CSSPropertyGridColumnEnd: | |
| 1255 case CSSPropertyGridColumnStart: | |
| 1256 case CSSPropertyGridRowEnd: | |
| 1257 case CSSPropertyGridRowStart: | |
| 1258 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled()); | |
| 1259 parsedValue = parseGridPosition(); | |
| 1260 break; | |
| 1261 | |
| 1262 case CSSPropertyGridColumn: | |
| 1263 case CSSPropertyGridRow: | |
| 1264 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled()); | |
| 1265 return parseGridItemPositionShorthand(propId, important); | |
| 1266 | |
| 1267 case CSSPropertyGridArea: | |
| 1268 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled()); | |
| 1269 return parseGridAreaShorthand(important); | |
| 1270 | |
| 1271 case CSSPropertyGridTemplateAreas: | |
| 1272 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled()); | |
| 1273 parsedValue = parseGridTemplateAreas(); | |
| 1274 break; | |
| 1275 | |
| 1276 case CSSPropertyGridTemplate: | |
| 1277 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled()); | |
| 1278 return parseGridTemplateShorthand(important); | |
| 1279 | |
| 1280 case CSSPropertyGrid: | |
| 1281 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled()); | |
| 1282 return parseGridShorthand(important); | |
| 1283 | |
| 1284 case CSSPropertyWebkitMarginCollapse: { | |
| 1285 ShorthandScope scope(this, CSSPropertyWebkitMarginCollapse); | |
| 1286 if (!parseValue(webkitMarginCollapseShorthand().properties()[0], importa nt)) | |
| 1287 return false; | |
| 1288 if (!m_valueList->current()) { | |
| 1289 CSSValue* value = m_parsedProperties.last().value(); | |
| 1290 addProperty(webkitMarginCollapseShorthand().properties()[1], value, important); | |
| 1291 return true; | |
| 1292 } | |
| 1293 if (!parseValue(webkitMarginCollapseShorthand().properties()[1], importa nt)) | |
| 1294 return false; | |
| 1295 return !m_valueList->current(); | |
| 1296 } | |
| 1297 case CSSPropertyWebkitColumnCount: | |
| 1298 parsedValue = parseColumnCount(); | |
| 1299 break; | |
| 1300 case CSSPropertyWebkitColumnGap: // normal | <length> | |
| 1301 if (id == CSSValueNormal) | |
| 1302 validPrimitive = true; | |
| 1303 else | |
| 1304 validPrimitive = validUnit(value, FLength | FNonNeg); | |
| 1305 break; | |
| 1306 case CSSPropertyWebkitColumnSpan: // none | all | 1 (will be dropped in the unprefixed property) | |
| 1307 validPrimitive = id == CSSValueAll || id == CSSValueNone || (value->unit () == CSSPrimitiveValue::UnitType::Number && value->fValue == 1); | |
| 1308 break; | |
| 1309 case CSSPropertyWebkitColumnWidth: // auto | <length> | |
| 1310 parsedValue = parseColumnWidth(); | |
| 1311 break; | |
| 1312 case CSSPropertyWillChange: | |
| 1313 parsedValue = parseWillChange(); | |
| 1314 break; | |
| 1315 // End of CSS3 properties | |
| 1316 | |
| 1317 // Apple specific properties. These will never be standardized and are pure ly to | |
| 1318 // support custom WebKit-based Apple applications. | |
| 1319 case CSSPropertyWebkitLineClamp: | |
| 1320 // When specifying number of lines, don't allow 0 as a valid value | |
| 1321 // When specifying either type of unit, require non-negative integers | |
| 1322 validPrimitive = (!id && !isCalculation(value) && validUnit(value, FInte ger | FPercent | FNonNeg) && (value->unit() == CSSPrimitiveValue::UnitType::Perc entage || value->fValue)); | |
| 1323 break; | |
| 1324 | |
| 1325 case CSSPropertyWebkitFontSizeDelta: // <length> | |
| 1326 validPrimitive = validUnit(value, FLength | FUnitlessQuirk); | |
| 1327 break; | |
| 1328 | |
| 1329 case CSSPropertyWebkitHighlight: | |
| 1330 if (id == CSSValueNone) { | |
| 1331 validPrimitive = true; | |
| 1332 } else if (value->unit() == CSSPrimitiveValue::UnitType::String) { | |
| 1333 parsedValue = createPrimitiveStringValue(value); | |
| 1334 m_valueList->next(); | |
| 1335 } | |
| 1336 break; | |
| 1337 | |
| 1338 case CSSPropertyWebkitHyphenateCharacter: | |
| 1339 case CSSPropertyWebkitLocale: | |
| 1340 if (id == CSSValueAuto) { | |
| 1341 validPrimitive = true; | |
| 1342 } else if (value->unit() == CSSPrimitiveValue::UnitType::String) { | |
| 1343 parsedValue = createPrimitiveStringValue(value); | |
| 1344 m_valueList->next(); | |
| 1345 } | |
| 1346 break; | |
| 1347 | |
| 1348 // End Apple-specific properties | |
| 1349 | |
| 1350 case CSSPropertyWebkitAppRegion: | |
| 1351 if (id >= CSSValueDrag && id <= CSSValueNoDrag) | |
| 1352 validPrimitive = true; | |
| 1353 break; | |
| 1354 | |
| 1355 case CSSPropertyWebkitTapHighlightColor: | |
| 1356 parsedValue = parseColor(m_valueList->current()); | |
| 1357 if (parsedValue) | |
| 1358 m_valueList->next(); | |
| 1359 break; | |
| 1360 | |
| 1361 /* shorthand properties */ | |
| 1362 case CSSPropertyBackground: { | |
| 1363 // Position must come before color in this array because a plain old "0" is a legal color | |
| 1364 // in quirks mode but it's usually the X coordinate of a position. | |
| 1365 const CSSPropertyID properties[] = { CSSPropertyBackgroundImage, CSSProp ertyBackgroundRepeat, | |
| 1366 CSSPropertyBackgroundAttachment, CSSPropertyB ackgroundPosition, CSSPropertyBackgroundOrigin, | |
| 1367 CSSPropertyBackgroundClip, CSSPropertyBackgro undColor, CSSPropertyBackgroundSize }; | |
| 1368 return parseFillShorthand(propId, properties, WTF_ARRAY_LENGTH(propertie s), important); | |
| 1369 } | |
| 1370 case CSSPropertyWebkitMask: { | |
| 1371 const CSSPropertyID properties[] = { CSSPropertyWebkitMaskImage, CSSProp ertyWebkitMaskRepeat, | |
| 1372 CSSPropertyWebkitMaskPosition, CSSPropertyWebkitMaskOrigin, CSSPrope rtyWebkitMaskClip, CSSPropertyWebkitMaskSize }; | |
| 1373 return parseFillShorthand(propId, properties, WTF_ARRAY_LENGTH(propertie s), important); | |
| 1374 } | |
| 1375 case CSSPropertyBorder: | |
| 1376 // [ 'border-width' || 'border-style' || <color> ] | inherit | |
| 1377 { | |
| 1378 if (parseShorthand(propId, borderShorthandForParsing(), important)) { | |
| 1379 // The CSS3 Borders and Backgrounds specification says that border a lso resets border-image. It's as | |
| 1380 // though a value of none was specified for the image. | |
| 1381 addExpandedPropertyForValue(CSSPropertyBorderImage, cssValuePool().c reateImplicitInitialValue(), important); | |
| 1382 return true; | |
| 1383 } | |
| 1384 return false; | |
| 1385 } | |
| 1386 case CSSPropertyBorderTop: | |
| 1387 // [ 'border-top-width' || 'border-style' || <color> ] | inherit | |
| 1388 return parseShorthand(propId, borderTopShorthand(), important); | |
| 1389 case CSSPropertyBorderRight: | |
| 1390 // [ 'border-right-width' || 'border-style' || <color> ] | inherit | |
| 1391 return parseShorthand(propId, borderRightShorthand(), important); | |
| 1392 case CSSPropertyBorderBottom: | |
| 1393 // [ 'border-bottom-width' || 'border-style' || <color> ] | inherit | |
| 1394 return parseShorthand(propId, borderBottomShorthand(), important); | |
| 1395 case CSSPropertyBorderLeft: | |
| 1396 // [ 'border-left-width' || 'border-style' || <color> ] | inherit | |
| 1397 return parseShorthand(propId, borderLeftShorthand(), important); | |
| 1398 case CSSPropertyWebkitBorderStart: | |
| 1399 return parseShorthand(propId, webkitBorderStartShorthand(), important); | |
| 1400 case CSSPropertyWebkitBorderEnd: | |
| 1401 return parseShorthand(propId, webkitBorderEndShorthand(), important); | |
| 1402 case CSSPropertyWebkitBorderBefore: | |
| 1403 return parseShorthand(propId, webkitBorderBeforeShorthand(), important); | |
| 1404 case CSSPropertyWebkitBorderAfter: | |
| 1405 return parseShorthand(propId, webkitBorderAfterShorthand(), important); | |
| 1406 case CSSPropertyOutline: | |
| 1407 // [ 'outline-color' || 'outline-style' || 'outline-width' ] | inherit | |
| 1408 return parseShorthand(propId, outlineShorthand(), important); | |
| 1409 case CSSPropertyBorderColor: | |
| 1410 // <color>{1,4} | inherit | |
| 1411 return parse4Values(propId, borderColorShorthand().properties(), importa nt); | |
| 1412 case CSSPropertyBorderWidth: | |
| 1413 // <border-width>{1,4} | inherit | |
| 1414 return parse4Values(propId, borderWidthShorthand().properties(), importa nt); | |
| 1415 case CSSPropertyBorderStyle: | |
| 1416 // <border-style>{1,4} | inherit | |
| 1417 return parse4Values(propId, borderStyleShorthand().properties(), importa nt); | |
| 1418 case CSSPropertyMargin: | |
| 1419 // <margin-width>{1,4} | inherit | |
| 1420 return parse4Values(propId, marginShorthand().properties(), important); | |
| 1421 case CSSPropertyPadding: | |
| 1422 // <padding-width>{1,4} | inherit | |
| 1423 return parse4Values(propId, paddingShorthand().properties(), important); | |
| 1424 case CSSPropertyFlexFlow: | |
| 1425 return parseShorthand(propId, flexFlowShorthand(), important); | |
| 1426 case CSSPropertyFont: | |
| 1427 // [ [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-height' ]? | |
| 1428 // 'font-family' ] | caption | icon | menu | message-box | small-caption | status-bar | inherit | |
| 1429 if (id >= CSSValueCaption && id <= CSSValueStatusBar) | |
| 1430 return parseSystemFont(important); | |
| 1431 return parseFont(important); | |
| 1432 case CSSPropertyListStyle: | |
| 1433 return parseShorthand(propId, listStyleShorthand(), important); | |
| 1434 case CSSPropertyWebkitColumns: | |
| 1435 return parseColumnsShorthand(important); | |
| 1436 case CSSPropertyWebkitColumnRule: | |
| 1437 return parseShorthand(propId, webkitColumnRuleShorthand(), important); | |
| 1438 case CSSPropertyWebkitTextStroke: | |
| 1439 return parseShorthand(propId, webkitTextStrokeShorthand(), important); | |
| 1440 case CSSPropertyAnimation: | |
| 1441 return parseAnimationShorthand(unresolvedProperty == CSSPropertyAliasWeb kitAnimation, important); | |
| 1442 case CSSPropertyTransition: | |
| 1443 return parseTransitionShorthand(important); | |
| 1444 case CSSPropertyInvalid: | |
| 1445 return false; | |
| 1446 case CSSPropertyPage: | |
| 1447 parsedValue = parsePage(); | |
| 1448 break; | |
| 1449 // CSS Text Layout Module Level 3: Vertical writing support | |
| 1450 case CSSPropertyWebkitTextEmphasis: | |
| 1451 return parseShorthand(propId, webkitTextEmphasisShorthand(), important); | |
| 1452 | |
| 1453 case CSSPropertyWebkitTextEmphasisStyle: | |
| 1454 parsedValue = parseTextEmphasisStyle(); | |
| 1455 break; | |
| 1456 | |
| 1457 case CSSPropertyWebkitTextOrientation: | |
| 1458 // FIXME: For now just support sideways, sideways-right, upright and ver tical-right. | |
| 1459 if (id == CSSValueSideways || id == CSSValueSidewaysRight || id == CSSVa lueVerticalRight || id == CSSValueUpright) | |
| 1460 validPrimitive = true; | |
| 1461 break; | |
| 1462 | |
| 1463 case CSSPropertyWebkitFontFeatureSettings: | |
| 1464 if (id == CSSValueNormal) | |
| 1465 validPrimitive = true; | |
| 1466 else | |
| 1467 parsedValue = parseFontFeatureSettings(); | |
| 1468 break; | |
| 1469 | |
| 1470 case CSSPropertyFontVariantLigatures: | |
| 1471 if (id == CSSValueNormal) | |
| 1472 validPrimitive = true; | |
| 1473 else | |
| 1474 return parseFontVariantLigatures(important); | |
| 1475 break; | |
| 1476 case CSSPropertyWebkitClipPath: | |
| 1477 if (id == CSSValueNone) { | |
| 1478 validPrimitive = true; | |
| 1479 } else if (value->m_unit == CSSParserValue::Function) { | |
| 1480 parsedValue = parseBasicShape(); | |
| 1481 } else if (value->unit() == CSSPrimitiveValue::UnitType::URI) { | |
| 1482 parsedValue = CSSPrimitiveValue::create(value->string, CSSPrimitiveV alue::UnitType::URI); | |
| 1483 addProperty(propId, parsedValue.release(), important); | |
| 1484 return true; | |
| 1485 } | |
| 1486 break; | |
| 1487 case CSSPropertyShapeOutside: | |
| 1488 if (id == CSSValueNone) | |
| 1489 validPrimitive = true; | |
| 1490 else | |
| 1491 parsedValue = parseShapeProperty(propId); | |
| 1492 break; | |
| 1493 case CSSPropertyShapeMargin: | |
| 1494 validPrimitive = validUnit(value, FLength | FPercent | FNonNeg); | |
| 1495 break; | |
| 1496 case CSSPropertyShapeImageThreshold: | |
| 1497 validPrimitive = validUnit(value, FNumber); | |
| 1498 break; | |
| 1499 | |
| 1500 case CSSPropertyTouchAction: | |
| 1501 parsedValue = parseTouchAction(); | |
| 1502 break; | |
| 1503 | |
| 1504 case CSSPropertyAlignContent: | |
| 1505 parsedValue = parseContentDistributionOverflowPosition(); | |
| 1506 break; | |
| 1507 | |
| 1508 case CSSPropertyAlignSelf: | |
| 1509 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled()); | |
| 1510 return parseItemPositionOverflowPosition(propId, important); | |
| 1511 | |
| 1512 case CSSPropertyAlignItems: | |
| 1513 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled()); | |
| 1514 return parseItemPositionOverflowPosition(propId, important); | |
| 1515 | |
| 1516 // Properties below are validated inside parseViewportProperty, because we | |
| 1517 // check for parser state. We need to invalidate if someone adds them outsid e | |
| 1518 // a @viewport rule. | |
| 1519 case CSSPropertyMaxZoom: | |
| 1520 case CSSPropertyMinZoom: | |
| 1521 case CSSPropertyOrientation: | |
| 1522 case CSSPropertyUserZoom: | |
| 1523 validPrimitive = false; | |
| 1524 break; | |
| 1525 | |
| 1526 case CSSPropertyScrollSnapPointsX: | |
| 1527 case CSSPropertyScrollSnapPointsY: | |
| 1528 parsedValue = parseScrollSnapPoints(); | |
| 1529 break; | |
| 1530 case CSSPropertyScrollSnapCoordinate: | |
| 1531 parsedValue = parseScrollSnapCoordinate(); | |
| 1532 break; | |
| 1533 case CSSPropertyScrollSnapDestination: | |
| 1534 parsedValue = parsePosition(m_valueList); | |
| 1535 break; | |
| 1536 | |
| 1537 default: | |
| 1538 return parseSVGValue(propId, important); | |
| 1539 } | |
| 1540 | |
| 1541 if (validPrimitive) { | |
| 1542 parsedValue = parseValidPrimitive(id, value); | |
| 1543 m_valueList->next(); | |
| 1544 } | |
| 1545 ASSERT(!m_parsedCalculation); | |
| 1546 if (parsedValue) { | |
| 1547 if (!m_valueList->current() || inShorthand()) { | |
| 1548 addProperty(propId, parsedValue.release(), important); | |
| 1549 return true; | |
| 1550 } | |
| 1551 } | |
| 1552 return false; | |
| 1553 } | |
| 1554 | |
| 1555 void CSSPropertyParser::addFillValue(RefPtrWillBeRawPtr<CSSValue>& lval, PassRef PtrWillBeRawPtr<CSSValue> rval) | |
| 1556 { | |
| 1557 if (lval) { | |
| 1558 if (lval->isBaseValueList()) | |
| 1559 toCSSValueList(lval.get())->append(rval); | |
| 1560 else { | |
| 1561 PassRefPtrWillBeRawPtr<CSSValue> oldlVal(lval.release()); | |
| 1562 PassRefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createComm aSeparated(); | |
| 1563 list->append(oldlVal); | |
| 1564 list->append(rval); | |
| 1565 lval = list; | |
| 1566 } | |
| 1567 } | |
| 1568 else | |
| 1569 lval = rval; | |
| 1570 } | |
| 1571 | |
| 1572 static bool parseBackgroundClip(CSSParserValue* parserValue, RefPtrWillBeRawPtr< CSSValue>& cssValue) | |
| 1573 { | |
| 1574 if (parserValue->id == CSSValueBorderBox || parserValue->id == CSSValuePaddi ngBox | |
| 1575 || parserValue->id == CSSValueContentBox || parserValue->id == CSSValueW ebkitText) { | |
| 1576 cssValue = cssValuePool().createIdentifierValue(parserValue->id); | |
| 1577 return true; | |
| 1578 } | |
| 1579 return false; | |
| 1580 } | |
| 1581 | |
| 1582 const int cMaxFillProperties = 9; | |
| 1583 | |
| 1584 bool CSSPropertyParser::parseFillShorthand(CSSPropertyID propId, const CSSProper tyID* properties, int numProperties, bool important) | |
| 1585 { | |
| 1586 ASSERT(numProperties <= cMaxFillProperties); | |
| 1587 if (numProperties > cMaxFillProperties) | |
| 1588 return false; | |
| 1589 | |
| 1590 ShorthandScope scope(this, propId); | |
| 1591 | |
| 1592 bool parsedProperty[cMaxFillProperties] = { false }; | |
| 1593 RefPtrWillBeRawPtr<CSSValue> values[cMaxFillProperties]; | |
| 1594 #if ENABLE(OILPAN) | |
| 1595 // Zero initialize the array of raw pointers. | |
| 1596 memset(&values, 0, sizeof(values)); | |
| 1597 #endif | |
| 1598 RefPtrWillBeRawPtr<CSSValue> clipValue = nullptr; | |
| 1599 RefPtrWillBeRawPtr<CSSValue> positionYValue = nullptr; | |
| 1600 RefPtrWillBeRawPtr<CSSValue> repeatYValue = nullptr; | |
| 1601 bool foundClip = false; | |
| 1602 int i; | |
| 1603 bool foundPositionCSSProperty = false; | |
| 1604 | |
| 1605 while (m_valueList->current()) { | |
| 1606 CSSParserValue* val = m_valueList->current(); | |
| 1607 if (isComma(val)) { | |
| 1608 // We hit the end. Fill in all remaining values with the initial va lue. | |
| 1609 m_valueList->next(); | |
| 1610 for (i = 0; i < numProperties; ++i) { | |
| 1611 if (properties[i] == CSSPropertyBackgroundColor && parsedPropert y[i]) | |
| 1612 // Color is not allowed except as the last item in a list fo r backgrounds. | |
| 1613 // Reject the entire property. | |
| 1614 return false; | |
| 1615 | |
| 1616 if (!parsedProperty[i] && properties[i] != CSSPropertyBackground Color) { | |
| 1617 addFillValue(values[i], cssValuePool().createImplicitInitial Value()); | |
| 1618 if (properties[i] == CSSPropertyBackgroundPosition || proper ties[i] == CSSPropertyWebkitMaskPosition) | |
| 1619 addFillValue(positionYValue, cssValuePool().createImplic itInitialValue()); | |
| 1620 if (properties[i] == CSSPropertyBackgroundRepeat || properti es[i] == CSSPropertyWebkitMaskRepeat) | |
| 1621 addFillValue(repeatYValue, cssValuePool().createImplicit InitialValue()); | |
| 1622 if ((properties[i] == CSSPropertyBackgroundOrigin || propert ies[i] == CSSPropertyWebkitMaskOrigin) && !parsedProperty[i]) { | |
| 1623 // If background-origin wasn't present, then reset backg round-clip also. | |
| 1624 addFillValue(clipValue, cssValuePool().createImplicitIni tialValue()); | |
| 1625 } | |
| 1626 } | |
| 1627 parsedProperty[i] = false; | |
| 1628 } | |
| 1629 if (!m_valueList->current()) | |
| 1630 break; | |
| 1631 } | |
| 1632 | |
| 1633 bool sizeCSSPropertyExpected = false; | |
| 1634 if (isForwardSlashOperator(val) && foundPositionCSSProperty) { | |
| 1635 sizeCSSPropertyExpected = true; | |
| 1636 m_valueList->next(); | |
| 1637 } | |
| 1638 | |
| 1639 foundPositionCSSProperty = false; | |
| 1640 bool found = false; | |
| 1641 for (i = 0; !found && i < numProperties; ++i) { | |
| 1642 | |
| 1643 if (sizeCSSPropertyExpected && (properties[i] != CSSPropertyBackgrou ndSize && properties[i] != CSSPropertyWebkitMaskSize)) | |
| 1644 continue; | |
| 1645 if (!sizeCSSPropertyExpected && (properties[i] == CSSPropertyBackgro undSize || properties[i] == CSSPropertyWebkitMaskSize)) | |
| 1646 continue; | |
| 1647 | |
| 1648 if (!parsedProperty[i]) { | |
| 1649 RefPtrWillBeRawPtr<CSSValue> val1 = nullptr; | |
| 1650 RefPtrWillBeRawPtr<CSSValue> val2 = nullptr; | |
| 1651 CSSPropertyID propId1, propId2; | |
| 1652 CSSParserValue* parserValue = m_valueList->current(); | |
| 1653 // parseFillProperty() may modify m_implicitShorthand, so we MUS T reset it | |
| 1654 // before EACH return below. | |
| 1655 if (parserValue && parseFillProperty(properties[i], propId1, pro pId2, val1, val2)) { | |
| 1656 parsedProperty[i] = found = true; | |
| 1657 addFillValue(values[i], val1.release()); | |
| 1658 if (properties[i] == CSSPropertyBackgroundPosition || proper ties[i] == CSSPropertyWebkitMaskPosition) | |
| 1659 addFillValue(positionYValue, val2.release()); | |
| 1660 if (properties[i] == CSSPropertyBackgroundRepeat || properti es[i] == CSSPropertyWebkitMaskRepeat) | |
| 1661 addFillValue(repeatYValue, val2.release()); | |
| 1662 if (properties[i] == CSSPropertyBackgroundOrigin || properti es[i] == CSSPropertyWebkitMaskOrigin) { | |
| 1663 // Reparse the value as a clip, and see if we succeed. | |
| 1664 if (parseBackgroundClip(parserValue, val1)) | |
| 1665 addFillValue(clipValue, val1.release()); // The prop erty parsed successfully. | |
| 1666 else | |
| 1667 addFillValue(clipValue, cssValuePool().createImplici tInitialValue()); // Some value was used for origin that is not supported by cli p. Just reset clip instead. | |
| 1668 } | |
| 1669 if (properties[i] == CSSPropertyBackgroundClip || properties [i] == CSSPropertyWebkitMaskClip) { | |
| 1670 // Update clipValue | |
| 1671 addFillValue(clipValue, val1.release()); | |
| 1672 foundClip = true; | |
| 1673 } | |
| 1674 if (properties[i] == CSSPropertyBackgroundPosition || proper ties[i] == CSSPropertyWebkitMaskPosition) | |
| 1675 foundPositionCSSProperty = true; | |
| 1676 } | |
| 1677 } | |
| 1678 } | |
| 1679 | |
| 1680 // if we didn't find at least one match, this is an | |
| 1681 // invalid shorthand and we have to ignore it | |
| 1682 if (!found) { | |
| 1683 m_implicitShorthand = false; | |
| 1684 return false; | |
| 1685 } | |
| 1686 } | |
| 1687 | |
| 1688 // Now add all of the properties we found. | |
| 1689 for (i = 0; i < numProperties; i++) { | |
| 1690 // Fill in any remaining properties with the initial value. | |
| 1691 if (!parsedProperty[i]) { | |
| 1692 addFillValue(values[i], cssValuePool().createImplicitInitialValue()) ; | |
| 1693 if (properties[i] == CSSPropertyBackgroundPosition || properties[i] == CSSPropertyWebkitMaskPosition) | |
| 1694 addFillValue(positionYValue, cssValuePool().createImplicitInitia lValue()); | |
| 1695 if (properties[i] == CSSPropertyBackgroundRepeat || properties[i] == CSSPropertyWebkitMaskRepeat) | |
| 1696 addFillValue(repeatYValue, cssValuePool().createImplicitInitialV alue()); | |
| 1697 if (properties[i] == CSSPropertyBackgroundOrigin || properties[i] == CSSPropertyWebkitMaskOrigin) { | |
| 1698 // If background-origin wasn't present, then reset background-cl ip also. | |
| 1699 addFillValue(clipValue, cssValuePool().createImplicitInitialValu e()); | |
| 1700 } | |
| 1701 } | |
| 1702 if (properties[i] == CSSPropertyBackgroundPosition) { | |
| 1703 addProperty(CSSPropertyBackgroundPositionX, values[i].release(), imp ortant); | |
| 1704 // it's OK to call positionYValue.release() since we only see CSSPro pertyBackgroundPosition once | |
| 1705 addProperty(CSSPropertyBackgroundPositionY, positionYValue.release() , important); | |
| 1706 } else if (properties[i] == CSSPropertyWebkitMaskPosition) { | |
| 1707 addProperty(CSSPropertyWebkitMaskPositionX, values[i].release(), imp ortant); | |
| 1708 // it's OK to call positionYValue.release() since we only see CSSPro pertyWebkitMaskPosition once | |
| 1709 addProperty(CSSPropertyWebkitMaskPositionY, positionYValue.release() , important); | |
| 1710 } else if (properties[i] == CSSPropertyBackgroundRepeat) { | |
| 1711 addProperty(CSSPropertyBackgroundRepeatX, values[i].release(), impor tant); | |
| 1712 // it's OK to call repeatYValue.release() since we only see CSSPrope rtyBackgroundPosition once | |
| 1713 addProperty(CSSPropertyBackgroundRepeatY, repeatYValue.release(), im portant); | |
| 1714 } else if (properties[i] == CSSPropertyWebkitMaskRepeat) { | |
| 1715 addProperty(CSSPropertyWebkitMaskRepeatX, values[i].release(), impor tant); | |
| 1716 // it's OK to call repeatYValue.release() since we only see CSSPrope rtyBackgroundPosition once | |
| 1717 addProperty(CSSPropertyWebkitMaskRepeatY, repeatYValue.release(), im portant); | |
| 1718 } else if ((properties[i] == CSSPropertyBackgroundClip || properties[i] == CSSPropertyWebkitMaskClip) && !foundClip) | |
| 1719 // Value is already set while updating origin | |
| 1720 continue; | |
| 1721 else if (properties[i] == CSSPropertyBackgroundSize && !parsedProperty[i ] && m_context.useLegacyBackgroundSizeShorthandBehavior()) | |
| 1722 continue; | |
| 1723 else | |
| 1724 addProperty(properties[i], values[i].release(), important); | |
| 1725 | |
| 1726 // Add in clip values when we hit the corresponding origin property. | |
| 1727 if (properties[i] == CSSPropertyBackgroundOrigin && !foundClip) | |
| 1728 addProperty(CSSPropertyBackgroundClip, clipValue.release(), importan t); | |
| 1729 else if (properties[i] == CSSPropertyWebkitMaskOrigin && !foundClip) | |
| 1730 addProperty(CSSPropertyWebkitMaskClip, clipValue.release(), importan t); | |
| 1731 } | |
| 1732 | |
| 1733 m_implicitShorthand = false; | |
| 1734 return true; | |
| 1735 } | |
| 1736 | |
| 1737 static bool isValidTransitionPropertyList(CSSValueList* value) | |
| 1738 { | |
| 1739 if (value->length() < 2) | |
| 1740 return true; | |
| 1741 for (auto& property : *value) { | |
| 1742 // FIXME: Shorthand parsing shouldn't add initial to the list since it w on't round-trip | |
| 1743 if (property->isInitialValue()) | |
| 1744 continue; | |
| 1745 CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(property.get()); | |
| 1746 if (primitiveValue->isValueID() && primitiveValue->getValueID() == CSSVa lueNone) | |
| 1747 return false; | |
| 1748 } | |
| 1749 return true; | |
| 1750 } | |
| 1751 | |
| 1752 bool CSSPropertyParser::parseAnimationShorthand(bool useLegacyparsing, bool impo rtant) | |
| 1753 { | |
| 1754 const StylePropertyShorthand& animationProperties = animationShorthandForPar sing(); | |
| 1755 const unsigned numProperties = 8; | |
| 1756 | |
| 1757 // The list of properties in the shorthand should be the same | |
| 1758 // length as the list with animation name in last position, even though they are | |
| 1759 // in a different order. | |
| 1760 ASSERT(numProperties == animationProperties.length()); | |
| 1761 ASSERT(numProperties == animationShorthand().length()); | |
| 1762 | |
| 1763 ShorthandScope scope(this, CSSPropertyAnimation); | |
| 1764 | |
| 1765 bool parsedProperty[numProperties] = { false }; | |
| 1766 RefPtrWillBeRawPtr<CSSValueList> values[numProperties]; | |
| 1767 for (size_t i = 0; i < numProperties; ++i) | |
| 1768 values[i] = CSSValueList::createCommaSeparated(); | |
| 1769 | |
| 1770 while (m_valueList->current()) { | |
| 1771 if (consumeComma(m_valueList)) { | |
| 1772 // We hit the end. Fill in all remaining values with the initial val ue. | |
| 1773 for (size_t i = 0; i < numProperties; ++i) { | |
| 1774 if (!parsedProperty[i]) | |
| 1775 values[i]->append(cssValuePool().createImplicitInitialValue( )); | |
| 1776 parsedProperty[i] = false; | |
| 1777 } | |
| 1778 if (!m_valueList->current()) | |
| 1779 break; | |
| 1780 } | |
| 1781 | |
| 1782 bool found = false; | |
| 1783 for (size_t i = 0; i < numProperties; ++i) { | |
| 1784 if (parsedProperty[i]) | |
| 1785 continue; | |
| 1786 if (RefPtrWillBeRawPtr<CSSValue> val = parseAnimationProperty(animat ionProperties.properties()[i], useLegacyparsing)) { | |
| 1787 parsedProperty[i] = found = true; | |
| 1788 values[i]->append(val.release()); | |
| 1789 break; | |
| 1790 } | |
| 1791 } | |
| 1792 | |
| 1793 // if we didn't find at least one match, this is an | |
| 1794 // invalid shorthand and we have to ignore it | |
| 1795 if (!found) | |
| 1796 return false; | |
| 1797 } | |
| 1798 | |
| 1799 for (size_t i = 0; i < numProperties; ++i) { | |
| 1800 // If we didn't find the property, set an intial value. | |
| 1801 if (!parsedProperty[i]) | |
| 1802 values[i]->append(cssValuePool().createImplicitInitialValue()); | |
| 1803 | |
| 1804 addProperty(animationProperties.properties()[i], values[i].release(), im portant); | |
| 1805 } | |
| 1806 | |
| 1807 return true; | |
| 1808 } | |
| 1809 | |
| 1810 bool CSSPropertyParser::parseTransitionShorthand(bool important) | |
| 1811 { | |
| 1812 const unsigned numProperties = 4; | |
| 1813 const StylePropertyShorthand& shorthand = transitionShorthandForParsing(); | |
| 1814 ASSERT(numProperties == shorthand.length()); | |
| 1815 | |
| 1816 ShorthandScope scope(this, CSSPropertyTransition); | |
| 1817 | |
| 1818 bool parsedProperty[numProperties] = { false }; | |
| 1819 RefPtrWillBeRawPtr<CSSValueList> values[numProperties]; | |
| 1820 for (size_t i = 0; i < numProperties; ++i) | |
| 1821 values[i] = CSSValueList::createCommaSeparated(); | |
| 1822 | |
| 1823 while (m_valueList->current()) { | |
| 1824 if (consumeComma(m_valueList)) { | |
| 1825 // We hit the end. Fill in all remaining values with the initial val ue. | |
| 1826 for (size_t i = 0; i < numProperties; ++i) { | |
| 1827 if (!parsedProperty[i]) | |
| 1828 values[i]->append(cssValuePool().createImplicitInitialValue( )); | |
| 1829 parsedProperty[i] = false; | |
| 1830 } | |
| 1831 if (!m_valueList->current()) | |
| 1832 break; | |
| 1833 } | |
| 1834 | |
| 1835 bool found = false; | |
| 1836 for (size_t i = 0; i < numProperties; ++i) { | |
| 1837 if (parsedProperty[i]) | |
| 1838 continue; | |
| 1839 if (RefPtrWillBeRawPtr<CSSValue> val = parseAnimationProperty(shorth and.properties()[i], false)) { | |
| 1840 parsedProperty[i] = found = true; | |
| 1841 values[i]->append(val.release()); | |
| 1842 break; | |
| 1843 } | |
| 1844 } | |
| 1845 | |
| 1846 // if we didn't find at least one match, this is an | |
| 1847 // invalid shorthand and we have to ignore it | |
| 1848 if (!found) | |
| 1849 return false; | |
| 1850 } | |
| 1851 | |
| 1852 ASSERT(shorthand.properties()[3] == CSSPropertyTransitionProperty); | |
| 1853 if (!isValidTransitionPropertyList(values[3].get())) | |
| 1854 return false; | |
| 1855 | |
| 1856 // Fill in any remaining properties with the initial value and add | |
| 1857 for (size_t i = 0; i < numProperties; ++i) { | |
| 1858 if (!parsedProperty[i]) | |
| 1859 values[i]->append(cssValuePool().createImplicitInitialValue()); | |
| 1860 addProperty(shorthand.properties()[i], values[i].release(), important); | |
| 1861 } | |
| 1862 | |
| 1863 return true; | |
| 1864 } | |
| 1865 | |
| 1866 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseColumnWidth() | |
| 1867 { | |
| 1868 CSSParserValue* value = m_valueList->current(); | |
| 1869 // Always parse lengths in strict mode here, since it would be ambiguous oth erwise when used in | |
| 1870 // the 'columns' shorthand property. | |
| 1871 if (value->id == CSSValueAuto || (validUnit(value, FLength | FNonNeg, HTMLSt andardMode) && (m_parsedCalculation || value->fValue != 0))) { | |
| 1872 RefPtrWillBeRawPtr<CSSValue> parsedValue = parseValidPrimitive(value->id , value); | |
| 1873 m_valueList->next(); | |
| 1874 return parsedValue; | |
| 1875 } | |
| 1876 return nullptr; | |
| 1877 } | |
| 1878 | |
| 1879 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseColumnCount() | |
| 1880 { | |
| 1881 CSSParserValue* value = m_valueList->current(); | |
| 1882 if (value->id == CSSValueAuto || validUnit(value, FPositiveInteger)) { | |
| 1883 RefPtrWillBeRawPtr<CSSValue> parsedValue = parseValidPrimitive(value->id , value); | |
| 1884 m_valueList->next(); | |
| 1885 return parsedValue; | |
| 1886 } | |
| 1887 return nullptr; | |
| 1888 } | |
| 1889 | |
| 1890 bool CSSPropertyParser::parseColumnsShorthand(bool important) | |
| 1891 { | |
| 1892 RefPtrWillBeRawPtr<CSSValue> columnWidth = nullptr; | |
| 1893 RefPtrWillBeRawPtr<CSSValue> columnCount = nullptr; | |
| 1894 | |
| 1895 for (unsigned propertiesParsed = 0; CSSParserValue* value = m_valueList->cur rent(); propertiesParsed++) { | |
| 1896 if (propertiesParsed >= 2) | |
| 1897 return false; // Too many values for this shorthand. Invalid declara tion. | |
| 1898 if (value->id == CSSValueAuto) { | |
| 1899 // Skip 'auto' as we will use it for initial value if no width/count was parsed. | |
| 1900 m_valueList->next(); | |
| 1901 } else { | |
| 1902 if (!columnWidth) { | |
| 1903 if ((columnWidth = parseColumnWidth())) | |
| 1904 continue; | |
| 1905 } | |
| 1906 if (!columnCount) { | |
| 1907 if ((columnCount = parseColumnCount())) | |
| 1908 continue; | |
| 1909 } | |
| 1910 // If we didn't find at least one match, this is an | |
| 1911 // invalid shorthand and we have to ignore it. | |
| 1912 return false; | |
| 1913 } | |
| 1914 } | |
| 1915 | |
| 1916 if (!columnWidth) | |
| 1917 columnWidth = cssValuePool().createIdentifierValue(CSSValueAuto); | |
| 1918 addProperty(CSSPropertyWebkitColumnWidth, columnWidth, important); | |
| 1919 if (!columnCount) | |
| 1920 columnCount = cssValuePool().createIdentifierValue(CSSValueAuto); | |
| 1921 addProperty(CSSPropertyWebkitColumnCount, columnCount, important); | |
| 1922 return true; | |
| 1923 } | |
| 1924 | |
| 1925 bool CSSPropertyParser::parseShorthand(CSSPropertyID propId, const StyleProperty Shorthand& shorthand, bool important) | |
| 1926 { | |
| 1927 // We try to match as many properties as possible | |
| 1928 // We set up an array of booleans to mark which property has been found, | |
| 1929 // and we try to search for properties until it makes no longer any sense. | |
| 1930 ShorthandScope scope(this, propId); | |
| 1931 | |
| 1932 bool found = false; | |
| 1933 unsigned propertiesParsed = 0; | |
| 1934 bool propertyFound[6] = { false, false, false, false, false, false }; // 6 i s enough size. | |
| 1935 | |
| 1936 while (m_valueList->current()) { | |
| 1937 found = false; | |
| 1938 for (unsigned propIndex = 0; !found && propIndex < shorthand.length(); + +propIndex) { | |
| 1939 if (!propertyFound[propIndex] && parseValue(shorthand.properties()[p ropIndex], important)) { | |
| 1940 propertyFound[propIndex] = found = true; | |
| 1941 propertiesParsed++; | |
| 1942 } | |
| 1943 } | |
| 1944 | |
| 1945 // if we didn't find at least one match, this is an | |
| 1946 // invalid shorthand and we have to ignore it | |
| 1947 if (!found) | |
| 1948 return false; | |
| 1949 } | |
| 1950 | |
| 1951 if (propertiesParsed == shorthand.length()) | |
| 1952 return true; | |
| 1953 | |
| 1954 // Fill in any remaining properties with the initial value. | |
| 1955 ImplicitScope implicitScope(this); | |
| 1956 const StylePropertyShorthand* const* const propertiesForInitialization = sho rthand.propertiesForInitialization(); | |
| 1957 for (unsigned i = 0; i < shorthand.length(); ++i) { | |
| 1958 if (propertyFound[i]) | |
| 1959 continue; | |
| 1960 | |
| 1961 if (propertiesForInitialization) { | |
| 1962 const StylePropertyShorthand& initProperties = *(propertiesForInitia lization[i]); | |
| 1963 for (unsigned propIndex = 0; propIndex < initProperties.length(); ++ propIndex) | |
| 1964 addProperty(initProperties.properties()[propIndex], cssValuePool ().createImplicitInitialValue(), important); | |
| 1965 } else | |
| 1966 addProperty(shorthand.properties()[i], cssValuePool().createImplicit InitialValue(), important); | |
| 1967 } | |
| 1968 | |
| 1969 return true; | |
| 1970 } | |
| 1971 | |
| 1972 bool CSSPropertyParser::parse4Values(CSSPropertyID propId, const CSSPropertyID * properties, bool important) | |
| 1973 { | |
| 1974 /* From the CSS 2 specs, 8.3 | |
| 1975 * If there is only one value, it applies to all sides. If there are two val ues, the top and | |
| 1976 * bottom margins are set to the first value and the right and left margins are set to the second. | |
| 1977 * If there are three values, the top is set to the first value, the left an d right are set to the | |
| 1978 * second, and the bottom is set to the third. If there are four values, the y apply to the top, | |
| 1979 * right, bottom, and left, respectively. | |
| 1980 */ | |
| 1981 | |
| 1982 int num = inShorthand() ? 1 : m_valueList->size(); | |
| 1983 | |
| 1984 ShorthandScope scope(this, propId); | |
| 1985 | |
| 1986 // the order is top, right, bottom, left | |
| 1987 switch (num) { | |
| 1988 case 1: { | |
| 1989 if (!parseValue(properties[0], important)) | |
| 1990 return false; | |
| 1991 CSSValue* value = m_parsedProperties.last().value(); | |
| 1992 ImplicitScope implicitScope(this); | |
| 1993 addProperty(properties[1], value, important); | |
| 1994 addProperty(properties[2], value, important); | |
| 1995 addProperty(properties[3], value, important); | |
| 1996 break; | |
| 1997 } | |
| 1998 case 2: { | |
| 1999 if (!parseValue(properties[0], important) || !parseValue(properties[ 1], important)) | |
| 2000 return false; | |
| 2001 CSSValue* value = m_parsedProperties[m_parsedProperties.size() - 2]. value(); | |
| 2002 ImplicitScope implicitScope(this); | |
| 2003 addProperty(properties[2], value, important); | |
| 2004 value = m_parsedProperties[m_parsedProperties.size() - 2].value(); | |
| 2005 addProperty(properties[3], value, important); | |
| 2006 break; | |
| 2007 } | |
| 2008 case 3: { | |
| 2009 if (!parseValue(properties[0], important) || !parseValue(properties[ 1], important) || !parseValue(properties[2], important)) | |
| 2010 return false; | |
| 2011 CSSValue* value = m_parsedProperties[m_parsedProperties.size() - 2]. value(); | |
| 2012 ImplicitScope implicitScope(this); | |
| 2013 addProperty(properties[3], value, important); | |
| 2014 break; | |
| 2015 } | |
| 2016 case 4: { | |
| 2017 if (!parseValue(properties[0], important) || !parseValue(properties[ 1], important) || | |
| 2018 !parseValue(properties[2], important) || !parseValue(properties[ 3], important)) | |
| 2019 return false; | |
| 2020 break; | |
| 2021 } | |
| 2022 default: { | |
| 2023 return false; | |
| 2024 } | |
| 2025 } | |
| 2026 | |
| 2027 return true; | |
| 2028 } | |
| 2029 | |
| 2030 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseScrollSnapPoints() | |
| 2031 { | |
| 2032 CSSParserValue* value = m_valueList->current(); | |
| 2033 | |
| 2034 if (value->id == CSSValueNone) { | |
| 2035 m_valueList->next(); | |
| 2036 return cssValuePool().createIdentifierValue(CSSValueNone); | |
| 2037 } | |
| 2038 | |
| 2039 if (value->m_unit == CSSParserValue::Function && value->function->id == CSSV alueRepeat) { | |
| 2040 // The spec defines the following grammar: repeat( <length>) | |
| 2041 CSSParserValueList* arguments = value->function->args.get(); | |
| 2042 if (!arguments || arguments->size() != 1) | |
| 2043 return nullptr; | |
| 2044 | |
| 2045 CSSParserValue* repeatValue = arguments->valueAt(0); | |
| 2046 if (validUnit(repeatValue, FNonNeg | FLength | FPercent) && (m_parsedCal culation || repeatValue->fValue > 0)) { | |
| 2047 RefPtrWillBeRawPtr<CSSFunctionValue> result = CSSFunctionValue::crea te(CSSValueRepeat); | |
| 2048 result->append(parseValidPrimitive(repeatValue->id, repeatValue)); | |
| 2049 m_valueList->next(); | |
| 2050 return result.release(); | |
| 2051 } | |
| 2052 } | |
| 2053 | |
| 2054 return nullptr; | |
| 2055 } | |
| 2056 | |
| 2057 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseScrollSnapCoordinate() | |
| 2058 { | |
| 2059 if (m_valueList->current()->id == CSSValueNone) { | |
| 2060 m_valueList->next(); | |
| 2061 return cssValuePool().createIdentifierValue(CSSValueNone); | |
| 2062 } | |
| 2063 | |
| 2064 return parsePositionList(m_valueList); | |
| 2065 } | |
| 2066 | |
| 2067 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::parsePage() | |
| 2068 { | |
| 2069 CSSParserValue* value = m_valueList->current(); | |
| 2070 m_valueList->next(); | |
| 2071 ASSERT(value); | |
| 2072 | |
| 2073 if (value->id == CSSValueAuto) | |
| 2074 return cssValuePool().createIdentifierValue(value->id); | |
| 2075 if (value->m_unit == CSSParserValue::Identifier) | |
| 2076 return createPrimitiveCustomIdentValue(value); | |
| 2077 return nullptr; | |
| 2078 } | |
| 2079 | |
| 2080 // <length>{1,2} | auto | [ <page-size> || [ portrait | landscape] ] | |
| 2081 PassRefPtrWillBeRawPtr<CSSValueList> CSSPropertyParser::parseSize() | |
| 2082 { | |
| 2083 CSSParserValue* value = m_valueList->current(); | |
| 2084 ASSERT(value); | |
| 2085 | |
| 2086 RefPtrWillBeRawPtr<CSSValueList> parsedValues = CSSValueList::createSpaceSep arated(); | |
| 2087 | |
| 2088 // First parameter. | |
| 2089 SizeParameterType paramType = parseSizeParameter(parsedValues.get(), value, None); | |
| 2090 if (paramType == None) | |
| 2091 return nullptr; | |
| 2092 value = m_valueList->next(); | |
| 2093 | |
| 2094 // Second parameter, if any. | |
| 2095 if (value) { | |
| 2096 paramType = parseSizeParameter(parsedValues.get(), value, paramType); | |
| 2097 if (paramType == None) | |
| 2098 return nullptr; | |
| 2099 m_valueList->next(); | |
| 2100 } | |
| 2101 | |
| 2102 return parsedValues.release(); | |
| 2103 } | |
| 2104 | |
| 2105 CSSPropertyParser::SizeParameterType CSSPropertyParser::parseSizeParameter(CSSVa lueList* parsedValues, CSSParserValue* value, SizeParameterType prevParamType) | |
| 2106 { | |
| 2107 switch (value->id) { | |
| 2108 case CSSValueAuto: | |
| 2109 if (prevParamType == None) { | |
| 2110 parsedValues->append(cssValuePool().createIdentifierValue(value->id) ); | |
| 2111 return Auto; | |
| 2112 } | |
| 2113 return None; | |
| 2114 case CSSValueLandscape: | |
| 2115 case CSSValuePortrait: | |
| 2116 if (prevParamType == None || prevParamType == PageSize) { | |
| 2117 parsedValues->append(cssValuePool().createIdentifierValue(value->id) ); | |
| 2118 return Orientation; | |
| 2119 } | |
| 2120 return None; | |
| 2121 case CSSValueA3: | |
| 2122 case CSSValueA4: | |
| 2123 case CSSValueA5: | |
| 2124 case CSSValueB4: | |
| 2125 case CSSValueB5: | |
| 2126 case CSSValueLedger: | |
| 2127 case CSSValueLegal: | |
| 2128 case CSSValueLetter: | |
| 2129 if (prevParamType == None || prevParamType == Orientation) { | |
| 2130 // Normalize to Page Size then Orientation order by prepending for s impler StyleBuilder handling | |
| 2131 parsedValues->prepend(cssValuePool().createIdentifierValue(value->id )); | |
| 2132 return PageSize; | |
| 2133 } | |
| 2134 return None; | |
| 2135 case 0: | |
| 2136 if (validUnit(value, FLength | FNonNeg) && (prevParamType == None || pre vParamType == Length)) { | |
| 2137 parsedValues->append(createPrimitiveNumericValue(value)); | |
| 2138 return Length; | |
| 2139 } | |
| 2140 return None; | |
| 2141 default: | |
| 2142 return None; | |
| 2143 } | |
| 2144 } | 240 } |
| 2145 | 241 |
| 2146 // [ <string> <string> ]+ | none, but none is handled in parseValue | |
| 2147 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseQuotes() | |
| 2148 { | |
| 2149 RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createSpaceSeparated (); | |
| 2150 while (CSSParserValue* val = m_valueList->current()) { | |
| 2151 RefPtrWillBeRawPtr<CSSValue> parsedValue = nullptr; | |
| 2152 if (val->unit() != CSSPrimitiveValue::UnitType::String) | |
| 2153 return nullptr; | |
| 2154 parsedValue = createPrimitiveStringValue(val); | |
| 2155 values->append(parsedValue.release()); | |
| 2156 m_valueList->next(); | |
| 2157 } | |
| 2158 if (values->length() && values->length() % 2 == 0) | |
| 2159 return values.release(); | |
| 2160 return nullptr; | |
| 2161 } | |
| 2162 | |
| 2163 // [ <string> | <uri> | <counter> | attr(X) | open-quote | close-quote | no-open -quote | no-close-quote ]+ | inherit | |
| 2164 // in CSS 2.1 this got somewhat reduced: | |
| 2165 // [ <string> | attr(X) | open-quote | close-quote | no-open-quote | no-close-qu ote ]+ | inherit | |
| 2166 PassRefPtrWillBeRawPtr<CSSValueList> CSSPropertyParser::parseContent() | |
| 2167 { | |
| 2168 RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createSpaceSeparated (); | |
| 2169 | |
| 2170 while (CSSParserValue* val = m_valueList->current()) { | |
| 2171 RefPtrWillBeRawPtr<CSSValue> parsedValue = nullptr; | |
| 2172 if (val->unit() == CSSPrimitiveValue::UnitType::URI) { | |
| 2173 // url | |
| 2174 parsedValue = createCSSImageValueWithReferrer(val->string, completeU RL(val->string)); | |
| 2175 } else if (val->m_unit == CSSParserValue::Function) { | |
| 2176 // attr(X) | counter(X [,Y]) | counters(X, Y, [,Z]) | -webkit-gradie nt(...) | |
| 2177 CSSParserValueList* args = val->function->args.get(); | |
| 2178 if (!args) | |
| 2179 return nullptr; | |
| 2180 if (val->function->id == CSSValueAttr) { | |
| 2181 parsedValue = parseAttr(args); | |
| 2182 } else if (val->function->id == CSSValueCounter) { | |
| 2183 parsedValue = parseCounterContent(args, false); | |
| 2184 } else if (val->function->id == CSSValueCounters) { | |
| 2185 parsedValue = parseCounterContent(args, true); | |
| 2186 } else if (val->function->id == CSSValueWebkitImageSet) { | |
| 2187 parsedValue = parseImageSet(m_valueList); | |
| 2188 } else if (isGeneratedImageValue(val)) { | |
| 2189 if (!parseGeneratedImage(m_valueList, parsedValue)) | |
| 2190 return nullptr; | |
| 2191 } | |
| 2192 } else if (val->m_unit == CSSParserValue::Identifier) { | |
| 2193 switch (val->id) { | |
| 2194 case CSSValueOpenQuote: | |
| 2195 case CSSValueCloseQuote: | |
| 2196 case CSSValueNoOpenQuote: | |
| 2197 case CSSValueNoCloseQuote: | |
| 2198 case CSSValueNone: | |
| 2199 case CSSValueNormal: | |
| 2200 parsedValue = cssValuePool().createIdentifierValue(val->id); | |
| 2201 default: | |
| 2202 break; | |
| 2203 } | |
| 2204 } else if (val->unit() == CSSPrimitiveValue::UnitType::String) { | |
| 2205 parsedValue = createPrimitiveStringValue(val); | |
| 2206 } | |
| 2207 if (!parsedValue) | |
| 2208 return nullptr; | |
| 2209 values->append(parsedValue.release()); | |
| 2210 m_valueList->next(); | |
| 2211 } | |
| 2212 | |
| 2213 return values.release(); | |
| 2214 } | |
| 2215 | |
| 2216 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAttr(CSSParserValueList * args) | |
| 2217 { | |
| 2218 if (args->size() != 1) | |
| 2219 return nullptr; | |
| 2220 | |
| 2221 CSSParserValue* a = args->current(); | |
| 2222 | |
| 2223 if (a->m_unit != CSSParserValue::Identifier) | |
| 2224 return nullptr; | |
| 2225 | |
| 2226 String attrName = a->string; | |
| 2227 // CSS allows identifiers with "-" at the start, like "-webkit-mask-image". | |
| 2228 // But HTML attribute names can't have those characters, and we should not | |
| 2229 // even parse them inside attr(). | |
| 2230 if (attrName[0] == '-') | |
| 2231 return nullptr; | |
| 2232 | |
| 2233 if (m_context.isHTMLDocument()) | |
| 2234 attrName = attrName.lower(); | |
| 2235 | |
| 2236 RefPtrWillBeRawPtr<CSSFunctionValue> attrValue = CSSFunctionValue::create(CS SValueAttr); | |
| 2237 attrValue->append(CSSPrimitiveValue::create(attrName, CSSPrimitiveValue::Uni tType::CustomIdentifier)); | |
| 2238 return attrValue.release(); | |
| 2239 } | |
| 2240 | |
| 2241 bool CSSPropertyParser::acceptQuirkyColors(CSSPropertyID propertyId) const | |
| 2242 { | |
| 2243 if (!inQuirksMode()) | |
| 2244 return false; | |
| 2245 switch (propertyId) { | |
| 2246 case CSSPropertyBackgroundColor: | |
| 2247 case CSSPropertyBorderBottomColor: | |
| 2248 case CSSPropertyBorderLeftColor: | |
| 2249 case CSSPropertyBorderRightColor: | |
| 2250 case CSSPropertyBorderTopColor: | |
| 2251 return !inShorthand() || m_currentShorthand == CSSPropertyBorderColor; | |
| 2252 case CSSPropertyColor: | |
| 2253 return true; | |
| 2254 default: | |
| 2255 break; | |
| 2256 } | |
| 2257 return false; | |
| 2258 } | |
| 2259 | |
| 2260 bool CSSPropertyParser::isColorKeyword(CSSValueID id) | |
| 2261 { | |
| 2262 // Named colors and color keywords: | |
| 2263 // | |
| 2264 // <named-color> | |
| 2265 // 'aqua', 'black', 'blue', ..., 'yellow' (CSS3: "basic color keywords") | |
| 2266 // 'aliceblue', ..., 'yellowgreen' (CSS3: "extended color keywords" ) | |
| 2267 // 'transparent' | |
| 2268 // | |
| 2269 // 'currentcolor' | |
| 2270 // | |
| 2271 // <deprecated-system-color> | |
| 2272 // 'ActiveBorder', ..., 'WindowText' | |
| 2273 // | |
| 2274 // WebKit proprietary/internal: | |
| 2275 // '-webkit-link' | |
| 2276 // '-webkit-activelink' | |
| 2277 // '-internal-active-list-box-selection' | |
| 2278 // '-internal-active-list-box-selection-text' | |
| 2279 // '-internal-inactive-list-box-selection' | |
| 2280 // '-internal-inactive-list-box-selection-text' | |
| 2281 // '-webkit-focus-ring-color' | |
| 2282 // '-webkit-text' | |
| 2283 // | |
| 2284 return (id >= CSSValueAqua && id <= CSSValueWebkitText) | |
| 2285 || (id >= CSSValueAliceblue && id <= CSSValueYellowgreen) | |
| 2286 || id == CSSValueMenu; | |
| 2287 } | |
| 2288 | |
| 2289 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::parseColor(const CS SParserValue* value, bool acceptQuirkyColors) | |
| 2290 { | |
| 2291 CSSValueID id = value->id; | |
| 2292 if (isColorKeyword(id)) { | |
| 2293 if (!isValueAllowedInMode(id, m_context.mode())) | |
| 2294 return nullptr; | |
| 2295 if (id == CSSValueWebkitText && m_context.useCounter()) | |
| 2296 m_context.useCounter()->count(UseCounter::WebkitTextInColorProperty) ; | |
| 2297 return cssValuePool().createIdentifierValue(id); | |
| 2298 } | |
| 2299 RGBA32 c = Color::transparent; | |
| 2300 if (!parseColorFromValue(value, c, acceptQuirkyColors)) | |
| 2301 return nullptr; | |
| 2302 return cssValuePool().createColorValue(c); | |
| 2303 } | |
| 2304 | |
| 2305 bool CSSPropertyParser::parseFillImage(CSSParserValueList* valueList, RefPtrWill BeRawPtr<CSSValue>& value) | |
| 2306 { | |
| 2307 if (valueList->current()->id == CSSValueNone) { | |
| 2308 value = cssValuePool().createIdentifierValue(CSSValueNone); | |
| 2309 return true; | |
| 2310 } | |
| 2311 if (valueList->current()->unit() == CSSPrimitiveValue::UnitType::URI) { | |
| 2312 value = createCSSImageValueWithReferrer(valueList->current()->string, co mpleteURL(valueList->current()->string)); | |
| 2313 return true; | |
| 2314 } | |
| 2315 | |
| 2316 if (isGeneratedImageValue(valueList->current())) | |
| 2317 return parseGeneratedImage(valueList, value); | |
| 2318 | |
| 2319 if (valueList->current()->m_unit == CSSParserValue::Function && valueList->c urrent()->function->id == CSSValueWebkitImageSet) { | |
| 2320 value = parseImageSet(m_valueList); | |
| 2321 if (value) | |
| 2322 return true; | |
| 2323 } | |
| 2324 | |
| 2325 return false; | |
| 2326 } | |
| 2327 | |
| 2328 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseFillPositionX(CSSParser ValueList* valueList) | |
| 2329 { | |
| 2330 int id = valueList->current()->id; | |
| 2331 if (id == CSSValueLeft || id == CSSValueRight || id == CSSValueCenter) { | |
| 2332 int percent = 0; | |
| 2333 if (id == CSSValueRight) | |
| 2334 percent = 100; | |
| 2335 else if (id == CSSValueCenter) | |
| 2336 percent = 50; | |
| 2337 return cssValuePool().createValue(percent, CSSPrimitiveValue::UnitType:: Percentage); | |
| 2338 } | |
| 2339 if (validUnit(valueList->current(), FPercent | FLength)) | |
| 2340 return createPrimitiveNumericValue(valueList->current()); | |
| 2341 return nullptr; | |
| 2342 } | |
| 2343 | |
| 2344 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseFillPositionY(CSSParser ValueList* valueList) | |
| 2345 { | |
| 2346 int id = valueList->current()->id; | |
| 2347 if (id == CSSValueTop || id == CSSValueBottom || id == CSSValueCenter) { | |
| 2348 int percent = 0; | |
| 2349 if (id == CSSValueBottom) | |
| 2350 percent = 100; | |
| 2351 else if (id == CSSValueCenter) | |
| 2352 percent = 50; | |
| 2353 return cssValuePool().createValue(percent, CSSPrimitiveValue::UnitType:: Percentage); | |
| 2354 } | |
| 2355 if (validUnit(valueList->current(), FPercent | FLength)) | |
| 2356 return createPrimitiveNumericValue(valueList->current()); | |
| 2357 return nullptr; | |
| 2358 } | |
| 2359 | |
| 2360 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::parseFillPositionCo mponent(CSSParserValueList* valueList, unsigned& cumulativeFlags, FillPositionFl ag& individualFlag, FillPositionParsingMode parsingMode, Units unitless) | |
| 2361 { | |
| 2362 CSSValueID id = valueList->current()->id; | |
| 2363 if (id == CSSValueLeft || id == CSSValueTop || id == CSSValueRight || id == CSSValueBottom || id == CSSValueCenter) { | |
| 2364 int percent = 0; | |
| 2365 if (id == CSSValueLeft || id == CSSValueRight) { | |
| 2366 if (cumulativeFlags & XFillPosition) | |
| 2367 return nullptr; | |
| 2368 cumulativeFlags |= XFillPosition; | |
| 2369 individualFlag = XFillPosition; | |
| 2370 if (id == CSSValueRight) | |
| 2371 percent = 100; | |
| 2372 } | |
| 2373 else if (id == CSSValueTop || id == CSSValueBottom) { | |
| 2374 if (cumulativeFlags & YFillPosition) | |
| 2375 return nullptr; | |
| 2376 cumulativeFlags |= YFillPosition; | |
| 2377 individualFlag = YFillPosition; | |
| 2378 if (id == CSSValueBottom) | |
| 2379 percent = 100; | |
| 2380 } else if (id == CSSValueCenter) { | |
| 2381 // Center is ambiguous, so we're not sure which position we've found yet, an x or a y. | |
| 2382 percent = 50; | |
| 2383 cumulativeFlags |= AmbiguousFillPosition; | |
| 2384 individualFlag = AmbiguousFillPosition; | |
| 2385 } | |
| 2386 | |
| 2387 if (parsingMode == ResolveValuesAsKeyword) | |
| 2388 return cssValuePool().createIdentifierValue(id); | |
| 2389 | |
| 2390 return cssValuePool().createValue(percent, CSSPrimitiveValue::UnitType:: Percentage); | |
| 2391 } | |
| 2392 if (validUnit(valueList->current(), FPercent | FLength | unitless)) { | |
| 2393 if (!cumulativeFlags) { | |
| 2394 cumulativeFlags |= XFillPosition; | |
| 2395 individualFlag = XFillPosition; | |
| 2396 } else if (cumulativeFlags & (XFillPosition | AmbiguousFillPosition)) { | |
| 2397 cumulativeFlags |= YFillPosition; | |
| 2398 individualFlag = YFillPosition; | |
| 2399 } else { | |
| 2400 if (m_parsedCalculation) | |
| 2401 m_parsedCalculation.release(); | |
| 2402 return nullptr; | |
| 2403 } | |
| 2404 return createPrimitiveNumericValue(valueList->current()); | |
| 2405 } | |
| 2406 return nullptr; | |
| 2407 } | |
| 2408 | |
| 2409 static bool isValueConflictingWithCurrentEdge(int value1, int value2) | |
| 2410 { | |
| 2411 if ((value1 == CSSValueLeft || value1 == CSSValueRight) && (value2 == CSSVal ueLeft || value2 == CSSValueRight)) | |
| 2412 return true; | |
| 2413 | |
| 2414 if ((value1 == CSSValueTop || value1 == CSSValueBottom) && (value2 == CSSVal ueTop || value2 == CSSValueBottom)) | |
| 2415 return true; | |
| 2416 | |
| 2417 return false; | |
| 2418 } | |
| 2419 | |
| 2420 static bool isFillPositionKeyword(CSSValueID value) | |
| 2421 { | |
| 2422 return value == CSSValueLeft || value == CSSValueTop || value == CSSValueBot tom || value == CSSValueRight || value == CSSValueCenter; | |
| 2423 } | |
| 2424 | |
| 2425 void CSSPropertyParser::parse4ValuesFillPosition(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& value1, RefPtrWillBeRawPtr<CSSValue>& value2, Pass RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue1, PassRefPtrWillBeRawPtr<CSSPr imitiveValue> parsedValue2) | |
| 2426 { | |
| 2427 // [ left | right ] [ <percentage] | <length> ] && [ top | bottom ] [ <perce ntage> | <length> ] | |
| 2428 // In the case of 4 values <position> requires the second value to be a leng th or a percentage. | |
| 2429 if (isFillPositionKeyword(parsedValue2->getValueID())) | |
| 2430 return; | |
| 2431 | |
| 2432 unsigned cumulativeFlags = 0; | |
| 2433 FillPositionFlag value3Flag = InvalidFillPosition; | |
| 2434 RefPtrWillBeRawPtr<CSSPrimitiveValue> value3 = parseFillPositionComponent(va lueList, cumulativeFlags, value3Flag, ResolveValuesAsKeyword); | |
| 2435 if (!value3) | |
| 2436 return; | |
| 2437 | |
| 2438 CSSValueID ident1 = parsedValue1->getValueID(); | |
| 2439 CSSValueID ident3 = value3->getValueID(); | |
| 2440 | |
| 2441 if (ident1 == CSSValueCenter) | |
| 2442 return; | |
| 2443 | |
| 2444 if (!isFillPositionKeyword(ident3) || ident3 == CSSValueCenter) | |
| 2445 return; | |
| 2446 | |
| 2447 // We need to check if the values are not conflicting, e.g. they are not on the same edge. It is | |
| 2448 // needed as the second call to parseFillPositionComponent was on purpose no t checking it. In the | |
| 2449 // case of two values top 20px is invalid but in the case of 4 values it bec omes valid. | |
| 2450 if (isValueConflictingWithCurrentEdge(ident1, ident3)) | |
| 2451 return; | |
| 2452 | |
| 2453 valueList->next(); | |
| 2454 | |
| 2455 cumulativeFlags = 0; | |
| 2456 FillPositionFlag value4Flag = InvalidFillPosition; | |
| 2457 RefPtrWillBeRawPtr<CSSPrimitiveValue> value4 = parseFillPositionComponent(va lueList, cumulativeFlags, value4Flag, ResolveValuesAsKeyword); | |
| 2458 if (!value4) | |
| 2459 return; | |
| 2460 | |
| 2461 // 4th value must be a length or a percentage. | |
| 2462 if (isFillPositionKeyword(value4->getValueID())) | |
| 2463 return; | |
| 2464 | |
| 2465 value1 = CSSValuePair::create(parsedValue1, parsedValue2, CSSValuePair::Drop IdenticalValues); | |
| 2466 value2 = CSSValuePair::create(value3, value4, CSSValuePair::DropIdenticalVal ues); | |
| 2467 | |
| 2468 if (ident1 == CSSValueTop || ident1 == CSSValueBottom) | |
| 2469 value1.swap(value2); | |
| 2470 | |
| 2471 valueList->next(); | |
| 2472 } | |
| 2473 void CSSPropertyParser::parse3ValuesFillPosition(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& value1, RefPtrWillBeRawPtr<CSSValue>& value2, Pass RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue1, PassRefPtrWillBeRawPtr<CSSPr imitiveValue> parsedValue2) | |
| 2474 { | |
| 2475 unsigned cumulativeFlags = 0; | |
| 2476 FillPositionFlag value3Flag = InvalidFillPosition; | |
| 2477 RefPtrWillBeRawPtr<CSSPrimitiveValue> value3 = parseFillPositionComponent(va lueList, cumulativeFlags, value3Flag, ResolveValuesAsKeyword); | |
| 2478 | |
| 2479 // value3 is not an expected value, we return. | |
| 2480 if (!value3) | |
| 2481 return; | |
| 2482 | |
| 2483 valueList->next(); | |
| 2484 | |
| 2485 bool swapNeeded = false; | |
| 2486 CSSValueID ident1 = parsedValue1->getValueID(); | |
| 2487 CSSValueID ident2 = parsedValue2->getValueID(); | |
| 2488 CSSValueID ident3 = value3->getValueID(); | |
| 2489 | |
| 2490 CSSValueID firstPositionKeyword; | |
| 2491 CSSValueID secondPositionKeyword; | |
| 2492 | |
| 2493 if (ident1 == CSSValueCenter) { | |
| 2494 // <position> requires the first 'center' to be followed by a keyword. | |
| 2495 if (!isFillPositionKeyword(ident2)) | |
| 2496 return; | |
| 2497 | |
| 2498 // If 'center' is the first keyword then the last one needs to be a leng th. | |
| 2499 if (isFillPositionKeyword(ident3)) | |
| 2500 return; | |
| 2501 | |
| 2502 firstPositionKeyword = CSSValueLeft; | |
| 2503 if (ident2 == CSSValueLeft || ident2 == CSSValueRight) { | |
| 2504 firstPositionKeyword = CSSValueTop; | |
| 2505 swapNeeded = true; | |
| 2506 } | |
| 2507 value1 = CSSValuePair::create(cssValuePool().createIdentifierValue(first PositionKeyword), cssValuePool().createValue(50, CSSPrimitiveValue::UnitType::Pe rcentage), CSSValuePair::DropIdenticalValues); | |
| 2508 value2 = CSSValuePair::create(parsedValue2, value3, CSSValuePair::DropId enticalValues); | |
| 2509 } else if (ident3 == CSSValueCenter) { | |
| 2510 if (isFillPositionKeyword(ident2)) | |
| 2511 return; | |
| 2512 | |
| 2513 secondPositionKeyword = CSSValueTop; | |
| 2514 if (ident1 == CSSValueTop || ident1 == CSSValueBottom) { | |
| 2515 secondPositionKeyword = CSSValueLeft; | |
| 2516 swapNeeded = true; | |
| 2517 } | |
| 2518 value1 = CSSValuePair::create(parsedValue1, parsedValue2, CSSValuePair:: DropIdenticalValues); | |
| 2519 value2 = CSSValuePair::create(cssValuePool().createIdentifierValue(secon dPositionKeyword), cssValuePool().createValue(50, CSSPrimitiveValue::UnitType::P ercentage), CSSValuePair::DropIdenticalValues); | |
| 2520 } else { | |
| 2521 RefPtrWillBeRawPtr<CSSPrimitiveValue> firstPositionValue = nullptr; | |
| 2522 RefPtrWillBeRawPtr<CSSPrimitiveValue> secondPositionValue = nullptr; | |
| 2523 | |
| 2524 if (isFillPositionKeyword(ident2)) { | |
| 2525 // To match CSS grammar, we should only accept: [ center | left | ri ght | bottom | top ] [ left | right | top | bottom ] [ <percentage> | <length> ] . | |
| 2526 ASSERT(ident2 != CSSValueCenter); | |
| 2527 | |
| 2528 if (isFillPositionKeyword(ident3)) | |
| 2529 return; | |
| 2530 | |
| 2531 secondPositionValue = value3; | |
| 2532 secondPositionKeyword = ident2; | |
| 2533 firstPositionValue = cssValuePool().createValue(0, CSSPrimitiveValue ::UnitType::Percentage); | |
| 2534 } else { | |
| 2535 // Per CSS, we should only accept: [ right | left | top | bottom ] [ <percentage> | <length> ] [ center | left | right | bottom | top ]. | |
| 2536 if (!isFillPositionKeyword(ident3)) | |
| 2537 return; | |
| 2538 | |
| 2539 firstPositionValue = parsedValue2; | |
| 2540 secondPositionKeyword = ident3; | |
| 2541 secondPositionValue = cssValuePool().createValue(0, CSSPrimitiveValu e::UnitType::Percentage); | |
| 2542 } | |
| 2543 | |
| 2544 if (isValueConflictingWithCurrentEdge(ident1, secondPositionKeyword)) | |
| 2545 return; | |
| 2546 | |
| 2547 value1 = CSSValuePair::create(parsedValue1, firstPositionValue, CSSValue Pair::DropIdenticalValues); | |
| 2548 value2 = CSSValuePair::create(cssValuePool().createIdentifierValue(secon dPositionKeyword), secondPositionValue, CSSValuePair::DropIdenticalValues); | |
| 2549 } | |
| 2550 | |
| 2551 if (ident1 == CSSValueTop || ident1 == CSSValueBottom || swapNeeded) | |
| 2552 value1.swap(value2); | |
| 2553 | |
| 2554 #if ENABLE(ASSERT) | |
| 2555 const CSSValuePair& first = toCSSValuePair(*value1); | |
| 2556 const CSSValuePair& second = toCSSValuePair(*value2); | |
| 2557 ident1 = toCSSPrimitiveValue(first.first()).getValueID(); | |
| 2558 ident2 = toCSSPrimitiveValue(second.first()).getValueID(); | |
| 2559 ASSERT(ident1 == CSSValueLeft || ident1 == CSSValueRight); | |
| 2560 ASSERT(ident2 == CSSValueBottom || ident2 == CSSValueTop); | |
| 2561 #endif | |
| 2562 } | |
| 2563 | |
| 2564 inline bool CSSPropertyParser::isPotentialPositionValue(CSSParserValue* value) | |
| 2565 { | |
| 2566 return isFillPositionKeyword(value->id) || validUnit(value, FPercent | FLeng th, ReleaseParsedCalcValue); | |
| 2567 } | |
| 2568 | |
| 2569 void CSSPropertyParser::parseFillPosition(CSSParserValueList* valueList, RefPtrW illBeRawPtr<CSSValue>& value1, RefPtrWillBeRawPtr<CSSValue>& value2, Units unitl ess) | |
| 2570 { | |
| 2571 unsigned numberOfValues = 0; | |
| 2572 for (unsigned i = valueList->currentIndex(); i < valueList->size(); ++i, ++n umberOfValues) { | |
| 2573 CSSParserValue* current = valueList->valueAt(i); | |
| 2574 if (!current || isComma(current) || isForwardSlashOperator(current) || ! isPotentialPositionValue(current)) | |
| 2575 break; | |
| 2576 } | |
| 2577 | |
| 2578 if (numberOfValues > 4) | |
| 2579 return; | |
| 2580 | |
| 2581 // If we are parsing two values, we can safely call the CSS 2.1 parsing func tion and return. | |
| 2582 if (numberOfValues <= 2) { | |
| 2583 parse2ValuesFillPosition(valueList, value1, value2, unitless); | |
| 2584 return; | |
| 2585 } | |
| 2586 | |
| 2587 ASSERT(numberOfValues > 2 && numberOfValues <= 4); | |
| 2588 | |
| 2589 CSSParserValue* value = valueList->current(); | |
| 2590 | |
| 2591 // <position> requires the first value to be a background keyword. | |
| 2592 if (!isFillPositionKeyword(value->id)) | |
| 2593 return; | |
| 2594 | |
| 2595 // Parse the first value. We're just making sure that it is one of the valid keywords or a percentage/length. | |
| 2596 unsigned cumulativeFlags = 0; | |
| 2597 FillPositionFlag value1Flag = InvalidFillPosition; | |
| 2598 FillPositionFlag value2Flag = InvalidFillPosition; | |
| 2599 value1 = parseFillPositionComponent(valueList, cumulativeFlags, value1Flag, ResolveValuesAsKeyword); | |
| 2600 if (!value1) | |
| 2601 return; | |
| 2602 | |
| 2603 valueList->next(); | |
| 2604 | |
| 2605 // In case we are parsing more than two values, relax the check inside of pa rseFillPositionComponent. top 20px is | |
| 2606 // a valid start for <position>. | |
| 2607 cumulativeFlags = AmbiguousFillPosition; | |
| 2608 value2 = parseFillPositionComponent(valueList, cumulativeFlags, value2Flag, ResolveValuesAsKeyword); | |
| 2609 if (value2) | |
| 2610 valueList->next(); | |
| 2611 else { | |
| 2612 value1.clear(); | |
| 2613 return; | |
| 2614 } | |
| 2615 | |
| 2616 RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue1 = toCSSPrimitiveValue(val ue1.get()); | |
| 2617 RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue2 = toCSSPrimitiveValue(val ue2.get()); | |
| 2618 | |
| 2619 value1.clear(); | |
| 2620 value2.clear(); | |
| 2621 | |
| 2622 // Per CSS3 syntax, <position> can't have 'center' as its second keyword as we have more arguments to follow. | |
| 2623 if (parsedValue2->getValueID() == CSSValueCenter) | |
| 2624 return; | |
| 2625 | |
| 2626 if (numberOfValues == 3) | |
| 2627 parse3ValuesFillPosition(valueList, value1, value2, parsedValue1.release (), parsedValue2.release()); | |
| 2628 else | |
| 2629 parse4ValuesFillPosition(valueList, value1, value2, parsedValue1.release (), parsedValue2.release()); | |
| 2630 } | |
| 2631 | |
| 2632 void CSSPropertyParser::parse2ValuesFillPosition(CSSParserValueList* valueList, RefPtrWillBeRawPtr<CSSValue>& value1, RefPtrWillBeRawPtr<CSSValue>& value2, Unit s unitless) | |
| 2633 { | |
| 2634 // Parse the first value. We're just making sure that it is one of the vali d keywords or a percentage/length. | |
| 2635 unsigned cumulativeFlags = 0; | |
| 2636 FillPositionFlag value1Flag = InvalidFillPosition; | |
| 2637 FillPositionFlag value2Flag = InvalidFillPosition; | |
| 2638 value1 = parseFillPositionComponent(valueList, cumulativeFlags, value1Flag, ResolveValuesAsPercent, unitless); | |
| 2639 if (!value1) | |
| 2640 return; | |
| 2641 | |
| 2642 // It only takes one value for background-position to be correctly parsed if it was specified in a shorthand (since we | |
| 2643 // can assume that any other values belong to the rest of the shorthand). I f we're not parsing a shorthand, though, the | |
| 2644 // value was explicitly specified for our property. | |
| 2645 CSSParserValue* value = valueList->next(); | |
| 2646 | |
| 2647 // First check for the comma. If so, we are finished parsing this value or value pair. | |
| 2648 if (value && isComma(value)) | |
| 2649 value = 0; | |
| 2650 | |
| 2651 if (value) { | |
| 2652 value2 = parseFillPositionComponent(valueList, cumulativeFlags, value2Fl ag, ResolveValuesAsPercent, unitless); | |
| 2653 if (value2) | |
| 2654 valueList->next(); | |
| 2655 else { | |
| 2656 if (!inShorthand()) { | |
| 2657 value1.clear(); | |
| 2658 return; | |
| 2659 } | |
| 2660 } | |
| 2661 } | |
| 2662 | |
| 2663 if (!value2) { | |
| 2664 // Only one value was specified. If that value was not a keyword, then i t sets the x position, and the y position | |
| 2665 // is simply 50%. This is our default. | |
| 2666 // For keywords, the keyword was either an x-keyword (left/right), a y-k eyword (top/bottom), or an ambiguous keyword (center). | |
| 2667 // For left/right/center, the default of 50% in the y is still correct. | |
| 2668 value2 = cssValuePool().createValue(50, CSSPrimitiveValue::UnitType::Per centage); | |
| 2669 } | |
| 2670 | |
| 2671 if (value1Flag == YFillPosition || value2Flag == XFillPosition) | |
| 2672 value1.swap(value2); | |
| 2673 } | |
| 2674 | |
| 2675 void CSSPropertyParser::parseFillRepeat(RefPtrWillBeRawPtr<CSSValue>& value1, Re fPtrWillBeRawPtr<CSSValue>& value2) | |
| 2676 { | |
| 2677 CSSValueID id = m_valueList->current()->id; | |
| 2678 if (id == CSSValueRepeatX) { | |
| 2679 m_implicitShorthand = true; | |
| 2680 value1 = cssValuePool().createIdentifierValue(CSSValueRepeat); | |
| 2681 value2 = cssValuePool().createIdentifierValue(CSSValueNoRepeat); | |
| 2682 m_valueList->next(); | |
| 2683 return; | |
| 2684 } | |
| 2685 if (id == CSSValueRepeatY) { | |
| 2686 m_implicitShorthand = true; | |
| 2687 value1 = cssValuePool().createIdentifierValue(CSSValueNoRepeat); | |
| 2688 value2 = cssValuePool().createIdentifierValue(CSSValueRepeat); | |
| 2689 m_valueList->next(); | |
| 2690 return; | |
| 2691 } | |
| 2692 if (id == CSSValueRepeat || id == CSSValueNoRepeat || id == CSSValueRound || id == CSSValueSpace) | |
| 2693 value1 = cssValuePool().createIdentifierValue(id); | |
| 2694 else { | |
| 2695 value1 = nullptr; | |
| 2696 return; | |
| 2697 } | |
| 2698 | |
| 2699 CSSParserValue* value = m_valueList->next(); | |
| 2700 | |
| 2701 // Parse the second value if one is available | |
| 2702 if (value && !isComma(value)) { | |
| 2703 id = value->id; | |
| 2704 if (id == CSSValueRepeat || id == CSSValueNoRepeat || id == CSSValueRoun d || id == CSSValueSpace) { | |
| 2705 value2 = cssValuePool().createIdentifierValue(id); | |
| 2706 m_valueList->next(); | |
| 2707 return; | |
| 2708 } | |
| 2709 } | |
| 2710 | |
| 2711 // If only one value was specified, value2 is the same as value1. | |
| 2712 m_implicitShorthand = true; | |
| 2713 value2 = cssValuePool().createIdentifierValue(toCSSPrimitiveValue(value1.get ())->getValueID()); | |
| 2714 } | |
| 2715 | |
| 2716 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseFillSize(CSSPropertyID unresolvedProperty) | |
| 2717 { | |
| 2718 CSSParserValue* value = m_valueList->current(); | |
| 2719 m_valueList->next(); | |
| 2720 | |
| 2721 if (value->id == CSSValueContain || value->id == CSSValueCover) | |
| 2722 return cssValuePool().createIdentifierValue(value->id); | |
| 2723 | |
| 2724 RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue1 = nullptr; | |
| 2725 | |
| 2726 if (value->id == CSSValueAuto) | |
| 2727 parsedValue1 = cssValuePool().createIdentifierValue(CSSValueAuto); | |
| 2728 else { | |
| 2729 if (!validUnit(value, FLength | FPercent)) | |
| 2730 return nullptr; | |
| 2731 parsedValue1 = createPrimitiveNumericValue(value); | |
| 2732 } | |
| 2733 | |
| 2734 RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue2 = nullptr; | |
| 2735 value = m_valueList->current(); | |
| 2736 if (value) { | |
| 2737 if (value->id == CSSValueAuto) { | |
| 2738 // `auto' is the default | |
| 2739 m_valueList->next(); | |
| 2740 } else if (validUnit(value, FLength | FPercent)) { | |
| 2741 parsedValue2 = createPrimitiveNumericValue(value); | |
| 2742 m_valueList->next(); | |
| 2743 } | |
| 2744 } else if (unresolvedProperty == CSSPropertyAliasWebkitBackgroundSize) { | |
| 2745 // For backwards compatibility we set the second value to the first if i t is omitted. | |
| 2746 // We only need to do this for -webkit-background-size. It should be saf e to let masks match | |
| 2747 // the real property. | |
| 2748 parsedValue2 = parsedValue1; | |
| 2749 } | |
| 2750 | |
| 2751 if (!parsedValue2) | |
| 2752 return parsedValue1; | |
| 2753 | |
| 2754 return CSSValuePair::create(parsedValue1.release(), parsedValue2.release(), CSSValuePair::KeepIdenticalValues); | |
| 2755 } | |
| 2756 | |
| 2757 bool CSSPropertyParser::parseFillProperty(CSSPropertyID propId, CSSPropertyID& p ropId1, CSSPropertyID& propId2, | |
| 2758 RefPtrWillBeRawPtr<CSSValue>& retValue1, RefPtrWillBeRawPtr<CSSValue>& retVa lue2) | |
| 2759 { | |
| 2760 // We initially store the first value in value/value2, and only create | |
| 2761 // CSSValueLists if we have more values. | |
| 2762 RefPtrWillBeRawPtr<CSSValueList> values = nullptr; | |
| 2763 RefPtrWillBeRawPtr<CSSValueList> values2 = nullptr; | |
| 2764 RefPtrWillBeRawPtr<CSSValue> value = nullptr; | |
| 2765 RefPtrWillBeRawPtr<CSSValue> value2 = nullptr; | |
| 2766 | |
| 2767 retValue1 = retValue2 = nullptr; | |
| 2768 propId1 = resolveCSSPropertyID(propId); | |
| 2769 propId2 = propId1; | |
| 2770 if (propId == CSSPropertyBackgroundPosition) { | |
| 2771 propId1 = CSSPropertyBackgroundPositionX; | |
| 2772 propId2 = CSSPropertyBackgroundPositionY; | |
| 2773 } else if (propId == CSSPropertyWebkitMaskPosition) { | |
| 2774 propId1 = CSSPropertyWebkitMaskPositionX; | |
| 2775 propId2 = CSSPropertyWebkitMaskPositionY; | |
| 2776 } else if (propId == CSSPropertyBackgroundRepeat) { | |
| 2777 propId1 = CSSPropertyBackgroundRepeatX; | |
| 2778 propId2 = CSSPropertyBackgroundRepeatY; | |
| 2779 } else if (propId == CSSPropertyWebkitMaskRepeat) { | |
| 2780 propId1 = CSSPropertyWebkitMaskRepeatX; | |
| 2781 propId2 = CSSPropertyWebkitMaskRepeatY; | |
| 2782 } | |
| 2783 | |
| 2784 while (true) { | |
| 2785 RefPtrWillBeRawPtr<CSSValue> currValue = nullptr; | |
| 2786 RefPtrWillBeRawPtr<CSSValue> currValue2 = nullptr; | |
| 2787 | |
| 2788 Units unitless = FUnknown; | |
| 2789 CSSParserValue* val = m_valueList->current(); | |
| 2790 ASSERT(val); | |
| 2791 | |
| 2792 switch (propId) { | |
| 2793 case CSSPropertyBackgroundColor: | |
| 2794 currValue = parseColor(val); | |
| 2795 if (currValue) | |
| 2796 m_valueList->next(); | |
| 2797 break; | |
| 2798 case CSSPropertyBackgroundAttachment: | |
| 2799 if (val->id == CSSValueScroll || val->id == CSSValueFixed || val->id == CSSValueLocal) { | |
| 2800 currValue = cssValuePool().createIdentifierValue(val->id); | |
| 2801 m_valueList->next(); | |
| 2802 } | |
| 2803 break; | |
| 2804 case CSSPropertyBackgroundImage: | |
| 2805 case CSSPropertyWebkitMaskImage: | |
| 2806 if (parseFillImage(m_valueList, currValue)) | |
| 2807 m_valueList->next(); | |
| 2808 break; | |
| 2809 case CSSPropertyWebkitBackgroundClip: | |
| 2810 case CSSPropertyWebkitBackgroundOrigin: | |
| 2811 case CSSPropertyWebkitMaskClip: | |
| 2812 case CSSPropertyWebkitMaskOrigin: | |
| 2813 // The first three values here are deprecated and do not apply to th e version of the property that has | |
| 2814 // the -webkit- prefix removed. | |
| 2815 if (val->id == CSSValueBorder || val->id == CSSValuePadding || val-> id == CSSValueContent | |
| 2816 || val->id == CSSValueBorderBox || val->id == CSSValuePaddingBox || val->id == CSSValueContentBox | |
| 2817 || ((propId == CSSPropertyWebkitBackgroundClip || propId == CSSP ropertyWebkitMaskClip) | |
| 2818 && (val->id == CSSValueText || val->id == CSSValueWebkitText ))) { | |
| 2819 if (val->id == CSSValueWebkitText && m_context.useCounter()) | |
| 2820 m_context.useCounter()->count(UseCounter::WebkitTextInClipPr operty); | |
| 2821 currValue = cssValuePool().createIdentifierValue(val->id); | |
| 2822 m_valueList->next(); | |
| 2823 } | |
| 2824 break; | |
| 2825 case CSSPropertyBackgroundClip: | |
| 2826 if (parseBackgroundClip(val, currValue)) { | |
| 2827 if (val->id == CSSValueWebkitText && m_context.useCounter()) | |
| 2828 m_context.useCounter()->count(UseCounter::WebkitTextInClipPr operty); | |
| 2829 m_valueList->next(); | |
| 2830 } | |
| 2831 break; | |
| 2832 case CSSPropertyBackgroundOrigin: | |
| 2833 if (val->id == CSSValueBorderBox || val->id == CSSValuePaddingBox || val->id == CSSValueContentBox) { | |
| 2834 currValue = cssValuePool().createIdentifierValue(val->id); | |
| 2835 m_valueList->next(); | |
| 2836 } | |
| 2837 break; | |
| 2838 case CSSPropertyBackgroundPosition: | |
| 2839 if (!inShorthand()) | |
| 2840 unitless = FUnitlessQuirk; | |
| 2841 // fall-through | |
| 2842 case CSSPropertyWebkitMaskPosition: | |
| 2843 parseFillPosition(m_valueList, currValue, currValue2, unitless); | |
| 2844 // parseFillPosition advances the m_valueList pointer. | |
| 2845 break; | |
| 2846 case CSSPropertyBackgroundPositionX: | |
| 2847 case CSSPropertyWebkitMaskPositionX: { | |
| 2848 currValue = parseFillPositionX(m_valueList); | |
| 2849 if (currValue) | |
| 2850 m_valueList->next(); | |
| 2851 break; | |
| 2852 } | |
| 2853 case CSSPropertyBackgroundPositionY: | |
| 2854 case CSSPropertyWebkitMaskPositionY: { | |
| 2855 currValue = parseFillPositionY(m_valueList); | |
| 2856 if (currValue) | |
| 2857 m_valueList->next(); | |
| 2858 break; | |
| 2859 } | |
| 2860 case CSSPropertyWebkitBackgroundComposite: | |
| 2861 case CSSPropertyWebkitMaskComposite: | |
| 2862 if (val->id >= CSSValueClear && val->id <= CSSValuePlusLighter) { | |
| 2863 currValue = cssValuePool().createIdentifierValue(val->id); | |
| 2864 m_valueList->next(); | |
| 2865 } | |
| 2866 break; | |
| 2867 case CSSPropertyBackgroundBlendMode: | |
| 2868 if (val->id == CSSValueNormal || val->id == CSSValueMultiply | |
| 2869 || val->id == CSSValueScreen || val->id == CSSValueOverlay || va l->id == CSSValueDarken | |
| 2870 || val->id == CSSValueLighten || val->id == CSSValueColorDodge || val->id == CSSValueColorBurn | |
| 2871 || val->id == CSSValueHardLight || val->id == CSSValueSoftLight || val->id == CSSValueDifference | |
| 2872 || val->id == CSSValueExclusion || val->id == CSSValueHue || val ->id == CSSValueSaturation | |
| 2873 || val->id == CSSValueColor || val->id == CSSValueLuminosity) { | |
| 2874 currValue = cssValuePool().createIdentifierValue(val->id); | |
| 2875 m_valueList->next(); | |
| 2876 } | |
| 2877 break; | |
| 2878 case CSSPropertyBackgroundRepeat: | |
| 2879 case CSSPropertyWebkitMaskRepeat: | |
| 2880 parseFillRepeat(currValue, currValue2); | |
| 2881 // parseFillRepeat advances the m_valueList pointer | |
| 2882 break; | |
| 2883 case CSSPropertyBackgroundSize: | |
| 2884 case CSSPropertyAliasWebkitBackgroundSize: | |
| 2885 case CSSPropertyWebkitMaskSize: { | |
| 2886 currValue = parseFillSize(propId); | |
| 2887 break; | |
| 2888 } | |
| 2889 case CSSPropertyMaskSourceType: { | |
| 2890 ASSERT(RuntimeEnabledFeatures::cssMaskSourceTypeEnabled()); | |
| 2891 if (val->id == CSSValueAuto || val->id == CSSValueAlpha || val->id = = CSSValueLuminance) { | |
| 2892 currValue = cssValuePool().createIdentifierValue(val->id); | |
| 2893 m_valueList->next(); | |
| 2894 } else { | |
| 2895 currValue = nullptr; | |
| 2896 } | |
| 2897 break; | |
| 2898 } | |
| 2899 default: | |
| 2900 break; | |
| 2901 } | |
| 2902 if (!currValue) | |
| 2903 return false; | |
| 2904 | |
| 2905 if (value && !values) { | |
| 2906 values = CSSValueList::createCommaSeparated(); | |
| 2907 values->append(value.release()); | |
| 2908 } | |
| 2909 | |
| 2910 if (value2 && !values2) { | |
| 2911 values2 = CSSValueList::createCommaSeparated(); | |
| 2912 values2->append(value2.release()); | |
| 2913 } | |
| 2914 | |
| 2915 if (values) | |
| 2916 values->append(currValue.release()); | |
| 2917 else | |
| 2918 value = currValue.release(); | |
| 2919 if (currValue2) { | |
| 2920 if (values2) | |
| 2921 values2->append(currValue2.release()); | |
| 2922 else | |
| 2923 value2 = currValue2.release(); | |
| 2924 } | |
| 2925 | |
| 2926 // When parsing any fill shorthand property, we let it handle building u p the lists for all | |
| 2927 // properties. | |
| 2928 if (inShorthand()) | |
| 2929 break; | |
| 2930 | |
| 2931 if (!m_valueList->current()) | |
| 2932 break; | |
| 2933 if (!consumeComma(m_valueList) || !m_valueList->current()) | |
| 2934 return false; | |
| 2935 } | |
| 2936 | |
| 2937 if (values) { | |
| 2938 ASSERT(values->length()); | |
| 2939 retValue1 = values.release(); | |
| 2940 if (values2) { | |
| 2941 ASSERT(values2->length()); | |
| 2942 retValue2 = values2.release(); | |
| 2943 } | |
| 2944 } else { | |
| 2945 ASSERT(value); | |
| 2946 retValue1 = value.release(); | |
| 2947 retValue2 = value2.release(); | |
| 2948 } | |
| 2949 | |
| 2950 return true; | |
| 2951 } | |
| 2952 | |
| 2953 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationDelay() | |
| 2954 { | |
| 2955 CSSParserValue* value = m_valueList->current(); | |
| 2956 if (validUnit(value, FTime)) | |
| 2957 return createPrimitiveNumericValue(value); | |
| 2958 return nullptr; | |
| 2959 } | |
| 2960 | |
| 2961 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationDirection() | |
| 2962 { | |
| 2963 CSSParserValue* value = m_valueList->current(); | |
| 2964 if (value->id == CSSValueNormal || value->id == CSSValueAlternate || value-> id == CSSValueReverse || value->id == CSSValueAlternateReverse) | |
| 2965 return cssValuePool().createIdentifierValue(value->id); | |
| 2966 return nullptr; | |
| 2967 } | |
| 2968 | |
| 2969 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationDuration() | |
| 2970 { | |
| 2971 CSSParserValue* value = m_valueList->current(); | |
| 2972 if (validUnit(value, FTime | FNonNeg)) | |
| 2973 return createPrimitiveNumericValue(value); | |
| 2974 return nullptr; | |
| 2975 } | |
| 2976 | |
| 2977 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationFillMode() | |
| 2978 { | |
| 2979 CSSParserValue* value = m_valueList->current(); | |
| 2980 if (value->id == CSSValueNone || value->id == CSSValueForwards || value->id == CSSValueBackwards || value->id == CSSValueBoth) | |
| 2981 return cssValuePool().createIdentifierValue(value->id); | |
| 2982 return nullptr; | |
| 2983 } | |
| 2984 | |
| 2985 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationIterationCount () | |
| 2986 { | |
| 2987 CSSParserValue* value = m_valueList->current(); | |
| 2988 if (value->id == CSSValueInfinite) | |
| 2989 return cssValuePool().createIdentifierValue(value->id); | |
| 2990 if (validUnit(value, FNumber | FNonNeg)) | |
| 2991 return createPrimitiveNumericValue(value); | |
| 2992 return nullptr; | |
| 2993 } | |
| 2994 | |
| 2995 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationName(bool allo wQuotedName) | |
| 2996 { | |
| 2997 CSSParserValue* value = m_valueList->current(); | |
| 2998 | |
| 2999 if (value->id == CSSValueNone) | |
| 3000 return cssValuePool().createIdentifierValue(CSSValueNone); | |
| 3001 | |
| 3002 if (value->m_unit == CSSParserValue::Identifier) | |
| 3003 return createPrimitiveCustomIdentValue(value); | |
| 3004 | |
| 3005 if (allowQuotedName && value->unit() == CSSPrimitiveValue::UnitType::String) { | |
| 3006 // Legacy support for strings in prefixed animations | |
| 3007 if (m_context.useCounter()) | |
| 3008 m_context.useCounter()->count(UseCounter::QuotedAnimationName); | |
| 3009 if (equalIgnoringCase(value->string, "none")) | |
| 3010 return cssValuePool().createIdentifierValue(CSSValueNone); | |
| 3011 return createPrimitiveCustomIdentValue(value); | |
| 3012 } | |
| 3013 | |
| 3014 return nullptr; | |
| 3015 } | |
| 3016 | |
| 3017 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationPlayState() | |
| 3018 { | |
| 3019 CSSParserValue* value = m_valueList->current(); | |
| 3020 if (value->id == CSSValueRunning || value->id == CSSValuePaused) | |
| 3021 return cssValuePool().createIdentifierValue(value->id); | |
| 3022 return nullptr; | |
| 3023 } | |
| 3024 | |
| 3025 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationProperty() | |
| 3026 { | |
| 3027 CSSParserValue* value = m_valueList->current(); | |
| 3028 if (value->m_unit != CSSParserValue::Identifier) | |
| 3029 return nullptr; | |
| 3030 CSSPropertyID property = unresolvedCSSPropertyID(value->string); | |
| 3031 if (property) { | |
| 3032 ASSERT(CSSPropertyMetadata::isEnabledProperty(property)); | |
| 3033 return cssValuePool().createIdentifierValue(property); | |
| 3034 } | |
| 3035 if (value->id == CSSValueNone) | |
| 3036 return cssValuePool().createIdentifierValue(CSSValueNone); | |
| 3037 if (value->id == CSSValueInitial || value->id == CSSValueInherit) | |
| 3038 return nullptr; | |
| 3039 return createPrimitiveCustomIdentValue(value); | |
| 3040 } | |
| 3041 | |
| 3042 bool CSSPropertyParser::parseCubicBezierTimingFunctionValue(CSSParserValueList*& args, double& result) | |
| 3043 { | |
| 3044 CSSParserValue* v = args->current(); | |
| 3045 if (!validUnit(v, FNumber)) | |
| 3046 return false; | |
| 3047 result = v->fValue; | |
| 3048 v = args->next(); | |
| 3049 if (!v) | |
| 3050 // The last number in the function has no comma after it, so we're done. | |
| 3051 return true; | |
| 3052 return consumeComma(args); | |
| 3053 } | |
| 3054 | |
| 3055 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationTimingFunction () | |
| 3056 { | |
| 3057 CSSParserValue* value = m_valueList->current(); | |
| 3058 if (value->id == CSSValueEase || value->id == CSSValueLinear || value->id == CSSValueEaseIn || value->id == CSSValueEaseOut | |
| 3059 || value->id == CSSValueEaseInOut || value->id == CSSValueStepStart || v alue->id == CSSValueStepEnd | |
| 3060 || value->id == CSSValueStepMiddle) | |
| 3061 return cssValuePool().createIdentifierValue(value->id); | |
| 3062 | |
| 3063 // We must be a function. | |
| 3064 if (value->m_unit != CSSParserValue::Function) | |
| 3065 return nullptr; | |
| 3066 | |
| 3067 CSSParserValueList* args = value->function->args.get(); | |
| 3068 | |
| 3069 if (value->function->id == CSSValueSteps) { | |
| 3070 // For steps, 1 or 2 params must be specified (comma-separated) | |
| 3071 if (!args || (args->size() != 1 && args->size() != 3)) | |
| 3072 return nullptr; | |
| 3073 | |
| 3074 // There are two values. | |
| 3075 int numSteps; | |
| 3076 StepsTimingFunction::StepAtPosition stepAtPosition = StepsTimingFunction ::End; | |
| 3077 | |
| 3078 CSSParserValue* v = args->current(); | |
| 3079 if (!validUnit(v, FInteger)) | |
| 3080 return nullptr; | |
| 3081 numSteps = clampTo<int>(v->fValue); | |
| 3082 if (numSteps < 1) | |
| 3083 return nullptr; | |
| 3084 | |
| 3085 if (args->next()) { | |
| 3086 // There is a comma so we need to parse the second value | |
| 3087 if (!consumeComma(args)) | |
| 3088 return nullptr; | |
| 3089 switch (args->current()->id) { | |
| 3090 case CSSValueMiddle: | |
| 3091 if (!RuntimeEnabledFeatures::webAnimationsAPIEnabled()) | |
| 3092 return nullptr; | |
| 3093 stepAtPosition = StepsTimingFunction::Middle; | |
| 3094 break; | |
| 3095 case CSSValueStart: | |
| 3096 stepAtPosition = StepsTimingFunction::Start; | |
| 3097 break; | |
| 3098 case CSSValueEnd: | |
| 3099 stepAtPosition = StepsTimingFunction::End; | |
| 3100 break; | |
| 3101 default: | |
| 3102 return nullptr; | |
| 3103 } | |
| 3104 } | |
| 3105 | |
| 3106 return CSSStepsTimingFunctionValue::create(numSteps, stepAtPosition); | |
| 3107 } | |
| 3108 | |
| 3109 if (value->function->id == CSSValueCubicBezier) { | |
| 3110 // For cubic bezier, 4 values must be specified. | |
| 3111 if (!args || args->size() != 7) | |
| 3112 return nullptr; | |
| 3113 | |
| 3114 // There are two points specified. The x values must be between 0 and 1 but the y values can exceed this range. | |
| 3115 double x1, y1, x2, y2; | |
| 3116 | |
| 3117 if (!parseCubicBezierTimingFunctionValue(args, x1)) | |
| 3118 return nullptr; | |
| 3119 if (x1 < 0 || x1 > 1) | |
| 3120 return nullptr; | |
| 3121 if (!parseCubicBezierTimingFunctionValue(args, y1)) | |
| 3122 return nullptr; | |
| 3123 if (!parseCubicBezierTimingFunctionValue(args, x2)) | |
| 3124 return nullptr; | |
| 3125 if (x2 < 0 || x2 > 1) | |
| 3126 return nullptr; | |
| 3127 if (!parseCubicBezierTimingFunctionValue(args, y2)) | |
| 3128 return nullptr; | |
| 3129 | |
| 3130 return CSSCubicBezierTimingFunctionValue::create(x1, y1, x2, y2); | |
| 3131 } | |
| 3132 | |
| 3133 return nullptr; | |
| 3134 } | |
| 3135 | |
| 3136 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseAnimationProperty(CSSPr opertyID propId, bool useLegacyParsing) | |
| 3137 { | |
| 3138 RefPtrWillBeRawPtr<CSSValue> value = nullptr; | |
| 3139 switch (propId) { | |
| 3140 case CSSPropertyAnimationDelay: | |
| 3141 case CSSPropertyTransitionDelay: | |
| 3142 value = parseAnimationDelay(); | |
| 3143 break; | |
| 3144 case CSSPropertyAnimationDirection: | |
| 3145 value = parseAnimationDirection(); | |
| 3146 break; | |
| 3147 case CSSPropertyAnimationDuration: | |
| 3148 case CSSPropertyTransitionDuration: | |
| 3149 value = parseAnimationDuration(); | |
| 3150 break; | |
| 3151 case CSSPropertyAnimationFillMode: | |
| 3152 value = parseAnimationFillMode(); | |
| 3153 break; | |
| 3154 case CSSPropertyAnimationIterationCount: | |
| 3155 value = parseAnimationIterationCount(); | |
| 3156 break; | |
| 3157 case CSSPropertyAnimationName: | |
| 3158 value = parseAnimationName(useLegacyParsing); | |
| 3159 break; | |
| 3160 case CSSPropertyAnimationPlayState: | |
| 3161 value = parseAnimationPlayState(); | |
| 3162 break; | |
| 3163 case CSSPropertyTransitionProperty: | |
| 3164 value = parseAnimationProperty(); | |
| 3165 break; | |
| 3166 case CSSPropertyAnimationTimingFunction: | |
| 3167 case CSSPropertyTransitionTimingFunction: | |
| 3168 value = parseAnimationTimingFunction(); | |
| 3169 break; | |
| 3170 default: | |
| 3171 ASSERT_NOT_REACHED(); | |
| 3172 return nullptr; | |
| 3173 } | |
| 3174 | |
| 3175 if (value) | |
| 3176 m_valueList->next(); | |
| 3177 return value.release(); | |
| 3178 } | |
| 3179 | |
| 3180 PassRefPtrWillBeRawPtr<CSSValueList> CSSPropertyParser::parseAnimationPropertyLi st(CSSPropertyID propId, bool useLegacyParsing) | |
| 3181 { | |
| 3182 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createCommaSeparated() ; | |
| 3183 while (true) { | |
| 3184 RefPtrWillBeRawPtr<CSSValue> value = parseAnimationProperty(propId, useL egacyParsing); | |
| 3185 if (!value) | |
| 3186 return nullptr; | |
| 3187 list->append(value.release()); | |
| 3188 if (!m_valueList->current()) | |
| 3189 break; | |
| 3190 if (!consumeComma(m_valueList) || !m_valueList->current()) | |
| 3191 return nullptr; | |
| 3192 } | |
| 3193 if (propId == CSSPropertyTransitionProperty && !isValidTransitionPropertyLis t(list.get())) | |
| 3194 return nullptr; | |
| 3195 ASSERT(list->length()); | |
| 3196 return list.release(); | |
| 3197 } | |
| 3198 | |
| 3199 static inline bool isCSSWideKeyword(const CSSParserValue& value) | |
| 3200 { | |
| 3201 return value.id == CSSValueInitial || value.id == CSSValueInherit || value.i d == CSSValueUnset || value.id == CSSValueDefault; | |
| 3202 } | |
| 3203 | |
| 3204 static inline bool isValidCustomIdentForGridPositions(const CSSParserValue& valu e) | |
| 3205 { | |
| 3206 // FIXME: we need a more general solution for <custom-ident> in all properti es. | |
| 3207 return value.m_unit == CSSParserValue::Identifier && value.id != CSSValueSpa n && value.id != CSSValueAuto && !isCSSWideKeyword(value); | |
| 3208 } | |
| 3209 | |
| 3210 // The function parses [ <integer> || <custom-ident> ] in <grid-line> (which can be stand alone or with 'span'). | |
| 3211 bool CSSPropertyParser::parseIntegerOrCustomIdentFromGridPosition(RefPtrWillBeRa wPtr<CSSPrimitiveValue>& numericValue, RefPtrWillBeRawPtr<CSSPrimitiveValue>& gr idLineName) | |
| 3212 { | |
| 3213 CSSParserValue* value = m_valueList->current(); | |
| 3214 if (validUnit(value, FInteger) && value->fValue) { | |
| 3215 numericValue = createPrimitiveNumericValue(value); | |
| 3216 value = m_valueList->next(); | |
| 3217 if (value && isValidCustomIdentForGridPositions(*value)) { | |
| 3218 gridLineName = createPrimitiveCustomIdentValue(m_valueList->current( )); | |
| 3219 m_valueList->next(); | |
| 3220 } | |
| 3221 return true; | |
| 3222 } | |
| 3223 | |
| 3224 if (isValidCustomIdentForGridPositions(*value)) { | |
| 3225 gridLineName = createPrimitiveCustomIdentValue(m_valueList->current()); | |
| 3226 value = m_valueList->next(); | |
| 3227 if (value && validUnit(value, FInteger) && value->fValue) { | |
| 3228 numericValue = createPrimitiveNumericValue(value); | |
| 3229 m_valueList->next(); | |
| 3230 } | |
| 3231 return true; | |
| 3232 } | |
| 3233 | |
| 3234 return false; | |
| 3235 } | |
| 3236 | |
| 3237 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseGridPosition() | |
| 3238 { | |
| 3239 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled()); | |
| 3240 | |
| 3241 CSSParserValue* value = m_valueList->current(); | |
| 3242 if (value->id == CSSValueAuto) { | |
| 3243 m_valueList->next(); | |
| 3244 return cssValuePool().createIdentifierValue(CSSValueAuto); | |
| 3245 } | |
| 3246 | |
| 3247 RefPtrWillBeRawPtr<CSSPrimitiveValue> numericValue = nullptr; | |
| 3248 RefPtrWillBeRawPtr<CSSPrimitiveValue> gridLineName = nullptr; | |
| 3249 bool hasSeenSpanKeyword = false; | |
| 3250 | |
| 3251 if (parseIntegerOrCustomIdentFromGridPosition(numericValue, gridLineName)) { | |
| 3252 value = m_valueList->current(); | |
| 3253 if (value && value->id == CSSValueSpan) { | |
| 3254 hasSeenSpanKeyword = true; | |
| 3255 m_valueList->next(); | |
| 3256 } | |
| 3257 } else if (value->id == CSSValueSpan) { | |
| 3258 hasSeenSpanKeyword = true; | |
| 3259 if (CSSParserValue* nextValue = m_valueList->next()) { | |
| 3260 if (!isForwardSlashOperator(nextValue) && !parseIntegerOrCustomIdent FromGridPosition(numericValue, gridLineName)) | |
| 3261 return nullptr; | |
| 3262 } | |
| 3263 } | |
| 3264 | |
| 3265 // Check that we have consumed all the value list. For shorthands, the parse r will pass | |
| 3266 // the whole value list (including the opposite position). | |
| 3267 if (m_valueList->current() && !isForwardSlashOperator(m_valueList->current() )) | |
| 3268 return nullptr; | |
| 3269 | |
| 3270 // If we didn't parse anything, this is not a valid grid position. | |
| 3271 if (!hasSeenSpanKeyword && !gridLineName && !numericValue) | |
| 3272 return nullptr; | |
| 3273 | |
| 3274 // Negative numbers are not allowed for span (but are for <integer>). | |
| 3275 if (hasSeenSpanKeyword && numericValue && numericValue->getIntValue() < 0) | |
| 3276 return nullptr; | |
| 3277 | |
| 3278 // For the <custom-ident> case. | |
| 3279 if (gridLineName && !numericValue && !hasSeenSpanKeyword) | |
| 3280 return cssValuePool().createValue(gridLineName->getStringValue(), CSSPri mitiveValue::UnitType::CustomIdentifier); | |
| 3281 | |
| 3282 RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createSpaceSeparated (); | |
| 3283 if (hasSeenSpanKeyword) | |
| 3284 values->append(cssValuePool().createIdentifierValue(CSSValueSpan)); | |
| 3285 if (numericValue) | |
| 3286 values->append(numericValue.release()); | |
| 3287 if (gridLineName) | |
| 3288 values->append(gridLineName.release()); | |
| 3289 ASSERT(values->length()); | |
| 3290 return values.release(); | |
| 3291 } | |
| 3292 | |
| 3293 static PassRefPtrWillBeRawPtr<CSSValue> gridMissingGridPositionValue(CSSValue* v alue) | |
| 3294 { | |
| 3295 if (value->isPrimitiveValue() && toCSSPrimitiveValue(value)->isCustomIdent() ) | |
| 3296 return value; | |
| 3297 | |
| 3298 return cssValuePool().createIdentifierValue(CSSValueAuto); | |
| 3299 } | |
| 3300 | |
| 3301 bool CSSPropertyParser::parseGridItemPositionShorthand(CSSPropertyID shorthandId , bool important) | |
| 3302 { | |
| 3303 ShorthandScope scope(this, shorthandId); | |
| 3304 const StylePropertyShorthand& shorthand = shorthandForProperty(shorthandId); | |
| 3305 ASSERT(shorthand.length() == 2); | |
| 3306 | |
| 3307 RefPtrWillBeRawPtr<CSSValue> startValue = parseGridPosition(); | |
| 3308 if (!startValue) | |
| 3309 return false; | |
| 3310 | |
| 3311 RefPtrWillBeRawPtr<CSSValue> endValue = nullptr; | |
| 3312 if (m_valueList->current()) { | |
| 3313 if (!isForwardSlashOperator(m_valueList->current())) | |
| 3314 return false; | |
| 3315 | |
| 3316 if (!m_valueList->next()) | |
| 3317 return false; | |
| 3318 | |
| 3319 endValue = parseGridPosition(); | |
| 3320 if (!endValue || m_valueList->current()) | |
| 3321 return false; | |
| 3322 } else { | |
| 3323 endValue = gridMissingGridPositionValue(startValue.get()); | |
| 3324 } | |
| 3325 | |
| 3326 addProperty(shorthand.properties()[0], startValue, important); | |
| 3327 addProperty(shorthand.properties()[1], endValue, important); | |
| 3328 return true; | |
| 3329 } | |
| 3330 | |
| 3331 bool CSSPropertyParser::parseGridTemplateRowsAndAreas(PassRefPtrWillBeRawPtr<CSS Value> templateColumns, bool important) | |
| 3332 { | |
| 3333 NamedGridAreaMap gridAreaMap; | |
| 3334 size_t rowCount = 0; | |
| 3335 size_t columnCount = 0; | |
| 3336 bool trailingIdentWasAdded = false; | |
| 3337 RefPtrWillBeRawPtr<CSSValueList> templateRows = CSSValueList::createSpaceSep arated(); | |
| 3338 | |
| 3339 // At least template-areas strings must be defined. | |
| 3340 if (!m_valueList->current()) | |
| 3341 return false; | |
| 3342 | |
| 3343 while (m_valueList->current()) { | |
| 3344 // Handle leading <custom-ident>*. | |
| 3345 if (!parseGridLineNames(*m_valueList, *templateRows, trailingIdentWasAdd ed ? toCSSGridLineNamesValue(templateRows->item(templateRows->length() - 1)) : n ullptr)) | |
| 3346 return false; | |
| 3347 | |
| 3348 // Handle a template-area's row. | |
| 3349 if (!parseGridTemplateAreasRow(gridAreaMap, rowCount, columnCount)) | |
| 3350 return false; | |
| 3351 ++rowCount; | |
| 3352 | |
| 3353 // Handle template-rows's track-size. | |
| 3354 if (m_valueList->current() && m_valueList->current()->unit() != CSSPrimi tiveValue::UnitType::String) { | |
| 3355 RefPtrWillBeRawPtr<CSSValue> value = parseGridTrackSize(*m_valueList ); | |
| 3356 if (!value) | |
| 3357 return false; | |
| 3358 templateRows->append(value); | |
| 3359 } else { | |
| 3360 templateRows->append(cssValuePool().createIdentifierValue(CSSValueAu to)); | |
| 3361 } | |
| 3362 | |
| 3363 // This will handle the trailing/leading <custom-ident>* in the grammar. | |
| 3364 if (!parseGridLineNames(*m_valueList, *templateRows)) | |
| 3365 return false; | |
| 3366 trailingIdentWasAdded = templateRows->item(templateRows->length() - 1)-> isGridLineNamesValue(); | |
| 3367 } | |
| 3368 | |
| 3369 // [<track-list> /]? | |
| 3370 if (templateColumns) | |
| 3371 addProperty(CSSPropertyGridTemplateColumns, templateColumns, important); | |
| 3372 else | |
| 3373 addProperty(CSSPropertyGridTemplateColumns, cssValuePool().createIdenti fierValue(CSSValueNone), important); | |
| 3374 | |
| 3375 // [<line-names>? <string> [<track-size> <line-names>]? ]+ | |
| 3376 RefPtrWillBeRawPtr<CSSValue> templateAreas = CSSGridTemplateAreasValue::crea te(gridAreaMap, rowCount, columnCount); | |
| 3377 addProperty(CSSPropertyGridTemplateAreas, templateAreas.release(), important ); | |
| 3378 addProperty(CSSPropertyGridTemplateRows, templateRows.release(), important); | |
| 3379 | |
| 3380 return true; | |
| 3381 } | |
| 3382 | |
| 3383 | |
| 3384 bool CSSPropertyParser::parseGridTemplateShorthand(bool important) | |
| 3385 { | |
| 3386 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled()); | |
| 3387 | |
| 3388 ShorthandScope scope(this, CSSPropertyGridTemplate); | |
| 3389 ASSERT(gridTemplateShorthand().length() == 3); | |
| 3390 | |
| 3391 // At least "none" must be defined. | |
| 3392 if (!m_valueList->current()) | |
| 3393 return false; | |
| 3394 | |
| 3395 bool firstValueIsNone = m_valueList->current()->id == CSSValueNone; | |
| 3396 | |
| 3397 // 1- 'none' case. | |
| 3398 if (firstValueIsNone && !m_valueList->next()) { | |
| 3399 addProperty(CSSPropertyGridTemplateColumns, cssValuePool().createIdentif ierValue(CSSValueNone), important); | |
| 3400 addProperty(CSSPropertyGridTemplateRows, cssValuePool().createIdentifier Value(CSSValueNone), important); | |
| 3401 addProperty(CSSPropertyGridTemplateAreas, cssValuePool().createIdentifie rValue(CSSValueNone), important); | |
| 3402 return true; | |
| 3403 } | |
| 3404 | |
| 3405 unsigned index = 0; | |
| 3406 RefPtrWillBeRawPtr<CSSValue> columnsValue = nullptr; | |
| 3407 if (firstValueIsNone) { | |
| 3408 columnsValue = cssValuePool().createIdentifierValue(CSSValueNone); | |
| 3409 } else { | |
| 3410 columnsValue = parseGridTrackList(); | |
| 3411 } | |
| 3412 | |
| 3413 // 2- <grid-template-columns> / <grid-template-columns> syntax. | |
| 3414 if (columnsValue) { | |
| 3415 if (!(m_valueList->current() && isForwardSlashOperator(m_valueList->curr ent()) && m_valueList->next())) | |
| 3416 return false; | |
| 3417 index = m_valueList->currentIndex(); | |
| 3418 if (RefPtrWillBeRawPtr<CSSValue> rowsValue = parseGridTrackList()) { | |
| 3419 if (m_valueList->current()) | |
| 3420 return false; | |
| 3421 addProperty(CSSPropertyGridTemplateColumns, columnsValue, important) ; | |
| 3422 addProperty(CSSPropertyGridTemplateRows, rowsValue, important); | |
| 3423 addProperty(CSSPropertyGridTemplateAreas, cssValuePool().createIdent ifierValue(CSSValueNone), important); | |
| 3424 return true; | |
| 3425 } | |
| 3426 } | |
| 3427 | |
| 3428 | |
| 3429 // 3- [<track-list> /]? [<line-names>? <string> [<track-size> <line-names>]? ]+ syntax. | |
| 3430 // The template-columns <track-list> can't be 'none'. | |
| 3431 if (firstValueIsNone) | |
| 3432 return false; | |
| 3433 // It requires to rewind parsing due to previous syntax failures. | |
| 3434 m_valueList->setCurrentIndex(index); | |
| 3435 return parseGridTemplateRowsAndAreas(columnsValue, important); | |
| 3436 } | |
| 3437 | |
| 3438 bool CSSPropertyParser::parseGridShorthand(bool important) | |
| 3439 { | |
| 3440 ShorthandScope scope(this, CSSPropertyGrid); | |
| 3441 ASSERT(shorthandForProperty(CSSPropertyGrid).length() == 6); | |
| 3442 | |
| 3443 // 1- <grid-template> | |
| 3444 if (parseGridTemplateShorthand(important)) { | |
| 3445 // It can only be specified the explicit or the implicit grid properties in a single grid declaration. | |
| 3446 // The sub-properties not specified are set to their initial value, as n ormal for shorthands. | |
| 3447 addProperty(CSSPropertyGridAutoFlow, cssValuePool().createImplicitInitia lValue(), important); | |
| 3448 addProperty(CSSPropertyGridAutoColumns, cssValuePool().createImplicitIni tialValue(), important); | |
| 3449 addProperty(CSSPropertyGridAutoRows, cssValuePool().createImplicitInitia lValue(), important); | |
| 3450 return true; | |
| 3451 } | |
| 3452 | |
| 3453 // Need to rewind parsing to explore the alternative syntax of this shorthan d. | |
| 3454 m_valueList->setCurrentIndex(0); | |
| 3455 | |
| 3456 // 2- <grid-auto-flow> [ <grid-auto-columns> [ / <grid-auto-rows> ]? ] | |
| 3457 if (!parseValue(CSSPropertyGridAutoFlow, important)) | |
| 3458 return false; | |
| 3459 | |
| 3460 RefPtrWillBeRawPtr<CSSValue> autoColumnsValue = nullptr; | |
| 3461 RefPtrWillBeRawPtr<CSSValue> autoRowsValue = nullptr; | |
| 3462 | |
| 3463 if (m_valueList->current()) { | |
| 3464 autoColumnsValue = parseGridTrackSize(*m_valueList); | |
| 3465 if (!autoColumnsValue) | |
| 3466 return false; | |
| 3467 if (m_valueList->current()) { | |
| 3468 if (!isForwardSlashOperator(m_valueList->current()) || !m_valueList- >next()) | |
| 3469 return false; | |
| 3470 autoRowsValue = parseGridTrackSize(*m_valueList); | |
| 3471 if (!autoRowsValue) | |
| 3472 return false; | |
| 3473 } | |
| 3474 if (m_valueList->current()) | |
| 3475 return false; | |
| 3476 } else { | |
| 3477 // Other omitted values are set to their initial values. | |
| 3478 autoColumnsValue = cssValuePool().createImplicitInitialValue(); | |
| 3479 autoRowsValue = cssValuePool().createImplicitInitialValue(); | |
| 3480 } | |
| 3481 | |
| 3482 // if <grid-auto-rows> value is omitted, it is set to the value specified fo r grid-auto-columns. | |
| 3483 if (!autoRowsValue) | |
| 3484 autoRowsValue = autoColumnsValue; | |
| 3485 | |
| 3486 addProperty(CSSPropertyGridAutoColumns, autoColumnsValue, important); | |
| 3487 addProperty(CSSPropertyGridAutoRows, autoRowsValue, important); | |
| 3488 | |
| 3489 // It can only be specified the explicit or the implicit grid properties in a single grid declaration. | |
| 3490 // The sub-properties not specified are set to their initial value, as norma l for shorthands. | |
| 3491 addProperty(CSSPropertyGridTemplateColumns, cssValuePool().createImplicitIni tialValue(), important); | |
| 3492 addProperty(CSSPropertyGridTemplateRows, cssValuePool().createImplicitInitia lValue(), important); | |
| 3493 addProperty(CSSPropertyGridTemplateAreas, cssValuePool().createImplicitIniti alValue(), important); | |
| 3494 | |
| 3495 return true; | |
| 3496 } | |
| 3497 | |
| 3498 bool CSSPropertyParser::parseGridAreaShorthand(bool important) | |
| 3499 { | |
| 3500 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled()); | |
| 3501 | |
| 3502 ShorthandScope scope(this, CSSPropertyGridArea); | |
| 3503 const StylePropertyShorthand& shorthand = gridAreaShorthand(); | |
| 3504 ASSERT_UNUSED(shorthand, shorthand.length() == 4); | |
| 3505 | |
| 3506 RefPtrWillBeRawPtr<CSSValue> rowStartValue = parseGridPosition(); | |
| 3507 if (!rowStartValue) | |
| 3508 return false; | |
| 3509 | |
| 3510 RefPtrWillBeRawPtr<CSSValue> columnStartValue = nullptr; | |
| 3511 if (!parseSingleGridAreaLonghand(columnStartValue)) | |
| 3512 return false; | |
| 3513 | |
| 3514 RefPtrWillBeRawPtr<CSSValue> rowEndValue = nullptr; | |
| 3515 if (!parseSingleGridAreaLonghand(rowEndValue)) | |
| 3516 return false; | |
| 3517 | |
| 3518 RefPtrWillBeRawPtr<CSSValue> columnEndValue = nullptr; | |
| 3519 if (!parseSingleGridAreaLonghand(columnEndValue)) | |
| 3520 return false; | |
| 3521 | |
| 3522 if (!columnStartValue) | |
| 3523 columnStartValue = gridMissingGridPositionValue(rowStartValue.get()); | |
| 3524 | |
| 3525 if (!rowEndValue) | |
| 3526 rowEndValue = gridMissingGridPositionValue(rowStartValue.get()); | |
| 3527 | |
| 3528 if (!columnEndValue) | |
| 3529 columnEndValue = gridMissingGridPositionValue(columnStartValue.get()); | |
| 3530 | |
| 3531 addProperty(CSSPropertyGridRowStart, rowStartValue, important); | |
| 3532 addProperty(CSSPropertyGridColumnStart, columnStartValue, important); | |
| 3533 addProperty(CSSPropertyGridRowEnd, rowEndValue, important); | |
| 3534 addProperty(CSSPropertyGridColumnEnd, columnEndValue, important); | |
| 3535 return true; | |
| 3536 } | |
| 3537 | |
| 3538 bool CSSPropertyParser::parseSingleGridAreaLonghand(RefPtrWillBeRawPtr<CSSValue> & property) | |
| 3539 { | |
| 3540 if (!m_valueList->current()) | |
| 3541 return true; | |
| 3542 | |
| 3543 if (!isForwardSlashOperator(m_valueList->current())) | |
| 3544 return false; | |
| 3545 | |
| 3546 if (!m_valueList->next()) | |
| 3547 return false; | |
| 3548 | |
| 3549 property = parseGridPosition(); | |
| 3550 return true; | |
| 3551 } | |
| 3552 | |
| 3553 static inline bool isClosingBracket(const CSSParserValue& value) | |
| 3554 { | |
| 3555 return value.m_unit == CSSParserValue::Operator && value.iValue == ']'; | |
| 3556 } | |
| 3557 | |
| 3558 bool CSSPropertyParser::parseGridLineNames(CSSParserValueList& inputList, CSSVal ueList& valueList, CSSGridLineNamesValue* previousNamedAreaTrailingLineNames) | |
| 3559 { | |
| 3560 if (!inputList.current() || inputList.current()->m_unit != CSSParserValue::O perator || inputList.current()->iValue != '[') | |
| 3561 return true; | |
| 3562 | |
| 3563 // Skip '[' | |
| 3564 inputList.next(); | |
| 3565 | |
| 3566 RefPtrWillBeRawPtr<CSSGridLineNamesValue> lineNames = previousNamedAreaTrail ingLineNames; | |
| 3567 if (!lineNames) | |
| 3568 lineNames = CSSGridLineNamesValue::create(); | |
| 3569 | |
| 3570 while (CSSParserValue* identValue = inputList.current()) { | |
| 3571 if (isClosingBracket(*identValue)) | |
| 3572 break; | |
| 3573 | |
| 3574 if (!isValidCustomIdentForGridPositions(*identValue)) | |
| 3575 return false; | |
| 3576 | |
| 3577 RefPtrWillBeRawPtr<CSSPrimitiveValue> lineName = createPrimitiveCustomId entValue(identValue); | |
| 3578 lineNames->append(lineName.release()); | |
| 3579 inputList.next(); | |
| 3580 } | |
| 3581 | |
| 3582 if (!inputList.current() || !isClosingBracket(*inputList.current())) | |
| 3583 return false; | |
| 3584 | |
| 3585 if (!previousNamedAreaTrailingLineNames) | |
| 3586 valueList.append(lineNames.release()); | |
| 3587 | |
| 3588 // Consume ']' | |
| 3589 inputList.next(); | |
| 3590 return true; | |
| 3591 } | |
| 3592 | |
| 3593 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseGridTrackList() | |
| 3594 { | |
| 3595 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled()); | |
| 3596 | |
| 3597 CSSParserValue* value = m_valueList->current(); | |
| 3598 if (value->id == CSSValueNone) { | |
| 3599 m_valueList->next(); | |
| 3600 return cssValuePool().createIdentifierValue(CSSValueNone); | |
| 3601 } | |
| 3602 | |
| 3603 RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createSpaceSeparated (); | |
| 3604 // Handle leading <custom-ident>*. | |
| 3605 if (!parseGridLineNames(*m_valueList, *values)) | |
| 3606 return nullptr; | |
| 3607 | |
| 3608 bool seenTrackSizeOrRepeatFunction = false; | |
| 3609 while (CSSParserValue* currentValue = m_valueList->current()) { | |
| 3610 if (isForwardSlashOperator(currentValue)) | |
| 3611 break; | |
| 3612 if (currentValue->m_unit == CSSParserValue::Function && currentValue->fu nction->id == CSSValueRepeat) { | |
| 3613 if (!parseGridTrackRepeatFunction(*values)) | |
| 3614 return nullptr; | |
| 3615 seenTrackSizeOrRepeatFunction = true; | |
| 3616 } else { | |
| 3617 RefPtrWillBeRawPtr<CSSValue> value = parseGridTrackSize(*m_valueList ); | |
| 3618 if (!value) | |
| 3619 return nullptr; | |
| 3620 values->append(value); | |
| 3621 seenTrackSizeOrRepeatFunction = true; | |
| 3622 } | |
| 3623 // This will handle the trailing <custom-ident>* in the grammar. | |
| 3624 if (!parseGridLineNames(*m_valueList, *values)) | |
| 3625 return nullptr; | |
| 3626 } | |
| 3627 | |
| 3628 // We should have found a <track-size> or else it is not a valid <track-list > | |
| 3629 if (!seenTrackSizeOrRepeatFunction) | |
| 3630 return nullptr; | |
| 3631 | |
| 3632 return values; | |
| 3633 } | |
| 3634 | |
| 3635 bool CSSPropertyParser::parseGridTrackRepeatFunction(CSSValueList& list) | |
| 3636 { | |
| 3637 CSSParserValueList* arguments = m_valueList->current()->function->args.get() ; | |
| 3638 if (!arguments || arguments->size() < 3 || !validUnit(arguments->valueAt(0), FPositiveInteger) || !isComma(arguments->valueAt(1))) | |
| 3639 return false; | |
| 3640 | |
| 3641 ASSERT(arguments->valueAt(0)->fValue > 0); | |
| 3642 size_t repetitions = clampTo<size_t>(arguments->valueAt(0)->fValue, 0, kGrid MaxTracks); | |
| 3643 | |
| 3644 RefPtrWillBeRawPtr<CSSValueList> repeatedValues = CSSValueList::createSpaceS eparated(); | |
| 3645 arguments->next(); // Skip the repetition count. | |
| 3646 arguments->next(); // Skip the comma. | |
| 3647 | |
| 3648 // Handle leading <custom-ident>*. | |
| 3649 if (!parseGridLineNames(*arguments, *repeatedValues)) | |
| 3650 return false; | |
| 3651 | |
| 3652 size_t numberOfTracks = 0; | |
| 3653 while (arguments->current()) { | |
| 3654 RefPtrWillBeRawPtr<CSSValue> trackSize = parseGridTrackSize(*arguments); | |
| 3655 if (!trackSize) | |
| 3656 return false; | |
| 3657 | |
| 3658 repeatedValues->append(trackSize); | |
| 3659 ++numberOfTracks; | |
| 3660 | |
| 3661 // This takes care of any trailing <custom-ident>* in the grammar. | |
| 3662 if (!parseGridLineNames(*arguments, *repeatedValues)) | |
| 3663 return false; | |
| 3664 } | |
| 3665 | |
| 3666 // We should have found at least one <track-size> or else it is not a valid <track-list>. | |
| 3667 if (!numberOfTracks) | |
| 3668 return false; | |
| 3669 | |
| 3670 // We clamp the number of repetitions to a multiple of the repeat() track li st's size, while staying below the max | |
| 3671 // grid size. | |
| 3672 repetitions = std::min(repetitions, kGridMaxTracks / numberOfTracks); | |
| 3673 | |
| 3674 for (size_t i = 0; i < repetitions; ++i) { | |
| 3675 for (size_t j = 0; j < repeatedValues->length(); ++j) | |
| 3676 list.append(repeatedValues->item(j)); | |
| 3677 } | |
| 3678 | |
| 3679 // parseGridTrackSize iterated over the repeat arguments, move to the next v alue. | |
| 3680 m_valueList->next(); | |
| 3681 return true; | |
| 3682 } | |
| 3683 | |
| 3684 | |
| 3685 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseGridTrackSize(CSSParser ValueList& inputList) | |
| 3686 { | |
| 3687 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled()); | |
| 3688 | |
| 3689 CSSParserValue* currentValue = inputList.current(); | |
| 3690 inputList.next(); | |
| 3691 | |
| 3692 if (currentValue->id == CSSValueAuto) | |
| 3693 return cssValuePool().createIdentifierValue(CSSValueAuto); | |
| 3694 | |
| 3695 if (currentValue->m_unit == CSSParserValue::Function && currentValue->functi on->id == CSSValueMinmax) { | |
| 3696 // The spec defines the following grammar: minmax( <track-breadth> , <tr ack-breadth> ) | |
| 3697 CSSParserValueList* arguments = currentValue->function->args.get(); | |
| 3698 if (!arguments || arguments->size() != 3 || !isComma(arguments->valueAt( 1))) | |
| 3699 return nullptr; | |
| 3700 | |
| 3701 RefPtrWillBeRawPtr<CSSPrimitiveValue> minTrackBreadth = parseGridBreadth (arguments->valueAt(0)); | |
| 3702 if (!minTrackBreadth) | |
| 3703 return nullptr; | |
| 3704 | |
| 3705 RefPtrWillBeRawPtr<CSSPrimitiveValue> maxTrackBreadth = parseGridBreadth (arguments->valueAt(2)); | |
| 3706 if (!maxTrackBreadth) | |
| 3707 return nullptr; | |
| 3708 | |
| 3709 RefPtrWillBeRawPtr<CSSFunctionValue> result = CSSFunctionValue::create(C SSValueMinmax); | |
| 3710 result->append(minTrackBreadth); | |
| 3711 result->append(maxTrackBreadth); | |
| 3712 return result.release(); | |
| 3713 } | |
| 3714 | |
| 3715 return parseGridBreadth(currentValue); | |
| 3716 } | |
| 3717 | |
| 3718 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::parseGridBreadth(CS SParserValue* currentValue) | |
| 3719 { | |
| 3720 if (currentValue->id == CSSValueMinContent || currentValue->id == CSSValueMa xContent || currentValue->id == CSSValueAuto) | |
| 3721 return cssValuePool().createIdentifierValue(currentValue->id); | |
| 3722 | |
| 3723 if (currentValue->unit() == CSSPrimitiveValue::UnitType::Fraction) { | |
| 3724 double flexValue = currentValue->fValue; | |
| 3725 | |
| 3726 // Fractional unit is a non-negative dimension. | |
| 3727 if (flexValue <= 0) | |
| 3728 return nullptr; | |
| 3729 | |
| 3730 return cssValuePool().createValue(flexValue, CSSPrimitiveValue::UnitType ::Fraction); | |
| 3731 } | |
| 3732 | |
| 3733 if (!validUnit(currentValue, FNonNeg | FLength | FPercent)) | |
| 3734 return nullptr; | |
| 3735 | |
| 3736 return createPrimitiveNumericValue(currentValue); | |
| 3737 } | |
| 3738 | |
| 3739 static Vector<String> parseGridTemplateAreasColumnNames(const String& gridRowNam es) | |
| 3740 { | |
| 3741 ASSERT(!gridRowNames.isEmpty()); | |
| 3742 Vector<String> columnNames; | |
| 3743 // Using StringImpl to avoid checks and indirection in every call to String: :operator[]. | |
| 3744 StringImpl& text = *gridRowNames.impl(); | |
| 3745 | |
| 3746 StringBuilder areaName; | |
| 3747 for (unsigned i = 0; i < text.length(); ++i) { | |
| 3748 if (text[i] == ' ') { | |
| 3749 if (!areaName.isEmpty()) { | |
| 3750 columnNames.append(areaName.toString()); | |
| 3751 areaName.clear(); | |
| 3752 } | |
| 3753 continue; | |
| 3754 } | |
| 3755 if (text[i] == '.') { | |
| 3756 if (areaName == ".") | |
| 3757 continue; | |
| 3758 if (!areaName.isEmpty()) { | |
| 3759 columnNames.append(areaName.toString()); | |
| 3760 areaName.clear(); | |
| 3761 } | |
| 3762 } else { | |
| 3763 if (areaName == ".") { | |
| 3764 columnNames.append(areaName.toString()); | |
| 3765 areaName.clear(); | |
| 3766 } | |
| 3767 } | |
| 3768 | |
| 3769 areaName.append(text[i]); | |
| 3770 } | |
| 3771 | |
| 3772 if (!areaName.isEmpty()) | |
| 3773 columnNames.append(areaName.toString()); | |
| 3774 | |
| 3775 return columnNames; | |
| 3776 } | |
| 3777 | |
| 3778 bool CSSPropertyParser::parseGridTemplateAreasRow(NamedGridAreaMap& gridAreaMap, const size_t rowCount, size_t& columnCount) | |
| 3779 { | |
| 3780 CSSParserValue* currentValue = m_valueList->current(); | |
| 3781 if (!currentValue || currentValue->unit() != CSSPrimitiveValue::UnitType::St ring) | |
| 3782 return false; | |
| 3783 | |
| 3784 String gridRowNames = currentValue->string; | |
| 3785 if (gridRowNames.isEmpty() || gridRowNames.containsOnlyWhitespace()) | |
| 3786 return false; | |
| 3787 | |
| 3788 Vector<String> columnNames = parseGridTemplateAreasColumnNames(gridRowNames) ; | |
| 3789 if (!columnCount) { | |
| 3790 columnCount = columnNames.size(); | |
| 3791 ASSERT(columnCount); | |
| 3792 } else if (columnCount != columnNames.size()) { | |
| 3793 // The declaration is invalid is all the rows don't have the number of c olumns. | |
| 3794 return false; | |
| 3795 } | |
| 3796 | |
| 3797 for (size_t currentCol = 0; currentCol < columnCount; ++currentCol) { | |
| 3798 const String& gridAreaName = columnNames[currentCol]; | |
| 3799 | |
| 3800 // Unamed areas are always valid (we consider them to be 1x1). | |
| 3801 if (gridAreaName == ".") | |
| 3802 continue; | |
| 3803 | |
| 3804 // We handle several grid areas with the same name at once to simplify t he validation code. | |
| 3805 size_t lookAheadCol; | |
| 3806 for (lookAheadCol = currentCol; lookAheadCol < (columnCount - 1); ++look AheadCol) { | |
| 3807 if (columnNames[lookAheadCol + 1] != gridAreaName) | |
| 3808 break; | |
| 3809 } | |
| 3810 | |
| 3811 NamedGridAreaMap::iterator gridAreaIt = gridAreaMap.find(gridAreaName); | |
| 3812 if (gridAreaIt == gridAreaMap.end()) { | |
| 3813 gridAreaMap.add(gridAreaName, GridCoordinate(GridSpan(rowCount, rowC ount), GridSpan(currentCol, lookAheadCol))); | |
| 3814 } else { | |
| 3815 GridCoordinate& gridCoordinate = gridAreaIt->value; | |
| 3816 | |
| 3817 // The following checks test that the grid area is a single filled-i n rectangle. | |
| 3818 // 1. The new row is adjacent to the previously parsed row. | |
| 3819 if (rowCount != gridCoordinate.rows.resolvedFinalPosition.next().toI nt()) | |
| 3820 return false; | |
| 3821 | |
| 3822 // 2. The new area starts at the same position as the previously par sed area. | |
| 3823 if (currentCol != gridCoordinate.columns.resolvedInitialPosition.toI nt()) | |
| 3824 return false; | |
| 3825 | |
| 3826 // 3. The new area ends at the same position as the previously parse d area. | |
| 3827 if (lookAheadCol != gridCoordinate.columns.resolvedFinalPosition.toI nt()) | |
| 3828 return false; | |
| 3829 | |
| 3830 ++gridCoordinate.rows.resolvedFinalPosition; | |
| 3831 } | |
| 3832 currentCol = lookAheadCol; | |
| 3833 } | |
| 3834 | |
| 3835 m_valueList->next(); | |
| 3836 return true; | |
| 3837 } | |
| 3838 | |
| 3839 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseGridTemplateAreas() | |
| 3840 { | |
| 3841 if (m_valueList->current() && m_valueList->current()->id == CSSValueNone) { | |
| 3842 m_valueList->next(); | |
| 3843 return cssValuePool().createIdentifierValue(CSSValueNone); | |
| 3844 } | |
| 3845 | |
| 3846 NamedGridAreaMap gridAreaMap; | |
| 3847 size_t rowCount = 0; | |
| 3848 size_t columnCount = 0; | |
| 3849 | |
| 3850 while (m_valueList->current()) { | |
| 3851 if (!parseGridTemplateAreasRow(gridAreaMap, rowCount, columnCount)) | |
| 3852 return nullptr; | |
| 3853 ++rowCount; | |
| 3854 } | |
| 3855 | |
| 3856 if (!rowCount || !columnCount) | |
| 3857 return nullptr; | |
| 3858 | |
| 3859 return CSSGridTemplateAreasValue::create(gridAreaMap, rowCount, columnCount) ; | |
| 3860 } | |
| 3861 | |
| 3862 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseGridAutoFlow(CSSParserV alueList& list) | |
| 3863 { | |
| 3864 // [ row | column ] || dense | |
| 3865 ASSERT(RuntimeEnabledFeatures::cssGridLayoutEnabled()); | |
| 3866 | |
| 3867 CSSParserValue* value = list.current(); | |
| 3868 if (!value) | |
| 3869 return nullptr; | |
| 3870 | |
| 3871 RefPtrWillBeRawPtr<CSSValueList> parsedValues = CSSValueList::createSpaceSep arated(); | |
| 3872 | |
| 3873 // First parameter. | |
| 3874 CSSValueID firstId = value->id; | |
| 3875 if (firstId != CSSValueRow && firstId != CSSValueColumn && firstId != CSSVal ueDense) | |
| 3876 return nullptr; | |
| 3877 parsedValues->append(cssValuePool().createIdentifierValue(firstId)); | |
| 3878 | |
| 3879 // Second parameter, if any. | |
| 3880 value = list.next(); | |
| 3881 if (value) { | |
| 3882 switch (firstId) { | |
| 3883 case CSSValueRow: | |
| 3884 case CSSValueColumn: | |
| 3885 if (value->id != CSSValueDense) | |
| 3886 return parsedValues; | |
| 3887 break; | |
| 3888 case CSSValueDense: | |
| 3889 if (value->id != CSSValueRow && value->id != CSSValueColumn) | |
| 3890 return parsedValues; | |
| 3891 break; | |
| 3892 default: | |
| 3893 return parsedValues; | |
| 3894 } | |
| 3895 parsedValues->append(cssValuePool().createIdentifierValue(value->id)); | |
| 3896 list.next(); | |
| 3897 } | |
| 3898 | |
| 3899 return parsedValues; | |
| 3900 } | |
| 3901 | |
| 3902 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseCounterContent(CSSParse rValueList* args, bool counters) | |
| 3903 { | |
| 3904 unsigned numArgs = args->size(); | |
| 3905 if (counters && numArgs != 3 && numArgs != 5) | |
| 3906 return nullptr; | |
| 3907 if (!counters && numArgs != 1 && numArgs != 3) | |
| 3908 return nullptr; | |
| 3909 | |
| 3910 CSSParserValue* i = args->current(); | |
| 3911 if (i->m_unit != CSSParserValue::Identifier) | |
| 3912 return nullptr; | |
| 3913 RefPtrWillBeRawPtr<CSSPrimitiveValue> identifier = createPrimitiveCustomIden tValue(i); | |
| 3914 | |
| 3915 RefPtrWillBeRawPtr<CSSPrimitiveValue> separator = nullptr; | |
| 3916 if (!counters) | |
| 3917 separator = cssValuePool().createValue(String(), CSSPrimitiveValue::Unit Type::CustomIdentifier); | |
| 3918 else { | |
| 3919 args->next(); | |
| 3920 if (!consumeComma(args)) | |
| 3921 return nullptr; | |
| 3922 | |
| 3923 i = args->current(); | |
| 3924 if (i->unit() != CSSPrimitiveValue::UnitType::String) | |
| 3925 return nullptr; | |
| 3926 | |
| 3927 separator = createPrimitiveCustomIdentValue(i); | |
| 3928 } | |
| 3929 | |
| 3930 RefPtrWillBeRawPtr<CSSPrimitiveValue> listStyle = nullptr; | |
| 3931 i = args->next(); | |
| 3932 if (!i) // Make the list style default decimal | |
| 3933 listStyle = cssValuePool().createIdentifierValue(CSSValueDecimal); | |
| 3934 else { | |
| 3935 if (!consumeComma(args)) | |
| 3936 return nullptr; | |
| 3937 | |
| 3938 i = args->current(); | |
| 3939 if (i->m_unit != CSSParserValue::Identifier) | |
| 3940 return nullptr; | |
| 3941 | |
| 3942 CSSValueID listStyleID = CSSValueInvalid; | |
| 3943 if (i->id == CSSValueNone || (i->id >= CSSValueDisc && i->id <= CSSValue KatakanaIroha)) | |
| 3944 listStyleID = i->id; | |
| 3945 else | |
| 3946 return nullptr; | |
| 3947 | |
| 3948 listStyle = cssValuePool().createIdentifierValue(listStyleID); | |
| 3949 } | |
| 3950 | |
| 3951 return CSSCounterValue::create(identifier.release(), listStyle.release(), se parator.release()); | |
| 3952 } | |
| 3953 | |
| 3954 PassRefPtrWillBeRawPtr<CSSQuadValue> CSSPropertyParser::parseClipShape() | |
| 3955 { | |
| 3956 CSSParserValue* value = m_valueList->current(); | |
| 3957 CSSParserValueList* args = value->function->args.get(); | |
| 3958 | |
| 3959 if (value->function->id != CSSValueRect || !args) | |
| 3960 return nullptr; | |
| 3961 | |
| 3962 // rect(t, r, b, l) || rect(t r b l) | |
| 3963 if (args->size() != 4 && args->size() != 7) | |
| 3964 return nullptr; | |
| 3965 int i = 0; | |
| 3966 CSSParserValue* a = args->current(); | |
| 3967 | |
| 3968 RefPtrWillBeRawPtr<CSSPrimitiveValue> top = nullptr; | |
| 3969 RefPtrWillBeRawPtr<CSSPrimitiveValue> right = nullptr; | |
| 3970 RefPtrWillBeRawPtr<CSSPrimitiveValue> bottom = nullptr; | |
| 3971 RefPtrWillBeRawPtr<CSSPrimitiveValue> left = nullptr; | |
| 3972 while (a) { | |
| 3973 if (a->id != CSSValueAuto && !validUnit(a, FLength | FUnitlessQuirk)) | |
| 3974 return nullptr; | |
| 3975 RefPtrWillBeRawPtr<CSSPrimitiveValue> length = a->id == CSSValueAuto ? | |
| 3976 cssValuePool().createIdentifierValue(CSSValueAuto) : | |
| 3977 createPrimitiveNumericValue(a); | |
| 3978 if (i == 0) | |
| 3979 top = length; | |
| 3980 else if (i == 1) | |
| 3981 right = length; | |
| 3982 else if (i == 2) | |
| 3983 bottom = length; | |
| 3984 else | |
| 3985 left = length; | |
| 3986 a = args->next(); | |
| 3987 if (a && args->size() == 7) { | |
| 3988 if (!consumeComma(args)) | |
| 3989 return nullptr; | |
| 3990 a = args->current(); | |
| 3991 } | |
| 3992 i++; | |
| 3993 } | |
| 3994 m_valueList->next(); | |
| 3995 return CSSQuadValue::create(top.release(), right.release(), bottom.release() , left.release(), CSSQuadValue::SerializeAsRect); | |
| 3996 } | |
| 3997 | |
| 3998 static void completeBorderRadii(RefPtrWillBeRawPtr<CSSPrimitiveValue> radii[4]) | |
| 3999 { | |
| 4000 if (radii[3]) | |
| 4001 return; | |
| 4002 if (!radii[2]) { | |
| 4003 if (!radii[1]) | |
| 4004 radii[1] = radii[0]; | |
| 4005 radii[2] = radii[0]; | |
| 4006 } | |
| 4007 radii[3] = radii[1]; | |
| 4008 } | |
| 4009 | |
| 4010 // FIXME: This should be refactored with parseBorderRadius. | |
| 4011 // parseBorderRadius contains support for some legacy radius construction. | |
| 4012 PassRefPtrWillBeRawPtr<CSSBasicShape> CSSPropertyParser::parseInsetRoundedCorner s(PassRefPtrWillBeRawPtr<CSSBasicShapeInset> shape, CSSParserValueList* args) | |
| 4013 { | |
| 4014 CSSParserValue* argument = args->next(); | |
| 4015 | |
| 4016 if (!argument) | |
| 4017 return nullptr; | |
| 4018 | |
| 4019 Vector<CSSParserValue*> radiusArguments; | |
| 4020 while (argument) { | |
| 4021 radiusArguments.append(argument); | |
| 4022 argument = args->next(); | |
| 4023 } | |
| 4024 | |
| 4025 unsigned num = radiusArguments.size(); | |
| 4026 if (!num || num > 9) | |
| 4027 return nullptr; | |
| 4028 | |
| 4029 // FIXME: Refactor completeBorderRadii and the array | |
| 4030 RefPtrWillBeRawPtr<CSSPrimitiveValue> radii[2][4]; | |
| 4031 #if ENABLE(OILPAN) | |
| 4032 // Zero initialize the array of raw pointers. | |
| 4033 memset(&radii, 0, sizeof(radii)); | |
| 4034 #endif | |
| 4035 | |
| 4036 unsigned indexAfterSlash = 0; | |
| 4037 for (unsigned i = 0; i < num; ++i) { | |
| 4038 CSSParserValue* value = radiusArguments.at(i); | |
| 4039 if (value->m_unit == CSSParserValue::Operator) { | |
| 4040 if (value->iValue != '/') | |
| 4041 return nullptr; | |
| 4042 | |
| 4043 if (!i || indexAfterSlash || i + 1 == num) | |
| 4044 return nullptr; | |
| 4045 | |
| 4046 indexAfterSlash = i + 1; | |
| 4047 completeBorderRadii(radii[0]); | |
| 4048 continue; | |
| 4049 } | |
| 4050 | |
| 4051 if (i - indexAfterSlash >= 4) | |
| 4052 return nullptr; | |
| 4053 | |
| 4054 if (!validUnit(value, FLength | FPercent | FNonNeg)) | |
| 4055 return nullptr; | |
| 4056 | |
| 4057 RefPtrWillBeRawPtr<CSSPrimitiveValue> radius = createPrimitiveNumericVal ue(value); | |
| 4058 | |
| 4059 if (!indexAfterSlash) | |
| 4060 radii[0][i] = radius; | |
| 4061 else | |
| 4062 radii[1][i - indexAfterSlash] = radius.release(); | |
| 4063 } | |
| 4064 | |
| 4065 if (!indexAfterSlash) { | |
| 4066 completeBorderRadii(radii[0]); | |
| 4067 for (unsigned i = 0; i < 4; ++i) | |
| 4068 radii[1][i] = radii[0][i]; | |
| 4069 } else { | |
| 4070 completeBorderRadii(radii[1]); | |
| 4071 } | |
| 4072 shape->setTopLeftRadius(CSSValuePair::create(radii[0][0].release(), radii[1] [0].release(), CSSValuePair::DropIdenticalValues)); | |
| 4073 shape->setTopRightRadius(CSSValuePair::create(radii[0][1].release(), radii[1 ][1].release(), CSSValuePair::DropIdenticalValues)); | |
| 4074 shape->setBottomRightRadius(CSSValuePair::create(radii[0][2].release(), radi i[1][2].release(), CSSValuePair::DropIdenticalValues)); | |
| 4075 shape->setBottomLeftRadius(CSSValuePair::create(radii[0][3].release(), radii [1][3].release(), CSSValuePair::DropIdenticalValues)); | |
| 4076 | |
| 4077 return shape; | |
| 4078 } | |
| 4079 | |
| 4080 PassRefPtrWillBeRawPtr<CSSBasicShape> CSSPropertyParser::parseBasicShapeInset(CS SParserValueList* args) | |
| 4081 { | |
| 4082 ASSERT(args); | |
| 4083 | |
| 4084 RefPtrWillBeRawPtr<CSSBasicShapeInset> shape = CSSBasicShapeInset::create(); | |
| 4085 | |
| 4086 CSSParserValue* argument = args->current(); | |
| 4087 WillBeHeapVector<RefPtrWillBeMember<CSSPrimitiveValue>> widthArguments; | |
| 4088 bool hasRoundedInset = false; | |
| 4089 | |
| 4090 while (argument) { | |
| 4091 if (argument->m_unit == CSSParserValue::Identifier && argument->id == CS SValueRound) { | |
| 4092 hasRoundedInset = true; | |
| 4093 break; | |
| 4094 } | |
| 4095 | |
| 4096 Units unitFlags = FLength | FPercent; | |
| 4097 if (!validUnit(argument, unitFlags) || widthArguments.size() > 4) | |
| 4098 return nullptr; | |
| 4099 | |
| 4100 widthArguments.append(createPrimitiveNumericValue(argument)); | |
| 4101 argument = args->next(); | |
| 4102 } | |
| 4103 | |
| 4104 switch (widthArguments.size()) { | |
| 4105 case 1: { | |
| 4106 shape->updateShapeSize1Value(widthArguments[0].get()); | |
| 4107 break; | |
| 4108 } | |
| 4109 case 2: { | |
| 4110 shape->updateShapeSize2Values(widthArguments[0].get(), widthArguments[1] .get()); | |
| 4111 break; | |
| 4112 } | |
| 4113 case 3: { | |
| 4114 shape->updateShapeSize3Values(widthArguments[0].get(), widthArguments[1] .get(), widthArguments[2].get()); | |
| 4115 break; | |
| 4116 } | |
| 4117 case 4: { | |
| 4118 shape->updateShapeSize4Values(widthArguments[0].get(), widthArguments[1] .get(), widthArguments[2].get(), widthArguments[3].get()); | |
| 4119 break; | |
| 4120 } | |
| 4121 default: | |
| 4122 return nullptr; | |
| 4123 } | |
| 4124 | |
| 4125 if (hasRoundedInset) | |
| 4126 return parseInsetRoundedCorners(shape, args); | |
| 4127 return shape; | |
| 4128 } | |
| 4129 | |
| 4130 static bool isContentDistributionKeyword(CSSValueID id) | |
| 4131 { | |
| 4132 return id == CSSValueSpaceBetween || id == CSSValueSpaceAround | |
| 4133 || id == CSSValueSpaceEvenly || id == CSSValueStretch; | |
| 4134 } | |
| 4135 | |
| 4136 static bool isContentPositionKeyword(CSSValueID id) | |
| 4137 { | |
| 4138 return id == CSSValueStart || id == CSSValueEnd || id == CSSValueCenter | |
| 4139 || id == CSSValueFlexStart || id == CSSValueFlexEnd | |
| 4140 || id == CSSValueLeft || id == CSSValueRight; | |
| 4141 } | |
| 4142 | |
| 4143 static bool isBaselinePositionKeyword(CSSValueID id) | |
| 4144 { | |
| 4145 return id == CSSValueBaseline || id == CSSValueLastBaseline; | |
| 4146 } | |
| 4147 | |
| 4148 static bool isAlignmentOverflowKeyword(CSSValueID id) | |
| 4149 { | |
| 4150 return id == CSSValueTrue || id == CSSValueSafe; | |
| 4151 } | |
| 4152 | |
| 4153 static bool isItemPositionKeyword(CSSValueID id) | |
| 4154 { | |
| 4155 return id == CSSValueStart || id == CSSValueEnd || id == CSSValueCenter | |
| 4156 || id == CSSValueSelfStart || id == CSSValueSelfEnd || id == CSSValueFle xStart | |
| 4157 || id == CSSValueFlexEnd || id == CSSValueLeft || id == CSSValueRight; | |
| 4158 } | |
| 4159 | |
| 4160 bool CSSPropertyParser::parseLegacyPosition(CSSPropertyID propId, bool important ) | |
| 4161 { | |
| 4162 // [ legacy && [ left | right | center ] | |
| 4163 | |
| 4164 CSSParserValue* value = m_valueList->current(); | |
| 4165 ASSERT(value); | |
| 4166 | |
| 4167 if (value->id == CSSValueLegacy) { | |
| 4168 value = m_valueList->next(); | |
| 4169 if (!value) | |
| 4170 return false; | |
| 4171 if (value->id != CSSValueCenter && value->id != CSSValueLeft && value->i d != CSSValueRight) | |
| 4172 return false; | |
| 4173 } else if (value->id == CSSValueCenter || value->id == CSSValueLeft || value ->id == CSSValueRight) { | |
| 4174 if (!m_valueList->next() || m_valueList->current()->id != CSSValueLegacy ) | |
| 4175 return false; | |
| 4176 } else { | |
| 4177 return false; | |
| 4178 } | |
| 4179 | |
| 4180 addProperty(propId, CSSValuePair::create(cssValuePool().createIdentifierValu e(CSSValueLegacy), cssValuePool().createIdentifierValue(value->id), CSSValuePair ::DropIdenticalValues), important); | |
| 4181 return !m_valueList->next(); | |
| 4182 } | |
| 4183 | |
| 4184 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseContentDistributionOver flowPosition() | |
| 4185 { | |
| 4186 // auto | <baseline-position> | <content-distribution> || [ <overflow-positi on>? && <content-position> ] | |
| 4187 // <baseline-position> = baseline | last-baseline; | |
| 4188 // <content-distribution> = space-between | space-around | space-evenly | st retch; | |
| 4189 // <content-position> = center | start | end | flex-start | flex-end | left | right; | |
| 4190 // <overflow-position> = true | safe | |
| 4191 | |
| 4192 // auto | <baseline-position> | |
| 4193 CSSParserValue* value = m_valueList->current(); | |
| 4194 if (value->id == CSSValueAuto || isBaselinePositionKeyword(value->id)) { | |
| 4195 m_valueList->next(); | |
| 4196 return CSSContentDistributionValue::create(CSSValueInvalid, value->id, C SSValueInvalid); | |
| 4197 } | |
| 4198 | |
| 4199 CSSValueID distribution = CSSValueInvalid; | |
| 4200 CSSValueID position = CSSValueInvalid; | |
| 4201 CSSValueID overflow = CSSValueInvalid; | |
| 4202 while (value) { | |
| 4203 if (isContentDistributionKeyword(value->id)) { | |
| 4204 if (distribution != CSSValueInvalid) | |
| 4205 return nullptr; | |
| 4206 distribution = value->id; | |
| 4207 } else if (isContentPositionKeyword(value->id)) { | |
| 4208 if (position != CSSValueInvalid) | |
| 4209 return nullptr; | |
| 4210 position = value->id; | |
| 4211 } else if (isAlignmentOverflowKeyword(value->id)) { | |
| 4212 if (overflow != CSSValueInvalid) | |
| 4213 return nullptr; | |
| 4214 overflow = value->id; | |
| 4215 } else { | |
| 4216 return nullptr; | |
| 4217 } | |
| 4218 value = m_valueList->next(); | |
| 4219 } | |
| 4220 | |
| 4221 // The grammar states that we should have at least <content-distribution> or | |
| 4222 // <content-position> ( <content-distribution> || <content-position> ). | |
| 4223 if (position == CSSValueInvalid && distribution == CSSValueInvalid) | |
| 4224 return nullptr; | |
| 4225 | |
| 4226 // The grammar states that <overflow-position> must be associated to <conten t-position>. | |
| 4227 if (overflow != CSSValueInvalid && position == CSSValueInvalid) | |
| 4228 return nullptr; | |
| 4229 | |
| 4230 return CSSContentDistributionValue::create(distribution, position, overflow) ; | |
| 4231 } | |
| 4232 | |
| 4233 bool CSSPropertyParser::parseItemPositionOverflowPosition(CSSPropertyID propId, bool important) | |
| 4234 { | |
| 4235 // auto | stretch | <baseline-position> | [<item-position> && <overflow-posi tion>? ] | |
| 4236 // <baseline-position> = baseline | last-baseline; | |
| 4237 // <item-position> = center | start | end | self-start | self-end | flex-sta rt | flex-end | left | right; | |
| 4238 // <overflow-position> = true | safe | |
| 4239 | |
| 4240 CSSParserValue* value = m_valueList->current(); | |
| 4241 ASSERT(value); | |
| 4242 | |
| 4243 if (value->id == CSSValueAuto || value->id == CSSValueStretch || isBaselineP ositionKeyword(value->id)) { | |
| 4244 if (m_valueList->next()) | |
| 4245 return false; | |
| 4246 | |
| 4247 addProperty(propId, cssValuePool().createIdentifierValue(value->id), imp ortant); | |
| 4248 return true; | |
| 4249 } | |
| 4250 | |
| 4251 RefPtrWillBeRawPtr<CSSPrimitiveValue> position = nullptr; | |
| 4252 RefPtrWillBeRawPtr<CSSPrimitiveValue> overflowAlignmentKeyword = nullptr; | |
| 4253 if (isItemPositionKeyword(value->id)) { | |
| 4254 position = cssValuePool().createIdentifierValue(value->id); | |
| 4255 value = m_valueList->next(); | |
| 4256 if (value) { | |
| 4257 if (isAlignmentOverflowKeyword(value->id)) | |
| 4258 overflowAlignmentKeyword = cssValuePool().createIdentifierValue( value->id); | |
| 4259 else | |
| 4260 return false; | |
| 4261 } | |
| 4262 } else if (isAlignmentOverflowKeyword(value->id)) { | |
| 4263 overflowAlignmentKeyword = cssValuePool().createIdentifierValue(value->i d); | |
| 4264 value = m_valueList->next(); | |
| 4265 if (value && isItemPositionKeyword(value->id)) | |
| 4266 position = cssValuePool().createIdentifierValue(value->id); | |
| 4267 else | |
| 4268 return false; | |
| 4269 } else { | |
| 4270 return false; | |
| 4271 } | |
| 4272 | |
| 4273 if (m_valueList->next()) | |
| 4274 return false; | |
| 4275 | |
| 4276 ASSERT(position); | |
| 4277 if (overflowAlignmentKeyword) | |
| 4278 addProperty(propId, CSSValuePair::create(position, overflowAlignmentKeyw ord, CSSValuePair::DropIdenticalValues), important); | |
| 4279 else | |
| 4280 addProperty(propId, position.release(), important); | |
| 4281 | |
| 4282 return true; | |
| 4283 } | |
| 4284 | |
| 4285 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::parseShapeRadius(CS SParserValue* value) | |
| 4286 { | |
| 4287 if (value->id == CSSValueClosestSide || value->id == CSSValueFarthestSide) | |
| 4288 return cssValuePool().createIdentifierValue(value->id); | |
| 4289 | |
| 4290 if (!validUnit(value, FLength | FPercent | FNonNeg)) | |
| 4291 return nullptr; | |
| 4292 | |
| 4293 return createPrimitiveNumericValue(value); | |
| 4294 } | |
| 4295 | |
| 4296 PassRefPtrWillBeRawPtr<CSSBasicShape> CSSPropertyParser::parseBasicShapeCircle(C SSParserValueList* args) | |
| 4297 { | |
| 4298 ASSERT(args); | |
| 4299 | |
| 4300 // circle(radius) | |
| 4301 // circle(radius at <position>) | |
| 4302 // circle(at <position>) | |
| 4303 // where position defines centerX and centerY using a CSS <position> data ty pe. | |
| 4304 RefPtrWillBeRawPtr<CSSBasicShapeCircle> shape = CSSBasicShapeCircle::create( ); | |
| 4305 | |
| 4306 for (CSSParserValue* argument = args->current(); argument; argument = args-> next()) { | |
| 4307 // The call to parseFillPosition below should consume all of the | |
| 4308 // arguments except the first two. Thus, and index greater than one | |
| 4309 // indicates an invalid production. | |
| 4310 if (args->currentIndex() > 1) | |
| 4311 return nullptr; | |
| 4312 | |
| 4313 if (!args->currentIndex() && argument->id != CSSValueAt) { | |
| 4314 if (RefPtrWillBeRawPtr<CSSPrimitiveValue> radius = parseShapeRadius( argument)) { | |
| 4315 shape->setRadius(radius); | |
| 4316 continue; | |
| 4317 } | |
| 4318 | |
| 4319 return nullptr; | |
| 4320 } | |
| 4321 | |
| 4322 if (argument->id == CSSValueAt && args->next()) { | |
| 4323 RefPtrWillBeRawPtr<CSSValue> centerX = nullptr; | |
| 4324 RefPtrWillBeRawPtr<CSSValue> centerY = nullptr; | |
| 4325 parseFillPosition(args, centerX, centerY); | |
| 4326 if (centerX && centerY && !args->current()) { | |
| 4327 shape->setCenterX(centerX); | |
| 4328 shape->setCenterY(centerY); | |
| 4329 } else { | |
| 4330 return nullptr; | |
| 4331 } | |
| 4332 } else { | |
| 4333 return nullptr; | |
| 4334 } | |
| 4335 } | |
| 4336 | |
| 4337 return shape; | |
| 4338 } | |
| 4339 | |
| 4340 PassRefPtrWillBeRawPtr<CSSBasicShape> CSSPropertyParser::parseBasicShapeEllipse( CSSParserValueList* args) | |
| 4341 { | |
| 4342 ASSERT(args); | |
| 4343 | |
| 4344 // ellipse(radiusX) | |
| 4345 // ellipse(radiusX at <position>) | |
| 4346 // ellipse(radiusX radiusY) | |
| 4347 // ellipse(radiusX radiusY at <position>) | |
| 4348 // ellipse(at <position>) | |
| 4349 // where position defines centerX and centerY using a CSS <position> data ty pe. | |
| 4350 RefPtrWillBeRawPtr<CSSBasicShapeEllipse> shape = CSSBasicShapeEllipse::creat e(); | |
| 4351 | |
| 4352 for (CSSParserValue* argument = args->current(); argument; argument = args-> next()) { | |
| 4353 // The call to parseFillPosition below should consume all of the | |
| 4354 // arguments except the first three. Thus, an index greater than two | |
| 4355 // indicates an invalid production. | |
| 4356 if (args->currentIndex() > 2) | |
| 4357 return nullptr; | |
| 4358 | |
| 4359 if (args->currentIndex() < 2 && argument->id != CSSValueAt) { | |
| 4360 if (RefPtrWillBeRawPtr<CSSPrimitiveValue> radius = parseShapeRadius( argument)) { | |
| 4361 if (!shape->radiusX()) | |
| 4362 shape->setRadiusX(radius); | |
| 4363 else | |
| 4364 shape->setRadiusY(radius); | |
| 4365 continue; | |
| 4366 } | |
| 4367 | |
| 4368 return nullptr; | |
| 4369 } | |
| 4370 | |
| 4371 if (argument->id != CSSValueAt || !args->next()) // expecting ellipse(.. at <position>) | |
| 4372 return nullptr; | |
| 4373 RefPtrWillBeRawPtr<CSSValue> centerX = nullptr; | |
| 4374 RefPtrWillBeRawPtr<CSSValue> centerY = nullptr; | |
| 4375 parseFillPosition(args, centerX, centerY); | |
| 4376 if (!centerX || !centerY || args->current()) | |
| 4377 return nullptr; | |
| 4378 | |
| 4379 shape->setCenterX(centerX); | |
| 4380 shape->setCenterY(centerY); | |
| 4381 } | |
| 4382 | |
| 4383 return shape; | |
| 4384 } | |
| 4385 | |
| 4386 PassRefPtrWillBeRawPtr<CSSBasicShape> CSSPropertyParser::parseBasicShapePolygon( CSSParserValueList* args) | |
| 4387 { | |
| 4388 ASSERT(args); | |
| 4389 | |
| 4390 unsigned size = args->size(); | |
| 4391 if (!size) | |
| 4392 return nullptr; | |
| 4393 | |
| 4394 RefPtrWillBeRawPtr<CSSBasicShapePolygon> shape = CSSBasicShapePolygon::creat e(); | |
| 4395 | |
| 4396 CSSParserValue* argument = args->current(); | |
| 4397 if (argument->id == CSSValueEvenodd || argument->id == CSSValueNonzero) { | |
| 4398 shape->setWindRule(argument->id == CSSValueEvenodd ? RULE_EVENODD : RULE _NONZERO); | |
| 4399 args->next(); | |
| 4400 | |
| 4401 if (!consumeComma(args)) | |
| 4402 return nullptr; | |
| 4403 | |
| 4404 size -= 2; | |
| 4405 } | |
| 4406 | |
| 4407 // <length> <length>, ... <length> <length> -> each pair has 3 elements exce pt the last one | |
| 4408 if (!size || (size % 3) - 2) | |
| 4409 return nullptr; | |
| 4410 | |
| 4411 while (true) { | |
| 4412 CSSParserValue* argumentX = args->current(); | |
| 4413 if (!argumentX || !validUnit(argumentX, FLength | FPercent)) | |
| 4414 return nullptr; | |
| 4415 RefPtrWillBeRawPtr<CSSPrimitiveValue> xLength = createPrimitiveNumericVa lue(argumentX); | |
| 4416 | |
| 4417 CSSParserValue* argumentY = args->next(); | |
| 4418 if (!argumentY || !validUnit(argumentY, FLength | FPercent)) | |
| 4419 return nullptr; | |
| 4420 RefPtrWillBeRawPtr<CSSPrimitiveValue> yLength = createPrimitiveNumericVa lue(argumentY); | |
| 4421 | |
| 4422 shape->appendPoint(xLength.release(), yLength.release()); | |
| 4423 | |
| 4424 if (!args->next()) | |
| 4425 break; | |
| 4426 if (!consumeComma(args)) | |
| 4427 return nullptr; | |
| 4428 } | |
| 4429 | |
| 4430 return shape; | |
| 4431 } | |
| 4432 | |
| 4433 static bool isBoxValue(CSSValueID valueId) | |
| 4434 { | |
| 4435 switch (valueId) { | |
| 4436 case CSSValueContentBox: | |
| 4437 case CSSValuePaddingBox: | |
| 4438 case CSSValueBorderBox: | |
| 4439 case CSSValueMarginBox: | |
| 4440 return true; | |
| 4441 default: | |
| 4442 break; | |
| 4443 } | |
| 4444 | |
| 4445 return false; | |
| 4446 } | |
| 4447 | |
| 4448 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseShapeProperty(CSSProper tyID propId) | |
| 4449 { | |
| 4450 RefPtrWillBeRawPtr<CSSValue> imageValue = nullptr; | |
| 4451 if (parseFillImage(m_valueList, imageValue)) { | |
| 4452 m_valueList->next(); | |
| 4453 return imageValue.release(); | |
| 4454 } | |
| 4455 | |
| 4456 return parseBasicShapeAndOrBox(); | |
| 4457 } | |
| 4458 | |
| 4459 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseBasicShapeAndOrBox() | |
| 4460 { | |
| 4461 CSSParserValue* value = m_valueList->current(); | |
| 4462 | |
| 4463 bool shapeFound = false; | |
| 4464 bool boxFound = false; | |
| 4465 CSSValueID valueId; | |
| 4466 | |
| 4467 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated() ; | |
| 4468 for (unsigned i = 0; i < 2; ++i) { | |
| 4469 if (!value) | |
| 4470 break; | |
| 4471 valueId = value->id; | |
| 4472 if (value->m_unit == CSSParserValue::Function && !shapeFound) { | |
| 4473 // parseBasicShape already asks for the next value list item. | |
| 4474 RefPtrWillBeRawPtr<CSSPrimitiveValue> shapeValue = parseBasicShape() ; | |
| 4475 if (!shapeValue) | |
| 4476 return nullptr; | |
| 4477 list->append(shapeValue.release()); | |
| 4478 shapeFound = true; | |
| 4479 } else if (isBoxValue(valueId) && !boxFound) { | |
| 4480 list->append(parseValidPrimitive(valueId, value)); | |
| 4481 boxFound = true; | |
| 4482 m_valueList->next(); | |
| 4483 } else { | |
| 4484 return nullptr; | |
| 4485 } | |
| 4486 | |
| 4487 value = m_valueList->current(); | |
| 4488 } | |
| 4489 | |
| 4490 if (m_valueList->current()) | |
| 4491 return nullptr; | |
| 4492 return list.release(); | |
| 4493 } | |
| 4494 | |
| 4495 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::parseBasicShape() | |
| 4496 { | |
| 4497 CSSParserValue* value = m_valueList->current(); | |
| 4498 ASSERT(value->m_unit == CSSParserValue::Function); | |
| 4499 CSSParserValueList* args = value->function->args.get(); | |
| 4500 | |
| 4501 if (!args) | |
| 4502 return nullptr; | |
| 4503 | |
| 4504 RefPtrWillBeRawPtr<CSSBasicShape> shape = nullptr; | |
| 4505 if (value->function->id == CSSValueCircle) | |
| 4506 shape = parseBasicShapeCircle(args); | |
| 4507 else if (value->function->id == CSSValueEllipse) | |
| 4508 shape = parseBasicShapeEllipse(args); | |
| 4509 else if (value->function->id == CSSValuePolygon) | |
| 4510 shape = parseBasicShapePolygon(args); | |
| 4511 else if (value->function->id == CSSValueInset) | |
| 4512 shape = parseBasicShapeInset(args); | |
| 4513 | |
| 4514 if (!shape) | |
| 4515 return nullptr; | |
| 4516 | |
| 4517 m_valueList->next(); | |
| 4518 | |
| 4519 return cssValuePool().createValue(shape.release()); | |
| 4520 } | |
| 4521 | |
| 4522 // [ 'font-style' || 'font-variant' || 'font-weight' ]? 'font-size' [ / 'line-he ight' ]? 'font-family' | |
| 4523 bool CSSPropertyParser::parseFont(bool important) | |
| 4524 { | |
| 4525 // Let's check if there is an inherit or initial somewhere in the shorthand. | |
| 4526 for (unsigned i = 0; i < m_valueList->size(); ++i) { | |
| 4527 if (m_valueList->valueAt(i)->id == CSSValueInherit || m_valueList->value At(i)->id == CSSValueInitial) | |
| 4528 return false; | |
| 4529 } | |
| 4530 | |
| 4531 ShorthandScope scope(this, CSSPropertyFont); | |
| 4532 // Optional font-style, font-variant and font-weight. | |
| 4533 bool fontStyleParsed = false; | |
| 4534 bool fontVariantParsed = false; | |
| 4535 bool fontWeightParsed = false; | |
| 4536 bool fontStretchParsed = false; | |
| 4537 CSSParserValue* value = m_valueList->current(); | |
| 4538 for (; value; value = m_valueList->next()) { | |
| 4539 if (!fontStyleParsed && CSSParserFastPaths::isValidKeywordPropertyAndVal ue(CSSPropertyFontStyle, value->id)) { | |
| 4540 addProperty(CSSPropertyFontStyle, cssValuePool().createIdentifierVal ue(value->id), important); | |
| 4541 fontStyleParsed = true; | |
| 4542 } else if (!fontVariantParsed && (value->id == CSSValueNormal || value-> id == CSSValueSmallCaps)) { | |
| 4543 // Font variant in the shorthand is particular, it only accepts norm al or small-caps. | |
| 4544 addProperty(CSSPropertyFontVariant, cssValuePool().createIdentifierV alue(value->id), important); | |
| 4545 fontVariantParsed = true; | |
| 4546 } else if (!fontWeightParsed && parseFontWeight(important)) { | |
| 4547 fontWeightParsed = true; | |
| 4548 } else if (!fontStretchParsed && CSSParserFastPaths::isValidKeywordPrope rtyAndValue(CSSPropertyFontStretch, value->id)) { | |
| 4549 addProperty(CSSPropertyFontStretch, cssValuePool().createIdentifierV alue(value->id), important); | |
| 4550 fontStretchParsed = true; | |
| 4551 } else { | |
| 4552 break; | |
| 4553 } | |
| 4554 } | |
| 4555 | |
| 4556 if (!value) | |
| 4557 return false; | |
| 4558 | |
| 4559 if (!fontStyleParsed) | |
| 4560 addProperty(CSSPropertyFontStyle, cssValuePool().createIdentifierValue(C SSValueNormal), important, true); | |
| 4561 if (!fontVariantParsed) | |
| 4562 addProperty(CSSPropertyFontVariant, cssValuePool().createIdentifierValue (CSSValueNormal), important, true); | |
| 4563 if (!fontWeightParsed) | |
| 4564 addProperty(CSSPropertyFontWeight, cssValuePool().createIdentifierValue( CSSValueNormal), important, true); | |
| 4565 if (!fontStretchParsed) | |
| 4566 addProperty(CSSPropertyFontStretch, cssValuePool().createIdentifierValue (CSSValueNormal), important, true); | |
| 4567 | |
| 4568 // Now a font size _must_ come. | |
| 4569 // <absolute-size> | <relative-size> | <length> | <percentage> | inherit | |
| 4570 if (!parseFontSize(important)) | |
| 4571 return false; | |
| 4572 | |
| 4573 value = m_valueList->current(); | |
| 4574 if (!value) | |
| 4575 return false; | |
| 4576 | |
| 4577 if (isForwardSlashOperator(value)) { | |
| 4578 // The line-height property. | |
| 4579 value = m_valueList->next(); | |
| 4580 if (!value) | |
| 4581 return false; | |
| 4582 RefPtrWillBeRawPtr<CSSPrimitiveValue> lineHeight = parseLineHeight(); | |
| 4583 if (!lineHeight) | |
| 4584 return false; | |
| 4585 addProperty(CSSPropertyLineHeight, lineHeight.release(), important); | |
| 4586 } else { | |
| 4587 addProperty(CSSPropertyLineHeight, cssValuePool().createIdentifierValue( CSSValueNormal), important, true); | |
| 4588 } | |
| 4589 | |
| 4590 // Font family must come now. | |
| 4591 RefPtrWillBeRawPtr<CSSValue> parsedFamilyValue = parseFontFamily(); | |
| 4592 if (!parsedFamilyValue) | |
| 4593 return false; | |
| 4594 | |
| 4595 addProperty(CSSPropertyFontFamily, parsedFamilyValue.release(), important); | |
| 4596 | |
| 4597 // FIXME: http://www.w3.org/TR/2011/WD-css3-fonts-20110324/#font-prop requir es that | |
| 4598 // "font-stretch", "font-size-adjust", and "font-kerning" be reset to their initial values | |
| 4599 // but we don't seem to support them at the moment. They should also be adde d here once implemented. | |
| 4600 if (m_valueList->current()) | |
| 4601 return false; | |
| 4602 | |
| 4603 return true; | |
| 4604 } | |
| 4605 | |
| 4606 bool CSSPropertyParser::parseSystemFont(bool important) | |
| 4607 { | |
| 4608 CSSValueID systemFontID = m_valueList->valueAt(0)->id; | |
| 4609 ASSERT(systemFontID >= CSSValueCaption && systemFontID <= CSSValueStatusBar) ; | |
| 4610 if (m_valueList->next()) | |
| 4611 return false; | |
| 4612 | |
| 4613 FontStyle fontStyle = FontStyleNormal; | |
| 4614 FontWeight fontWeight = FontWeightNormal; | |
| 4615 float fontSize = 0; | |
| 4616 AtomicString fontFamily; | |
| 4617 LayoutTheme::theme().systemFont(systemFontID, fontStyle, fontWeight, fontSiz e, fontFamily); | |
| 4618 | |
| 4619 ShorthandScope scope(this, CSSPropertyFont); | |
| 4620 addProperty(CSSPropertyFontStyle, cssValuePool().createIdentifierValue(fontS tyle == FontStyleItalic ? CSSValueItalic : CSSValueNormal), important); | |
| 4621 addProperty(CSSPropertyFontWeight, cssValuePool().createValue(fontWeight), i mportant); | |
| 4622 addProperty(CSSPropertyFontSize, cssValuePool().createValue(fontSize, CSSPri mitiveValue::UnitType::Pixels), important); | |
| 4623 RefPtrWillBeRawPtr<CSSValueList> fontFamilyList = CSSValueList::createCommaS eparated(); | |
| 4624 fontFamilyList->append(cssValuePool().createFontFamilyValue(fontFamily)); | |
| 4625 addProperty(CSSPropertyFontFamily, fontFamilyList.release(), important); | |
| 4626 | |
| 4627 addProperty(CSSPropertyFontStretch, cssValuePool().createIdentifierValue(CSS ValueNormal), important); | |
| 4628 addProperty(CSSPropertyFontVariant, cssValuePool().createIdentifierValue(CSS ValueNormal), important); | |
| 4629 addProperty(CSSPropertyLineHeight, cssValuePool().createIdentifierValue(CSSV alueNormal), important); | |
| 4630 return true; | |
| 4631 } | |
| 4632 | |
| 4633 class FontFamilyValueBuilder { | |
| 4634 STACK_ALLOCATED(); | |
| 4635 public: | |
| 4636 FontFamilyValueBuilder(CSSValueList* list) | |
| 4637 : m_list(list) | |
| 4638 { | |
| 4639 } | |
| 4640 | |
| 4641 void add(const CSSParserString& string) | |
| 4642 { | |
| 4643 if (!m_builder.isEmpty()) | |
| 4644 m_builder.append(' '); | |
| 4645 | |
| 4646 if (string.is8Bit()) { | |
| 4647 m_builder.append(string.characters8(), string.length()); | |
| 4648 return; | |
| 4649 } | |
| 4650 | |
| 4651 m_builder.append(string.characters16(), string.length()); | |
| 4652 } | |
| 4653 | |
| 4654 void commit() | |
| 4655 { | |
| 4656 if (m_builder.isEmpty()) | |
| 4657 return; | |
| 4658 m_list->append(cssValuePool().createFontFamilyValue(m_builder.toString() )); | |
| 4659 m_builder.clear(); | |
| 4660 } | |
| 4661 | |
| 4662 private: | |
| 4663 StringBuilder m_builder; | |
| 4664 RawPtrWillBeMember<CSSValueList> m_list; | |
| 4665 }; | |
| 4666 | |
| 4667 PassRefPtrWillBeRawPtr<CSSValueList> CSSPropertyParser::parseFontFamily() | |
| 4668 { | |
| 4669 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createCommaSeparated() ; | |
| 4670 CSSParserValue* value = m_valueList->current(); | |
| 4671 | |
| 4672 FontFamilyValueBuilder familyBuilder(list.get()); | |
| 4673 bool inFamily = false; | |
| 4674 | |
| 4675 while (value) { | |
| 4676 CSSParserValue* nextValue = m_valueList->next(); | |
| 4677 bool nextValBreaksFont = !nextValue || isComma(nextValue); | |
| 4678 bool nextValIsFontName = nextValue && | |
| 4679 ((nextValue->id >= CSSValueSerif && nextValue->id <= CSSValueWebkitB ody) || | |
| 4680 (nextValue->unit() == CSSPrimitiveValue::UnitType::String || nextVal ue->m_unit == CSSParserValue::Identifier)); | |
| 4681 | |
| 4682 if (isCSSWideKeyword(*value) && !inFamily) { | |
| 4683 if (nextValBreaksFont) | |
| 4684 return nullptr; | |
| 4685 else if (nextValIsFontName) | |
| 4686 value = nextValue; | |
| 4687 continue; | |
| 4688 } | |
| 4689 | |
| 4690 if (value->id >= CSSValueSerif && value->id <= CSSValueWebkitBody) { | |
| 4691 if (inFamily) | |
| 4692 familyBuilder.add(value->string); | |
| 4693 else if (nextValBreaksFont || !nextValIsFontName) | |
| 4694 list->append(cssValuePool().createIdentifierValue(value->id)); | |
| 4695 else { | |
| 4696 familyBuilder.commit(); | |
| 4697 familyBuilder.add(value->string); | |
| 4698 inFamily = true; | |
| 4699 } | |
| 4700 } else if (value->unit() == CSSPrimitiveValue::UnitType::String) { | |
| 4701 // Strings never share in a family name. | |
| 4702 inFamily = false; | |
| 4703 familyBuilder.commit(); | |
| 4704 list->append(cssValuePool().createFontFamilyValue(value->string)); | |
| 4705 } else if (value->m_unit == CSSParserValue::Identifier) { | |
| 4706 if (inFamily) | |
| 4707 familyBuilder.add(value->string); | |
| 4708 else if (nextValBreaksFont || !nextValIsFontName) | |
| 4709 list->append(cssValuePool().createFontFamilyValue(value->string) ); | |
| 4710 else { | |
| 4711 familyBuilder.commit(); | |
| 4712 familyBuilder.add(value->string); | |
| 4713 inFamily = true; | |
| 4714 } | |
| 4715 } else { | |
| 4716 break; | |
| 4717 } | |
| 4718 | |
| 4719 if (!nextValue) | |
| 4720 break; | |
| 4721 | |
| 4722 if (nextValBreaksFont) { | |
| 4723 value = m_valueList->next(); | |
| 4724 familyBuilder.commit(); | |
| 4725 inFamily = false; | |
| 4726 } | |
| 4727 else if (nextValIsFontName) | |
| 4728 value = nextValue; | |
| 4729 else | |
| 4730 break; | |
| 4731 } | |
| 4732 familyBuilder.commit(); | |
| 4733 if (!list->length() || (m_ruleType == StyleRule::FontFace && list->length() > 1)) | |
| 4734 list = nullptr; | |
| 4735 return list.release(); | |
| 4736 } | |
| 4737 | |
| 4738 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::parseLineHeight() | |
| 4739 { | |
| 4740 CSSParserValue* value = m_valueList->current(); | |
| 4741 CSSValueID id = value->id; | |
| 4742 | |
| 4743 // normal | <number> | <length> | <percentage> | inherit | |
| 4744 if (id == CSSValueNormal) { | |
| 4745 m_valueList->next(); | |
| 4746 return cssValuePool().createIdentifierValue(id); | |
| 4747 } | |
| 4748 | |
| 4749 if (!validUnit(value, FNumber | FLength | FPercent | FNonNeg)) | |
| 4750 return nullptr; | |
| 4751 // The line-height property can accept both percents and numbers but additiv e opertaions are | |
| 4752 // not permitted on them in calc() expressions. | |
| 4753 if (m_parsedCalculation && m_parsedCalculation->category() == CalcPercentNum ber) { | |
| 4754 m_parsedCalculation.release(); | |
| 4755 return nullptr; | |
| 4756 } | |
| 4757 m_valueList->next(); | |
| 4758 return createPrimitiveNumericValue(value); | |
| 4759 } | |
| 4760 | |
| 4761 bool CSSPropertyParser::parseFontSize(bool important) | |
| 4762 { | |
| 4763 CSSParserValue* value = m_valueList->current(); | |
| 4764 CSSValueID id = value->id; | |
| 4765 bool validPrimitive = false; | |
| 4766 // <absolute-size> | <relative-size> | <length> | <percentage> | inherit | |
| 4767 if (id >= CSSValueXxSmall && id <= CSSValueLarger) | |
| 4768 validPrimitive = true; | |
| 4769 else | |
| 4770 validPrimitive = validUnit(value, FLength | FPercent | FNonNeg | (inShor thand() ? FUnknown : FUnitlessQuirk)); | |
| 4771 if (validPrimitive && (!m_valueList->next() || inShorthand())) | |
| 4772 addProperty(CSSPropertyFontSize, parseValidPrimitive(id, value), importa nt); | |
| 4773 return validPrimitive; | |
| 4774 } | |
| 4775 | |
| 4776 bool CSSPropertyParser::parseFontVariant(bool important) | |
| 4777 { | |
| 4778 RefPtrWillBeRawPtr<CSSValueList> values = nullptr; | |
| 4779 if (m_valueList->size() > 1) | |
| 4780 values = CSSValueList::createCommaSeparated(); | |
| 4781 bool expectComma = false; | |
| 4782 for (CSSParserValue* val = m_valueList->current(); val; val = m_valueList->c urrent()) { | |
| 4783 RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue = nullptr; | |
| 4784 if (!expectComma) { | |
| 4785 expectComma = true; | |
| 4786 if (val->id == CSSValueNormal || val->id == CSSValueSmallCaps) | |
| 4787 parsedValue = cssValuePool().createIdentifierValue(val->id); | |
| 4788 else if (val->id == CSSValueAll && !values) { | |
| 4789 // FIXME: CSSPropertyParser::parseFontVariant() implements | |
| 4790 // the old css3 draft: | |
| 4791 // http://www.w3.org/TR/2002/WD-css3-webfonts-20020802/#font-var iant | |
| 4792 // 'all' is only allowed in @font-face and with no other values. Make a value list to | |
| 4793 // indicate that we are in the @font-face case. | |
| 4794 values = CSSValueList::createCommaSeparated(); | |
| 4795 parsedValue = cssValuePool().createIdentifierValue(val->id); | |
| 4796 } | |
| 4797 } else if (consumeComma(m_valueList)) { | |
| 4798 expectComma = false; | |
| 4799 continue; | |
| 4800 } | |
| 4801 | |
| 4802 if (!parsedValue) | |
| 4803 return false; | |
| 4804 | |
| 4805 m_valueList->next(); | |
| 4806 | |
| 4807 if (values) | |
| 4808 values->append(parsedValue.release()); | |
| 4809 else { | |
| 4810 addProperty(CSSPropertyFontVariant, parsedValue.release(), important ); | |
| 4811 return true; | |
| 4812 } | |
| 4813 } | |
| 4814 | |
| 4815 if (values && values->length()) { | |
| 4816 if (m_ruleType != StyleRule::FontFace) | |
| 4817 return false; | |
| 4818 addProperty(CSSPropertyFontVariant, values.release(), important); | |
| 4819 return true; | |
| 4820 } | |
| 4821 | |
| 4822 return false; | |
| 4823 } | |
| 4824 | |
| 4825 bool CSSPropertyParser::parseFontWeight(bool important) | |
| 4826 { | |
| 4827 CSSParserValue* value = m_valueList->current(); | |
| 4828 if (value->id >= CSSValueNormal && value->id <= CSSValueLighter) { | |
| 4829 addProperty(CSSPropertyFontWeight, cssValuePool().createIdentifierValue( value->id), important); | |
| 4830 return true; | |
| 4831 } | |
| 4832 if (value->unit() == CSSPrimitiveValue::UnitType::Number) { | |
| 4833 int weight = static_cast<int>(value->fValue); | |
| 4834 if (!(weight % 100) && weight >= 100 && weight <= 900) { | |
| 4835 addProperty(CSSPropertyFontWeight, cssValuePool().createIdentifierVa lue(static_cast<CSSValueID>(CSSValue100 + weight / 100 - 1)), important); | |
| 4836 return true; | |
| 4837 } | |
| 4838 } | |
| 4839 return false; | |
| 4840 } | |
| 4841 | |
| 4842 bool CSSPropertyParser::parseFontFaceSrcURI(CSSValueList* valueList) | |
| 4843 { | |
| 4844 RefPtrWillBeRawPtr<CSSFontFaceSrcValue> uriValue(CSSFontFaceSrcValue::create (completeURL(m_valueList->current()->string), m_context.shouldCheckContentSecuri tyPolicy())); | |
| 4845 uriValue->setReferrer(m_context.referrer()); | |
| 4846 | |
| 4847 CSSParserValue* value = m_valueList->next(); | |
| 4848 if (!value || value->m_unit != CSSParserValue::Function || value->function-> id != CSSValueFormat) { | |
| 4849 valueList->append(uriValue.release()); | |
| 4850 return true; | |
| 4851 } | |
| 4852 | |
| 4853 // FIXME: http://www.w3.org/TR/2011/WD-css3-fonts-20111004/ says that format () contains a comma-separated list of strings, | |
| 4854 // but CSSFontFaceSrcValue stores only one format. Allowing one format for n ow. | |
| 4855 CSSParserValueList* args = value->function->args.get(); | |
| 4856 if (!args || args->size() != 1 || (args->current()->unit() != CSSPrimitiveVa lue::UnitType::String && args->current()->m_unit != CSSParserValue::Identifier)) | |
| 4857 return false; | |
| 4858 uriValue->setFormat(args->current()->string); | |
| 4859 valueList->append(uriValue.release()); | |
| 4860 m_valueList->next(); | |
| 4861 return true; | |
| 4862 } | |
| 4863 | |
| 4864 bool CSSPropertyParser::parseFontFaceSrcLocal(CSSValueList* valueList) | |
| 4865 { | |
| 4866 CSSParserValueList* args = m_valueList->current()->function->args.get(); | |
| 4867 if (!args || !args->size()) | |
| 4868 return false; | |
| 4869 m_valueList->next(); | |
| 4870 | |
| 4871 ContentSecurityPolicyDisposition shouldCheckContentSecurityPolicy = m_contex t.shouldCheckContentSecurityPolicy(); | |
| 4872 if (args->size() == 1 && args->current()->unit() == CSSPrimitiveValue::UnitT ype::String) { | |
| 4873 valueList->append(CSSFontFaceSrcValue::createLocal(args->current()->stri ng, shouldCheckContentSecurityPolicy)); | |
| 4874 } else if (args->current()->m_unit == CSSParserValue::Identifier) { | |
| 4875 StringBuilder builder; | |
| 4876 for (CSSParserValue* localValue = args->current(); localValue; localValu e = args->next()) { | |
| 4877 if (localValue->m_unit != CSSParserValue::Identifier) | |
| 4878 return false; | |
| 4879 if (!builder.isEmpty()) | |
| 4880 builder.append(' '); | |
| 4881 builder.append(localValue->string); | |
| 4882 } | |
| 4883 valueList->append(CSSFontFaceSrcValue::createLocal(builder.toString(), s houldCheckContentSecurityPolicy)); | |
| 4884 } else | |
| 4885 return false; | |
| 4886 | |
| 4887 return true; | |
| 4888 } | |
| 4889 | |
| 4890 PassRefPtrWillBeRawPtr<CSSValueList> CSSPropertyParser::parseFontFaceSrc() | |
| 4891 { | |
| 4892 RefPtrWillBeRawPtr<CSSValueList> values(CSSValueList::createCommaSeparated() ); | |
| 4893 | |
| 4894 while (true) { | |
| 4895 CSSParserValue* value = m_valueList->current(); | |
| 4896 if (!value) | |
| 4897 return nullptr; | |
| 4898 if (value->unit() == CSSPrimitiveValue::UnitType::URI) { | |
| 4899 if (!parseFontFaceSrcURI(values.get())) | |
| 4900 return nullptr; | |
| 4901 } else if (value->m_unit == CSSParserValue::Function && value->function- >id == CSSValueLocal) { | |
| 4902 if (!parseFontFaceSrcLocal(values.get())) | |
| 4903 return nullptr; | |
| 4904 } else { | |
| 4905 return nullptr; | |
| 4906 } | |
| 4907 | |
| 4908 if (!m_valueList->current()) | |
| 4909 return values.release(); | |
| 4910 if (!consumeComma(m_valueList)) | |
| 4911 return nullptr; | |
| 4912 } | |
| 4913 } | |
| 4914 | |
| 4915 PassRefPtrWillBeRawPtr<CSSValueList> CSSPropertyParser::parseFontFaceUnicodeRang e() | |
| 4916 { | |
| 4917 RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createCommaSeparated (); | |
| 4918 | |
| 4919 do { | |
| 4920 CSSParserValue* current = m_valueList->current(); | |
| 4921 if (!current || current->m_unit != CSSParserValue::UnicodeRange) | |
| 4922 return nullptr; | |
| 4923 | |
| 4924 UChar32 start = current->m_unicodeRange.start; | |
| 4925 UChar32 end = current->m_unicodeRange.end; | |
| 4926 if (start > end) | |
| 4927 return nullptr; | |
| 4928 values->append(CSSUnicodeRangeValue::create(start, end)); | |
| 4929 m_valueList->next(); | |
| 4930 } while (consumeComma(m_valueList)); | |
| 4931 | |
| 4932 return values.release(); | |
| 4933 } | |
| 4934 | |
| 4935 inline int CSSPropertyParser::colorIntFromValue(CSSParserValue* v) | |
| 4936 { | |
| 4937 bool isPercent; | |
| 4938 double value; | |
| 4939 | |
| 4940 if (m_parsedCalculation) { | |
| 4941 isPercent = m_parsedCalculation->category() == CalcPercent; | |
| 4942 value = m_parsedCalculation->doubleValue(); | |
| 4943 m_parsedCalculation.release(); | |
| 4944 } else { | |
| 4945 isPercent = v->unit() == CSSPrimitiveValue::UnitType::Percentage; | |
| 4946 value = v->fValue; | |
| 4947 } | |
| 4948 | |
| 4949 if (value <= 0.0) | |
| 4950 return 0; | |
| 4951 | |
| 4952 if (isPercent) { | |
| 4953 if (value >= 100.0) | |
| 4954 return 255; | |
| 4955 return static_cast<int>(value * 256.0 / 100.0); | |
| 4956 } | |
| 4957 | |
| 4958 if (value >= 255.0) | |
| 4959 return 255; | |
| 4960 | |
| 4961 return static_cast<int>(value); | |
| 4962 } | |
| 4963 | |
| 4964 bool CSSPropertyParser::parseColorParameters(const CSSParserValue* value, int* c olorArray, bool parseAlpha) | |
| 4965 { | |
| 4966 CSSParserValueList* args = value->function->args.get(); | |
| 4967 CSSParserValue* v = args->current(); | |
| 4968 Units unitType = FUnknown; | |
| 4969 // Get the first value and its type | |
| 4970 if (validUnit(v, FInteger)) | |
| 4971 unitType = FInteger; | |
| 4972 else if (validUnit(v, FPercent)) | |
| 4973 unitType = FPercent; | |
| 4974 else | |
| 4975 return false; | |
| 4976 | |
| 4977 colorArray[0] = colorIntFromValue(v); | |
| 4978 for (int i = 1; i < 3; i++) { | |
| 4979 args->next(); | |
| 4980 if (!consumeComma(args)) | |
| 4981 return false; | |
| 4982 v = args->current(); | |
| 4983 if (!validUnit(v, unitType)) | |
| 4984 return false; | |
| 4985 colorArray[i] = colorIntFromValue(v); | |
| 4986 } | |
| 4987 if (parseAlpha) { | |
| 4988 args->next(); | |
| 4989 if (!consumeComma(args)) | |
| 4990 return false; | |
| 4991 v = args->current(); | |
| 4992 if (!validUnit(v, FNumber)) | |
| 4993 return false; | |
| 4994 // Convert the floating pointer number of alpha to an integer in the ran ge [0, 256), | |
| 4995 // with an equal distribution across all 256 values. | |
| 4996 colorArray[3] = static_cast<int>(std::max(0.0, std::min(1.0, v->fValue)) * nextafter(256.0, 0.0)); | |
| 4997 } | |
| 4998 return true; | |
| 4999 } | |
| 5000 | |
| 5001 // The CSS3 specification defines the format of a HSL color as | |
| 5002 // hsl(<number>, <percent>, <percent>) | |
| 5003 // and with alpha, the format is | |
| 5004 // hsla(<number>, <percent>, <percent>, <number>) | |
| 5005 // The first value, HUE, is in an angle with a value between 0 and 360 | |
| 5006 bool CSSPropertyParser::parseHSLParameters(const CSSParserValue* value, double* colorArray, bool parseAlpha) | |
| 5007 { | |
| 5008 CSSParserValueList* args = value->function->args.get(); | |
| 5009 CSSParserValue* v = args->current(); | |
| 5010 // Get the first value | |
| 5011 if (!validUnit(v, FNumber)) | |
| 5012 return false; | |
| 5013 // normalize the Hue value and change it to be between 0 and 1.0 | |
| 5014 colorArray[0] = (((static_cast<int>(v->fValue) % 360) + 360) % 360) / 360.0; | |
| 5015 for (int i = 1; i < 3; i++) { | |
| 5016 args->next(); | |
| 5017 if (!consumeComma(args)) | |
| 5018 return false; | |
| 5019 v = args->current(); | |
| 5020 if (!validUnit(v, FPercent)) | |
| 5021 return false; | |
| 5022 double percentValue = m_parsedCalculation ? m_parsedCalculation.release( )->doubleValue() : v->fValue; | |
| 5023 colorArray[i] = std::max(0.0, std::min(100.0, percentValue)) / 100.0; // needs to be value between 0 and 1.0 | |
| 5024 } | |
| 5025 if (parseAlpha) { | |
| 5026 args->next(); | |
| 5027 if (!consumeComma(args)) | |
| 5028 return false; | |
| 5029 v = args->current(); | |
| 5030 if (!validUnit(v, FNumber)) | |
| 5031 return false; | |
| 5032 colorArray[3] = std::max(0.0, std::min(1.0, v->fValue)); | |
| 5033 } | |
| 5034 return true; | |
| 5035 } | |
| 5036 | |
| 5037 bool CSSPropertyParser::parseColorFromValue(const CSSParserValue* value, RGBA32& result, bool acceptQuirkyColors) | |
| 5038 { | |
| 5039 if (acceptQuirkyColors && value->unit() == CSSPrimitiveValue::UnitType::Numb er | |
| 5040 && value->fValue >= 0. && value->fValue < 1000000. && value->isInt) { | |
| 5041 String str = String::format("%06d", static_cast<int>(value->fValue)); | |
| 5042 return Color::parseHexColor(str, result); | |
| 5043 } | |
| 5044 if (acceptQuirkyColors && value->m_unit == CSSParserValue::DimensionList) { | |
| 5045 CSSParserValue* numberToken = value->valueList->valueAt(0); | |
| 5046 CSSParserValue* unitToken = value->valueList->valueAt(1); | |
| 5047 ASSERT(numberToken->unit() == CSSPrimitiveValue::UnitType::Number); | |
| 5048 ASSERT(unitToken->m_unit == CSSParserValue::Identifier); | |
| 5049 if (!numberToken->isInt || numberToken->fValue < 0) | |
| 5050 return false; | |
| 5051 String color = String::number(numberToken->fValue) + String(unitToken->s tring); | |
| 5052 if (color.length() > 6) | |
| 5053 return false; | |
| 5054 while (color.length() < 6) | |
| 5055 color = "0" + color; | |
| 5056 return Color::parseHexColor(color, result); | |
| 5057 } | |
| 5058 if (value->m_unit == CSSParserValue::Identifier) { | |
| 5059 Color color; | |
| 5060 if (!color.setNamedColor(value->string)) | |
| 5061 return acceptQuirkyColors && Color::parseHexColor(value->string, res ult); | |
| 5062 result = color.rgb(); | |
| 5063 return true; | |
| 5064 } | |
| 5065 if (value->m_unit == CSSParserValue::HexColor) { | |
| 5066 if (value->string.is8Bit()) | |
| 5067 return Color::parseHexColor(value->string.characters8(), value->stri ng.length(), result); | |
| 5068 return Color::parseHexColor(value->string.characters16(), value->string. length(), result); | |
| 5069 } | |
| 5070 | |
| 5071 if (value->m_unit == CSSParserValue::Function | |
| 5072 && value->function->args != 0 | |
| 5073 && value->function->args->size() == 5 /* rgb + two commas */ | |
| 5074 && value->function->id == CSSValueRgb) { | |
| 5075 int colorValues[3]; | |
| 5076 if (!parseColorParameters(value, colorValues, false)) | |
| 5077 return false; | |
| 5078 result = makeRGB(colorValues[0], colorValues[1], colorValues[2]); | |
| 5079 } else { | |
| 5080 if (value->m_unit == CSSParserValue::Function | |
| 5081 && value->function->args != 0 | |
| 5082 && value->function->args->size() == 7 /* rgba + three commas */ | |
| 5083 && value->function->id == CSSValueRgba) { | |
| 5084 int colorValues[4]; | |
| 5085 if (!parseColorParameters(value, colorValues, true)) | |
| 5086 return false; | |
| 5087 result = makeRGBA(colorValues[0], colorValues[1], colorValues[2], co lorValues[3]); | |
| 5088 } else if (value->m_unit == CSSParserValue::Function | |
| 5089 && value->function->args != 0 | |
| 5090 && value->function->args->size() == 5 /* hsl + two commas */ | |
| 5091 && value->function->id == CSSValueHsl) { | |
| 5092 double colorValues[3]; | |
| 5093 if (!parseHSLParameters(value, colorValues, false)) | |
| 5094 return false; | |
| 5095 result = makeRGBAFromHSLA(colorValues[0], colorValues[1], colorValue s[2], 1.0); | |
| 5096 } else if (value->m_unit == CSSParserValue::Function | |
| 5097 && value->function->args != 0 | |
| 5098 && value->function->args->size() == 7 /* hsla + three commas */ | |
| 5099 && value->function->id == CSSValueHsla) { | |
| 5100 double colorValues[4]; | |
| 5101 if (!parseHSLParameters(value, colorValues, true)) | |
| 5102 return false; | |
| 5103 result = makeRGBAFromHSLA(colorValues[0], colorValues[1], colorValue s[2], colorValues[3]); | |
| 5104 } else { | |
| 5105 return false; | |
| 5106 } | |
| 5107 } | |
| 5108 | |
| 5109 return true; | |
| 5110 } | |
| 5111 | |
| 5112 PassRefPtrWillBeRawPtr<CSSValueList> CSSPropertyParser::parseShadow(CSSParserVal ueList* valueList, CSSPropertyID propID) | |
| 5113 { | |
| 5114 RefPtrWillBeRawPtr<CSSValueList> shadowValueList = CSSValueList::createComma Separated(); | |
| 5115 const bool isBoxShadowProperty = propID == CSSPropertyBoxShadow; | |
| 5116 while (RefPtrWillBeRawPtr<CSSShadowValue> shadowValue = parseSingleShadow(va lueList, isBoxShadowProperty, isBoxShadowProperty)) { | |
| 5117 shadowValueList->append(shadowValue); | |
| 5118 if (!valueList->current()) | |
| 5119 break; | |
| 5120 if (!consumeComma(valueList)) | |
| 5121 return nullptr; | |
| 5122 } | |
| 5123 if (shadowValueList->length() == 0) | |
| 5124 return nullptr; | |
| 5125 return shadowValueList; | |
| 5126 } | |
| 5127 | |
| 5128 PassRefPtrWillBeRawPtr<CSSShadowValue> CSSPropertyParser::parseSingleShadow(CSSP arserValueList* valueList, bool allowInset, bool allowSpread) | |
| 5129 { | |
| 5130 RefPtrWillBeMember<CSSPrimitiveValue> style; | |
| 5131 RefPtrWillBeMember<CSSPrimitiveValue> color; | |
| 5132 Vector<RefPtrWillBeRawPtr<CSSPrimitiveValue>, 4> lengths; | |
| 5133 | |
| 5134 CSSParserValue* val = valueList->current(); | |
| 5135 if (!val) | |
| 5136 return nullptr; | |
| 5137 if (val->id == CSSValueInset) { | |
| 5138 if (!allowInset) | |
| 5139 return nullptr; | |
| 5140 style = cssValuePool().createIdentifierValue(val->id); | |
| 5141 val = valueList->next(); | |
| 5142 if (!val) | |
| 5143 return nullptr; | |
| 5144 } | |
| 5145 if ((color = parseColor(val))) | |
| 5146 val = valueList->next(); | |
| 5147 | |
| 5148 if (!val || !validUnit(val, FLength, HTMLStandardMode)) | |
| 5149 return nullptr; | |
| 5150 lengths.append(createPrimitiveNumericValue(val)); | |
| 5151 val = valueList->next(); | |
| 5152 | |
| 5153 if (!val || !validUnit(val, FLength, HTMLStandardMode)) | |
| 5154 return nullptr; | |
| 5155 lengths.append(createPrimitiveNumericValue(val)); | |
| 5156 val = valueList->next(); | |
| 5157 | |
| 5158 if (val && validUnit(val, FLength, HTMLStandardMode)) { | |
| 5159 // Blur radius must be non-negative. | |
| 5160 if (m_parsedCalculation ? m_parsedCalculation->isNegative() : !validUnit (val, FLength | FNonNeg, HTMLStandardMode)) { | |
| 5161 m_parsedCalculation.release(); | |
| 5162 return nullptr; | |
| 5163 } | |
| 5164 lengths.append(createPrimitiveNumericValue(val)); | |
| 5165 val = valueList->next(); | |
| 5166 if (val && validUnit(val, FLength, HTMLStandardMode)) { | |
| 5167 if (!allowSpread) | |
| 5168 return nullptr; | |
| 5169 lengths.append(createPrimitiveNumericValue(val)); | |
| 5170 val = valueList->next(); | |
| 5171 } | |
| 5172 } | |
| 5173 | |
| 5174 if (val) { | |
| 5175 if (RefPtrWillBeMember<CSSPrimitiveValue> colorValue = parseColor(val)) { | |
| 5176 if (color) | |
| 5177 return nullptr; | |
| 5178 color = colorValue; | |
| 5179 val = valueList->next(); | |
| 5180 } | |
| 5181 if (val && val->id == CSSValueInset) { | |
| 5182 if (!allowInset || style) | |
| 5183 return nullptr; | |
| 5184 style = cssValuePool().createIdentifierValue(val->id); | |
| 5185 val = valueList->next(); | |
| 5186 } | |
| 5187 } | |
| 5188 unsigned lengthsSeen = lengths.size(); | |
| 5189 return CSSShadowValue::create(lengths.at(0), lengths.at(1), | |
| 5190 lengthsSeen > 2 ? lengths.at(2) : nullptr, | |
| 5191 lengthsSeen > 3 ? lengths.at(3) : nullptr, | |
| 5192 style.release(), color.release()); | |
| 5193 } | |
| 5194 | |
| 5195 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseReflect() | |
| 5196 { | |
| 5197 // box-reflect: <direction> <offset> <mask> | |
| 5198 | |
| 5199 // Direction comes first. | |
| 5200 CSSParserValue* val = m_valueList->current(); | |
| 5201 RefPtrWillBeRawPtr<CSSPrimitiveValue> direction = nullptr; | |
| 5202 switch (val->id) { | |
| 5203 case CSSValueAbove: | |
| 5204 case CSSValueBelow: | |
| 5205 case CSSValueLeft: | |
| 5206 case CSSValueRight: | |
| 5207 direction = cssValuePool().createIdentifierValue(val->id); | |
| 5208 break; | |
| 5209 default: | |
| 5210 return nullptr; | |
| 5211 } | |
| 5212 | |
| 5213 // The offset comes next. | |
| 5214 val = m_valueList->next(); | |
| 5215 RefPtrWillBeRawPtr<CSSPrimitiveValue> offset = nullptr; | |
| 5216 if (!val) | |
| 5217 offset = cssValuePool().createValue(0, CSSPrimitiveValue::UnitType::Pixe ls); | |
| 5218 else { | |
| 5219 if (!validUnit(val, FLength | FPercent)) | |
| 5220 return nullptr; | |
| 5221 offset = createPrimitiveNumericValue(val); | |
| 5222 } | |
| 5223 | |
| 5224 // Now for the mask. | |
| 5225 RefPtrWillBeRawPtr<CSSValue> mask = nullptr; | |
| 5226 val = m_valueList->next(); | |
| 5227 if (val) { | |
| 5228 mask = parseBorderImage(CSSPropertyWebkitBoxReflect); | |
| 5229 if (!mask) | |
| 5230 return nullptr; | |
| 5231 } | |
| 5232 | |
| 5233 return CSSReflectValue::create(direction.release(), offset.release(), mask.r elease()); | |
| 5234 } | |
| 5235 | |
| 5236 static bool isFlexBasisMiddleArg(double flexGrow, double flexShrink, double unse tValue, int argSize) | |
| 5237 { | |
| 5238 return flexGrow != unsetValue && flexShrink == unsetValue && argSize == 3; | |
| 5239 } | |
| 5240 | |
| 5241 bool CSSPropertyParser::parseFlex(CSSParserValueList* args, bool important) | |
| 5242 { | |
| 5243 if (!args || !args->size() || args->size() > 3) | |
| 5244 return false; | |
| 5245 static const double unsetValue = -1; | |
| 5246 double flexGrow = unsetValue; | |
| 5247 double flexShrink = unsetValue; | |
| 5248 RefPtrWillBeRawPtr<CSSPrimitiveValue> flexBasis = nullptr; | |
| 5249 | |
| 5250 while (CSSParserValue* arg = args->current()) { | |
| 5251 if (validUnit(arg, FNumber | FNonNeg)) { | |
| 5252 if (flexGrow == unsetValue) | |
| 5253 flexGrow = arg->fValue; | |
| 5254 else if (flexShrink == unsetValue) | |
| 5255 flexShrink = arg->fValue; | |
| 5256 else if (!arg->fValue) { | |
| 5257 // flex only allows a basis of 0 (sans units) if flex-grow and f lex-shrink values have already been set. | |
| 5258 flexBasis = cssValuePool().createValue(0, CSSPrimitiveValue::Uni tType::Pixels); | |
| 5259 } else { | |
| 5260 // We only allow 3 numbers without units if the last value is 0. E.g., flex:1 1 1 is invalid. | |
| 5261 return false; | |
| 5262 } | |
| 5263 } else if (!flexBasis && (arg->id == CSSValueAuto || validUnit(arg, FLen gth | FPercent | FNonNeg)) && !isFlexBasisMiddleArg(flexGrow, flexShrink, unsetV alue, args->size())) | |
| 5264 flexBasis = parseValidPrimitive(arg->id, arg); | |
| 5265 else { | |
| 5266 // Not a valid arg for flex. | |
| 5267 return false; | |
| 5268 } | |
| 5269 args->next(); | |
| 5270 } | |
| 5271 | |
| 5272 if (flexGrow == unsetValue) | |
| 5273 flexGrow = 1; | |
| 5274 if (flexShrink == unsetValue) | |
| 5275 flexShrink = 1; | |
| 5276 if (!flexBasis) | |
| 5277 flexBasis = cssValuePool().createValue(0, CSSPrimitiveValue::UnitType::P ercentage); | |
| 5278 | |
| 5279 addProperty(CSSPropertyFlexGrow, cssValuePool().createValue(clampTo<float>(f lexGrow), CSSPrimitiveValue::UnitType::Number), important); | |
| 5280 addProperty(CSSPropertyFlexShrink, cssValuePool().createValue(clampTo<float> (flexShrink), CSSPrimitiveValue::UnitType::Number), important); | |
| 5281 addProperty(CSSPropertyFlexBasis, flexBasis, important); | |
| 5282 return true; | |
| 5283 } | |
| 5284 | |
| 5285 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parsePosition(CSSParserValue List* valueList) | |
| 5286 { | |
| 5287 RefPtrWillBeRawPtr<CSSValue> xValue = nullptr; | |
| 5288 RefPtrWillBeRawPtr<CSSValue> yValue = nullptr; | |
| 5289 parseFillPosition(valueList, xValue, yValue); | |
| 5290 if (!xValue || !yValue) | |
| 5291 return nullptr; | |
| 5292 return CSSValuePair::create(xValue.release(), yValue.release(), CSSValuePair ::KeepIdenticalValues); | |
| 5293 } | |
| 5294 | |
| 5295 // Parses a list of comma separated positions. i.e., <position># | |
| 5296 PassRefPtrWillBeRawPtr<CSSValueList> CSSPropertyParser::parsePositionList(CSSPar serValueList* valueList) | |
| 5297 { | |
| 5298 RefPtrWillBeRawPtr<CSSValueList> positions = CSSValueList::createCommaSepara ted(); | |
| 5299 while (true) { | |
| 5300 // parsePosition consumes values until it reaches a separator [,/], | |
| 5301 // an invalid token, or end of the list | |
| 5302 RefPtrWillBeRawPtr<CSSValue> position = parsePosition(valueList); | |
| 5303 if (!position) | |
| 5304 return nullptr; | |
| 5305 positions->append(position); | |
| 5306 | |
| 5307 if (!valueList->current()) | |
| 5308 break; | |
| 5309 if (!consumeComma(valueList) || !valueList->current()) | |
| 5310 return nullptr; | |
| 5311 } | |
| 5312 | |
| 5313 return positions.release(); | |
| 5314 } | |
| 5315 | |
| 5316 class BorderImageParseContext { | |
| 5317 STACK_ALLOCATED(); | |
| 5318 public: | |
| 5319 BorderImageParseContext() | |
| 5320 : m_canAdvance(false) | |
| 5321 , m_allowCommit(true) | |
| 5322 , m_allowImage(true) | |
| 5323 , m_allowImageSlice(true) | |
| 5324 , m_allowRepeat(true) | |
| 5325 , m_allowForwardSlashOperator(false) | |
| 5326 , m_allowWidth(false) | |
| 5327 , m_requireOutset(false) | |
| 5328 {} | |
| 5329 | |
| 5330 bool canAdvance() const { return m_canAdvance; } | |
| 5331 void setCanAdvance(bool canAdvance) { m_canAdvance = canAdvance; } | |
| 5332 | |
| 5333 bool allowCommit() const { return m_allowCommit; } | |
| 5334 bool allowImage() const { return m_allowImage; } | |
| 5335 bool allowImageSlice() const { return m_allowImageSlice; } | |
| 5336 bool allowRepeat() const { return m_allowRepeat; } | |
| 5337 bool allowForwardSlashOperator() const { return m_allowForwardSlashOperator; } | |
| 5338 | |
| 5339 bool allowWidth() const { return m_allowWidth; } | |
| 5340 bool requireOutset() const { return m_requireOutset; } | |
| 5341 | |
| 5342 void commitImage(PassRefPtrWillBeRawPtr<CSSValue> image) | |
| 5343 { | |
| 5344 m_image = image; | |
| 5345 m_canAdvance = true; | |
| 5346 m_allowCommit = true; | |
| 5347 m_allowImage = false; | |
| 5348 m_allowForwardSlashOperator = false; | |
| 5349 m_allowWidth = false; | |
| 5350 m_requireOutset = false; | |
| 5351 m_allowImageSlice = !m_imageSlice; | |
| 5352 m_allowRepeat = !m_repeat; | |
| 5353 } | |
| 5354 void commitImageSlice(PassRefPtrWillBeRawPtr<CSSBorderImageSliceValue> slice ) | |
| 5355 { | |
| 5356 m_imageSlice = slice; | |
| 5357 m_canAdvance = true; | |
| 5358 m_allowCommit = true; | |
| 5359 m_allowForwardSlashOperator = true; | |
| 5360 m_allowImageSlice = false; | |
| 5361 m_allowWidth = false; | |
| 5362 m_requireOutset = false; | |
| 5363 m_allowImage = !m_image; | |
| 5364 m_allowRepeat = !m_repeat; | |
| 5365 } | |
| 5366 void commitForwardSlashOperator() | |
| 5367 { | |
| 5368 m_canAdvance = true; | |
| 5369 m_allowCommit = false; | |
| 5370 m_allowImage = false; | |
| 5371 m_allowImageSlice = false; | |
| 5372 m_allowRepeat = false; | |
| 5373 if (!m_borderWidth && !m_allowWidth) { | |
| 5374 m_allowForwardSlashOperator = true; | |
| 5375 m_allowWidth = true; | |
| 5376 m_requireOutset = false; | |
| 5377 } else { | |
| 5378 m_allowForwardSlashOperator = false; | |
| 5379 m_requireOutset = true; | |
| 5380 m_allowWidth = false; | |
| 5381 } | |
| 5382 } | |
| 5383 void commitBorderWidth(PassRefPtrWillBeRawPtr<CSSQuadValue> width) | |
| 5384 { | |
| 5385 m_borderWidth = width; | |
| 5386 m_canAdvance = true; | |
| 5387 m_allowCommit = true; | |
| 5388 m_allowForwardSlashOperator = true; | |
| 5389 m_allowImageSlice = false; | |
| 5390 m_allowWidth = false; | |
| 5391 m_requireOutset = false; | |
| 5392 m_allowImage = !m_image; | |
| 5393 m_allowRepeat = !m_repeat; | |
| 5394 } | |
| 5395 void commitBorderOutset(PassRefPtrWillBeRawPtr<CSSQuadValue> outset) | |
| 5396 { | |
| 5397 m_outset = outset; | |
| 5398 m_canAdvance = true; | |
| 5399 m_allowCommit = true; | |
| 5400 m_allowImageSlice = false; | |
| 5401 m_allowForwardSlashOperator = false; | |
| 5402 m_allowWidth = false; | |
| 5403 m_requireOutset = false; | |
| 5404 m_allowImage = !m_image; | |
| 5405 m_allowRepeat = !m_repeat; | |
| 5406 } | |
| 5407 void commitRepeat(PassRefPtrWillBeRawPtr<CSSValue> repeat) | |
| 5408 { | |
| 5409 m_repeat = repeat; | |
| 5410 m_canAdvance = true; | |
| 5411 m_allowCommit = true; | |
| 5412 m_allowRepeat = false; | |
| 5413 m_allowForwardSlashOperator = false; | |
| 5414 m_allowWidth = false; | |
| 5415 m_requireOutset = false; | |
| 5416 m_allowImageSlice = !m_imageSlice; | |
| 5417 m_allowImage = !m_image; | |
| 5418 } | |
| 5419 | |
| 5420 PassRefPtrWillBeRawPtr<CSSValue> commitCSSValue() | |
| 5421 { | |
| 5422 return createBorderImageValue(m_image, m_imageSlice.get(), m_borderWidth .get(), m_outset.get(), m_repeat.get()); | |
| 5423 } | |
| 5424 | |
| 5425 bool m_canAdvance; | |
| 5426 | |
| 5427 bool m_allowCommit; | |
| 5428 bool m_allowImage; | |
| 5429 bool m_allowImageSlice; | |
| 5430 bool m_allowRepeat; | |
| 5431 bool m_allowForwardSlashOperator; | |
| 5432 | |
| 5433 bool m_allowWidth; | |
| 5434 bool m_requireOutset; | |
| 5435 | |
| 5436 RefPtrWillBeMember<CSSValue> m_image; | |
| 5437 RefPtrWillBeMember<CSSBorderImageSliceValue> m_imageSlice; | |
| 5438 RefPtrWillBeMember<CSSQuadValue> m_borderWidth; | |
| 5439 RefPtrWillBeMember<CSSQuadValue> m_outset; | |
| 5440 | |
| 5441 RefPtrWillBeMember<CSSValue> m_repeat; | |
| 5442 }; | |
| 5443 | |
| 5444 bool CSSPropertyParser::buildBorderImageParseContext(CSSPropertyID propId, Borde rImageParseContext& context) | |
| 5445 { | |
| 5446 CSSPropertyParser::ShorthandScope scope(this, propId); | |
| 5447 while (CSSParserValue* val = m_valueList->current()) { | |
| 5448 context.setCanAdvance(false); | |
| 5449 | |
| 5450 if (!context.canAdvance() && context.allowForwardSlashOperator() && isFo rwardSlashOperator(val)) | |
| 5451 context.commitForwardSlashOperator(); | |
| 5452 | |
| 5453 if (!context.canAdvance() && context.allowImage()) { | |
| 5454 if (val->unit() == CSSPrimitiveValue::UnitType::URI) { | |
| 5455 context.commitImage(createCSSImageValueWithReferrer(val->string, m_context.completeURL(val->string))); | |
| 5456 } else if (isGeneratedImageValue(val)) { | |
| 5457 RefPtrWillBeRawPtr<CSSValue> value = nullptr; | |
| 5458 if (parseGeneratedImage(m_valueList, value)) | |
| 5459 context.commitImage(value.release()); | |
| 5460 else | |
| 5461 return false; | |
| 5462 } else if (val->m_unit == CSSParserValue::Function && val->function- >id == CSSValueWebkitImageSet) { | |
| 5463 RefPtrWillBeRawPtr<CSSValue> value = parseImageSet(m_valueList); | |
| 5464 if (value) | |
| 5465 context.commitImage(value.release()); | |
| 5466 else | |
| 5467 return false; | |
| 5468 } else if (val->id == CSSValueNone) | |
| 5469 context.commitImage(cssValuePool().createIdentifierValue(CSSValu eNone)); | |
| 5470 } | |
| 5471 | |
| 5472 if (!context.canAdvance() && context.allowImageSlice()) { | |
| 5473 RefPtrWillBeRawPtr<CSSBorderImageSliceValue> imageSlice = nullptr; | |
| 5474 if (parseBorderImageSlice(propId, imageSlice)) | |
| 5475 context.commitImageSlice(imageSlice.release()); | |
| 5476 } | |
| 5477 | |
| 5478 if (!context.canAdvance() && context.allowRepeat()) { | |
| 5479 RefPtrWillBeRawPtr<CSSValue> repeat = nullptr; | |
| 5480 if (parseBorderImageRepeat(repeat)) | |
| 5481 context.commitRepeat(repeat.release()); | |
| 5482 } | |
| 5483 | |
| 5484 if (!context.canAdvance() && context.allowWidth()) { | |
| 5485 RefPtrWillBeRawPtr<CSSQuadValue> borderWidth = nullptr; | |
| 5486 if (parseBorderImageWidth(borderWidth)) | |
| 5487 context.commitBorderWidth(borderWidth.release()); | |
| 5488 } | |
| 5489 | |
| 5490 if (!context.canAdvance() && context.requireOutset()) { | |
| 5491 RefPtrWillBeRawPtr<CSSQuadValue> borderOutset = nullptr; | |
| 5492 if (parseBorderImageOutset(borderOutset)) | |
| 5493 context.commitBorderOutset(borderOutset.release()); | |
| 5494 } | |
| 5495 | |
| 5496 if (!context.canAdvance()) | |
| 5497 return false; | |
| 5498 | |
| 5499 m_valueList->next(); | |
| 5500 } | |
| 5501 | |
| 5502 return context.allowCommit(); | |
| 5503 } | |
| 5504 | |
| 5505 void CSSPropertyParser::commitBorderImageProperty(CSSPropertyID propId, PassRefP trWillBeRawPtr<CSSValue> value, bool important) | |
| 5506 { | |
| 5507 if (value) | |
| 5508 addProperty(propId, value, important); | |
| 5509 else | |
| 5510 addProperty(propId, cssValuePool().createImplicitInitialValue(), importa nt, true); | |
| 5511 } | |
| 5512 | |
| 5513 bool CSSPropertyParser::parseBorderImageShorthand(CSSPropertyID propId, bool imp ortant) | |
| 5514 { | |
| 5515 BorderImageParseContext context; | |
| 5516 if (buildBorderImageParseContext(propId, context)) { | |
| 5517 switch (propId) { | |
| 5518 case CSSPropertyWebkitMaskBoxImage: | |
| 5519 commitBorderImageProperty(CSSPropertyWebkitMaskBoxImageSource, conte xt.m_image, important); | |
| 5520 commitBorderImageProperty(CSSPropertyWebkitMaskBoxImageSlice, contex t.m_imageSlice.get(), important); | |
| 5521 commitBorderImageProperty(CSSPropertyWebkitMaskBoxImageWidth, contex t.m_borderWidth.get(), important); | |
| 5522 commitBorderImageProperty(CSSPropertyWebkitMaskBoxImageOutset, conte xt.m_outset.get(), important); | |
| 5523 commitBorderImageProperty(CSSPropertyWebkitMaskBoxImageRepeat, conte xt.m_repeat.get(), important); | |
| 5524 return true; | |
| 5525 case CSSPropertyBorderImage: | |
| 5526 commitBorderImageProperty(CSSPropertyBorderImageSource, context.m_im age, important); | |
| 5527 commitBorderImageProperty(CSSPropertyBorderImageSlice, context.m_ima geSlice.get(), important); | |
| 5528 commitBorderImageProperty(CSSPropertyBorderImageWidth, context.m_bor derWidth.get(), important); | |
| 5529 commitBorderImageProperty(CSSPropertyBorderImageOutset, context.m_ou tset.get(), important); | |
| 5530 commitBorderImageProperty(CSSPropertyBorderImageRepeat, context.m_re peat, important); | |
| 5531 return true; | |
| 5532 default: | |
| 5533 ASSERT_NOT_REACHED(); | |
| 5534 return false; | |
| 5535 } | |
| 5536 } | |
| 5537 return false; | |
| 5538 } | |
| 5539 | |
| 5540 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseBorderImage(CSSProperty ID propId) | |
| 5541 { | |
| 5542 BorderImageParseContext context; | |
| 5543 if (buildBorderImageParseContext(propId, context)) { | |
| 5544 return context.commitCSSValue(); | |
| 5545 } | |
| 5546 return nullptr; | |
| 5547 } | |
| 5548 | |
| 5549 static bool isBorderImageRepeatKeyword(int id) | |
| 5550 { | |
| 5551 return id == CSSValueStretch || id == CSSValueRepeat || id == CSSValueSpace || id == CSSValueRound; | |
| 5552 } | |
| 5553 | |
| 5554 bool CSSPropertyParser::parseBorderImageRepeat(RefPtrWillBeRawPtr<CSSValue>& res ult) | |
| 5555 { | |
| 5556 RefPtrWillBeRawPtr<CSSPrimitiveValue> firstValue = nullptr; | |
| 5557 RefPtrWillBeRawPtr<CSSPrimitiveValue> secondValue = nullptr; | |
| 5558 CSSParserValue* val = m_valueList->current(); | |
| 5559 if (!val) | |
| 5560 return false; | |
| 5561 if (isBorderImageRepeatKeyword(val->id)) | |
| 5562 firstValue = cssValuePool().createIdentifierValue(val->id); | |
| 5563 else | |
| 5564 return false; | |
| 5565 | |
| 5566 val = m_valueList->next(); | |
| 5567 if (val) { | |
| 5568 if (isBorderImageRepeatKeyword(val->id)) | |
| 5569 secondValue = cssValuePool().createIdentifierValue(val->id); | |
| 5570 else if (!inShorthand()) { | |
| 5571 // If we're not parsing a shorthand then we are invalid. | |
| 5572 return false; | |
| 5573 } else { | |
| 5574 // We need to rewind the value list, so that when its advanced we'll | |
| 5575 // end up back at this value. | |
| 5576 m_valueList->previous(); | |
| 5577 secondValue = firstValue; | |
| 5578 } | |
| 5579 } else | |
| 5580 secondValue = firstValue; | |
| 5581 | |
| 5582 result = CSSValuePair::create(firstValue, secondValue, CSSValuePair::DropIde nticalValues); | |
| 5583 return true; | |
| 5584 } | |
| 5585 | |
| 5586 class BorderImageSliceParseContext { | |
| 5587 STACK_ALLOCATED(); | |
| 5588 public: | |
| 5589 BorderImageSliceParseContext() | |
| 5590 : m_allowNumber(true) | |
| 5591 , m_allowFill(true) | |
| 5592 , m_allowFinalCommit(false) | |
| 5593 , m_fill(false) | |
| 5594 { } | |
| 5595 | |
| 5596 bool allowNumber() const { return m_allowNumber; } | |
| 5597 bool allowFill() const { return m_allowFill; } | |
| 5598 bool allowFinalCommit() const { return m_allowFinalCommit; } | |
| 5599 CSSPrimitiveValue* top() const { return m_top.get(); } | |
| 5600 | |
| 5601 void commitNumber(PassRefPtrWillBeRawPtr<CSSPrimitiveValue> val) | |
| 5602 { | |
| 5603 if (!m_top) | |
| 5604 m_top = val; | |
| 5605 else if (!m_right) | |
| 5606 m_right = val; | |
| 5607 else if (!m_bottom) | |
| 5608 m_bottom = val; | |
| 5609 else { | |
| 5610 ASSERT(!m_left); | |
| 5611 m_left = val; | |
| 5612 } | |
| 5613 | |
| 5614 m_allowNumber = !m_left; | |
| 5615 m_allowFinalCommit = true; | |
| 5616 } | |
| 5617 | |
| 5618 void commitFill() { m_fill = true; m_allowFill = false; m_allowNumber = !m_t op; } | |
| 5619 | |
| 5620 PassRefPtrWillBeRawPtr<CSSBorderImageSliceValue> commitBorderImageSlice() | |
| 5621 { | |
| 5622 // We need to clone and repeat values for any omissions. | |
| 5623 ASSERT(m_top); | |
| 5624 if (!m_right) { | |
| 5625 m_right = m_top; | |
| 5626 m_bottom = m_top; | |
| 5627 m_left = m_top; | |
| 5628 } | |
| 5629 if (!m_bottom) { | |
| 5630 m_bottom = m_top; | |
| 5631 m_left = m_right; | |
| 5632 } | |
| 5633 if (!m_left) | |
| 5634 m_left = m_right; | |
| 5635 | |
| 5636 return CSSBorderImageSliceValue::create(CSSQuadValue::create(m_top.relea se(), m_right.release(), m_bottom.release(), m_left.release(), CSSQuadValue::Ser ializeAsQuad), m_fill); | |
| 5637 } | |
| 5638 | |
| 5639 private: | |
| 5640 bool m_allowNumber; | |
| 5641 bool m_allowFill; | |
| 5642 bool m_allowFinalCommit; | |
| 5643 | |
| 5644 RefPtrWillBeMember<CSSPrimitiveValue> m_top; | |
| 5645 RefPtrWillBeMember<CSSPrimitiveValue> m_right; | |
| 5646 RefPtrWillBeMember<CSSPrimitiveValue> m_bottom; | |
| 5647 RefPtrWillBeMember<CSSPrimitiveValue> m_left; | |
| 5648 | |
| 5649 bool m_fill; | |
| 5650 }; | |
| 5651 | |
| 5652 bool CSSPropertyParser::parseBorderImageSlice(CSSPropertyID propId, RefPtrWillBe RawPtr<CSSBorderImageSliceValue>& result) | |
| 5653 { | |
| 5654 BorderImageSliceParseContext context; | |
| 5655 for (CSSParserValue* val = m_valueList->current(); val; val = m_valueList->n ext()) { | |
| 5656 // FIXME calc() http://webkit.org/b/16662 : calc is parsed but values ar e not created yet. | |
| 5657 if (context.allowNumber() && !isCalculation(val) && validUnit(val, FInte ger | FNonNeg | FPercent)) { | |
| 5658 context.commitNumber(createPrimitiveNumericValue(val)); | |
| 5659 } else if (context.allowFill() && val->id == CSSValueFill) { | |
| 5660 context.commitFill(); | |
| 5661 } else if (!inShorthand()) { | |
| 5662 // If we're not parsing a shorthand then we are invalid. | |
| 5663 return false; | |
| 5664 } else { | |
| 5665 if (context.allowFinalCommit()) { | |
| 5666 // We're going to successfully parse, but we don't want to consu me this token. | |
| 5667 m_valueList->previous(); | |
| 5668 } | |
| 5669 break; | |
| 5670 } | |
| 5671 } | |
| 5672 | |
| 5673 if (context.allowFinalCommit()) { | |
| 5674 // FIXME: For backwards compatibility, -webkit-border-image, -webkit-mas k-box-image and -webkit-box-reflect have to do a fill by default. | |
| 5675 // FIXME: What do we do with -webkit-box-reflect and -webkit-mask-box-im age? Probably just have to leave them filling... | |
| 5676 if (propId == CSSPropertyWebkitBorderImage || propId == CSSPropertyWebki tMaskBoxImage || propId == CSSPropertyWebkitBoxReflect) | |
| 5677 context.commitFill(); | |
| 5678 | |
| 5679 // Need to fully commit as a single value. | |
| 5680 result = context.commitBorderImageSlice(); | |
| 5681 return true; | |
| 5682 } | |
| 5683 | |
| 5684 return false; | |
| 5685 } | |
| 5686 | |
| 5687 class BorderImageQuadParseContext { | |
| 5688 STACK_ALLOCATED(); | |
| 5689 public: | |
| 5690 BorderImageQuadParseContext() | |
| 5691 : m_allowNumber(true) | |
| 5692 , m_allowFinalCommit(false) | |
| 5693 { } | |
| 5694 | |
| 5695 bool allowNumber() const { return m_allowNumber; } | |
| 5696 bool allowFinalCommit() const { return m_allowFinalCommit; } | |
| 5697 CSSPrimitiveValue* top() const { return m_top.get(); } | |
| 5698 | |
| 5699 void commitNumber(PassRefPtrWillBeRawPtr<CSSPrimitiveValue> val) | |
| 5700 { | |
| 5701 if (!m_top) | |
| 5702 m_top = val; | |
| 5703 else if (!m_right) | |
| 5704 m_right = val; | |
| 5705 else if (!m_bottom) | |
| 5706 m_bottom = val; | |
| 5707 else { | |
| 5708 ASSERT(!m_left); | |
| 5709 m_left = val; | |
| 5710 } | |
| 5711 | |
| 5712 m_allowNumber = !m_left; | |
| 5713 m_allowFinalCommit = true; | |
| 5714 } | |
| 5715 | |
| 5716 void setTop(PassRefPtrWillBeRawPtr<CSSPrimitiveValue> val) { m_top = val; } | |
| 5717 | |
| 5718 PassRefPtrWillBeRawPtr<CSSQuadValue> commitBorderImageQuad() | |
| 5719 { | |
| 5720 // We need to clone and repeat values for any omissions. | |
| 5721 ASSERT(m_top); | |
| 5722 if (!m_right) { | |
| 5723 m_right = m_top; | |
| 5724 m_bottom = m_top; | |
| 5725 m_left = m_top; | |
| 5726 } | |
| 5727 if (!m_bottom) { | |
| 5728 m_bottom = m_top; | |
| 5729 m_left = m_right; | |
| 5730 } | |
| 5731 if (!m_left) | |
| 5732 m_left = m_right; | |
| 5733 | |
| 5734 return CSSQuadValue::create(m_top.release(), m_right.release(), m_bottom .release(), m_left.release(), CSSQuadValue::SerializeAsQuad); | |
| 5735 } | |
| 5736 | |
| 5737 private: | |
| 5738 bool m_allowNumber; | |
| 5739 bool m_allowFinalCommit; | |
| 5740 | |
| 5741 RefPtrWillBeMember<CSSPrimitiveValue> m_top; | |
| 5742 RefPtrWillBeMember<CSSPrimitiveValue> m_right; | |
| 5743 RefPtrWillBeMember<CSSPrimitiveValue> m_bottom; | |
| 5744 RefPtrWillBeMember<CSSPrimitiveValue> m_left; | |
| 5745 }; | |
| 5746 | |
| 5747 bool CSSPropertyParser::parseBorderImageQuad(Units validUnits, RefPtrWillBeRawPt r<CSSQuadValue>& result) | |
| 5748 { | |
| 5749 BorderImageQuadParseContext context; | |
| 5750 for (CSSParserValue* val = m_valueList->current(); val; val = m_valueList->n ext()) { | |
| 5751 if (context.allowNumber() && (validUnit(val, validUnits, HTMLStandardMod e) || val->id == CSSValueAuto)) { | |
| 5752 if (val->id == CSSValueAuto) | |
| 5753 context.commitNumber(cssValuePool().createIdentifierValue(val->i d)); | |
| 5754 else | |
| 5755 context.commitNumber(createPrimitiveNumericValue(val)); | |
| 5756 } else if (!inShorthand()) { | |
| 5757 // If we're not parsing a shorthand then we are invalid. | |
| 5758 return false; | |
| 5759 } else { | |
| 5760 if (context.allowFinalCommit()) | |
| 5761 m_valueList->previous(); // The shorthand loop will advance back to this point. | |
| 5762 break; | |
| 5763 } | |
| 5764 } | |
| 5765 | |
| 5766 if (context.allowFinalCommit()) { | |
| 5767 // Need to fully commit as a single value. | |
| 5768 result = context.commitBorderImageQuad(); | |
| 5769 return true; | |
| 5770 } | |
| 5771 return false; | |
| 5772 } | |
| 5773 | |
| 5774 bool CSSPropertyParser::parseBorderImageWidth(RefPtrWillBeRawPtr<CSSQuadValue>& result) | |
| 5775 { | |
| 5776 return parseBorderImageQuad(FLength | FNumber | FNonNeg | FPercent, result); | |
| 5777 } | |
| 5778 | |
| 5779 bool CSSPropertyParser::parseBorderImageOutset(RefPtrWillBeRawPtr<CSSQuadValue>& result) | |
| 5780 { | |
| 5781 return parseBorderImageQuad(FLength | FNumber | FNonNeg, result); | |
| 5782 } | |
| 5783 | |
| 5784 bool CSSPropertyParser::parseBorderRadius(CSSPropertyID unresolvedProperty, bool important) | |
| 5785 { | |
| 5786 unsigned num = m_valueList->size(); | |
| 5787 if (num > 9) | |
| 5788 return false; | |
| 5789 | |
| 5790 ShorthandScope scope(this, unresolvedProperty); | |
| 5791 RefPtrWillBeRawPtr<CSSPrimitiveValue> radii[2][4]; | |
| 5792 #if ENABLE(OILPAN) | |
| 5793 // Zero initialize the array of raw pointers. | |
| 5794 memset(&radii, 0, sizeof(radii)); | |
| 5795 #endif | |
| 5796 | |
| 5797 unsigned indexAfterSlash = 0; | |
| 5798 for (unsigned i = 0; i < num; ++i) { | |
| 5799 CSSParserValue* value = m_valueList->valueAt(i); | |
| 5800 if (value->m_unit == CSSParserValue::Operator) { | |
| 5801 if (value->iValue != '/') | |
| 5802 return false; | |
| 5803 | |
| 5804 if (!i || indexAfterSlash || i + 1 == num || num > i + 5) | |
| 5805 return false; | |
| 5806 | |
| 5807 indexAfterSlash = i + 1; | |
| 5808 completeBorderRadii(radii[0]); | |
| 5809 continue; | |
| 5810 } | |
| 5811 | |
| 5812 if (i - indexAfterSlash >= 4) | |
| 5813 return false; | |
| 5814 | |
| 5815 if (!validUnit(value, FLength | FPercent | FNonNeg)) | |
| 5816 return false; | |
| 5817 | |
| 5818 RefPtrWillBeRawPtr<CSSPrimitiveValue> radius = createPrimitiveNumericVal ue(value); | |
| 5819 | |
| 5820 if (!indexAfterSlash) { | |
| 5821 radii[0][i] = radius; | |
| 5822 | |
| 5823 // Legacy syntax: -webkit-border-radius: l1 l2; is equivalent to bor der-radius: l1 / l2; | |
| 5824 if (num == 2 && unresolvedProperty == CSSPropertyAliasWebkitBorderRa dius) { | |
| 5825 indexAfterSlash = 1; | |
| 5826 completeBorderRadii(radii[0]); | |
| 5827 } | |
| 5828 } else | |
| 5829 radii[1][i - indexAfterSlash] = radius.release(); | |
| 5830 } | |
| 5831 | |
| 5832 if (!indexAfterSlash) { | |
| 5833 completeBorderRadii(radii[0]); | |
| 5834 for (unsigned i = 0; i < 4; ++i) | |
| 5835 radii[1][i] = radii[0][i]; | |
| 5836 } else | |
| 5837 completeBorderRadii(radii[1]); | |
| 5838 | |
| 5839 ImplicitScope implicitScope(this); | |
| 5840 addProperty(CSSPropertyBorderTopLeftRadius, CSSValuePair::create(radii[0][0] .release(), radii[1][0].release(), CSSValuePair::DropIdenticalValues), important ); | |
| 5841 addProperty(CSSPropertyBorderTopRightRadius, CSSValuePair::create(radii[0][1 ].release(), radii[1][1].release(), CSSValuePair::DropIdenticalValues), importan t); | |
| 5842 addProperty(CSSPropertyBorderBottomRightRadius, CSSValuePair::create(radii[0 ][2].release(), radii[1][2].release(), CSSValuePair::DropIdenticalValues), impor tant); | |
| 5843 addProperty(CSSPropertyBorderBottomLeftRadius, CSSValuePair::create(radii[0] [3].release(), radii[1][3].release(), CSSValuePair::DropIdenticalValues), import ant); | |
| 5844 return true; | |
| 5845 } | |
| 5846 | |
| 5847 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseCounter(int defaultValu e) | |
| 5848 { | |
| 5849 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createCommaSeparated() ; | |
| 5850 | |
| 5851 while (m_valueList->current()) { | |
| 5852 CSSParserValue* val = m_valueList->current(); | |
| 5853 if (val->m_unit != CSSParserValue::Identifier) | |
| 5854 return nullptr; | |
| 5855 RefPtrWillBeRawPtr<CSSPrimitiveValue> counterName = createPrimitiveCusto mIdentValue(val); | |
| 5856 m_valueList->next(); | |
| 5857 | |
| 5858 val = m_valueList->current(); | |
| 5859 int i = defaultValue; | |
| 5860 if (val && validUnit(val, FInteger)) { | |
| 5861 i = clampTo<int>(val->fValue); | |
| 5862 m_valueList->next(); | |
| 5863 } | |
| 5864 | |
| 5865 list->append(CSSValuePair::create(counterName.release(), | |
| 5866 cssValuePool().createValue(i, CSSPrimitiveValue::UnitType::Number), | |
| 5867 CSSValuePair::DropIdenticalValues)); | |
| 5868 } | |
| 5869 | |
| 5870 if (!list->length()) | |
| 5871 return nullptr; | |
| 5872 return list.release(); | |
| 5873 } | |
| 5874 | |
| 5875 // This should go away once we drop support for -webkit-gradient | |
| 5876 static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> parseDeprecatedGradientPoint(CS SParserValue* a, bool horizontal) | |
| 5877 { | |
| 5878 RefPtrWillBeRawPtr<CSSPrimitiveValue> result = nullptr; | |
| 5879 if (a->m_unit == CSSParserValue::Identifier) { | |
| 5880 if ((a->id == CSSValueLeft && horizontal) | |
| 5881 || (a->id == CSSValueTop && !horizontal)) | |
| 5882 result = cssValuePool().createValue(0., CSSPrimitiveValue::UnitType: :Percentage); | |
| 5883 else if ((a->id == CSSValueRight && horizontal) | |
| 5884 || (a->id == CSSValueBottom && !horizontal)) | |
| 5885 result = cssValuePool().createValue(100., CSSPrimitiveValue::UnitTyp e::Percentage); | |
| 5886 else if (a->id == CSSValueCenter) | |
| 5887 result = cssValuePool().createValue(50., CSSPrimitiveValue::UnitType ::Percentage); | |
| 5888 } else if (a->unit() == CSSPrimitiveValue::UnitType::Number || a->unit() == CSSPrimitiveValue::UnitType::Percentage) { | |
| 5889 result = cssValuePool().createValue(a->fValue, a->unit()); | |
| 5890 } | |
| 5891 return result; | |
| 5892 } | |
| 5893 | |
| 5894 // Used to parse colors for -webkit-gradient(...). | |
| 5895 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPropertyParser::parseDeprecatedGrad ientStopColor(const CSSParserValue* value) | |
| 5896 { | |
| 5897 // Disallow currentcolor. | |
| 5898 if (value->id == CSSValueCurrentcolor) | |
| 5899 return nullptr; | |
| 5900 return parseColor(value); | |
| 5901 } | |
| 5902 | |
| 5903 bool CSSPropertyParser::parseDeprecatedGradientColorStop(CSSParserValue* a, CSSG radientColorStop& stop) | |
| 5904 { | |
| 5905 if (a->m_unit != CSSParserValue::Function) | |
| 5906 return false; | |
| 5907 | |
| 5908 if (a->function->id != CSSValueFrom | |
| 5909 && a->function->id != CSSValueTo | |
| 5910 && a->function->id != CSSValueColorStop) | |
| 5911 return false; | |
| 5912 | |
| 5913 CSSParserValueList* args = a->function->args.get(); | |
| 5914 if (!args) | |
| 5915 return false; | |
| 5916 | |
| 5917 if (a->function->id == CSSValueFrom || a->function->id == CSSValueTo) { | |
| 5918 // The "from" and "to" stops expect 1 argument. | |
| 5919 if (args->size() != 1) | |
| 5920 return false; | |
| 5921 | |
| 5922 if (a->function->id == CSSValueFrom) | |
| 5923 stop.m_position = cssValuePool().createValue(0, CSSPrimitiveValue::U nitType::Number); | |
| 5924 else | |
| 5925 stop.m_position = cssValuePool().createValue(1, CSSPrimitiveValue::U nitType::Number); | |
| 5926 | |
| 5927 stop.m_color = parseDeprecatedGradientStopColor(args->current()); | |
| 5928 if (!stop.m_color) | |
| 5929 return false; | |
| 5930 } | |
| 5931 | |
| 5932 // The "color-stop" function expects 3 arguments. | |
| 5933 if (a->function->id == CSSValueColorStop) { | |
| 5934 if (args->size() != 3) | |
| 5935 return false; | |
| 5936 | |
| 5937 CSSParserValue* stopArg = args->current(); | |
| 5938 if (stopArg->unit() == CSSPrimitiveValue::UnitType::Percentage) | |
| 5939 stop.m_position = cssValuePool().createValue(stopArg->fValue / 100, CSSPrimitiveValue::UnitType::Number); | |
| 5940 else if (stopArg->unit() == CSSPrimitiveValue::UnitType::Number) | |
| 5941 stop.m_position = cssValuePool().createValue(stopArg->fValue, CSSPri mitiveValue::UnitType::Number); | |
| 5942 else | |
| 5943 return false; | |
| 5944 | |
| 5945 args->next(); | |
| 5946 if (!consumeComma(args)) | |
| 5947 return false; | |
| 5948 | |
| 5949 stop.m_color = parseDeprecatedGradientStopColor(args->current()); | |
| 5950 if (!stop.m_color) | |
| 5951 return false; | |
| 5952 } | |
| 5953 | |
| 5954 return true; | |
| 5955 } | |
| 5956 | |
| 5957 bool CSSPropertyParser::parseDeprecatedGradient(CSSParserValueList* valueList, R efPtrWillBeRawPtr<CSSValue>& gradient) | |
| 5958 { | |
| 5959 // Walk the arguments. | |
| 5960 CSSParserValueList* args = valueList->current()->function->args.get(); | |
| 5961 if (!args || args->size() == 0) | |
| 5962 return false; | |
| 5963 | |
| 5964 // The first argument is the gradient type. It is an identifier. | |
| 5965 CSSGradientType gradientType; | |
| 5966 CSSParserValue* a = args->current(); | |
| 5967 if (!a || a->m_unit != CSSParserValue::Identifier) | |
| 5968 return false; | |
| 5969 if (a->id == CSSValueLinear) | |
| 5970 gradientType = CSSDeprecatedLinearGradient; | |
| 5971 else if (a->id == CSSValueRadial) | |
| 5972 gradientType = CSSDeprecatedRadialGradient; | |
| 5973 else | |
| 5974 return false; | |
| 5975 | |
| 5976 RefPtrWillBeRawPtr<CSSGradientValue> result = nullptr; | |
| 5977 switch (gradientType) { | |
| 5978 case CSSDeprecatedLinearGradient: | |
| 5979 result = CSSLinearGradientValue::create(NonRepeating, gradientType); | |
| 5980 break; | |
| 5981 case CSSDeprecatedRadialGradient: | |
| 5982 result = CSSRadialGradientValue::create(NonRepeating, gradientType); | |
| 5983 break; | |
| 5984 default: | |
| 5985 // The rest of the gradient types shouldn't appear here. | |
| 5986 ASSERT_NOT_REACHED(); | |
| 5987 } | |
| 5988 args->next(); | |
| 5989 | |
| 5990 if (!consumeComma(args)) | |
| 5991 return false; | |
| 5992 | |
| 5993 // Next comes the starting point for the gradient as an x y pair. There is no | |
| 5994 // comma between the x and the y values. | |
| 5995 // First X. It can be left, right, number or percent. | |
| 5996 a = args->current(); | |
| 5997 if (!a) | |
| 5998 return false; | |
| 5999 RefPtrWillBeRawPtr<CSSPrimitiveValue> point = parseDeprecatedGradientPoint(a , true); | |
| 6000 if (!point) | |
| 6001 return false; | |
| 6002 result->setFirstX(point.release()); | |
| 6003 | |
| 6004 // First Y. It can be top, bottom, number or percent. | |
| 6005 a = args->next(); | |
| 6006 if (!a) | |
| 6007 return false; | |
| 6008 point = parseDeprecatedGradientPoint(a, false); | |
| 6009 if (!point) | |
| 6010 return false; | |
| 6011 result->setFirstY(point.release()); | |
| 6012 | |
| 6013 // Comma after the first point. | |
| 6014 args->next(); | |
| 6015 if (!consumeComma(args)) | |
| 6016 return false; | |
| 6017 | |
| 6018 // For radial gradients only, we now expect a numeric radius. | |
| 6019 if (gradientType == CSSDeprecatedRadialGradient) { | |
| 6020 a = args->current(); | |
| 6021 if (!a || a->unit() != CSSPrimitiveValue::UnitType::Number) | |
| 6022 return false; | |
| 6023 toCSSRadialGradientValue(result.get())->setFirstRadius(createPrimitiveNu mericValue(a)); | |
| 6024 | |
| 6025 // Comma after the first radius. | |
| 6026 args->next(); | |
| 6027 if (!consumeComma(args)) | |
| 6028 return false; | |
| 6029 } | |
| 6030 | |
| 6031 // Next is the ending point for the gradient as an x, y pair. | |
| 6032 // Second X. It can be left, right, number or percent. | |
| 6033 a = args->current(); | |
| 6034 if (!a) | |
| 6035 return false; | |
| 6036 point = parseDeprecatedGradientPoint(a, true); | |
| 6037 if (!point) | |
| 6038 return false; | |
| 6039 result->setSecondX(point.release()); | |
| 6040 | |
| 6041 // Second Y. It can be top, bottom, number or percent. | |
| 6042 a = args->next(); | |
| 6043 if (!a) | |
| 6044 return false; | |
| 6045 point = parseDeprecatedGradientPoint(a, false); | |
| 6046 if (!point) | |
| 6047 return false; | |
| 6048 result->setSecondY(point.release()); | |
| 6049 args->next(); | |
| 6050 | |
| 6051 // For radial gradients only, we now expect the second radius. | |
| 6052 if (gradientType == CSSDeprecatedRadialGradient) { | |
| 6053 // Comma after the second point. | |
| 6054 if (!consumeComma(args)) | |
| 6055 return false; | |
| 6056 | |
| 6057 a = args->current(); | |
| 6058 if (!a || a->unit() != CSSPrimitiveValue::UnitType::Number) | |
| 6059 return false; | |
| 6060 toCSSRadialGradientValue(result.get())->setSecondRadius(createPrimitiveN umericValue(a)); | |
| 6061 args->next(); | |
| 6062 } | |
| 6063 | |
| 6064 // We now will accept any number of stops (0 or more). | |
| 6065 a = args->current(); | |
| 6066 while (a) { | |
| 6067 // Look for the comma before the next stop. | |
| 6068 if (!consumeComma(args)) | |
| 6069 return false; | |
| 6070 | |
| 6071 // Now examine the stop itself. | |
| 6072 a = args->current(); | |
| 6073 if (!a) | |
| 6074 return false; | |
| 6075 | |
| 6076 // The function name needs to be one of "from", "to", or "color-stop." | |
| 6077 CSSGradientColorStop stop; | |
| 6078 if (!parseDeprecatedGradientColorStop(a, stop)) | |
| 6079 return false; | |
| 6080 result->addStop(stop); | |
| 6081 | |
| 6082 // Advance | |
| 6083 a = args->next(); | |
| 6084 } | |
| 6085 | |
| 6086 gradient = result.release(); | |
| 6087 return true; | |
| 6088 } | |
| 6089 | |
| 6090 static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> valueFromSideKeyword(CSSParserV alue* a, bool& isHorizontal) | |
| 6091 { | |
| 6092 if (a->m_unit != CSSParserValue::Identifier) | |
| 6093 return nullptr; | |
| 6094 | |
| 6095 switch (a->id) { | |
| 6096 case CSSValueLeft: | |
| 6097 case CSSValueRight: | |
| 6098 isHorizontal = true; | |
| 6099 break; | |
| 6100 case CSSValueTop: | |
| 6101 case CSSValueBottom: | |
| 6102 isHorizontal = false; | |
| 6103 break; | |
| 6104 default: | |
| 6105 return nullptr; | |
| 6106 } | |
| 6107 return cssValuePool().createIdentifierValue(a->id); | |
| 6108 } | |
| 6109 | |
| 6110 bool CSSPropertyParser::parseDeprecatedLinearGradient(CSSParserValueList* valueL ist, RefPtrWillBeRawPtr<CSSValue>& gradient, CSSGradientRepeat repeating) | |
| 6111 { | |
| 6112 RefPtrWillBeRawPtr<CSSLinearGradientValue> result = CSSLinearGradientValue:: create(repeating, CSSPrefixedLinearGradient); | |
| 6113 | |
| 6114 // Walk the arguments. | |
| 6115 CSSParserValueList* args = valueList->current()->function->args.get(); | |
| 6116 if (!args || !args->size()) | |
| 6117 return false; | |
| 6118 | |
| 6119 CSSParserValue* a = args->current(); | |
| 6120 if (!a) | |
| 6121 return false; | |
| 6122 | |
| 6123 bool expectComma = false; | |
| 6124 // Look for angle. | |
| 6125 if (validUnit(a, FAngle, HTMLStandardMode)) { | |
| 6126 result->setAngle(createPrimitiveNumericValue(a)); | |
| 6127 | |
| 6128 args->next(); | |
| 6129 expectComma = true; | |
| 6130 } else { | |
| 6131 // Look one or two optional keywords that indicate a side or corner. | |
| 6132 RefPtrWillBeRawPtr<CSSPrimitiveValue> startX = nullptr; | |
| 6133 RefPtrWillBeRawPtr<CSSPrimitiveValue> startY = nullptr; | |
| 6134 | |
| 6135 RefPtrWillBeRawPtr<CSSPrimitiveValue> location = nullptr; | |
| 6136 bool isHorizontal = false; | |
| 6137 if ((location = valueFromSideKeyword(a, isHorizontal))) { | |
| 6138 if (isHorizontal) | |
| 6139 startX = location; | |
| 6140 else | |
| 6141 startY = location; | |
| 6142 | |
| 6143 a = args->next(); | |
| 6144 if (a) { | |
| 6145 if ((location = valueFromSideKeyword(a, isHorizontal))) { | |
| 6146 if (isHorizontal) { | |
| 6147 if (startX) | |
| 6148 return false; | |
| 6149 startX = location; | |
| 6150 } else { | |
| 6151 if (startY) | |
| 6152 return false; | |
| 6153 startY = location; | |
| 6154 } | |
| 6155 | |
| 6156 args->next(); | |
| 6157 } | |
| 6158 } | |
| 6159 | |
| 6160 expectComma = true; | |
| 6161 } | |
| 6162 | |
| 6163 if (!startX && !startY) | |
| 6164 startY = cssValuePool().createIdentifierValue(CSSValueTop); | |
| 6165 | |
| 6166 result->setFirstX(startX.release()); | |
| 6167 result->setFirstY(startY.release()); | |
| 6168 } | |
| 6169 | |
| 6170 if (!parseGradientColorStops(args, result.get(), expectComma)) | |
| 6171 return false; | |
| 6172 | |
| 6173 if (!result->stopCount()) | |
| 6174 return false; | |
| 6175 | |
| 6176 gradient = result.release(); | |
| 6177 return true; | |
| 6178 } | |
| 6179 | |
| 6180 bool CSSPropertyParser::parseDeprecatedRadialGradient(CSSParserValueList* valueL ist, RefPtrWillBeRawPtr<CSSValue>& gradient, CSSGradientRepeat repeating) | |
| 6181 { | |
| 6182 RefPtrWillBeRawPtr<CSSRadialGradientValue> result = CSSRadialGradientValue:: create(repeating, CSSPrefixedRadialGradient); | |
| 6183 | |
| 6184 // Walk the arguments. | |
| 6185 CSSParserValueList* args = valueList->current()->function->args.get(); | |
| 6186 if (!args || !args->size()) | |
| 6187 return false; | |
| 6188 | |
| 6189 CSSParserValue* a = args->current(); | |
| 6190 if (!a) | |
| 6191 return false; | |
| 6192 | |
| 6193 bool expectComma = false; | |
| 6194 | |
| 6195 // Optional background-position | |
| 6196 RefPtrWillBeRawPtr<CSSValue> centerX = nullptr; | |
| 6197 RefPtrWillBeRawPtr<CSSValue> centerY = nullptr; | |
| 6198 // parse2ValuesFillPosition advances the args next pointer. | |
| 6199 parse2ValuesFillPosition(args, centerX, centerY); | |
| 6200 | |
| 6201 if ((centerX || centerY) && !consumeComma(args)) | |
| 6202 return false; | |
| 6203 | |
| 6204 a = args->current(); | |
| 6205 if (!a) | |
| 6206 return false; | |
| 6207 | |
| 6208 result->setFirstX(toCSSPrimitiveValue(centerX.get())); | |
| 6209 result->setSecondX(toCSSPrimitiveValue(centerX.get())); | |
| 6210 // CSS3 radial gradients always share the same start and end point. | |
| 6211 result->setFirstY(toCSSPrimitiveValue(centerY.get())); | |
| 6212 result->setSecondY(toCSSPrimitiveValue(centerY.get())); | |
| 6213 | |
| 6214 RefPtrWillBeRawPtr<CSSPrimitiveValue> shapeValue = nullptr; | |
| 6215 RefPtrWillBeRawPtr<CSSPrimitiveValue> sizeValue = nullptr; | |
| 6216 | |
| 6217 // Optional shape and/or size in any order. | |
| 6218 for (int i = 0; i < 2; ++i) { | |
| 6219 if (a->m_unit != CSSParserValue::Identifier) | |
| 6220 break; | |
| 6221 | |
| 6222 bool foundValue = false; | |
| 6223 switch (a->id) { | |
| 6224 case CSSValueCircle: | |
| 6225 case CSSValueEllipse: | |
| 6226 shapeValue = cssValuePool().createIdentifierValue(a->id); | |
| 6227 foundValue = true; | |
| 6228 break; | |
| 6229 case CSSValueClosestSide: | |
| 6230 case CSSValueClosestCorner: | |
| 6231 case CSSValueFarthestSide: | |
| 6232 case CSSValueFarthestCorner: | |
| 6233 case CSSValueContain: | |
| 6234 case CSSValueCover: | |
| 6235 sizeValue = cssValuePool().createIdentifierValue(a->id); | |
| 6236 foundValue = true; | |
| 6237 break; | |
| 6238 default: | |
| 6239 break; | |
| 6240 } | |
| 6241 | |
| 6242 if (foundValue) { | |
| 6243 a = args->next(); | |
| 6244 if (!a) | |
| 6245 return false; | |
| 6246 | |
| 6247 expectComma = true; | |
| 6248 } | |
| 6249 } | |
| 6250 | |
| 6251 result->setShape(shapeValue); | |
| 6252 result->setSizingBehavior(sizeValue); | |
| 6253 | |
| 6254 // Or, two lengths or percentages | |
| 6255 RefPtrWillBeRawPtr<CSSPrimitiveValue> horizontalSize = nullptr; | |
| 6256 RefPtrWillBeRawPtr<CSSPrimitiveValue> verticalSize = nullptr; | |
| 6257 | |
| 6258 if (!shapeValue && !sizeValue) { | |
| 6259 if (validUnit(a, FLength | FPercent)) { | |
| 6260 horizontalSize = createPrimitiveNumericValue(a); | |
| 6261 a = args->next(); | |
| 6262 if (!a) | |
| 6263 return false; | |
| 6264 | |
| 6265 expectComma = true; | |
| 6266 } | |
| 6267 | |
| 6268 if (validUnit(a, FLength | FPercent)) { | |
| 6269 verticalSize = createPrimitiveNumericValue(a); | |
| 6270 | |
| 6271 a = args->next(); | |
| 6272 if (!a) | |
| 6273 return false; | |
| 6274 expectComma = true; | |
| 6275 } | |
| 6276 } | |
| 6277 | |
| 6278 // Must have neither or both. | |
| 6279 if (!horizontalSize != !verticalSize) | |
| 6280 return false; | |
| 6281 | |
| 6282 result->setEndHorizontalSize(horizontalSize); | |
| 6283 result->setEndVerticalSize(verticalSize); | |
| 6284 | |
| 6285 if (!parseGradientColorStops(args, result.get(), expectComma)) | |
| 6286 return false; | |
| 6287 | |
| 6288 gradient = result.release(); | |
| 6289 return true; | |
| 6290 } | |
| 6291 | |
| 6292 bool CSSPropertyParser::parseLinearGradient(CSSParserValueList* valueList, RefPt rWillBeRawPtr<CSSValue>& gradient, CSSGradientRepeat repeating) | |
| 6293 { | |
| 6294 RefPtrWillBeRawPtr<CSSLinearGradientValue> result = CSSLinearGradientValue:: create(repeating, CSSLinearGradient); | |
| 6295 | |
| 6296 CSSParserFunction* function = valueList->current()->function; | |
| 6297 CSSParserValueList* args = function->args.get(); | |
| 6298 if (!args || !args->size()) | |
| 6299 return false; | |
| 6300 | |
| 6301 CSSParserValue* a = args->current(); | |
| 6302 if (!a) | |
| 6303 return false; | |
| 6304 | |
| 6305 bool expectComma = false; | |
| 6306 // Look for angle. | |
| 6307 if (validUnit(a, FAngle, HTMLStandardMode)) { | |
| 6308 result->setAngle(createPrimitiveNumericValue(a)); | |
| 6309 | |
| 6310 args->next(); | |
| 6311 expectComma = true; | |
| 6312 } else if (a->m_unit == CSSParserValue::Identifier && a->id == CSSValueTo) { | |
| 6313 // to [ [left | right] || [top | bottom] ] | |
| 6314 a = args->next(); | |
| 6315 if (!a) | |
| 6316 return false; | |
| 6317 | |
| 6318 RefPtrWillBeRawPtr<CSSPrimitiveValue> endX = nullptr; | |
| 6319 RefPtrWillBeRawPtr<CSSPrimitiveValue> endY = nullptr; | |
| 6320 RefPtrWillBeRawPtr<CSSPrimitiveValue> location = nullptr; | |
| 6321 bool isHorizontal = false; | |
| 6322 | |
| 6323 location = valueFromSideKeyword(a, isHorizontal); | |
| 6324 if (!location) | |
| 6325 return false; | |
| 6326 | |
| 6327 if (isHorizontal) | |
| 6328 endX = location; | |
| 6329 else | |
| 6330 endY = location; | |
| 6331 | |
| 6332 a = args->next(); | |
| 6333 if (!a) | |
| 6334 return false; | |
| 6335 | |
| 6336 location = valueFromSideKeyword(a, isHorizontal); | |
| 6337 if (location) { | |
| 6338 if (isHorizontal) { | |
| 6339 if (endX) | |
| 6340 return false; | |
| 6341 endX = location; | |
| 6342 } else { | |
| 6343 if (endY) | |
| 6344 return false; | |
| 6345 endY = location; | |
| 6346 } | |
| 6347 | |
| 6348 args->next(); | |
| 6349 } | |
| 6350 | |
| 6351 expectComma = true; | |
| 6352 result->setFirstX(endX.release()); | |
| 6353 result->setFirstY(endY.release()); | |
| 6354 } | |
| 6355 | |
| 6356 if (!parseGradientColorStops(args, result.get(), expectComma)) | |
| 6357 return false; | |
| 6358 | |
| 6359 if (!result->stopCount()) | |
| 6360 return false; | |
| 6361 | |
| 6362 gradient = result.release(); | |
| 6363 return true; | |
| 6364 } | |
| 6365 | |
| 6366 bool CSSPropertyParser::parseRadialGradient(CSSParserValueList* valueList, RefPt rWillBeRawPtr<CSSValue>& gradient, CSSGradientRepeat repeating) | |
| 6367 { | |
| 6368 RefPtrWillBeRawPtr<CSSRadialGradientValue> result = CSSRadialGradientValue:: create(repeating, CSSRadialGradient); | |
| 6369 | |
| 6370 CSSParserValueList* args = valueList->current()->function->args.get(); | |
| 6371 if (!args || !args->size()) | |
| 6372 return false; | |
| 6373 | |
| 6374 CSSParserValue* a = args->current(); | |
| 6375 if (!a) | |
| 6376 return false; | |
| 6377 | |
| 6378 bool expectComma = false; | |
| 6379 | |
| 6380 RefPtrWillBeRawPtr<CSSPrimitiveValue> shapeValue = nullptr; | |
| 6381 RefPtrWillBeRawPtr<CSSPrimitiveValue> sizeValue = nullptr; | |
| 6382 RefPtrWillBeRawPtr<CSSPrimitiveValue> horizontalSize = nullptr; | |
| 6383 RefPtrWillBeRawPtr<CSSPrimitiveValue> verticalSize = nullptr; | |
| 6384 | |
| 6385 // First part of grammar, the size/shape clause: | |
| 6386 // [ circle || <length> ] | | |
| 6387 // [ ellipse || [ <length> | <percentage> ]{2} ] | | |
| 6388 // [ [ circle | ellipse] || <size-keyword> ] | |
| 6389 for (int i = 0; i < 3; ++i) { | |
| 6390 if (a->m_unit == CSSParserValue::Identifier) { | |
| 6391 bool badIdent = false; | |
| 6392 switch (a->id) { | |
| 6393 case CSSValueCircle: | |
| 6394 case CSSValueEllipse: | |
| 6395 if (shapeValue) | |
| 6396 return false; | |
| 6397 shapeValue = cssValuePool().createIdentifierValue(a->id); | |
| 6398 break; | |
| 6399 case CSSValueClosestSide: | |
| 6400 case CSSValueClosestCorner: | |
| 6401 case CSSValueFarthestSide: | |
| 6402 case CSSValueFarthestCorner: | |
| 6403 if (sizeValue || horizontalSize) | |
| 6404 return false; | |
| 6405 sizeValue = cssValuePool().createIdentifierValue(a->id); | |
| 6406 break; | |
| 6407 default: | |
| 6408 badIdent = true; | |
| 6409 } | |
| 6410 | |
| 6411 if (badIdent) | |
| 6412 break; | |
| 6413 | |
| 6414 a = args->next(); | |
| 6415 if (!a) | |
| 6416 return false; | |
| 6417 } else if (validUnit(a, FLength | FPercent)) { | |
| 6418 | |
| 6419 if (sizeValue || horizontalSize) | |
| 6420 return false; | |
| 6421 horizontalSize = createPrimitiveNumericValue(a); | |
| 6422 | |
| 6423 a = args->next(); | |
| 6424 if (!a) | |
| 6425 return false; | |
| 6426 | |
| 6427 if (validUnit(a, FLength | FPercent)) { | |
| 6428 verticalSize = createPrimitiveNumericValue(a); | |
| 6429 ++i; | |
| 6430 a = args->next(); | |
| 6431 if (!a) | |
| 6432 return false; | |
| 6433 } | |
| 6434 } else | |
| 6435 break; | |
| 6436 } | |
| 6437 | |
| 6438 // You can specify size as a keyword or a length/percentage, not both. | |
| 6439 if (sizeValue && horizontalSize) | |
| 6440 return false; | |
| 6441 // Circles must have 0 or 1 lengths. | |
| 6442 if (shapeValue && shapeValue->getValueID() == CSSValueCircle && verticalSize ) | |
| 6443 return false; | |
| 6444 // Ellipses must have 0 or 2 length/percentages. | |
| 6445 if (shapeValue && shapeValue->getValueID() == CSSValueEllipse && horizontalS ize && !verticalSize) | |
| 6446 return false; | |
| 6447 // If there's only one size, it must be a length. | |
| 6448 if (!verticalSize && horizontalSize && horizontalSize->isPercentage()) | |
| 6449 return false; | |
| 6450 | |
| 6451 result->setShape(shapeValue); | |
| 6452 result->setSizingBehavior(sizeValue); | |
| 6453 result->setEndHorizontalSize(horizontalSize); | |
| 6454 result->setEndVerticalSize(verticalSize); | |
| 6455 | |
| 6456 // Second part of grammar, the center-position clause: | |
| 6457 // at <position> | |
| 6458 RefPtrWillBeRawPtr<CSSValue> centerX = nullptr; | |
| 6459 RefPtrWillBeRawPtr<CSSValue> centerY = nullptr; | |
| 6460 if (a->m_unit == CSSParserValue::Identifier && a->id == CSSValueAt) { | |
| 6461 a = args->next(); | |
| 6462 if (!a) | |
| 6463 return false; | |
| 6464 | |
| 6465 parseFillPosition(args, centerX, centerY); | |
| 6466 if (!(centerX && centerY)) | |
| 6467 return false; | |
| 6468 | |
| 6469 a = args->current(); | |
| 6470 if (!a) | |
| 6471 return false; | |
| 6472 result->setFirstX(centerX); | |
| 6473 result->setFirstY(centerY); | |
| 6474 // Right now, CSS radial gradients have the same start and end centers. | |
| 6475 result->setSecondX(centerX); | |
| 6476 result->setSecondY(centerY); | |
| 6477 } | |
| 6478 | |
| 6479 if (shapeValue || sizeValue || horizontalSize || centerX || centerY) | |
| 6480 expectComma = true; | |
| 6481 | |
| 6482 if (!parseGradientColorStops(args, result.get(), expectComma)) | |
| 6483 return false; | |
| 6484 | |
| 6485 gradient = result.release(); | |
| 6486 return true; | |
| 6487 } | |
| 6488 | |
| 6489 bool CSSPropertyParser::parseGradientColorStops(CSSParserValueList* valueList, C SSGradientValue* gradient, bool expectComma) | |
| 6490 { | |
| 6491 CSSParserValue* a = valueList->current(); | |
| 6492 | |
| 6493 // Now look for color stops. | |
| 6494 // <color-stop-list> = [ <color-stop> , <color-hint>? ]# , <color-stop> | |
| 6495 bool supportsColorHints = gradient->gradientType() == CSSLinearGradient | |
| 6496 || gradient->gradientType() == CSSRadialGradient; | |
| 6497 | |
| 6498 // The first color stop cannot be a color hint. | |
| 6499 bool previousStopWasColorHint = true; | |
| 6500 while (a) { | |
| 6501 // Look for the comma before the next stop. | |
| 6502 if (expectComma) { | |
| 6503 if (!isComma(a)) | |
| 6504 return false; | |
| 6505 | |
| 6506 a = valueList->next(); | |
| 6507 if (!a) | |
| 6508 return false; | |
| 6509 } | |
| 6510 | |
| 6511 // <color-stop> = <color> [ <percentage> | <length> ]? | |
| 6512 // <color-hint> = <length> | <percentage> | |
| 6513 CSSGradientColorStop stop; | |
| 6514 stop.m_color = parseColor(a); | |
| 6515 | |
| 6516 // Two hints in a row are not allowed. | |
| 6517 if (!stop.m_color && (!supportsColorHints || previousStopWasColorHint)) | |
| 6518 return false; | |
| 6519 previousStopWasColorHint = !stop.m_color; | |
| 6520 | |
| 6521 if (stop.m_color) | |
| 6522 a = valueList->next(); | |
| 6523 | |
| 6524 if (a) { | |
| 6525 if (validUnit(a, FLength | FPercent)) { | |
| 6526 stop.m_position = createPrimitiveNumericValue(a); | |
| 6527 a = valueList->next(); | |
| 6528 } | |
| 6529 } | |
| 6530 | |
| 6531 if (!stop.m_color && !stop.m_position) | |
| 6532 return false; | |
| 6533 | |
| 6534 gradient->addStop(stop); | |
| 6535 expectComma = true; | |
| 6536 } | |
| 6537 | |
| 6538 // The last color stop cannot be a color hint. | |
| 6539 if (previousStopWasColorHint) | |
| 6540 return false; | |
| 6541 | |
| 6542 // Must have 2 or more stops to be valid. | |
| 6543 return gradient->stopCount() >= 2; | |
| 6544 } | |
| 6545 | |
| 6546 bool CSSPropertyParser::parseGeneratedImage(CSSParserValueList* valueList, RefPt rWillBeRawPtr<CSSValue>& value) | |
| 6547 { | |
| 6548 CSSParserValue* val = valueList->current(); | |
| 6549 | |
| 6550 if (val->m_unit != CSSParserValue::Function) | |
| 6551 return false; | |
| 6552 | |
| 6553 if (val->function->id == CSSValueWebkitGradient) { | |
| 6554 // FIXME: This should send a deprecation message. | |
| 6555 if (m_context.useCounter()) | |
| 6556 m_context.useCounter()->count(UseCounter::DeprecatedWebKitGradient); | |
| 6557 return parseDeprecatedGradient(valueList, value); | |
| 6558 } | |
| 6559 | |
| 6560 if (val->function->id == CSSValueWebkitLinearGradient) { | |
| 6561 // FIXME: This should send a deprecation message. | |
| 6562 if (m_context.useCounter()) | |
| 6563 m_context.useCounter()->count(UseCounter::DeprecatedWebKitLinearGrad ient); | |
| 6564 return parseDeprecatedLinearGradient(valueList, value, NonRepeating); | |
| 6565 } | |
| 6566 | |
| 6567 if (val->function->id == CSSValueLinearGradient) | |
| 6568 return parseLinearGradient(valueList, value, NonRepeating); | |
| 6569 | |
| 6570 if (val->function->id == CSSValueWebkitRepeatingLinearGradient) { | |
| 6571 // FIXME: This should send a deprecation message. | |
| 6572 if (m_context.useCounter()) | |
| 6573 m_context.useCounter()->count(UseCounter::DeprecatedWebKitRepeatingL inearGradient); | |
| 6574 return parseDeprecatedLinearGradient(valueList, value, Repeating); | |
| 6575 } | |
| 6576 | |
| 6577 if (val->function->id == CSSValueRepeatingLinearGradient) | |
| 6578 return parseLinearGradient(valueList, value, Repeating); | |
| 6579 | |
| 6580 if (val->function->id == CSSValueWebkitRadialGradient) { | |
| 6581 // FIXME: This should send a deprecation message. | |
| 6582 if (m_context.useCounter()) | |
| 6583 m_context.useCounter()->count(UseCounter::DeprecatedWebKitRadialGrad ient); | |
| 6584 return parseDeprecatedRadialGradient(valueList, value, NonRepeating); | |
| 6585 } | |
| 6586 | |
| 6587 if (val->function->id == CSSValueRadialGradient) | |
| 6588 return parseRadialGradient(valueList, value, NonRepeating); | |
| 6589 | |
| 6590 if (val->function->id == CSSValueWebkitRepeatingRadialGradient) { | |
| 6591 if (m_context.useCounter()) | |
| 6592 m_context.useCounter()->count(UseCounter::DeprecatedWebKitRepeatingR adialGradient); | |
| 6593 return parseDeprecatedRadialGradient(valueList, value, Repeating); | |
| 6594 } | |
| 6595 | |
| 6596 if (val->function->id == CSSValueRepeatingRadialGradient) | |
| 6597 return parseRadialGradient(valueList, value, Repeating); | |
| 6598 | |
| 6599 if (val->function->id == CSSValueWebkitCanvas) | |
| 6600 return parseCanvas(valueList, value); | |
| 6601 | |
| 6602 if (val->function->id == CSSValueWebkitCrossFade) | |
| 6603 return parseCrossfade(valueList, value); | |
| 6604 | |
| 6605 return false; | |
| 6606 } | |
| 6607 | |
| 6608 bool CSSPropertyParser::parseCrossfade(CSSParserValueList* valueList, RefPtrWill BeRawPtr<CSSValue>& crossfade) | |
| 6609 { | |
| 6610 // Walk the arguments. | |
| 6611 CSSParserValueList* args = valueList->current()->function->args.get(); | |
| 6612 if (!args || args->size() != 5) | |
| 6613 return false; | |
| 6614 RefPtrWillBeRawPtr<CSSValue> fromImageValue = nullptr; | |
| 6615 RefPtrWillBeRawPtr<CSSValue> toImageValue = nullptr; | |
| 6616 | |
| 6617 // The first argument is the "from" image. It is a fill image. | |
| 6618 if (!args->current() || !parseFillImage(args, fromImageValue)) | |
| 6619 return false; | |
| 6620 args->next(); | |
| 6621 | |
| 6622 if (!consumeComma(args)) | |
| 6623 return false; | |
| 6624 | |
| 6625 // The second argument is the "to" image. It is a fill image. | |
| 6626 if (!args->current() || !parseFillImage(args, toImageValue)) | |
| 6627 return false; | |
| 6628 args->next(); | |
| 6629 | |
| 6630 if (!consumeComma(args)) | |
| 6631 return false; | |
| 6632 | |
| 6633 // The third argument is the crossfade value. It is a percentage or a fracti onal number. | |
| 6634 RefPtrWillBeRawPtr<CSSPrimitiveValue> percentage = nullptr; | |
| 6635 CSSParserValue* value = args->current(); | |
| 6636 if (!value) | |
| 6637 return false; | |
| 6638 | |
| 6639 if (value->unit() == CSSPrimitiveValue::UnitType::Percentage) | |
| 6640 percentage = cssValuePool().createValue(clampTo<double>(value->fValue / 100, 0, 1), CSSPrimitiveValue::UnitType::Number); | |
| 6641 else if (value->unit() == CSSPrimitiveValue::UnitType::Number) | |
| 6642 percentage = cssValuePool().createValue(clampTo<double>(value->fValue, 0 , 1), CSSPrimitiveValue::UnitType::Number); | |
| 6643 else | |
| 6644 return false; | |
| 6645 | |
| 6646 RefPtrWillBeRawPtr<CSSCrossfadeValue> result = CSSCrossfadeValue::create(fro mImageValue, toImageValue); | |
| 6647 result->setPercentage(percentage); | |
| 6648 | |
| 6649 crossfade = result; | |
| 6650 | |
| 6651 return true; | |
| 6652 } | |
| 6653 | |
| 6654 bool CSSPropertyParser::parseCanvas(CSSParserValueList* valueList, RefPtrWillBeR awPtr<CSSValue>& canvas) | |
| 6655 { | |
| 6656 // Walk the arguments. | |
| 6657 CSSParserValueList* args = valueList->current()->function->args.get(); | |
| 6658 if (!args || args->size() != 1) | |
| 6659 return false; | |
| 6660 | |
| 6661 // The first argument is the canvas name. It is an identifier. | |
| 6662 CSSParserValue* value = args->current(); | |
| 6663 if (!value || value->m_unit != CSSParserValue::Identifier) | |
| 6664 return false; | |
| 6665 | |
| 6666 canvas = CSSCanvasValue::create(value->string); | |
| 6667 return true; | |
| 6668 } | |
| 6669 | |
| 6670 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseImageSet(CSSParserValue List* valueList) | |
| 6671 { | |
| 6672 CSSParserValue* function = valueList->current(); | |
| 6673 | |
| 6674 if (function->m_unit != CSSParserValue::Function) | |
| 6675 return nullptr; | |
| 6676 | |
| 6677 CSSParserValueList* functionArgs = valueList->current()->function->args.get( ); | |
| 6678 if (!functionArgs || !functionArgs->size() || !functionArgs->current()) | |
| 6679 return nullptr; | |
| 6680 | |
| 6681 RefPtrWillBeRawPtr<CSSImageSetValue> imageSet = CSSImageSetValue::create(); | |
| 6682 | |
| 6683 while (functionArgs->current()) { | |
| 6684 CSSParserValue* arg = functionArgs->current(); | |
| 6685 if (arg->unit() != CSSPrimitiveValue::UnitType::URI) | |
| 6686 return nullptr; | |
| 6687 | |
| 6688 RefPtrWillBeRawPtr<CSSValue> image = createCSSImageValueWithReferrer(arg ->string, completeURL(arg->string)); | |
| 6689 imageSet->append(image); | |
| 6690 | |
| 6691 arg = functionArgs->next(); | |
| 6692 if (!arg) | |
| 6693 return nullptr; | |
| 6694 | |
| 6695 if (arg->m_unit != CSSParserValue::DimensionList) | |
| 6696 return nullptr; | |
| 6697 ASSERT(arg->valueList->valueAt(0)->unit() == CSSPrimitiveValue::UnitType ::Number); | |
| 6698 ASSERT(arg->valueList->valueAt(1)->m_unit == CSSParserValue::Identifier) ; | |
| 6699 if (String(arg->valueList->valueAt(1)->string) != "x") | |
| 6700 return nullptr; | |
| 6701 double imageScaleFactor = arg->valueList->valueAt(0)->fValue; | |
| 6702 if (imageScaleFactor <= 0) | |
| 6703 return nullptr; | |
| 6704 imageSet->append(cssValuePool().createValue(imageScaleFactor, CSSPrimiti veValue::UnitType::Number)); | |
| 6705 functionArgs->next(); | |
| 6706 | |
| 6707 // If there are no more arguments, we're done. | |
| 6708 if (!functionArgs->current()) | |
| 6709 break; | |
| 6710 | |
| 6711 // If there are more arguments, they should be after a comma. | |
| 6712 if (!consumeComma(functionArgs)) | |
| 6713 return nullptr; | |
| 6714 } | |
| 6715 | |
| 6716 return imageSet.release(); | |
| 6717 } | |
| 6718 | |
| 6719 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseWillChange() | |
| 6720 { | |
| 6721 RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::createCommaSeparated (); | |
| 6722 if (m_valueList->current()->id == CSSValueAuto) { | |
| 6723 // FIXME: This will be read back as an empty string instead of auto | |
| 6724 return values.release(); | |
| 6725 } | |
| 6726 | |
| 6727 // Every comma-separated list of identifiers is a valid will-change value, | |
| 6728 // unless the list includes an explicitly disallowed identifier. | |
| 6729 while (true) { | |
| 6730 CSSParserValue* currentValue = m_valueList->current(); | |
| 6731 if (!currentValue || currentValue->m_unit != CSSParserValue::Identifier) | |
| 6732 return nullptr; | |
| 6733 | |
| 6734 CSSPropertyID unresolvedProperty = unresolvedCSSPropertyID(currentValue- >string); | |
| 6735 if (unresolvedProperty) { | |
| 6736 ASSERT(CSSPropertyMetadata::isEnabledProperty(unresolvedProperty)); | |
| 6737 // Now "all" is used by both CSSValue and CSSPropertyValue. | |
| 6738 // Need to return nullptr when currentValue is CSSPropertyAll. | |
| 6739 if (unresolvedProperty == CSSPropertyWillChange || unresolvedPropert y == CSSPropertyAll) | |
| 6740 return nullptr; | |
| 6741 values->append(cssValuePool().createIdentifierValue(unresolvedProper ty)); | |
| 6742 } else { | |
| 6743 switch (currentValue->id) { | |
| 6744 case CSSValueNone: | |
| 6745 case CSSValueAll: | |
| 6746 case CSSValueAuto: | |
| 6747 case CSSValueDefault: | |
| 6748 case CSSValueInitial: | |
| 6749 case CSSValueInherit: | |
| 6750 return nullptr; | |
| 6751 case CSSValueContents: | |
| 6752 case CSSValueScrollPosition: | |
| 6753 values->append(cssValuePool().createIdentifierValue(currentValue ->id)); | |
| 6754 break; | |
| 6755 default: | |
| 6756 break; | |
| 6757 } | |
| 6758 } | |
| 6759 | |
| 6760 if (!m_valueList->next()) | |
| 6761 break; | |
| 6762 if (!consumeComma(m_valueList)) | |
| 6763 return nullptr; | |
| 6764 } | |
| 6765 | |
| 6766 return values.release(); | |
| 6767 } | |
| 6768 | |
| 6769 PassRefPtrWillBeRawPtr<CSSFunctionValue> CSSPropertyParser::parseBuiltinFilterAr guments(CSSParserValueList* args, CSSValueID filterType) | |
| 6770 { | |
| 6771 RefPtrWillBeRawPtr<CSSFunctionValue> filterValue = CSSFunctionValue::create( filterType); | |
| 6772 ASSERT(args); | |
| 6773 | |
| 6774 switch (filterType) { | |
| 6775 case CSSValueGrayscale: | |
| 6776 case CSSValueSepia: | |
| 6777 case CSSValueSaturate: | |
| 6778 case CSSValueInvert: | |
| 6779 case CSSValueOpacity: | |
| 6780 case CSSValueContrast: { | |
| 6781 // One optional argument, 0-1 or 0%-100%, if missing use 100%. | |
| 6782 if (args->size()) { | |
| 6783 CSSParserValue* value = args->current(); | |
| 6784 // FIXME (crbug.com/397061): Support calc expressions like calc(10% + 0.5) | |
| 6785 if (value->unit() != CSSPrimitiveValue::UnitType::Percentage && !val idUnit(value, FNumber | FNonNeg)) | |
| 6786 return nullptr; | |
| 6787 | |
| 6788 double amount = value->fValue; | |
| 6789 if (amount < 0) | |
| 6790 return nullptr; | |
| 6791 | |
| 6792 // Saturate and Contrast allow values over 100%. | |
| 6793 if (filterType != CSSValueSaturate | |
| 6794 && filterType != CSSValueContrast) { | |
| 6795 double maxAllowed = value->unit() == CSSPrimitiveValue::UnitType ::Percentage ? 100.0 : 1.0; | |
| 6796 if (amount > maxAllowed) | |
| 6797 return nullptr; | |
| 6798 } | |
| 6799 | |
| 6800 filterValue->append(cssValuePool().createValue(amount, value->unit() )); | |
| 6801 } | |
| 6802 break; | |
| 6803 } | |
| 6804 case CSSValueBrightness: { | |
| 6805 // One optional argument, if missing use 100%. | |
| 6806 if (args->size()) { | |
| 6807 CSSParserValue* value = args->current(); | |
| 6808 // FIXME (crbug.com/397061): Support calc expressions like calc(10% + 0.5) | |
| 6809 if (value->unit() != CSSPrimitiveValue::UnitType::Percentage && !val idUnit(value, FNumber)) | |
| 6810 return nullptr; | |
| 6811 | |
| 6812 filterValue->append(cssValuePool().createValue(value->fValue, value- >unit())); | |
| 6813 } | |
| 6814 break; | |
| 6815 } | |
| 6816 case CSSValueHueRotate: { | |
| 6817 // hue-rotate() takes one optional angle. | |
| 6818 if (args->size()) { | |
| 6819 CSSParserValue* argument = args->current(); | |
| 6820 if (!validUnit(argument, FAngle, HTMLStandardMode)) | |
| 6821 return nullptr; | |
| 6822 | |
| 6823 filterValue->append(createPrimitiveNumericValue(argument)); | |
| 6824 } | |
| 6825 break; | |
| 6826 } | |
| 6827 case CSSValueBlur: { | |
| 6828 // Blur takes a single length. Zero parameters are allowed. | |
| 6829 if (args->size()) { | |
| 6830 CSSParserValue* argument = args->current(); | |
| 6831 if (!validUnit(argument, FLength | FNonNeg, HTMLStandardMode)) | |
| 6832 return nullptr; | |
| 6833 | |
| 6834 filterValue->append(createPrimitiveNumericValue(argument)); | |
| 6835 } | |
| 6836 break; | |
| 6837 } | |
| 6838 case CSSValueDropShadow: { | |
| 6839 // drop-shadow() takes a single shadow. | |
| 6840 RefPtrWillBeRawPtr<CSSShadowValue> shadowValue = parseSingleShadow(args, false, true); | |
| 6841 if (!shadowValue) | |
| 6842 return nullptr; | |
| 6843 filterValue->append(shadowValue.release()); | |
| 6844 break; | |
| 6845 } | |
| 6846 default: | |
| 6847 return nullptr; | |
| 6848 } | |
| 6849 return filterValue.release(); | |
| 6850 } | |
| 6851 | |
| 6852 PassRefPtrWillBeRawPtr<CSSValueList> CSSPropertyParser::parseFilter() | |
| 6853 { | |
| 6854 if (!m_valueList) | |
| 6855 return nullptr; | |
| 6856 | |
| 6857 // The filter is a list of functional primitives that specify individual ope rations. | |
| 6858 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated() ; | |
| 6859 for (CSSParserValue* value = m_valueList->current(); value; value = m_valueL ist->next()) { | |
| 6860 if (value->unit() != CSSPrimitiveValue::UnitType::URI && (value->m_unit != CSSParserValue::Function || !value->function)) | |
| 6861 return nullptr; | |
| 6862 | |
| 6863 // See if the specified primitive is one we understand. | |
| 6864 if (value->unit() == CSSPrimitiveValue::UnitType::URI) { | |
| 6865 RefPtrWillBeRawPtr<CSSFunctionValue> referenceFilterValue = CSSFunct ionValue::create(CSSValueUrl); | |
| 6866 referenceFilterValue->append(CSSSVGDocumentValue::create(value->stri ng)); | |
| 6867 list->append(referenceFilterValue.release()); | |
| 6868 } else { | |
| 6869 CSSValueID filterType = value->function->id; | |
| 6870 unsigned maximumArgumentCount = filterType == CSSValueDropShadow ? 4 : 1; | |
| 6871 | |
| 6872 CSSParserValueList* args = value->function->args.get(); | |
| 6873 if (!args || args->size() > maximumArgumentCount) | |
| 6874 return nullptr; | |
| 6875 | |
| 6876 RefPtrWillBeRawPtr<CSSFunctionValue> filterValue = parseBuiltinFilte rArguments(args, filterType); | |
| 6877 if (!filterValue) | |
| 6878 return nullptr; | |
| 6879 | |
| 6880 list->append(filterValue); | |
| 6881 } | |
| 6882 } | |
| 6883 | |
| 6884 return list.release(); | |
| 6885 } | |
| 6886 | |
| 6887 PassRefPtrWillBeRawPtr<CSSValueList> CSSPropertyParser::parseTransformOrigin() | |
| 6888 { | |
| 6889 CSSParserValue* value = m_valueList->current(); | |
| 6890 CSSValueID id = value->id; | |
| 6891 RefPtrWillBeRawPtr<CSSValue> xValue = nullptr; | |
| 6892 RefPtrWillBeRawPtr<CSSValue> yValue = nullptr; | |
| 6893 RefPtrWillBeRawPtr<CSSValue> zValue = nullptr; | |
| 6894 if (id == CSSValueLeft || id == CSSValueRight) { | |
| 6895 xValue = cssValuePool().createIdentifierValue(id); | |
| 6896 } else if (id == CSSValueTop || id == CSSValueBottom) { | |
| 6897 yValue = cssValuePool().createIdentifierValue(id); | |
| 6898 } else if (id == CSSValueCenter) { | |
| 6899 // Unresolved as to whether this is X or Y. | |
| 6900 } else if (validUnit(value, FPercent | FLength)) { | |
| 6901 xValue = createPrimitiveNumericValue(value); | |
| 6902 } else { | |
| 6903 return nullptr; | |
| 6904 } | |
| 6905 | |
| 6906 value = m_valueList->next(); | |
| 6907 if (value) { | |
| 6908 id = value->id; | |
| 6909 if (!xValue && (id == CSSValueLeft || id == CSSValueRight)) { | |
| 6910 xValue = cssValuePool().createIdentifierValue(id); | |
| 6911 } else if (!yValue && (id == CSSValueTop || id == CSSValueBottom)) { | |
| 6912 yValue = cssValuePool().createIdentifierValue(id); | |
| 6913 } else if (id == CSSValueCenter) { | |
| 6914 // Resolved below. | |
| 6915 } else if (!yValue && validUnit(value, FPercent | FLength)) { | |
| 6916 yValue = createPrimitiveNumericValue(value); | |
| 6917 } else { | |
| 6918 return nullptr; | |
| 6919 } | |
| 6920 | |
| 6921 // If X or Y have not been resolved, they must be center. | |
| 6922 if (!xValue) | |
| 6923 xValue = cssValuePool().createIdentifierValue(CSSValueCenter); | |
| 6924 if (!yValue) | |
| 6925 yValue = cssValuePool().createIdentifierValue(CSSValueCenter); | |
| 6926 | |
| 6927 value = m_valueList->next(); | |
| 6928 if (value) { | |
| 6929 if (!validUnit(value, FLength)) | |
| 6930 return nullptr; | |
| 6931 zValue = createPrimitiveNumericValue(value); | |
| 6932 | |
| 6933 value = m_valueList->next(); | |
| 6934 if (value) | |
| 6935 return nullptr; | |
| 6936 } | |
| 6937 } else if (!xValue) { | |
| 6938 if (yValue) { | |
| 6939 xValue = cssValuePool().createValue(50, CSSPrimitiveValue::UnitType: :Percentage); | |
| 6940 } else { | |
| 6941 xValue = cssValuePool().createIdentifierValue(CSSValueCenter); | |
| 6942 } | |
| 6943 } | |
| 6944 | |
| 6945 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated() ; | |
| 6946 list->append(xValue.release()); | |
| 6947 if (yValue) | |
| 6948 list->append(yValue.release()); | |
| 6949 if (zValue) | |
| 6950 list->append(zValue.release()); | |
| 6951 return list.release(); | |
| 6952 } | |
| 6953 | |
| 6954 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseTouchAction() | |
| 6955 { | |
| 6956 CSSParserValue* value = m_valueList->current(); | |
| 6957 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated() ; | |
| 6958 if (m_valueList->size() == 1 && value && (value->id == CSSValueAuto || value ->id == CSSValueNone || value->id == CSSValueManipulation)) { | |
| 6959 list->append(cssValuePool().createIdentifierValue(value->id)); | |
| 6960 m_valueList->next(); | |
| 6961 return list.release(); | |
| 6962 } | |
| 6963 | |
| 6964 bool xSet = false; | |
| 6965 bool ySet = false; | |
| 6966 while (value) { | |
| 6967 switch (value->id) { | |
| 6968 case CSSValuePanX: | |
| 6969 case CSSValuePanRight: | |
| 6970 case CSSValuePanLeft: { | |
| 6971 if (xSet) | |
| 6972 return nullptr; | |
| 6973 xSet = true; | |
| 6974 if (value->id != CSSValuePanX && !RuntimeEnabledFeatures::cssTouchAc tionPanDirectionsEnabled()) | |
| 6975 return nullptr; | |
| 6976 | |
| 6977 RefPtrWillBeRawPtr<CSSValue> panValue = cssValuePool().createIdentif ierValue(value->id); | |
| 6978 list->append(panValue.release()); | |
| 6979 break; | |
| 6980 } | |
| 6981 case CSSValuePanY: | |
| 6982 case CSSValuePanDown: | |
| 6983 case CSSValuePanUp: { | |
| 6984 if (ySet) | |
| 6985 return nullptr; | |
| 6986 ySet = true; | |
| 6987 if (value->id != CSSValuePanY && !RuntimeEnabledFeatures::cssTouchAc tionPanDirectionsEnabled()) | |
| 6988 return nullptr; | |
| 6989 RefPtrWillBeRawPtr<CSSValue> panValue = cssValuePool().createIdentif ierValue(value->id); | |
| 6990 list->append(panValue.release()); | |
| 6991 break; | |
| 6992 } | |
| 6993 default: | |
| 6994 return nullptr; | |
| 6995 } | |
| 6996 value = m_valueList->next(); | |
| 6997 } | |
| 6998 | |
| 6999 if (list->length()) | |
| 7000 return list.release(); | |
| 7001 | |
| 7002 return nullptr; | |
| 7003 } | |
| 7004 | |
| 7005 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseTextDecoration() | |
| 7006 { | |
| 7007 CSSParserValue* value = m_valueList->current(); | |
| 7008 if (value && value->id == CSSValueNone) { | |
| 7009 m_valueList->next(); | |
| 7010 return cssValuePool().createIdentifierValue(CSSValueNone); | |
| 7011 } | |
| 7012 | |
| 7013 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated() ; | |
| 7014 bool isValid = true; | |
| 7015 while (isValid && value) { | |
| 7016 switch (value->id) { | |
| 7017 case CSSValueUnderline: | |
| 7018 case CSSValueOverline: | |
| 7019 case CSSValueLineThrough: | |
| 7020 case CSSValueBlink: | |
| 7021 // TODO(timloh): This will incorrectly accept "blink blink" | |
| 7022 list->append(cssValuePool().createIdentifierValue(value->id)); | |
| 7023 break; | |
| 7024 default: | |
| 7025 isValid = false; | |
| 7026 break; | |
| 7027 } | |
| 7028 if (isValid) | |
| 7029 value = m_valueList->next(); | |
| 7030 } | |
| 7031 | |
| 7032 // Values are either valid or in shorthand scope. | |
| 7033 if (list->length()) | |
| 7034 return list.release(); | |
| 7035 return nullptr; | |
| 7036 } | |
| 7037 | |
| 7038 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseTextEmphasisStyle() | |
| 7039 { | |
| 7040 RefPtrWillBeRawPtr<CSSPrimitiveValue> fill = nullptr; | |
| 7041 RefPtrWillBeRawPtr<CSSPrimitiveValue> shape = nullptr; | |
| 7042 | |
| 7043 for (CSSParserValue* value = m_valueList->current(); value; value = m_valueL ist->next()) { | |
| 7044 if (value->unit() == CSSPrimitiveValue::UnitType::String) { | |
| 7045 if (fill || shape) | |
| 7046 return nullptr; | |
| 7047 m_valueList->next(); | |
| 7048 return createPrimitiveStringValue(value); | |
| 7049 } | |
| 7050 | |
| 7051 if (value->id == CSSValueNone) { | |
| 7052 if (fill || shape) | |
| 7053 return nullptr; | |
| 7054 m_valueList->next(); | |
| 7055 return cssValuePool().createIdentifierValue(CSSValueNone); | |
| 7056 } | |
| 7057 | |
| 7058 if (value->id == CSSValueOpen || value->id == CSSValueFilled) { | |
| 7059 if (fill) | |
| 7060 return nullptr; | |
| 7061 fill = cssValuePool().createIdentifierValue(value->id); | |
| 7062 } else if (value->id == CSSValueDot || value->id == CSSValueCircle || va lue->id == CSSValueDoubleCircle || value->id == CSSValueTriangle || value->id == CSSValueSesame) { | |
| 7063 if (shape) | |
| 7064 return nullptr; | |
| 7065 shape = cssValuePool().createIdentifierValue(value->id); | |
| 7066 } else { | |
| 7067 break; | |
| 7068 } | |
| 7069 } | |
| 7070 | |
| 7071 if (fill && shape) { | |
| 7072 RefPtrWillBeRawPtr<CSSValueList> parsedValues = CSSValueList::createSpac eSeparated(); | |
| 7073 parsedValues->append(fill.release()); | |
| 7074 parsedValues->append(shape.release()); | |
| 7075 return parsedValues.release(); | |
| 7076 } | |
| 7077 if (fill) | |
| 7078 return fill.release(); | |
| 7079 if (shape) | |
| 7080 return shape.release(); | |
| 7081 | |
| 7082 return nullptr; | |
| 7083 } | |
| 7084 | |
| 7085 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseTextIndent() | |
| 7086 { | |
| 7087 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated() ; | |
| 7088 | |
| 7089 bool hasLengthOrPercentage = false; | |
| 7090 bool hasEachLine = false; | |
| 7091 bool hasHanging = false; | |
| 7092 | |
| 7093 for (CSSParserValue* value = m_valueList->current(); value; value = m_valueL ist->next()) { | |
| 7094 // <length> | <percentage> | inherit when RuntimeEnabledFeatures::css3Te xtEnabled() returns false | |
| 7095 if (!hasLengthOrPercentage && validUnit(value, FLength | FPercent | FUni tlessQuirk)) { | |
| 7096 list->append(createPrimitiveNumericValue(value)); | |
| 7097 hasLengthOrPercentage = true; | |
| 7098 continue; | |
| 7099 } | |
| 7100 | |
| 7101 // [ <length> | <percentage> ] && hanging? && each-line? | inherit | |
| 7102 // when RuntimeEnabledFeatures::css3TextEnabled() returns true | |
| 7103 if (RuntimeEnabledFeatures::css3TextEnabled()) { | |
| 7104 if (!hasEachLine && value->id == CSSValueEachLine) { | |
| 7105 list->append(cssValuePool().createIdentifierValue(CSSValueEachLi ne)); | |
| 7106 hasEachLine = true; | |
| 7107 continue; | |
| 7108 } | |
| 7109 if (!hasHanging && value->id == CSSValueHanging) { | |
| 7110 list->append(cssValuePool().createIdentifierValue(CSSValueHangin g)); | |
| 7111 hasHanging = true; | |
| 7112 continue; | |
| 7113 } | |
| 7114 } | |
| 7115 return nullptr; | |
| 7116 } | |
| 7117 | |
| 7118 if (!hasLengthOrPercentage) | |
| 7119 return nullptr; | |
| 7120 | |
| 7121 return list.release(); | |
| 7122 } | |
| 7123 | |
| 7124 bool CSSPropertyParser::parseFontFeatureTag(CSSValueList* settings) | |
| 7125 { | |
| 7126 // Feature tag name consists of 4-letter characters. | |
| 7127 static const unsigned tagNameLength = 4; | |
| 7128 | |
| 7129 CSSParserValue* value = m_valueList->current(); | |
| 7130 // Feature tag name comes first | |
| 7131 if (value->unit() != CSSPrimitiveValue::UnitType::String) | |
| 7132 return false; | |
| 7133 if (value->string.length() != tagNameLength) | |
| 7134 return false; | |
| 7135 for (unsigned i = 0; i < tagNameLength; ++i) { | |
| 7136 // Limits the range of characters to 0x20-0x7E, following the tag name r ules defiend in the OpenType specification. | |
| 7137 UChar character = value->string[i]; | |
| 7138 if (character < 0x20 || character > 0x7E) | |
| 7139 return false; | |
| 7140 } | |
| 7141 | |
| 7142 AtomicString tag = value->string; | |
| 7143 int tagValue = 1; | |
| 7144 // Feature tag values could follow: <integer> | on | off | |
| 7145 value = m_valueList->next(); | |
| 7146 if (value) { | |
| 7147 if (value->unit() == CSSPrimitiveValue::UnitType::Number && value->isInt && value->fValue >= 0) { | |
| 7148 tagValue = clampTo<int>(value->fValue); | |
| 7149 if (tagValue < 0) | |
| 7150 return false; | |
| 7151 m_valueList->next(); | |
| 7152 } else if (value->id == CSSValueOn || value->id == CSSValueOff) { | |
| 7153 tagValue = value->id == CSSValueOn; | |
| 7154 m_valueList->next(); | |
| 7155 } | |
| 7156 } | |
| 7157 settings->append(CSSFontFeatureValue::create(tag, tagValue)); | |
| 7158 return true; | |
| 7159 } | |
| 7160 | |
| 7161 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseFontFeatureSettings() | |
| 7162 { | |
| 7163 RefPtrWillBeRawPtr<CSSValueList> settings = CSSValueList::createCommaSeparat ed(); | |
| 7164 while (true) { | |
| 7165 if (!m_valueList->current() || !parseFontFeatureTag(settings.get())) | |
| 7166 return nullptr; | |
| 7167 if (!m_valueList->current()) | |
| 7168 break; | |
| 7169 if (!consumeComma(m_valueList)) | |
| 7170 return nullptr; | |
| 7171 } | |
| 7172 return settings.release(); | |
| 7173 } | |
| 7174 | |
| 7175 bool CSSPropertyParser::parseFontVariantLigatures(bool important) | |
| 7176 { | |
| 7177 RefPtrWillBeRawPtr<CSSValueList> ligatureValues = CSSValueList::createSpaceS eparated(); | |
| 7178 bool sawCommonLigaturesValue = false; | |
| 7179 bool sawDiscretionaryLigaturesValue = false; | |
| 7180 bool sawHistoricalLigaturesValue = false; | |
| 7181 bool sawContextualLigaturesValue = false; | |
| 7182 | |
| 7183 for (CSSParserValue* value = m_valueList->current(); value; value = m_valueL ist->next()) { | |
| 7184 if (value->m_unit != CSSParserValue::Identifier) | |
| 7185 return false; | |
| 7186 | |
| 7187 switch (value->id) { | |
| 7188 case CSSValueNoCommonLigatures: | |
| 7189 case CSSValueCommonLigatures: | |
| 7190 if (sawCommonLigaturesValue) | |
| 7191 return false; | |
| 7192 sawCommonLigaturesValue = true; | |
| 7193 ligatureValues->append(cssValuePool().createIdentifierValue(value->i d)); | |
| 7194 break; | |
| 7195 case CSSValueNoDiscretionaryLigatures: | |
| 7196 case CSSValueDiscretionaryLigatures: | |
| 7197 if (sawDiscretionaryLigaturesValue) | |
| 7198 return false; | |
| 7199 sawDiscretionaryLigaturesValue = true; | |
| 7200 ligatureValues->append(cssValuePool().createIdentifierValue(value->i d)); | |
| 7201 break; | |
| 7202 case CSSValueNoHistoricalLigatures: | |
| 7203 case CSSValueHistoricalLigatures: | |
| 7204 if (sawHistoricalLigaturesValue) | |
| 7205 return false; | |
| 7206 sawHistoricalLigaturesValue = true; | |
| 7207 ligatureValues->append(cssValuePool().createIdentifierValue(value->i d)); | |
| 7208 break; | |
| 7209 case CSSValueNoContextual: | |
| 7210 case CSSValueContextual: | |
| 7211 if (sawContextualLigaturesValue) | |
| 7212 return false; | |
| 7213 sawContextualLigaturesValue = true; | |
| 7214 ligatureValues->append(cssValuePool().createIdentifierValue(value->i d)); | |
| 7215 break; | |
| 7216 default: | |
| 7217 return false; | |
| 7218 } | |
| 7219 } | |
| 7220 | |
| 7221 if (!ligatureValues->length()) | |
| 7222 return false; | |
| 7223 | |
| 7224 addProperty(CSSPropertyFontVariantLigatures, ligatureValues.release(), impor tant); | |
| 7225 return true; | |
| 7226 } | |
| 7227 | |
| 7228 bool CSSPropertyParser::parseCalculation(CSSParserValue* value, ValueRange range ) | |
| 7229 { | |
| 7230 ASSERT(isCalculation(value)); | |
| 7231 | |
| 7232 CSSParserTokenRange args = value->calcFunction->args; | |
| 7233 | |
| 7234 ASSERT(!m_parsedCalculation); | |
| 7235 m_parsedCalculation = CSSCalcValue::create(args, range); | |
| 7236 | |
| 7237 if (!m_parsedCalculation) | |
| 7238 return false; | |
| 7239 | |
| 7240 return true; | |
| 7241 } | |
| 7242 | |
| 7243 bool CSSPropertyParser::parseFontFaceDescriptor(CSSPropertyID propId) | |
| 7244 { | |
| 7245 CSSParserValue* value = m_valueList->current(); | |
| 7246 ASSERT(value); | |
| 7247 CSSValueID id = value->id; | |
| 7248 RefPtrWillBeRawPtr<CSSValue> parsedValue = nullptr; | |
| 7249 | |
| 7250 switch (propId) { | |
| 7251 case CSSPropertyFontFamily: | |
| 7252 // <family-name> | |
| 7253 // TODO(rwlbuis): check there is only one family-name | |
| 7254 parsedValue = parseFontFamily(); | |
| 7255 break; | |
| 7256 case CSSPropertySrc: // This is a list of urls or local references. | |
| 7257 parsedValue = parseFontFaceSrc(); | |
| 7258 break; | |
| 7259 case CSSPropertyUnicodeRange: | |
| 7260 parsedValue = parseFontFaceUnicodeRange(); | |
| 7261 break; | |
| 7262 case CSSPropertyFontWeight: // normal | bold | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | |
| 7263 return parseFontWeight(false) && !m_valueList->next(); | |
| 7264 case CSSPropertyFontStretch: | |
| 7265 case CSSPropertyFontStyle: | |
| 7266 if (!CSSParserFastPaths::isValidKeywordPropertyAndValue(propId, id)) | |
| 7267 return false; | |
| 7268 addProperty(propId, cssValuePool().createIdentifierValue(id), false); | |
| 7269 return true; | |
| 7270 case CSSPropertyFontVariant: // normal | small-caps | inherit | |
| 7271 return parseFontVariant(false); | |
| 7272 case CSSPropertyWebkitFontFeatureSettings: | |
| 7273 if (id == CSSValueNormal) { | |
| 7274 parsedValue = cssValuePool().createIdentifierValue(CSSValueNormal); | |
| 7275 m_valueList->next(); | |
| 7276 } else { | |
| 7277 parsedValue = parseFontFeatureSettings(); | |
| 7278 } | |
| 7279 break; | |
| 7280 default: | |
| 7281 break; | |
| 7282 } | |
| 7283 | |
| 7284 if (!parsedValue || m_valueList->current()) | |
| 7285 return false; | |
| 7286 | |
| 7287 addProperty(propId, parsedValue.release(), false); | |
| 7288 return true; | |
| 7289 } | |
| 7290 | |
| 7291 bool CSSPropertyParser::parseViewportProperty(CSSPropertyID propId, bool importa nt) | |
| 7292 { | |
| 7293 ASSERT(RuntimeEnabledFeatures::cssViewportEnabled() || isUASheetBehavior(m_c ontext.mode())); | |
| 7294 | |
| 7295 CSSParserValue* value = m_valueList->current(); | |
| 7296 if (!value) | |
| 7297 return false; | |
| 7298 | |
| 7299 CSSValueID id = value->id; | |
| 7300 bool validPrimitive = false; | |
| 7301 | |
| 7302 switch (propId) { | |
| 7303 case CSSPropertyMinWidth: // auto | extend-to-zoom | <length> | <percentage> | |
| 7304 case CSSPropertyMaxWidth: | |
| 7305 case CSSPropertyMinHeight: | |
| 7306 case CSSPropertyMaxHeight: | |
| 7307 if (id == CSSValueAuto || id == CSSValueInternalExtendToZoom) | |
| 7308 validPrimitive = true; | |
| 7309 else | |
| 7310 validPrimitive = validUnit(value, FLength | FPercent | FNonNeg); | |
| 7311 break; | |
| 7312 case CSSPropertyWidth: // shorthand | |
| 7313 return parseViewportShorthand(propId, CSSPropertyMinWidth, CSSPropertyMa xWidth, important); | |
| 7314 case CSSPropertyHeight: | |
| 7315 return parseViewportShorthand(propId, CSSPropertyMinHeight, CSSPropertyM axHeight, important); | |
| 7316 case CSSPropertyMinZoom: // auto | <number> | <percentage> | |
| 7317 case CSSPropertyMaxZoom: | |
| 7318 case CSSPropertyZoom: | |
| 7319 if (id == CSSValueAuto) | |
| 7320 validPrimitive = true; | |
| 7321 else | |
| 7322 validPrimitive = validUnit(value, FNumber | FPercent | FNonNeg); | |
| 7323 break; | |
| 7324 case CSSPropertyUserZoom: // zoom | fixed | |
| 7325 if (id == CSSValueZoom || id == CSSValueFixed) | |
| 7326 validPrimitive = true; | |
| 7327 break; | |
| 7328 case CSSPropertyOrientation: // auto | portrait | landscape | |
| 7329 if (id == CSSValueAuto || id == CSSValuePortrait || id == CSSValueLandsc ape) | |
| 7330 validPrimitive = true; | |
| 7331 default: | |
| 7332 break; | |
| 7333 } | |
| 7334 | |
| 7335 RefPtrWillBeRawPtr<CSSValue> parsedValue = nullptr; | |
| 7336 if (validPrimitive) { | |
| 7337 parsedValue = parseValidPrimitive(id, value); | |
| 7338 m_valueList->next(); | |
| 7339 } | |
| 7340 | |
| 7341 if (parsedValue) { | |
| 7342 if (!m_valueList->current() || inShorthand()) { | |
| 7343 addProperty(propId, parsedValue.release(), important); | |
| 7344 return true; | |
| 7345 } | |
| 7346 } | |
| 7347 | |
| 7348 return false; | |
| 7349 } | |
| 7350 | |
| 7351 bool CSSPropertyParser::parseViewportShorthand(CSSPropertyID propId, CSSProperty ID first, CSSPropertyID second, bool important) | |
| 7352 { | |
| 7353 ASSERT(RuntimeEnabledFeatures::cssViewportEnabled() || isUASheetBehavior(m_c ontext.mode())); | |
| 7354 unsigned numValues = m_valueList->size(); | |
| 7355 | |
| 7356 if (numValues > 2) | |
| 7357 return false; | |
| 7358 | |
| 7359 ShorthandScope scope(this, propId); | |
| 7360 | |
| 7361 if (!parseViewportProperty(first, important)) | |
| 7362 return false; | |
| 7363 | |
| 7364 // If just one value is supplied, the second value | |
| 7365 // is implicitly initialized with the first value. | |
| 7366 if (numValues == 1) | |
| 7367 m_valueList->previous(); | |
| 7368 | |
| 7369 return parseViewportProperty(second, important); | |
| 7370 } | |
| 7371 | |
| 7372 template <typename CharacterType> | |
| 7373 static CSSPropertyID unresolvedCSSPropertyID(const CharacterType* propertyName, unsigned length) | |
| 7374 { | |
| 7375 char buffer[maxCSSPropertyNameLength + 1]; // 1 for null character | |
| 7376 | |
| 7377 for (unsigned i = 0; i != length; ++i) { | |
| 7378 CharacterType c = propertyName[i]; | |
| 7379 if (c == 0 || c >= 0x7F) | |
| 7380 return CSSPropertyInvalid; // illegal character | |
| 7381 buffer[i] = toASCIILower(c); | |
| 7382 } | |
| 7383 buffer[length] = '\0'; | |
| 7384 | |
| 7385 const char* name = buffer; | |
| 7386 const Property* hashTableEntry = findProperty(name, length); | |
| 7387 if (!hashTableEntry) | |
| 7388 return CSSPropertyInvalid; | |
| 7389 CSSPropertyID property = static_cast<CSSPropertyID>(hashTableEntry->id); | |
| 7390 if (!CSSPropertyMetadata::isEnabledProperty(property)) | |
| 7391 return CSSPropertyInvalid; | |
| 7392 return property; | |
| 7393 } | |
| 7394 | |
| 7395 CSSPropertyID unresolvedCSSPropertyID(const String& string) | |
| 7396 { | |
| 7397 unsigned length = string.length(); | |
| 7398 | |
| 7399 if (!length) | |
| 7400 return CSSPropertyInvalid; | |
| 7401 if (length > maxCSSPropertyNameLength) | |
| 7402 return CSSPropertyInvalid; | |
| 7403 | |
| 7404 return string.is8Bit() ? unresolvedCSSPropertyID(string.characters8(), lengt h) : unresolvedCSSPropertyID(string.characters16(), length); | |
| 7405 } | |
| 7406 | |
| 7407 CSSPropertyID unresolvedCSSPropertyID(const CSSParserString& string) | |
| 7408 { | |
| 7409 unsigned length = string.length(); | |
| 7410 | |
| 7411 if (!length) | |
| 7412 return CSSPropertyInvalid; | |
| 7413 if (length > maxCSSPropertyNameLength) | |
| 7414 return CSSPropertyInvalid; | |
| 7415 | |
| 7416 return string.is8Bit() ? unresolvedCSSPropertyID(string.characters8(), lengt h) : unresolvedCSSPropertyID(string.characters16(), length); | |
| 7417 } | |
| 7418 | |
| 7419 template <typename CharacterType> | |
| 7420 static CSSValueID cssValueKeywordID(const CharacterType* valueKeyword, unsigned length) | |
| 7421 { | |
| 7422 char buffer[maxCSSValueKeywordLength + 1]; // 1 for null character | |
| 7423 | |
| 7424 for (unsigned i = 0; i != length; ++i) { | |
| 7425 CharacterType c = valueKeyword[i]; | |
| 7426 if (c == 0 || c >= 0x7F) | |
| 7427 return CSSValueInvalid; // illegal character | |
| 7428 buffer[i] = WTF::toASCIILower(c); | |
| 7429 } | |
| 7430 buffer[length] = '\0'; | |
| 7431 | |
| 7432 const Value* hashTableEntry = findValue(buffer, length); | |
| 7433 return hashTableEntry ? static_cast<CSSValueID>(hashTableEntry->id) : CSSVal ueInvalid; | |
| 7434 } | |
| 7435 | |
| 7436 CSSValueID cssValueKeywordID(const CSSParserString& string) | |
| 7437 { | |
| 7438 unsigned length = string.length(); | |
| 7439 if (!length) | |
| 7440 return CSSValueInvalid; | |
| 7441 if (length > maxCSSValueKeywordLength) | |
| 7442 return CSSValueInvalid; | |
| 7443 | |
| 7444 return string.is8Bit() ? cssValueKeywordID(string.characters8(), length) : c ssValueKeywordID(string.characters16(), length); | |
| 7445 } | |
| 7446 | |
| 7447 bool CSSPropertyParser::isSystemColor(CSSValueID id) | |
| 7448 { | |
| 7449 return (id >= CSSValueActiveborder && id <= CSSValueWindowtext) || id == CSS ValueMenu; | |
| 7450 } | |
| 7451 | |
| 7452 bool CSSPropertyParser::parseSVGValue(CSSPropertyID propId, bool important) | |
| 7453 { | |
| 7454 CSSParserValue* value = m_valueList->current(); | |
| 7455 ASSERT(value); | |
| 7456 | |
| 7457 CSSValueID id = value->id; | |
| 7458 | |
| 7459 bool validPrimitive = false; | |
| 7460 RefPtrWillBeRawPtr<CSSValue> parsedValue = nullptr; | |
| 7461 | |
| 7462 switch (propId) { | |
| 7463 /* The comment to the right defines all valid value of these | |
| 7464 * properties as defined in SVG 1.1, Appendix N. Property index */ | |
| 7465 case CSSPropertyBaselineShift: | |
| 7466 // baseline | super | sub | <percentage> | <length> | inherit | |
| 7467 if (id == CSSValueBaseline || id == CSSValueSub || id == CSSValueSuper) | |
| 7468 validPrimitive = true; | |
| 7469 else | |
| 7470 validPrimitive = validUnit(value, FLength | FPercent, SVGAttributeMo de); | |
| 7471 break; | |
| 7472 | |
| 7473 case CSSPropertyClipPath: | |
| 7474 case CSSPropertyFilter: | |
| 7475 case CSSPropertyMarkerStart: | |
| 7476 case CSSPropertyMarkerMid: | |
| 7477 case CSSPropertyMarkerEnd: | |
| 7478 case CSSPropertyMask: | |
| 7479 if (id == CSSValueNone) { | |
| 7480 validPrimitive = true; | |
| 7481 } else if (value->unit() == CSSPrimitiveValue::UnitType::URI) { | |
| 7482 parsedValue = CSSPrimitiveValue::create(value->string, CSSPrimitiveV alue::UnitType::URI); | |
| 7483 if (parsedValue) | |
| 7484 m_valueList->next(); | |
| 7485 } | |
| 7486 break; | |
| 7487 | |
| 7488 case CSSPropertyStrokeMiterlimit: // <miterlimit> | inherit | |
| 7489 validPrimitive = validUnit(value, FNumber | FNonNeg, SVGAttributeMode); | |
| 7490 break; | |
| 7491 | |
| 7492 case CSSPropertyStrokeOpacity: // <opacity-value> | inherit | |
| 7493 case CSSPropertyFillOpacity: | |
| 7494 case CSSPropertyStopOpacity: | |
| 7495 case CSSPropertyFloodOpacity: | |
| 7496 validPrimitive = validUnit(value, FNumber | FPercent, SVGAttributeMode); | |
| 7497 break; | |
| 7498 | |
| 7499 /* Start of supported CSS properties with validation. This is needed for par seShortHand to work | |
| 7500 * correctly and allows optimization in applyRule(..) | |
| 7501 */ | |
| 7502 | |
| 7503 case CSSPropertyGlyphOrientationVertical: // auto | <angle> | inherit | |
| 7504 if (id == CSSValueAuto) { | |
| 7505 validPrimitive = true; | |
| 7506 break; | |
| 7507 } | |
| 7508 /* fallthrough intentional */ | |
| 7509 case CSSPropertyGlyphOrientationHorizontal: // <angle> (restricted to _deg_ per SVG 1.1 spec) | inherit | |
| 7510 if (value->unit() == CSSPrimitiveValue::UnitType::Degrees || value->unit () == CSSPrimitiveValue::UnitType::Number) { | |
| 7511 parsedValue = CSSPrimitiveValue::create(value->fValue, CSSPrimitiveV alue::UnitType::Degrees); | |
| 7512 | |
| 7513 if (parsedValue) | |
| 7514 m_valueList->next(); | |
| 7515 } | |
| 7516 break; | |
| 7517 | |
| 7518 case CSSPropertyFill: // <paint> | inherit | |
| 7519 case CSSPropertyStroke: // <paint> | inherit | |
| 7520 { | |
| 7521 if (id == CSSValueNone) { | |
| 7522 parsedValue = cssValuePool().createIdentifierValue(id); | |
| 7523 } else if (value->unit() == CSSPrimitiveValue::UnitType::URI) { | |
| 7524 if (m_valueList->next()) { | |
| 7525 RefPtrWillBeRawPtr<CSSValueList> values = CSSValueList::crea teSpaceSeparated(); | |
| 7526 values->append(CSSPrimitiveValue::create(value->string, CSSP rimitiveValue::UnitType::URI)); | |
| 7527 if (m_valueList->current()->id == CSSValueNone) | |
| 7528 parsedValue = cssValuePool().createIdentifierValue(m_val ueList->current()->id); | |
| 7529 else | |
| 7530 parsedValue = parseColor(m_valueList->current()); | |
| 7531 if (parsedValue) { | |
| 7532 values->append(parsedValue); | |
| 7533 parsedValue = values; | |
| 7534 } | |
| 7535 } | |
| 7536 if (!parsedValue) | |
| 7537 parsedValue = CSSPrimitiveValue::create(value->string, CSSPr imitiveValue::UnitType::URI); | |
| 7538 } else { | |
| 7539 parsedValue = parseColor(m_valueList->current()); | |
| 7540 } | |
| 7541 | |
| 7542 if (parsedValue) | |
| 7543 m_valueList->next(); | |
| 7544 } | |
| 7545 break; | |
| 7546 | |
| 7547 case CSSPropertyStopColor: // TODO : icccolor | |
| 7548 case CSSPropertyFloodColor: | |
| 7549 case CSSPropertyLightingColor: | |
| 7550 parsedValue = parseColor(m_valueList->current()); | |
| 7551 if (parsedValue) | |
| 7552 m_valueList->next(); | |
| 7553 | |
| 7554 break; | |
| 7555 | |
| 7556 case CSSPropertyPaintOrder: | |
| 7557 if (m_valueList->size() == 1 && id == CSSValueNormal) | |
| 7558 validPrimitive = true; | |
| 7559 else if ((parsedValue = parsePaintOrder())) | |
| 7560 m_valueList->next(); | |
| 7561 break; | |
| 7562 | |
| 7563 case CSSPropertyStrokeWidth: // <length> | inherit | |
| 7564 case CSSPropertyStrokeDashoffset: | |
| 7565 case CSSPropertyCx: | |
| 7566 case CSSPropertyCy: | |
| 7567 case CSSPropertyX: | |
| 7568 case CSSPropertyY: | |
| 7569 case CSSPropertyR: | |
| 7570 case CSSPropertyRx: | |
| 7571 case CSSPropertyRy: | |
| 7572 validPrimitive = validUnit(value, FLength | FPercent, SVGAttributeMode); | |
| 7573 break; | |
| 7574 case CSSPropertyStrokeDasharray: // none | <dasharray> | inherit | |
| 7575 if (id == CSSValueNone) | |
| 7576 validPrimitive = true; | |
| 7577 else | |
| 7578 parsedValue = parseSVGStrokeDasharray(); | |
| 7579 break; | |
| 7580 | |
| 7581 /* shorthand properties */ | |
| 7582 case CSSPropertyMarker: { | |
| 7583 ShorthandScope scope(this, propId); | |
| 7584 CSSPropertyParser::ImplicitScope implicitScope(this); | |
| 7585 if (!parseValue(CSSPropertyMarkerStart, important)) | |
| 7586 return false; | |
| 7587 if (m_valueList->current()) { | |
| 7588 rollbackLastProperties(1); | |
| 7589 return false; | |
| 7590 } | |
| 7591 CSSValue* value = m_parsedProperties.last().value(); | |
| 7592 addProperty(CSSPropertyMarkerMid, value, important); | |
| 7593 addProperty(CSSPropertyMarkerEnd, value, important); | |
| 7594 return true; | |
| 7595 } | |
| 7596 default: | |
| 7597 // If you crash here, it's because you added a css property and are not handling it | |
| 7598 // in either this switch statement or the one in CSSPropertyParser::pars eValue | |
| 7599 ASSERT_WITH_MESSAGE(0, "unimplemented propertyID: %d", propId); | |
| 7600 return false; | |
| 7601 } | |
| 7602 | |
| 7603 if (validPrimitive) { | |
| 7604 if (id) | |
| 7605 parsedValue = CSSPrimitiveValue::createIdentifier(id); | |
| 7606 else if (value->unit() == CSSPrimitiveValue::UnitType::String) | |
| 7607 parsedValue = CSSPrimitiveValue::create(value->string, value->unit() ); | |
| 7608 else if (value->unit() >= CSSPrimitiveValue::UnitType::Number && value-> unit() <= CSSPrimitiveValue::UnitType::Kilohertz) | |
| 7609 parsedValue = CSSPrimitiveValue::create(value->fValue, value->unit() ); | |
| 7610 else if (value->unit() == CSSPrimitiveValue::UnitType::Rems || value->un it() == CSSPrimitiveValue::UnitType::Chs) | |
| 7611 parsedValue = CSSPrimitiveValue::create(value->fValue, value->unit() ); | |
| 7612 else if (value->unit() == CSSPrimitiveValue::UnitType::QuirkyEms) | |
| 7613 parsedValue = CSSPrimitiveValue::create(value->fValue, CSSPrimitiveV alue::UnitType::QuirkyEms); | |
| 7614 if (isCalculation(value)) { | |
| 7615 // FIXME calc() http://webkit.org/b/16662 : actually create a CSSPri mitiveValue here, ie | |
| 7616 // parsedValue = CSSPrimitiveValue::create(m_parsedCalculation.relea se()); | |
| 7617 m_parsedCalculation.release(); | |
| 7618 parsedValue = nullptr; | |
| 7619 } | |
| 7620 m_valueList->next(); | |
| 7621 } | |
| 7622 if (!parsedValue || (m_valueList->current() && !inShorthand())) | |
| 7623 return false; | |
| 7624 | |
| 7625 addProperty(propId, parsedValue.release(), important); | |
| 7626 return true; | |
| 7627 } | |
| 7628 | |
| 7629 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseSVGStrokeDasharray() | |
| 7630 { | |
| 7631 RefPtrWillBeRawPtr<CSSValueList> ret = CSSValueList::createCommaSeparated(); | |
| 7632 CSSParserValue* value = m_valueList->current(); | |
| 7633 bool validPrimitive = true; | |
| 7634 while (value) { | |
| 7635 validPrimitive = validUnit(value, FLength | FPercent | FNonNeg, SVGAttri buteMode); | |
| 7636 if (!validPrimitive) | |
| 7637 break; | |
| 7638 if (value->id) | |
| 7639 ret->append(CSSPrimitiveValue::createIdentifier(value->id)); | |
| 7640 else if (value->unit() >= CSSPrimitiveValue::UnitType::Number && value-> unit() <= CSSPrimitiveValue::UnitType::Kilohertz) | |
| 7641 ret->append(CSSPrimitiveValue::create(value->fValue, value->unit())) ; | |
| 7642 else if (value->unit() == CSSPrimitiveValue::UnitType::Rems || value->un it() == CSSPrimitiveValue::UnitType::Chs) | |
| 7643 ret->append(CSSPrimitiveValue::create(value->fValue, value->unit())) ; | |
| 7644 value = m_valueList->next(); | |
| 7645 bool commaConsumed = consumeComma(m_valueList); | |
| 7646 value = m_valueList->current(); | |
| 7647 if (commaConsumed && !value) | |
| 7648 return nullptr; | |
| 7649 } | |
| 7650 if (!validPrimitive) | |
| 7651 return nullptr; | |
| 7652 return ret.release(); | |
| 7653 } | |
| 7654 | |
| 7655 // normal | [ fill || stroke || markers ] | |
| 7656 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parsePaintOrder() const | |
| 7657 { | |
| 7658 if (m_valueList->size() > 3) | |
| 7659 return nullptr; | |
| 7660 | |
| 7661 CSSParserValue* value = m_valueList->current(); | |
| 7662 ASSERT(value); | |
| 7663 | |
| 7664 Vector<CSSValueID, 3> paintTypeList; | |
| 7665 RefPtrWillBeRawPtr<CSSPrimitiveValue> fill = nullptr; | |
| 7666 RefPtrWillBeRawPtr<CSSPrimitiveValue> stroke = nullptr; | |
| 7667 RefPtrWillBeRawPtr<CSSPrimitiveValue> markers = nullptr; | |
| 7668 while (value) { | |
| 7669 if (value->id == CSSValueFill && !fill) | |
| 7670 fill = CSSPrimitiveValue::createIdentifier(value->id); | |
| 7671 else if (value->id == CSSValueStroke && !stroke) | |
| 7672 stroke = CSSPrimitiveValue::createIdentifier(value->id); | |
| 7673 else if (value->id == CSSValueMarkers && !markers) | |
| 7674 markers = CSSPrimitiveValue::createIdentifier(value->id); | |
| 7675 else | |
| 7676 return nullptr; | |
| 7677 paintTypeList.append(value->id); | |
| 7678 value = m_valueList->next(); | |
| 7679 } | |
| 7680 | |
| 7681 // After parsing we serialize the paint-order list. Since it is not possible to | |
| 7682 // pop a last list items from CSSValueList without bigger cost, we create th e | |
| 7683 // list after parsing. | |
| 7684 CSSValueID firstPaintOrderType = paintTypeList.at(0); | |
| 7685 RefPtrWillBeRawPtr<CSSValueList> paintOrderList = CSSValueList::createSpaceS eparated(); | |
| 7686 switch (firstPaintOrderType) { | |
| 7687 case CSSValueFill: | |
| 7688 case CSSValueStroke: | |
| 7689 paintOrderList->append(firstPaintOrderType == CSSValueFill ? fill.releas e() : stroke.release()); | |
| 7690 if (paintTypeList.size() > 1) { | |
| 7691 if (paintTypeList.at(1) == CSSValueMarkers) | |
| 7692 paintOrderList->append(markers.release()); | |
| 7693 } | |
| 7694 break; | |
| 7695 case CSSValueMarkers: | |
| 7696 paintOrderList->append(markers.release()); | |
| 7697 if (paintTypeList.size() > 1) { | |
| 7698 if (paintTypeList.at(1) == CSSValueStroke) | |
| 7699 paintOrderList->append(stroke.release()); | |
| 7700 } | |
| 7701 break; | |
| 7702 default: | |
| 7703 ASSERT_NOT_REACHED(); | |
| 7704 } | |
| 7705 | |
| 7706 return paintOrderList.release(); | |
| 7707 } | |
| 7708 | |
| 7709 class TransformOperationInfo { | |
| 7710 public: | |
| 7711 TransformOperationInfo(CSSValueID id) | |
| 7712 : m_validID(true) | |
| 7713 , m_allowSingleArgument(false) | |
| 7714 , m_argCount(1) | |
| 7715 , m_unit(CSSPropertyParser::FUnknown) | |
| 7716 { | |
| 7717 switch (id) { | |
| 7718 case CSSValueSkew: | |
| 7719 m_unit = CSSPropertyParser::FAngle; | |
| 7720 m_allowSingleArgument = true; | |
| 7721 m_argCount = 3; | |
| 7722 break; | |
| 7723 case CSSValueScale: | |
| 7724 m_unit = CSSPropertyParser::FNumber; | |
| 7725 m_allowSingleArgument = true; | |
| 7726 m_argCount = 3; | |
| 7727 break; | |
| 7728 case CSSValueSkewX: | |
| 7729 m_unit = CSSPropertyParser::FAngle; | |
| 7730 break; | |
| 7731 case CSSValueSkewY: | |
| 7732 m_unit = CSSPropertyParser::FAngle; | |
| 7733 break; | |
| 7734 case CSSValueMatrix: | |
| 7735 m_unit = CSSPropertyParser::FNumber; | |
| 7736 m_argCount = 11; | |
| 7737 break; | |
| 7738 case CSSValueRotate: | |
| 7739 m_unit = CSSPropertyParser::FAngle; | |
| 7740 break; | |
| 7741 case CSSValueScaleX: | |
| 7742 m_unit = CSSPropertyParser::FNumber; | |
| 7743 break; | |
| 7744 case CSSValueScaleY: | |
| 7745 m_unit = CSSPropertyParser::FNumber; | |
| 7746 break; | |
| 7747 case CSSValueScaleZ: | |
| 7748 m_unit = CSSPropertyParser::FNumber; | |
| 7749 break; | |
| 7750 case CSSValueScale3d: | |
| 7751 m_unit = CSSPropertyParser::FNumber; | |
| 7752 m_argCount = 5; | |
| 7753 break; | |
| 7754 case CSSValueRotateX: | |
| 7755 m_unit = CSSPropertyParser::FAngle; | |
| 7756 break; | |
| 7757 case CSSValueRotateY: | |
| 7758 m_unit = CSSPropertyParser::FAngle; | |
| 7759 break; | |
| 7760 case CSSValueRotateZ: | |
| 7761 m_unit = CSSPropertyParser::FAngle; | |
| 7762 break; | |
| 7763 case CSSValueMatrix3d: | |
| 7764 m_unit = CSSPropertyParser::FNumber; | |
| 7765 m_argCount = 31; | |
| 7766 break; | |
| 7767 case CSSValueRotate3d: | |
| 7768 m_unit = CSSPropertyParser::FNumber; | |
| 7769 m_argCount = 7; | |
| 7770 break; | |
| 7771 case CSSValueTranslate: | |
| 7772 m_unit = CSSPropertyParser::FLength | CSSPropertyParser::FPercent; | |
| 7773 m_allowSingleArgument = true; | |
| 7774 m_argCount = 3; | |
| 7775 break; | |
| 7776 case CSSValueTranslateX: | |
| 7777 m_unit = CSSPropertyParser::FLength | CSSPropertyParser::FPercent; | |
| 7778 break; | |
| 7779 case CSSValueTranslateY: | |
| 7780 m_unit = CSSPropertyParser::FLength | CSSPropertyParser::FPercent; | |
| 7781 break; | |
| 7782 case CSSValueTranslateZ: | |
| 7783 m_unit = CSSPropertyParser::FLength | CSSPropertyParser::FPercent; | |
| 7784 break; | |
| 7785 case CSSValuePerspective: | |
| 7786 m_unit = CSSPropertyParser::FNumber; | |
| 7787 break; | |
| 7788 case CSSValueTranslate3d: | |
| 7789 m_unit = CSSPropertyParser::FLength | CSSPropertyParser::FPercent; | |
| 7790 m_argCount = 5; | |
| 7791 break; | |
| 7792 default: | |
| 7793 m_validID = false; | |
| 7794 break; | |
| 7795 } | |
| 7796 } | |
| 7797 | |
| 7798 bool validID() const { return m_validID; } | |
| 7799 unsigned argCount() const { return m_argCount; } | |
| 7800 CSSPropertyParser::Units unit() const { return m_unit; } | |
| 7801 | |
| 7802 bool hasCorrectArgCount(unsigned argCount) { return m_argCount == argCount | | (m_allowSingleArgument && argCount == 1); } | |
| 7803 | |
| 7804 private: | |
| 7805 bool m_validID; | |
| 7806 bool m_allowSingleArgument; | |
| 7807 unsigned m_argCount; | |
| 7808 CSSPropertyParser::Units m_unit; | |
| 7809 }; | |
| 7810 | |
| 7811 PassRefPtrWillBeRawPtr<CSSValueList> CSSPropertyParser::parseTransform(bool useL egacyParsing) | |
| 7812 { | |
| 7813 if (!m_valueList) | |
| 7814 return nullptr; | |
| 7815 | |
| 7816 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated() ; | |
| 7817 for (CSSParserValue* value = m_valueList->current(); value; value = m_valueL ist->next()) { | |
| 7818 RefPtrWillBeRawPtr<CSSValue> parsedTransformValue = parseTransformValue( useLegacyParsing, value); | |
| 7819 if (!parsedTransformValue) | |
| 7820 return nullptr; | |
| 7821 | |
| 7822 list->append(parsedTransformValue.release()); | |
| 7823 } | |
| 7824 | |
| 7825 return list.release(); | |
| 7826 } | |
| 7827 | |
| 7828 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseTransformValue(bool use LegacyParsing, CSSParserValue *value) | |
| 7829 { | |
| 7830 if (value->m_unit != CSSParserValue::Function || !value->function) | |
| 7831 return nullptr; | |
| 7832 | |
| 7833 // Every primitive requires at least one argument. | |
| 7834 CSSParserValueList* args = value->function->args.get(); | |
| 7835 if (!args) | |
| 7836 return nullptr; | |
| 7837 | |
| 7838 // See if the specified primitive is one we understand. | |
| 7839 CSSValueID type = value->function->id; | |
| 7840 TransformOperationInfo info(type); | |
| 7841 if (!info.validID()) | |
| 7842 return nullptr; | |
| 7843 | |
| 7844 if (!info.hasCorrectArgCount(args->size())) | |
| 7845 return nullptr; | |
| 7846 | |
| 7847 // The transform is a list of functional primitives that specify transform o perations. | |
| 7848 // We collect a list of CSSFunctionValues, where each value specifies a sing le operation. | |
| 7849 | |
| 7850 // Create the new CSSFunctionValue for this operation and add it to our list . | |
| 7851 RefPtrWillBeRawPtr<CSSFunctionValue> transformValue = CSSFunctionValue::crea te(type); | |
| 7852 | |
| 7853 // Snag our values. | |
| 7854 CSSParserValue* a = args->current(); | |
| 7855 unsigned argNumber = 0; | |
| 7856 while (a) { | |
| 7857 CSSPropertyParser::Units unit = info.unit(); | |
| 7858 | |
| 7859 if (type == CSSValueRotate3d && argNumber == 3) { | |
| 7860 // 4th param of rotate3d() is an angle rather than a bare number, va lidate it as such | |
| 7861 if (!validUnit(a, FAngle, HTMLStandardMode)) | |
| 7862 return nullptr; | |
| 7863 } else if (type == CSSValueTranslate3d && argNumber == 2) { | |
| 7864 // 3rd param of translate3d() cannot be a percentage | |
| 7865 if (!validUnit(a, FLength, HTMLStandardMode)) | |
| 7866 return nullptr; | |
| 7867 } else if (type == CSSValueTranslateZ && !argNumber) { | |
| 7868 // 1st param of translateZ() cannot be a percentage | |
| 7869 if (!validUnit(a, FLength, HTMLStandardMode)) | |
| 7870 return nullptr; | |
| 7871 } else if (type == CSSValuePerspective && !argNumber) { | |
| 7872 // 1st param of perspective() must be a non-negative number (depreca ted) or length. | |
| 7873 if (!validUnit(a, FLength | FNonNeg, HTMLStandardMode)) { | |
| 7874 if (useLegacyParsing && validUnit(a, FNumber | FNonNeg, HTMLStan dardMode)) { | |
| 7875 a->setUnit(CSSPrimitiveValue::UnitType::Pixels); | |
| 7876 } else { | |
| 7877 return nullptr; | |
| 7878 } | |
| 7879 } | |
| 7880 } else if (!validUnit(a, unit, HTMLStandardMode)) { | |
| 7881 return nullptr; | |
| 7882 } | |
| 7883 | |
| 7884 // Add the value to the current transform operation. | |
| 7885 transformValue->append(createPrimitiveNumericValue(a)); | |
| 7886 | |
| 7887 a = args->next(); | |
| 7888 if (!a) | |
| 7889 break; | |
| 7890 if (!isComma(a)) | |
| 7891 return nullptr; | |
| 7892 a = args->next(); | |
| 7893 | |
| 7894 argNumber++; | |
| 7895 } | |
| 7896 | |
| 7897 return transformValue.release(); | |
| 7898 } | |
| 7899 | |
| 7900 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseMotionPath() | |
| 7901 { | |
| 7902 CSSParserValue* value = m_valueList->current(); | |
| 7903 | |
| 7904 // FIXME: Add support for <url>, <basic-shape>, <geometry-box>. | |
| 7905 if (value->m_unit != CSSParserValue::Function || value->function->id != CSSV aluePath) | |
| 7906 return nullptr; | |
| 7907 | |
| 7908 // FIXME: Add support for <fill-rule>. | |
| 7909 CSSParserValueList* functionArgs = value->function->args.get(); | |
| 7910 if (!functionArgs || functionArgs->size() != 1 || !functionArgs->current()) | |
| 7911 return nullptr; | |
| 7912 | |
| 7913 CSSParserValue* arg = functionArgs->current(); | |
| 7914 if (arg->unit() != CSSPrimitiveValue::UnitType::String) | |
| 7915 return nullptr; | |
| 7916 | |
| 7917 String pathString = arg->string; | |
| 7918 Path path; | |
| 7919 if (!buildPathFromString(pathString, path)) | |
| 7920 return nullptr; | |
| 7921 | |
| 7922 m_valueList->next(); | |
| 7923 return CSSPathValue::create(pathString); | |
| 7924 } | |
| 7925 | |
| 7926 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseMotionRotation() | |
| 7927 { | |
| 7928 RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated() ; | |
| 7929 bool hasAutoOrReverse = false; | |
| 7930 bool hasAngle = false; | |
| 7931 | |
| 7932 for (CSSParserValue* value = m_valueList->current(); value; value = m_valueL ist->next()) { | |
| 7933 if ((value->id == CSSValueAuto || value->id == CSSValueReverse) && !hasA utoOrReverse) { | |
| 7934 list->append(cssValuePool().createIdentifierValue(value->id)); | |
| 7935 hasAutoOrReverse = true; | |
| 7936 } else if (!hasAngle && validUnit(value, FAngle)) { | |
| 7937 list->append(createPrimitiveNumericValue(value)); | |
| 7938 hasAngle = true; | |
| 7939 } else { | |
| 7940 break; | |
| 7941 } | |
| 7942 } | |
| 7943 | |
| 7944 if (!list->length()) | |
| 7945 return nullptr; | |
| 7946 | |
| 7947 return list.release(); | |
| 7948 } | |
| 7949 | |
| 7950 } // namespace blink | 242 } // namespace blink |
| OLD | NEW |