mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
None of this code does anything anymore. R=eseidel@chromium.org Review URL: https://codereview.chromium.org/878303002
1606 lines
62 KiB
C++
1606 lines
62 KiB
C++
/*
|
|
* Copyright (C) 2003 Lars Knoll (knoll@kde.org)
|
|
* Copyright (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com)
|
|
* Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved.
|
|
* Copyright (C) 2007 Nicholas Shanks <webkit@nickshanks.com>
|
|
* Copyright (C) 2008 Eric Seidel <eric@webkit.org>
|
|
* Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
|
|
* Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved.
|
|
* Copyright (C) 2012 Intel Corporation. All rights reserved.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Library General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library General Public License
|
|
* along with this library; see the file COPYING.LIB. If not, write to
|
|
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
* Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#include "sky/engine/config.h"
|
|
#include "sky/engine/core/css/parser/BisonCSSParser.h"
|
|
|
|
#include <limits.h>
|
|
#include "gen/sky/core/CSSValueKeywords.h"
|
|
#include "gen/sky/core/StylePropertyShorthand.h"
|
|
#include "gen/sky/platform/RuntimeEnabledFeatures.h"
|
|
#include "sky/engine/core/css/CSSAspectRatioValue.h"
|
|
#include "sky/engine/core/css/CSSBasicShapes.h"
|
|
#include "sky/engine/core/css/CSSBorderImage.h"
|
|
#include "sky/engine/core/css/CSSCrossfadeValue.h"
|
|
#include "sky/engine/core/css/CSSCursorImageValue.h"
|
|
#include "sky/engine/core/css/CSSFontFaceSrcValue.h"
|
|
#include "sky/engine/core/css/CSSFontFeatureValue.h"
|
|
#include "sky/engine/core/css/CSSFunctionValue.h"
|
|
#include "sky/engine/core/css/CSSGradientValue.h"
|
|
#include "sky/engine/core/css/CSSImageSetValue.h"
|
|
#include "sky/engine/core/css/CSSImageValue.h"
|
|
#include "sky/engine/core/css/CSSInheritedValue.h"
|
|
#include "sky/engine/core/css/CSSInitialValue.h"
|
|
#include "sky/engine/core/css/CSSLineBoxContainValue.h"
|
|
#include "sky/engine/core/css/CSSPrimitiveValue.h"
|
|
#include "sky/engine/core/css/CSSPropertySourceData.h"
|
|
#include "sky/engine/core/css/CSSSelector.h"
|
|
#include "sky/engine/core/css/CSSShadowValue.h"
|
|
#include "sky/engine/core/css/CSSStyleSheet.h"
|
|
#include "sky/engine/core/css/CSSTimingFunctionValue.h"
|
|
#include "sky/engine/core/css/CSSTransformValue.h"
|
|
#include "sky/engine/core/css/CSSUnicodeRangeValue.h"
|
|
#include "sky/engine/core/css/CSSValueList.h"
|
|
#include "sky/engine/core/css/CSSValuePool.h"
|
|
#include "sky/engine/core/css/HashTools.h"
|
|
#include "sky/engine/core/css/Pair.h"
|
|
#include "sky/engine/core/css/Rect.h"
|
|
#include "sky/engine/core/css/StylePropertySet.h"
|
|
#include "sky/engine/core/css/StyleRule.h"
|
|
#include "sky/engine/core/css/StyleSheetContents.h"
|
|
#include "sky/engine/core/css/parser/CSSParserIdioms.h"
|
|
#include "sky/engine/core/dom/Document.h"
|
|
#include "sky/engine/core/frame/FrameConsole.h"
|
|
#include "sky/engine/core/frame/FrameHost.h"
|
|
#include "sky/engine/core/frame/LocalFrame.h"
|
|
#include "sky/engine/core/frame/Settings.h"
|
|
#include "sky/engine/core/html/parser/HTMLParserIdioms.h"
|
|
#include "sky/engine/core/inspector/ConsoleMessage.h"
|
|
#include "sky/engine/core/rendering/RenderTheme.h"
|
|
#include "sky/engine/platform/FloatConversion.h"
|
|
#include "sky/engine/wtf/BitArray.h"
|
|
#include "sky/engine/wtf/HexNumber.h"
|
|
#include "sky/engine/wtf/text/StringBuffer.h"
|
|
#include "sky/engine/wtf/text/StringBuilder.h"
|
|
#include "sky/engine/wtf/text/StringImpl.h"
|
|
#include "sky/engine/wtf/text/TextEncoding.h"
|
|
|
|
#define YYDEBUG 0
|
|
|
|
#if YYDEBUG > 0
|
|
extern int cssyydebug;
|
|
#endif
|
|
|
|
int cssyyparse(blink::BisonCSSParser*);
|
|
|
|
using namespace WTF;
|
|
|
|
namespace blink {
|
|
|
|
static const unsigned INVALID_NUM_PARSED_PROPERTIES = UINT_MAX;
|
|
|
|
BisonCSSParser::BisonCSSParser(const CSSParserContext& context)
|
|
: m_context(context)
|
|
, m_id(CSSPropertyInvalid)
|
|
, m_styleSheet(nullptr)
|
|
, m_supportsCondition(false)
|
|
, m_selectorListForParseSelector(0)
|
|
, m_numParsedPropertiesBeforeMarginBox(INVALID_NUM_PARSED_PROPERTIES)
|
|
, m_hadSyntacticallyValidCSSRule(false)
|
|
, m_ignoreErrors(false)
|
|
, m_defaultNamespace(starAtom)
|
|
, m_observer(0)
|
|
, m_source(0)
|
|
, m_ruleHeaderType(CSSRuleSourceData::UNKNOWN_RULE)
|
|
, m_allowImportRules(true)
|
|
, m_allowNamespaceDeclarations(true)
|
|
, m_inViewport(false)
|
|
, m_tokenizer(*this)
|
|
{
|
|
#if YYDEBUG > 0
|
|
cssyydebug = 1;
|
|
#endif
|
|
}
|
|
|
|
BisonCSSParser::~BisonCSSParser()
|
|
{
|
|
clearProperties();
|
|
|
|
deleteAllValues(m_floatingSelectors);
|
|
deleteAllValues(m_floatingSelectorVectors);
|
|
deleteAllValues(m_floatingValueLists);
|
|
deleteAllValues(m_floatingFunctions);
|
|
}
|
|
|
|
void BisonCSSParser::setupParser(const char* prefix, unsigned prefixLength, const String& string, const char* suffix, unsigned suffixLength)
|
|
{
|
|
m_tokenizer.setupTokenizer(prefix, prefixLength, string, suffix, suffixLength);
|
|
m_ruleHasHeader = true;
|
|
}
|
|
|
|
void BisonCSSParser::parseSheet(StyleSheetContents* sheet, const String& string)
|
|
{
|
|
setStyleSheet(sheet);
|
|
m_defaultNamespace = starAtom; // Reset the default namespace.
|
|
m_ignoreErrors = false;
|
|
m_tokenizer.m_lineNumber = 0;
|
|
m_source = &string;
|
|
m_tokenizer.m_internal = false;
|
|
setupParser("", string, "");
|
|
cssyyparse(this);
|
|
sheet->shrinkToFit();
|
|
m_source = 0;
|
|
m_rule = nullptr;
|
|
m_lineEndings.clear();
|
|
m_ignoreErrors = false;
|
|
m_tokenizer.m_internal = true;
|
|
}
|
|
|
|
PassRefPtr<StyleRuleBase> BisonCSSParser::parseRule(StyleSheetContents* sheet, const String& string)
|
|
{
|
|
setStyleSheet(sheet);
|
|
m_allowNamespaceDeclarations = false;
|
|
setupParser("@-internal-rule ", string, "");
|
|
cssyyparse(this);
|
|
return m_rule.release();
|
|
}
|
|
|
|
bool BisonCSSParser::parseSupportsCondition(const String& string)
|
|
{
|
|
m_supportsCondition = false;
|
|
setupParser("@-internal-supports-condition ", string, "");
|
|
cssyyparse(this);
|
|
return m_supportsCondition;
|
|
}
|
|
|
|
static inline bool isColorPropertyID(CSSPropertyID propertyId)
|
|
{
|
|
switch (propertyId) {
|
|
case CSSPropertyColor:
|
|
case CSSPropertyBackgroundColor:
|
|
case CSSPropertyBorderBottomColor:
|
|
case CSSPropertyBorderLeftColor:
|
|
case CSSPropertyBorderRightColor:
|
|
case CSSPropertyBorderTopColor:
|
|
case CSSPropertyOutlineColor:
|
|
case CSSPropertyWebkitBorderAfterColor:
|
|
case CSSPropertyWebkitBorderBeforeColor:
|
|
case CSSPropertyWebkitBorderEndColor:
|
|
case CSSPropertyWebkitBorderStartColor:
|
|
case CSSPropertyWebkitTextEmphasisColor:
|
|
case CSSPropertyWebkitTextFillColor:
|
|
case CSSPropertyWebkitTextStrokeColor:
|
|
case CSSPropertyTextDecorationColor:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static bool parseColorValue(MutableStylePropertySet* declaration, CSSPropertyID propertyId, const String& string, CSSParserMode cssParserMode)
|
|
{
|
|
ASSERT(!string.isEmpty());
|
|
bool quirksMode = isQuirksModeBehavior(cssParserMode);
|
|
if (!isColorPropertyID(propertyId))
|
|
return false;
|
|
CSSParserString cssString;
|
|
cssString.init(string);
|
|
CSSValueID valueID = cssValueKeywordID(cssString);
|
|
bool validPrimitive = false;
|
|
if (valueID == CSSValueCurrentcolor)
|
|
validPrimitive = true;
|
|
|
|
if (validPrimitive) {
|
|
RefPtr<CSSValue> value = cssValuePool().createIdentifierValue(valueID);
|
|
declaration->addParsedProperty(CSSProperty(propertyId, value.release()));
|
|
return true;
|
|
}
|
|
RGBA32 color;
|
|
if (!CSSPropertyParser::fastParseColor(color, string, !quirksMode && string[0] != '#'))
|
|
return false;
|
|
RefPtr<CSSValue> value = cssValuePool().createColorValue(color);
|
|
declaration->addParsedProperty(CSSProperty(propertyId, value.release()));
|
|
return true;
|
|
}
|
|
|
|
static inline bool isSimpleLengthPropertyID(CSSPropertyID propertyId, bool& acceptsNegativeNumbers)
|
|
{
|
|
switch (propertyId) {
|
|
case CSSPropertyFontSize:
|
|
case CSSPropertyHeight:
|
|
case CSSPropertyWidth:
|
|
case CSSPropertyMinHeight:
|
|
case CSSPropertyMinWidth:
|
|
case CSSPropertyPaddingBottom:
|
|
case CSSPropertyPaddingLeft:
|
|
case CSSPropertyPaddingRight:
|
|
case CSSPropertyPaddingTop:
|
|
case CSSPropertyWebkitLogicalWidth:
|
|
case CSSPropertyWebkitLogicalHeight:
|
|
case CSSPropertyWebkitMinLogicalWidth:
|
|
case CSSPropertyWebkitMinLogicalHeight:
|
|
case CSSPropertyWebkitPaddingAfter:
|
|
case CSSPropertyWebkitPaddingBefore:
|
|
case CSSPropertyWebkitPaddingEnd:
|
|
case CSSPropertyWebkitPaddingStart:
|
|
acceptsNegativeNumbers = false;
|
|
return true;
|
|
case CSSPropertyBottom:
|
|
case CSSPropertyLeft:
|
|
case CSSPropertyMarginBottom:
|
|
case CSSPropertyMarginLeft:
|
|
case CSSPropertyMarginRight:
|
|
case CSSPropertyMarginTop:
|
|
case CSSPropertyRight:
|
|
case CSSPropertyTop:
|
|
case CSSPropertyWebkitMarginAfter:
|
|
case CSSPropertyWebkitMarginBefore:
|
|
case CSSPropertyWebkitMarginEnd:
|
|
case CSSPropertyWebkitMarginStart:
|
|
acceptsNegativeNumbers = true;
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
template <typename CharacterType>
|
|
static inline bool parseSimpleLength(const CharacterType* characters, unsigned length, CSSPrimitiveValue::UnitType& unit, double& number)
|
|
{
|
|
if (length > 2 && (characters[length - 2] | 0x20) == 'p' && (characters[length - 1] | 0x20) == 'x') {
|
|
length -= 2;
|
|
unit = CSSPrimitiveValue::CSS_PX;
|
|
} else if (length > 1 && characters[length - 1] == '%') {
|
|
length -= 1;
|
|
unit = CSSPrimitiveValue::CSS_PERCENTAGE;
|
|
}
|
|
|
|
// We rely on charactersToDouble for validation as well. The function
|
|
// will set "ok" to "false" if the entire passed-in character range does
|
|
// not represent a double.
|
|
bool ok;
|
|
number = charactersToDouble(characters, length, &ok);
|
|
return ok;
|
|
}
|
|
|
|
static bool parseSimpleLengthValue(MutableStylePropertySet* declaration, CSSPropertyID propertyId, const String& string, CSSParserMode cssParserMode)
|
|
{
|
|
ASSERT(!string.isEmpty());
|
|
bool acceptsNegativeNumbers = false;
|
|
|
|
// In @viewport, width and height are shorthands, not simple length values.
|
|
if (isCSSViewportParsingEnabledForMode(cssParserMode) || !isSimpleLengthPropertyID(propertyId, acceptsNegativeNumbers))
|
|
return false;
|
|
|
|
unsigned length = string.length();
|
|
double number;
|
|
CSSPrimitiveValue::UnitType unit = CSSPrimitiveValue::CSS_NUMBER;
|
|
|
|
if (string.is8Bit()) {
|
|
if (!parseSimpleLength(string.characters8(), length, unit, number))
|
|
return false;
|
|
} else {
|
|
if (!parseSimpleLength(string.characters16(), length, unit, number))
|
|
return false;
|
|
}
|
|
|
|
if (unit == CSSPrimitiveValue::CSS_NUMBER) {
|
|
bool quirksMode = isQuirksModeBehavior(cssParserMode);
|
|
if (number && !quirksMode)
|
|
return false;
|
|
unit = CSSPrimitiveValue::CSS_PX;
|
|
}
|
|
if (number < 0 && !acceptsNegativeNumbers)
|
|
return false;
|
|
|
|
RefPtr<CSSValue> value = cssValuePool().createValue(number, unit);
|
|
declaration->addParsedProperty(CSSProperty(propertyId, value.release()));
|
|
return true;
|
|
}
|
|
|
|
bool isValidKeywordPropertyAndValue(CSSPropertyID propertyId, CSSValueID valueID, const CSSParserContext& parserContext)
|
|
{
|
|
if (valueID == CSSValueInvalid)
|
|
return false;
|
|
|
|
switch (propertyId) {
|
|
case CSSPropertyAll:
|
|
return valueID == CSSValueUnset;
|
|
case CSSPropertyBackgroundRepeatX: // repeat | no-repeat
|
|
case CSSPropertyBackgroundRepeatY: // repeat | no-repeat
|
|
return valueID == CSSValueRepeat || valueID == CSSValueNoRepeat;
|
|
case CSSPropertyBorderTopStyle: // <border-style>
|
|
case CSSPropertyBorderRightStyle: // Defined as: none | hidden | dotted | dashed |
|
|
case CSSPropertyBorderBottomStyle: // solid | double | groove | ridge | inset | outset
|
|
case CSSPropertyBorderLeftStyle:
|
|
case CSSPropertyWebkitBorderAfterStyle:
|
|
case CSSPropertyWebkitBorderBeforeStyle:
|
|
case CSSPropertyWebkitBorderEndStyle:
|
|
case CSSPropertyWebkitBorderStartStyle:
|
|
return valueID >= CSSValueNone && valueID <= CSSValueDouble;
|
|
case CSSPropertyBoxSizing:
|
|
return valueID == CSSValueBorderBox || valueID == CSSValueContentBox;
|
|
case CSSPropertyCaptionSide: // top | bottom | left | right
|
|
return valueID == CSSValueLeft || valueID == CSSValueRight || valueID == CSSValueTop || valueID == CSSValueBottom;
|
|
case CSSPropertyDirection: // ltr | rtl
|
|
return valueID == CSSValueLtr || valueID == CSSValueRtl;
|
|
case CSSPropertyDisplay:
|
|
// inline | block | list-item | inline-block | table |
|
|
// inline-table | table-row-group | table-header-group | table-footer-group | table-row |
|
|
// table-column-group | table-column | table-cell | table-caption | -webkit-box | -webkit-inline-box | none
|
|
// flex | inline-flex
|
|
return (valueID >= CSSValueInline && valueID <= CSSValueInlineFlex) || valueID == CSSValueNone;
|
|
case CSSPropertyEmptyCells: // show | hide
|
|
return valueID == CSSValueShow || valueID == CSSValueHide;
|
|
case CSSPropertyFontStyle: // normal | italic | oblique
|
|
return valueID == CSSValueNormal || valueID == CSSValueItalic || valueID == CSSValueOblique;
|
|
case CSSPropertyFontStretch: // normal | ultra-condensed | extra-condensed | condensed | semi-condensed | semi-expanded | expanded | extra-expanded | ultra-expanded
|
|
return valueID == CSSValueNormal || (valueID >= CSSValueUltraCondensed && valueID <= CSSValueUltraExpanded);
|
|
case CSSPropertyImageRendering: // auto | optimizeContrast | pixelated
|
|
return valueID == CSSValueAuto || valueID == CSSValueWebkitOptimizeContrast || (RuntimeEnabledFeatures::imageRenderingPixelatedEnabled() && valueID == CSSValuePixelated);
|
|
case CSSPropertyListStylePosition: // inside | outside
|
|
return valueID == CSSValueInside || valueID == CSSValueOutside;
|
|
case CSSPropertyListStyleType:
|
|
// See section CSS_PROP_LIST_STYLE_TYPE of file CSSValueKeywords.in
|
|
// for the list of supported list-style-types.
|
|
return (valueID >= CSSValueDisc && valueID <= CSSValueKatakanaIroha) || valueID == CSSValueNone;
|
|
case CSSPropertyObjectFit:
|
|
ASSERT(RuntimeEnabledFeatures::objectFitPositionEnabled());
|
|
return valueID == CSSValueFill || valueID == CSSValueContain || valueID == CSSValueCover || valueID == CSSValueNone || valueID == CSSValueScaleDown;
|
|
case CSSPropertyOutlineStyle: // (<border-style> except hidden) | auto
|
|
return valueID == CSSValueAuto || valueID == CSSValueNone || (valueID >= CSSValueInset && valueID <= CSSValueDouble);
|
|
case CSSPropertyOverflowWrap: // normal | break-word
|
|
case CSSPropertyWordWrap:
|
|
return valueID == CSSValueNormal || valueID == CSSValueBreakWord;
|
|
case CSSPropertyOverflowX: // visible | hidden | auto | overlay
|
|
return valueID == CSSValueVisible || valueID == CSSValueHidden || valueID == CSSValueAuto || valueID == CSSValueOverlay;
|
|
case CSSPropertyOverflowY: // visible | hidden | auto | overlay | -webkit-paged-x | -webkit-paged-y
|
|
return valueID == CSSValueVisible || valueID == CSSValueHidden || valueID == CSSValueAuto || valueID == CSSValueOverlay || valueID == CSSValueWebkitPagedX || valueID == CSSValueWebkitPagedY;
|
|
case CSSPropertyPageBreakAfter: // auto | always | avoid | left | right
|
|
case CSSPropertyPageBreakBefore:
|
|
case CSSPropertyPageBreakInside: // avoid | auto
|
|
case CSSPropertyPointerEvents:
|
|
// none | visiblePainted | visibleFill | visibleStroke | visible |
|
|
// painted | fill | stroke | auto | all | bounding-box
|
|
return valueID == CSSValueVisible || valueID == CSSValueNone || valueID == CSSValueAll || valueID == CSSValueAuto || (valueID >= CSSValueVisiblepainted && valueID <= CSSValueBoundingBox);
|
|
case CSSPropertyPosition: // static | relative | absolute | fixed
|
|
return valueID == CSSValueStatic || valueID == CSSValueRelative || valueID == CSSValueAbsolute || valueID == CSSValueFixed;
|
|
case CSSPropertySpeak: // none | normal | spell-out | digits | literal-punctuation | no-punctuation
|
|
return valueID == CSSValueNone || valueID == CSSValueNormal || valueID == CSSValueSpellOut || valueID == CSSValueDigits || valueID == CSSValueLiteralPunctuation || valueID == CSSValueNoPunctuation;
|
|
case CSSPropertyTableLayout: // auto | fixed
|
|
return valueID == CSSValueAuto || valueID == CSSValueFixed;
|
|
case CSSPropertyTextAlignLast:
|
|
// auto | start | end | left | right | center | justify
|
|
ASSERT(RuntimeEnabledFeatures::css3TextEnabled());
|
|
return (valueID >= CSSValueLeft && valueID <= CSSValueJustify) || valueID == CSSValueStart || valueID == CSSValueEnd || valueID == CSSValueAuto;
|
|
case CSSPropertyTextDecorationStyle:
|
|
// solid | double | dotted | dashed | wavy
|
|
ASSERT(RuntimeEnabledFeatures::css3TextDecorationsEnabled());
|
|
return valueID == CSSValueSolid || valueID == CSSValueDouble || valueID == CSSValueDotted || valueID == CSSValueDashed || valueID == CSSValueWavy;
|
|
case CSSPropertyTextJustify:
|
|
// auto | none | inter-word | distribute
|
|
ASSERT(RuntimeEnabledFeatures::css3TextEnabled());
|
|
return valueID == CSSValueInterWord || valueID == CSSValueDistribute || valueID == CSSValueAuto || valueID == CSSValueNone;
|
|
case CSSPropertyTextOverflow: // clip | ellipsis
|
|
return valueID == CSSValueClip || valueID == CSSValueEllipsis;
|
|
case CSSPropertyTextRendering: // auto | optimizeSpeed | optimizeLegibility | geometricPrecision
|
|
return valueID == CSSValueAuto || valueID == CSSValueOptimizespeed || valueID == CSSValueOptimizelegibility || valueID == CSSValueGeometricprecision;
|
|
case CSSPropertyUnicodeBidi:
|
|
return valueID == CSSValueNormal || valueID == CSSValueEmbed
|
|
|| valueID == CSSValueBidiOverride || valueID == CSSValueWebkitIsolate
|
|
|| valueID == CSSValueWebkitIsolateOverride || valueID == CSSValueWebkitPlaintext;
|
|
case CSSPropertyTouchActionDelay: // none | script
|
|
ASSERT(RuntimeEnabledFeatures::cssTouchActionDelayEnabled());
|
|
return valueID == CSSValueScript || valueID == CSSValueNone;
|
|
case CSSPropertyBackfaceVisibility:
|
|
case CSSPropertyWebkitBackfaceVisibility:
|
|
return valueID == CSSValueVisible || valueID == CSSValueHidden;
|
|
case CSSPropertyWebkitBoxDecorationBreak:
|
|
return valueID == CSSValueClone || valueID == CSSValueSlice;
|
|
case CSSPropertyAlignContent:
|
|
// FIXME: Per CSS alignment, this property should accept an optional <overflow-position>. We should share this parsing code with 'justify-self'.
|
|
return valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueSpaceBetween || valueID == CSSValueSpaceAround || valueID == CSSValueStretch;
|
|
case CSSPropertyAlignItems:
|
|
// FIXME: Per CSS alignment, this property should accept the same arguments as 'justify-self' so we should share its parsing code.
|
|
return valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueBaseline || valueID == CSSValueStretch;
|
|
case CSSPropertyAlignSelf:
|
|
// FIXME: Per CSS alignment, this property should accept the same arguments as 'justify-self' so we should share its parsing code.
|
|
return valueID == CSSValueAuto || valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueBaseline || valueID == CSSValueStretch;
|
|
case CSSPropertyFlexDirection:
|
|
return valueID == CSSValueRow || valueID == CSSValueRowReverse || valueID == CSSValueColumn || valueID == CSSValueColumnReverse;
|
|
case CSSPropertyFlexWrap:
|
|
return valueID == CSSValueNowrap || valueID == CSSValueWrap || valueID == CSSValueWrapReverse;
|
|
case CSSPropertyJustifyContent:
|
|
// FIXME: Per CSS alignment, this property should accept an optional <overflow-position>. We should share this parsing code with 'justify-self'.
|
|
return valueID == CSSValueFlexStart || valueID == CSSValueFlexEnd || valueID == CSSValueCenter || valueID == CSSValueSpaceBetween || valueID == CSSValueSpaceAround;
|
|
case CSSPropertyFontKerning:
|
|
return valueID == CSSValueAuto || valueID == CSSValueNormal || valueID == CSSValueNone;
|
|
case CSSPropertyWebkitFontSmoothing:
|
|
return valueID == CSSValueAuto || valueID == CSSValueNone || valueID == CSSValueAntialiased || valueID == CSSValueSubpixelAntialiased;
|
|
case CSSPropertyWebkitLineBreak: // auto | loose | normal | strict | after-white-space
|
|
return valueID == CSSValueAuto || valueID == CSSValueLoose || valueID == CSSValueNormal || valueID == CSSValueStrict || valueID == CSSValueAfterWhiteSpace;
|
|
case CSSPropertyWebkitRtlOrdering:
|
|
return valueID == CSSValueLogical || valueID == CSSValueVisual;
|
|
case CSSPropertyWebkitTextEmphasisPosition:
|
|
return valueID == CSSValueOver || valueID == CSSValueUnder;
|
|
case CSSPropertyTransformStyle:
|
|
case CSSPropertyWebkitTransformStyle:
|
|
return valueID == CSSValueFlat || valueID == CSSValuePreserve3d;
|
|
case CSSPropertyWebkitUserDrag: // auto | none | element
|
|
return valueID == CSSValueAuto || valueID == CSSValueNone || valueID == CSSValueElement;
|
|
case CSSPropertyWebkitUserModify: // read-only | read-write
|
|
return valueID == CSSValueReadOnly || valueID == CSSValueReadWrite || valueID == CSSValueReadWritePlaintextOnly;
|
|
case CSSPropertyWebkitUserSelect: // auto | none | text | all
|
|
return valueID == CSSValueAuto || valueID == CSSValueNone || valueID == CSSValueText || valueID == CSSValueAll;
|
|
case CSSPropertyWhiteSpace: // normal | pre | nowrap
|
|
return valueID == CSSValueNormal || valueID == CSSValuePre || valueID == CSSValuePreWrap || valueID == CSSValuePreLine || valueID == CSSValueNowrap;
|
|
case CSSPropertyWordBreak: // normal | break-all | break-word (this is a custom extension)
|
|
return valueID == CSSValueNormal || valueID == CSSValueBreakAll || valueID == CSSValueBreakWord;
|
|
default:
|
|
ASSERT_NOT_REACHED();
|
|
return false;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool isKeywordPropertyID(CSSPropertyID propertyId)
|
|
{
|
|
switch (propertyId) {
|
|
case CSSPropertyAlignItems:
|
|
case CSSPropertyAlignSelf:
|
|
case CSSPropertyAll:
|
|
case CSSPropertyBackgroundRepeatX:
|
|
case CSSPropertyBackgroundRepeatY:
|
|
case CSSPropertyBorderBottomStyle:
|
|
case CSSPropertyBorderLeftStyle:
|
|
case CSSPropertyBorderRightStyle:
|
|
case CSSPropertyBorderTopStyle:
|
|
case CSSPropertyBoxSizing:
|
|
case CSSPropertyCaptionSide:
|
|
case CSSPropertyDirection:
|
|
case CSSPropertyDisplay:
|
|
case CSSPropertyEmptyCells:
|
|
case CSSPropertyFontStyle:
|
|
case CSSPropertyFontStretch:
|
|
case CSSPropertyImageRendering:
|
|
case CSSPropertyListStylePosition:
|
|
case CSSPropertyListStyleType:
|
|
case CSSPropertyObjectFit:
|
|
case CSSPropertyOutlineStyle:
|
|
case CSSPropertyOverflowWrap:
|
|
case CSSPropertyOverflowX:
|
|
case CSSPropertyOverflowY:
|
|
case CSSPropertyPageBreakAfter:
|
|
case CSSPropertyPageBreakBefore:
|
|
case CSSPropertyPageBreakInside:
|
|
case CSSPropertyPointerEvents:
|
|
case CSSPropertyPosition:
|
|
case CSSPropertySpeak:
|
|
case CSSPropertyTableLayout:
|
|
case CSSPropertyTextAlignLast:
|
|
case CSSPropertyTextDecorationStyle:
|
|
case CSSPropertyTextJustify:
|
|
case CSSPropertyTextOverflow:
|
|
case CSSPropertyTextRendering:
|
|
case CSSPropertyTouchActionDelay:
|
|
case CSSPropertyUnicodeBidi:
|
|
case CSSPropertyBackfaceVisibility:
|
|
case CSSPropertyWebkitBackfaceVisibility:
|
|
case CSSPropertyWebkitBorderAfterStyle:
|
|
case CSSPropertyWebkitBorderBeforeStyle:
|
|
case CSSPropertyWebkitBorderEndStyle:
|
|
case CSSPropertyWebkitBorderStartStyle:
|
|
case CSSPropertyWebkitBoxDecorationBreak:
|
|
case CSSPropertyAlignContent:
|
|
case CSSPropertyFlexDirection:
|
|
case CSSPropertyFlexWrap:
|
|
case CSSPropertyJustifyContent:
|
|
case CSSPropertyFontKerning:
|
|
case CSSPropertyWebkitFontSmoothing:
|
|
case CSSPropertyWebkitLineBreak:
|
|
case CSSPropertyWebkitRtlOrdering:
|
|
case CSSPropertyWebkitTextEmphasisPosition:
|
|
case CSSPropertyTransformStyle:
|
|
case CSSPropertyWebkitTransformStyle:
|
|
case CSSPropertyWebkitUserDrag:
|
|
case CSSPropertyWebkitUserModify:
|
|
case CSSPropertyWebkitUserSelect:
|
|
case CSSPropertyWhiteSpace:
|
|
case CSSPropertyWordBreak:
|
|
case CSSPropertyWordWrap:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static bool parseKeywordValue(MutableStylePropertySet* declaration, CSSPropertyID propertyId, const String& string, const CSSParserContext& parserContext)
|
|
{
|
|
ASSERT(!string.isEmpty());
|
|
|
|
if (!isKeywordPropertyID(propertyId)) {
|
|
// All properties accept the values of "initial" and "inherit".
|
|
String lowerCaseString = string.lower();
|
|
if (lowerCaseString != "initial" && lowerCaseString != "inherit")
|
|
return false;
|
|
|
|
// Parse initial/inherit shorthands using the BisonCSSParser.
|
|
if (shorthandForProperty(propertyId).length())
|
|
return false;
|
|
}
|
|
|
|
CSSParserString cssString;
|
|
cssString.init(string);
|
|
CSSValueID valueID = cssValueKeywordID(cssString);
|
|
|
|
if (!valueID)
|
|
return false;
|
|
|
|
RefPtr<CSSValue> value = nullptr;
|
|
if (valueID == CSSValueInherit)
|
|
value = cssValuePool().createInheritedValue();
|
|
else if (valueID == CSSValueInitial)
|
|
value = cssValuePool().createExplicitInitialValue();
|
|
else if (isValidKeywordPropertyAndValue(propertyId, valueID, parserContext))
|
|
value = cssValuePool().createIdentifierValue(valueID);
|
|
else
|
|
return false;
|
|
|
|
declaration->addParsedProperty(CSSProperty(propertyId, value.release()));
|
|
return true;
|
|
}
|
|
|
|
template <typename CharType>
|
|
static bool parseTransformTranslateArguments(CharType*& pos, CharType* end, unsigned expectedCount, CSSTransformValue* transformValue)
|
|
{
|
|
while (expectedCount) {
|
|
size_t delimiter = WTF::find(pos, end - pos, expectedCount == 1 ? ')' : ',');
|
|
if (delimiter == kNotFound)
|
|
return false;
|
|
unsigned argumentLength = static_cast<unsigned>(delimiter);
|
|
CSSPrimitiveValue::UnitType unit = CSSPrimitiveValue::CSS_NUMBER;
|
|
double number;
|
|
if (!parseSimpleLength(pos, argumentLength, unit, number))
|
|
return false;
|
|
if (unit != CSSPrimitiveValue::CSS_PX && (number || unit != CSSPrimitiveValue::CSS_NUMBER))
|
|
return false;
|
|
transformValue->append(cssValuePool().createValue(number, CSSPrimitiveValue::CSS_PX));
|
|
pos += argumentLength + 1;
|
|
--expectedCount;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
template <typename CharType>
|
|
static bool parseTransformNumberArguments(CharType*& pos, CharType* end, unsigned expectedCount, CSSTransformValue* transformValue)
|
|
{
|
|
while (expectedCount) {
|
|
size_t delimiter = WTF::find(pos, end - pos, expectedCount == 1 ? ')' : ',');
|
|
if (delimiter == kNotFound)
|
|
return false;
|
|
unsigned argumentLength = static_cast<unsigned>(delimiter);
|
|
bool ok;
|
|
double number = charactersToDouble(pos, argumentLength, &ok);
|
|
if (!ok)
|
|
return false;
|
|
transformValue->append(cssValuePool().createValue(number, CSSPrimitiveValue::CSS_NUMBER));
|
|
pos += argumentLength + 1;
|
|
--expectedCount;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
template <typename CharType>
|
|
static PassRefPtr<CSSTransformValue> parseSimpleTransformValue(CharType*& pos, CharType* end)
|
|
{
|
|
static const int shortestValidTransformStringLength = 12;
|
|
|
|
if (end - pos < shortestValidTransformStringLength)
|
|
return nullptr;
|
|
|
|
const bool isTranslate = toASCIILower(pos[0]) == 't'
|
|
&& toASCIILower(pos[1]) == 'r'
|
|
&& toASCIILower(pos[2]) == 'a'
|
|
&& toASCIILower(pos[3]) == 'n'
|
|
&& toASCIILower(pos[4]) == 's'
|
|
&& toASCIILower(pos[5]) == 'l'
|
|
&& toASCIILower(pos[6]) == 'a'
|
|
&& toASCIILower(pos[7]) == 't'
|
|
&& toASCIILower(pos[8]) == 'e';
|
|
|
|
if (isTranslate) {
|
|
CSSTransformValue::TransformOperationType transformType;
|
|
unsigned expectedArgumentCount = 1;
|
|
unsigned argumentStart = 11;
|
|
CharType c9 = toASCIILower(pos[9]);
|
|
if (c9 == 'x' && pos[10] == '(') {
|
|
transformType = CSSTransformValue::TranslateXTransformOperation;
|
|
} else if (c9 == 'y' && pos[10] == '(') {
|
|
transformType = CSSTransformValue::TranslateYTransformOperation;
|
|
} else if (c9 == 'z' && pos[10] == '(') {
|
|
transformType = CSSTransformValue::TranslateZTransformOperation;
|
|
} else if (c9 == '(') {
|
|
transformType = CSSTransformValue::TranslateTransformOperation;
|
|
expectedArgumentCount = 2;
|
|
argumentStart = 10;
|
|
} else if (c9 == '3' && toASCIILower(pos[10]) == 'd' && pos[11] == '(') {
|
|
transformType = CSSTransformValue::Translate3DTransformOperation;
|
|
expectedArgumentCount = 3;
|
|
argumentStart = 12;
|
|
} else {
|
|
return nullptr;
|
|
}
|
|
pos += argumentStart;
|
|
RefPtr<CSSTransformValue> transformValue = CSSTransformValue::create(transformType);
|
|
if (!parseTransformTranslateArguments(pos, end, expectedArgumentCount, transformValue.get()))
|
|
return nullptr;
|
|
return transformValue.release();
|
|
}
|
|
|
|
const bool isMatrix3d = toASCIILower(pos[0]) == 'm'
|
|
&& toASCIILower(pos[1]) == 'a'
|
|
&& toASCIILower(pos[2]) == 't'
|
|
&& toASCIILower(pos[3]) == 'r'
|
|
&& toASCIILower(pos[4]) == 'i'
|
|
&& toASCIILower(pos[5]) == 'x'
|
|
&& pos[6] == '3'
|
|
&& toASCIILower(pos[7]) == 'd'
|
|
&& pos[8] == '(';
|
|
|
|
if (isMatrix3d) {
|
|
pos += 9;
|
|
RefPtr<CSSTransformValue> transformValue = CSSTransformValue::create(CSSTransformValue::Matrix3DTransformOperation);
|
|
if (!parseTransformNumberArguments(pos, end, 16, transformValue.get()))
|
|
return nullptr;
|
|
return transformValue.release();
|
|
}
|
|
|
|
const bool isScale3d = toASCIILower(pos[0]) == 's'
|
|
&& toASCIILower(pos[1]) == 'c'
|
|
&& toASCIILower(pos[2]) == 'a'
|
|
&& toASCIILower(pos[3]) == 'l'
|
|
&& toASCIILower(pos[4]) == 'e'
|
|
&& pos[5] == '3'
|
|
&& toASCIILower(pos[6]) == 'd'
|
|
&& pos[7] == '(';
|
|
|
|
if (isScale3d) {
|
|
pos += 8;
|
|
RefPtr<CSSTransformValue> transformValue = CSSTransformValue::create(CSSTransformValue::Scale3DTransformOperation);
|
|
if (!parseTransformNumberArguments(pos, end, 3, transformValue.get()))
|
|
return nullptr;
|
|
return transformValue.release();
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
template <typename CharType>
|
|
static PassRefPtr<CSSValueList> parseSimpleTransformList(CharType*& pos, CharType* end)
|
|
{
|
|
RefPtr<CSSValueList> transformList = nullptr;
|
|
while (pos < end) {
|
|
while (pos < end && isCSSSpace(*pos))
|
|
++pos;
|
|
RefPtr<CSSTransformValue> transformValue = parseSimpleTransformValue(pos, end);
|
|
if (!transformValue)
|
|
return nullptr;
|
|
if (!transformList)
|
|
transformList = CSSValueList::createSpaceSeparated();
|
|
transformList->append(transformValue.release());
|
|
if (pos < end) {
|
|
if (isCSSSpace(*pos))
|
|
return nullptr;
|
|
}
|
|
}
|
|
return transformList.release();
|
|
}
|
|
|
|
static bool parseSimpleTransform(MutableStylePropertySet* properties, CSSPropertyID propertyID, const String& string)
|
|
{
|
|
if (propertyID != CSSPropertyTransform && propertyID != CSSPropertyWebkitTransform)
|
|
return false;
|
|
if (string.isEmpty())
|
|
return false;
|
|
RefPtr<CSSValueList> transformList = nullptr;
|
|
if (string.is8Bit()) {
|
|
const LChar* pos = string.characters8();
|
|
const LChar* end = pos + string.length();
|
|
transformList = parseSimpleTransformList(pos, end);
|
|
if (!transformList)
|
|
return false;
|
|
} else {
|
|
const UChar* pos = string.characters16();
|
|
const UChar* end = pos + string.length();
|
|
transformList = parseSimpleTransformList(pos, end);
|
|
if (!transformList)
|
|
return false;
|
|
}
|
|
properties->addParsedProperty(CSSProperty(propertyID, transformList.release()));
|
|
return true;
|
|
}
|
|
|
|
PassRefPtr<CSSValueList> BisonCSSParser::parseFontFaceValue(const AtomicString& string)
|
|
{
|
|
if (string.isEmpty())
|
|
return nullptr;
|
|
RefPtr<MutableStylePropertySet> dummyStyle = MutableStylePropertySet::create();
|
|
if (!parseValue(dummyStyle.get(), CSSPropertyFontFamily, string, HTMLStandardMode, 0))
|
|
return nullptr;
|
|
|
|
RefPtr<CSSValue> fontFamily = dummyStyle->getPropertyCSSValue(CSSPropertyFontFamily);
|
|
if (!fontFamily->isValueList())
|
|
return nullptr;
|
|
|
|
return toCSSValueList(dummyStyle->getPropertyCSSValue(CSSPropertyFontFamily).get());
|
|
}
|
|
|
|
PassRefPtr<CSSValue> BisonCSSParser::parseAnimationTimingFunctionValue(const String& string)
|
|
{
|
|
if (string.isEmpty())
|
|
return nullptr;
|
|
RefPtr<MutableStylePropertySet> style = MutableStylePropertySet::create();
|
|
if (!parseValue(style.get(), CSSPropertyTransitionTimingFunction, string, HTMLStandardMode, 0))
|
|
return nullptr;
|
|
|
|
RefPtr<CSSValue> value = style->getPropertyCSSValue(CSSPropertyTransitionTimingFunction);
|
|
if (!value || value->isInitialValue() || value->isInheritedValue())
|
|
return nullptr;
|
|
CSSValueList* valueList = toCSSValueList(value.get());
|
|
if (valueList->length() > 1)
|
|
return nullptr;
|
|
return valueList->item(0);
|
|
}
|
|
|
|
bool BisonCSSParser::parseValue(MutableStylePropertySet* declaration, CSSPropertyID propertyID, const String& string, const Document& document)
|
|
{
|
|
ASSERT(!string.isEmpty());
|
|
|
|
CSSParserContext context(document);
|
|
|
|
if (parseSimpleLengthValue(declaration, propertyID, string, context.mode()))
|
|
return true;
|
|
if (parseColorValue(declaration, propertyID, string, context.mode()))
|
|
return true;
|
|
if (parseKeywordValue(declaration, propertyID, string, context))
|
|
return true;
|
|
|
|
BisonCSSParser parser(context);
|
|
return parser.parseValue(declaration, propertyID, string, static_cast<StyleSheetContents*>(0));
|
|
}
|
|
|
|
bool BisonCSSParser::parseValue(MutableStylePropertySet* declaration, CSSPropertyID propertyID, const String& string, CSSParserMode cssParserMode, StyleSheetContents* contextStyleSheet)
|
|
{
|
|
ASSERT(!string.isEmpty());
|
|
if (parseSimpleLengthValue(declaration, propertyID, string, cssParserMode))
|
|
return true;
|
|
if (parseColorValue(declaration, propertyID, string, cssParserMode))
|
|
return true;
|
|
|
|
CSSParserContext context;
|
|
if (contextStyleSheet)
|
|
context = contextStyleSheet->parserContext();
|
|
|
|
if (parseKeywordValue(declaration, propertyID, string, context))
|
|
return true;
|
|
if (parseSimpleTransform(declaration, propertyID, string))
|
|
return true;
|
|
|
|
BisonCSSParser parser(context);
|
|
return parser.parseValue(declaration, propertyID, string, contextStyleSheet);
|
|
}
|
|
|
|
bool BisonCSSParser::parseValue(MutableStylePropertySet* declaration, CSSPropertyID propertyID, const String& string, StyleSheetContents* contextStyleSheet)
|
|
{
|
|
setStyleSheet(contextStyleSheet);
|
|
|
|
setupParser("@-internal-value ", string, "");
|
|
|
|
m_id = propertyID;
|
|
|
|
cssyyparse(this);
|
|
|
|
m_rule = nullptr;
|
|
m_id = CSSPropertyInvalid;
|
|
|
|
bool ok = false;
|
|
if (!m_parsedProperties.isEmpty()) {
|
|
ok = true;
|
|
declaration->addParsedProperties(m_parsedProperties);
|
|
clearProperties();
|
|
}
|
|
|
|
return ok;
|
|
}
|
|
|
|
// The color will only be changed when string contains a valid CSS color, so callers
|
|
// can set it to a default color and ignore the boolean result.
|
|
bool BisonCSSParser::parseColor(RGBA32& color, const String& string, bool strict)
|
|
{
|
|
// First try creating a color specified by name, rgba(), rgb() or "#" syntax.
|
|
if (CSSPropertyParser::fastParseColor(color, string, strict))
|
|
return true;
|
|
|
|
BisonCSSParser parser(strictCSSParserContext());
|
|
|
|
// In case the fast-path parser didn't understand the color, try the full parser.
|
|
if (!parser.parseColor(string))
|
|
return false;
|
|
|
|
CSSValue* value = parser.m_parsedProperties.first().value();
|
|
if (!value->isPrimitiveValue())
|
|
return false;
|
|
|
|
CSSPrimitiveValue* primitiveValue = toCSSPrimitiveValue(value);
|
|
if (!primitiveValue->isRGBColor())
|
|
return false;
|
|
|
|
color = primitiveValue->getRGBA32Value();
|
|
return true;
|
|
}
|
|
|
|
StyleColor BisonCSSParser::colorFromRGBColorString(const String& colorString)
|
|
{
|
|
// FIXME: Rework css parser so it is more SVG aware.
|
|
RGBA32 color;
|
|
if (parseColor(color, colorString.stripWhiteSpace()))
|
|
return StyleColor(color);
|
|
// FIXME: This branch catches the string currentColor, but we should error if we have an illegal color value.
|
|
return StyleColor::currentColor();
|
|
}
|
|
|
|
bool BisonCSSParser::parseColor(const String& string)
|
|
{
|
|
setupParser("@-internal-decls color:", string, "");
|
|
cssyyparse(this);
|
|
m_rule = nullptr;
|
|
|
|
return !m_parsedProperties.isEmpty() && m_parsedProperties.first().id() == CSSPropertyColor;
|
|
}
|
|
|
|
bool BisonCSSParser::parseSystemColor(RGBA32& color, const String& string)
|
|
{
|
|
CSSParserString cssColor;
|
|
cssColor.init(string);
|
|
CSSValueID id = cssValueKeywordID(cssColor);
|
|
if (!CSSPropertyParser::isSystemColor(id))
|
|
return false;
|
|
|
|
Color parsedColor = RenderTheme::theme().systemColor(id);
|
|
color = parsedColor.rgb();
|
|
return true;
|
|
}
|
|
|
|
void BisonCSSParser::parseSelector(const String& string, CSSSelectorList& selectorList)
|
|
{
|
|
m_selectorListForParseSelector = &selectorList;
|
|
|
|
setupParser("@-internal-selector ", string, "");
|
|
|
|
cssyyparse(this);
|
|
|
|
m_selectorListForParseSelector = 0;
|
|
}
|
|
|
|
PassRefPtr<ImmutableStylePropertySet> BisonCSSParser::parseInlineStyleDeclaration(const String& string, Element* element)
|
|
{
|
|
Document& document = element->document();
|
|
CSSParserContext context = CSSParserContext(document.elementSheet().contents()->parserContext());
|
|
return BisonCSSParser(context).parseDeclaration(string, document.elementSheet().contents());
|
|
}
|
|
|
|
PassRefPtr<ImmutableStylePropertySet> BisonCSSParser::parseDeclaration(const String& string, StyleSheetContents* contextStyleSheet)
|
|
{
|
|
setStyleSheet(contextStyleSheet);
|
|
|
|
setupParser("@-internal-decls ", string, "");
|
|
cssyyparse(this);
|
|
m_rule = nullptr;
|
|
|
|
RefPtr<ImmutableStylePropertySet> style = createStylePropertySet();
|
|
clearProperties();
|
|
return style.release();
|
|
}
|
|
|
|
|
|
bool BisonCSSParser::parseDeclaration(MutableStylePropertySet* declaration, const String& string, CSSParserObserver* observer, StyleSheetContents* contextStyleSheet)
|
|
{
|
|
setStyleSheet(contextStyleSheet);
|
|
|
|
TemporaryChange<CSSParserObserver*> scopedObsever(m_observer, observer);
|
|
|
|
setupParser("@-internal-decls ", string, "");
|
|
if (m_observer) {
|
|
m_observer->startRuleHeader(CSSRuleSourceData::STYLE_RULE, 0);
|
|
m_observer->endRuleHeader(1);
|
|
m_observer->startRuleBody(0);
|
|
}
|
|
|
|
cssyyparse(this);
|
|
|
|
m_rule = nullptr;
|
|
|
|
bool ok = false;
|
|
if (!m_parsedProperties.isEmpty()) {
|
|
ok = true;
|
|
declaration->addParsedProperties(m_parsedProperties);
|
|
clearProperties();
|
|
}
|
|
|
|
if (m_observer)
|
|
m_observer->endRuleBody(string.length(), false);
|
|
|
|
return ok;
|
|
}
|
|
|
|
bool BisonCSSParser::parseAttributeMatchType(CSSSelector::AttributeMatchType& matchType, const String& string)
|
|
{
|
|
if (!RuntimeEnabledFeatures::cssAttributeCaseSensitivityEnabled() && !isUASheetBehavior(m_context.mode()))
|
|
return false;
|
|
if (string == "i") {
|
|
matchType = CSSSelector::CaseInsensitive;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static inline void filterProperties(const Vector<CSSProperty, 256>& input, Vector<CSSProperty, 256>& output, size_t& unusedEntries, BitArray<numCSSProperties>& seenProperties)
|
|
{
|
|
// Add properties in reverse order so that highest priority definitions are reached first. Duplicate definitions can then be ignored when found.
|
|
for (int i = input.size() - 1; i >= 0; --i) {
|
|
const CSSProperty& property = input[i];
|
|
const unsigned propertyIDIndex = property.id() - firstCSSProperty;
|
|
if (seenProperties.get(propertyIDIndex))
|
|
continue;
|
|
seenProperties.set(propertyIDIndex);
|
|
output[--unusedEntries] = property;
|
|
}
|
|
}
|
|
|
|
PassRefPtr<ImmutableStylePropertySet> BisonCSSParser::createStylePropertySet()
|
|
{
|
|
BitArray<numCSSProperties> seenProperties;
|
|
size_t unusedEntries = m_parsedProperties.size();
|
|
Vector<CSSProperty, 256> results(unusedEntries);
|
|
|
|
filterProperties(m_parsedProperties, results, unusedEntries, seenProperties);
|
|
if (unusedEntries)
|
|
results.remove(0, unusedEntries);
|
|
|
|
return ImmutableStylePropertySet::create(results.data(), results.size(), HTMLStandardMode);
|
|
}
|
|
|
|
void BisonCSSParser::rollbackLastProperties(int num)
|
|
{
|
|
ASSERT(num >= 0);
|
|
ASSERT(m_parsedProperties.size() >= static_cast<unsigned>(num));
|
|
m_parsedProperties.shrink(m_parsedProperties.size() - num);
|
|
}
|
|
|
|
void BisonCSSParser::clearProperties()
|
|
{
|
|
m_parsedProperties.clear();
|
|
m_numParsedPropertiesBeforeMarginBox = INVALID_NUM_PARSED_PROPERTIES;
|
|
}
|
|
|
|
void BisonCSSParser::setCurrentProperty(CSSPropertyID propId)
|
|
{
|
|
m_id = propId;
|
|
}
|
|
|
|
bool BisonCSSParser::parseValue(CSSPropertyID propId)
|
|
{
|
|
return CSSPropertyParser::parseValue(propId, m_valueList.get(), m_context, m_inViewport, m_parsedProperties, m_ruleHeaderType);
|
|
}
|
|
|
|
|
|
class TransformOperationInfo {
|
|
public:
|
|
TransformOperationInfo(const CSSParserString& name)
|
|
: m_type(CSSTransformValue::UnknownTransformOperation)
|
|
, m_argCount(1)
|
|
, m_allowSingleArgument(false)
|
|
, m_unit(CSSPropertyParser::FUnknown)
|
|
{
|
|
const UChar* characters;
|
|
unsigned nameLength = name.length();
|
|
|
|
const unsigned longestNameLength = 12;
|
|
UChar characterBuffer[longestNameLength];
|
|
if (name.is8Bit()) {
|
|
unsigned length = std::min(longestNameLength, nameLength);
|
|
const LChar* characters8 = name.characters8();
|
|
for (unsigned i = 0; i < length; ++i)
|
|
characterBuffer[i] = characters8[i];
|
|
characters = characterBuffer;
|
|
} else
|
|
characters = name.characters16();
|
|
|
|
SWITCH(characters, nameLength) {
|
|
CASE("skew(") {
|
|
m_unit = CSSPropertyParser::FAngle;
|
|
m_type = CSSTransformValue::SkewTransformOperation;
|
|
m_allowSingleArgument = true;
|
|
m_argCount = 3;
|
|
}
|
|
CASE("scale(") {
|
|
m_unit = CSSPropertyParser::FNumber;
|
|
m_type = CSSTransformValue::ScaleTransformOperation;
|
|
m_allowSingleArgument = true;
|
|
m_argCount = 3;
|
|
}
|
|
CASE("skewx(") {
|
|
m_unit = CSSPropertyParser::FAngle;
|
|
m_type = CSSTransformValue::SkewXTransformOperation;
|
|
}
|
|
CASE("skewy(") {
|
|
m_unit = CSSPropertyParser::FAngle;
|
|
m_type = CSSTransformValue::SkewYTransformOperation;
|
|
}
|
|
CASE("matrix(") {
|
|
m_unit = CSSPropertyParser::FNumber;
|
|
m_type = CSSTransformValue::MatrixTransformOperation;
|
|
m_argCount = 11;
|
|
}
|
|
CASE("rotate(") {
|
|
m_unit = CSSPropertyParser::FAngle;
|
|
m_type = CSSTransformValue::RotateTransformOperation;
|
|
}
|
|
CASE("scalex(") {
|
|
m_unit = CSSPropertyParser::FNumber;
|
|
m_type = CSSTransformValue::ScaleXTransformOperation;
|
|
}
|
|
CASE("scaley(") {
|
|
m_unit = CSSPropertyParser::FNumber;
|
|
m_type = CSSTransformValue::ScaleYTransformOperation;
|
|
}
|
|
CASE("scalez(") {
|
|
m_unit = CSSPropertyParser::FNumber;
|
|
m_type = CSSTransformValue::ScaleZTransformOperation;
|
|
}
|
|
CASE("scale3d(") {
|
|
m_unit = CSSPropertyParser::FNumber;
|
|
m_type = CSSTransformValue::Scale3DTransformOperation;
|
|
m_argCount = 5;
|
|
}
|
|
CASE("rotatex(") {
|
|
m_unit = CSSPropertyParser::FAngle;
|
|
m_type = CSSTransformValue::RotateXTransformOperation;
|
|
}
|
|
CASE("rotatey(") {
|
|
m_unit = CSSPropertyParser::FAngle;
|
|
m_type = CSSTransformValue::RotateYTransformOperation;
|
|
}
|
|
CASE("rotatez(") {
|
|
m_unit = CSSPropertyParser::FAngle;
|
|
m_type = CSSTransformValue::RotateZTransformOperation;
|
|
}
|
|
CASE("matrix3d(") {
|
|
m_unit = CSSPropertyParser::FNumber;
|
|
m_type = CSSTransformValue::Matrix3DTransformOperation;
|
|
m_argCount = 31;
|
|
}
|
|
CASE("rotate3d(") {
|
|
m_unit = CSSPropertyParser::FNumber;
|
|
m_type = CSSTransformValue::Rotate3DTransformOperation;
|
|
m_argCount = 7;
|
|
}
|
|
CASE("translate(") {
|
|
m_unit = CSSPropertyParser::FLength | CSSPropertyParser::FPercent;
|
|
m_type = CSSTransformValue::TranslateTransformOperation;
|
|
m_allowSingleArgument = true;
|
|
m_argCount = 3;
|
|
}
|
|
CASE("translatex(") {
|
|
m_unit = CSSPropertyParser::FLength | CSSPropertyParser::FPercent;
|
|
m_type = CSSTransformValue::TranslateXTransformOperation;
|
|
}
|
|
CASE("translatey(") {
|
|
m_unit = CSSPropertyParser::FLength | CSSPropertyParser::FPercent;
|
|
m_type = CSSTransformValue::TranslateYTransformOperation;
|
|
}
|
|
CASE("translatez(") {
|
|
m_unit = CSSPropertyParser::FLength | CSSPropertyParser::FPercent;
|
|
m_type = CSSTransformValue::TranslateZTransformOperation;
|
|
}
|
|
CASE("perspective(") {
|
|
m_unit = CSSPropertyParser::FNumber;
|
|
m_type = CSSTransformValue::PerspectiveTransformOperation;
|
|
}
|
|
CASE("translate3d(") {
|
|
m_unit = CSSPropertyParser::FLength | CSSPropertyParser::FPercent;
|
|
m_type = CSSTransformValue::Translate3DTransformOperation;
|
|
m_argCount = 5;
|
|
}
|
|
}
|
|
}
|
|
|
|
CSSTransformValue::TransformOperationType type() const { return m_type; }
|
|
unsigned argCount() const { return m_argCount; }
|
|
CSSPropertyParser::Units unit() const { return m_unit; }
|
|
|
|
bool unknown() const { return m_type == CSSTransformValue::UnknownTransformOperation; }
|
|
bool hasCorrectArgCount(unsigned argCount) { return m_argCount == argCount || (m_allowSingleArgument && argCount == 1); }
|
|
|
|
private:
|
|
CSSTransformValue::TransformOperationType m_type;
|
|
unsigned m_argCount;
|
|
bool m_allowSingleArgument;
|
|
CSSPropertyParser::Units m_unit;
|
|
};
|
|
|
|
PassRefPtr<CSSValueList> CSSPropertyParser::parseTransform(CSSPropertyID propId)
|
|
{
|
|
if (!m_valueList)
|
|
return nullptr;
|
|
|
|
RefPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
|
|
for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
|
|
RefPtr<CSSValue> parsedTransformValue = parseTransformValue(propId, value);
|
|
if (!parsedTransformValue)
|
|
return nullptr;
|
|
|
|
list->append(parsedTransformValue.release());
|
|
}
|
|
|
|
return list.release();
|
|
}
|
|
|
|
PassRefPtr<CSSValue> CSSPropertyParser::parseTransformValue(CSSPropertyID propId, CSSParserValue *value)
|
|
{
|
|
if (value->unit != CSSParserValue::Function || !value->function)
|
|
return nullptr;
|
|
|
|
// Every primitive requires at least one argument.
|
|
CSSParserValueList* args = value->function->args.get();
|
|
if (!args)
|
|
return nullptr;
|
|
|
|
// See if the specified primitive is one we understand.
|
|
TransformOperationInfo info(value->function->name);
|
|
if (info.unknown())
|
|
return nullptr;
|
|
|
|
if (!info.hasCorrectArgCount(args->size()))
|
|
return nullptr;
|
|
|
|
// The transform is a list of functional primitives that specify transform operations.
|
|
// We collect a list of CSSTransformValues, where each value specifies a single operation.
|
|
|
|
// Create the new CSSTransformValue for this operation and add it to our list.
|
|
RefPtr<CSSTransformValue> transformValue = CSSTransformValue::create(info.type());
|
|
|
|
// Snag our values.
|
|
CSSParserValue* a = args->current();
|
|
unsigned argNumber = 0;
|
|
while (a) {
|
|
CSSPropertyParser::Units unit = info.unit();
|
|
|
|
if (info.type() == CSSTransformValue::Rotate3DTransformOperation && argNumber == 3) {
|
|
// 4th param of rotate3d() is an angle rather than a bare number, validate it as such
|
|
if (!validUnit(a, FAngle, HTMLStandardMode))
|
|
return nullptr;
|
|
} else if (info.type() == CSSTransformValue::Translate3DTransformOperation && argNumber == 2) {
|
|
// 3rd param of translate3d() cannot be a percentage
|
|
if (!validUnit(a, FLength, HTMLStandardMode))
|
|
return nullptr;
|
|
} else if (info.type() == CSSTransformValue::TranslateZTransformOperation && !argNumber) {
|
|
// 1st param of translateZ() cannot be a percentage
|
|
if (!validUnit(a, FLength, HTMLStandardMode))
|
|
return nullptr;
|
|
} else if (info.type() == CSSTransformValue::PerspectiveTransformOperation && !argNumber) {
|
|
// 1st param of perspective() must be a non-negative number (deprecated) or length.
|
|
if ((propId == CSSPropertyWebkitTransform && !validUnit(a, FNumber | FLength | FNonNeg, HTMLStandardMode))
|
|
|| (propId == CSSPropertyTransform && !validUnit(a, FLength | FNonNeg, HTMLStandardMode)))
|
|
return nullptr;
|
|
} else if (!validUnit(a, unit, HTMLStandardMode)) {
|
|
return nullptr;
|
|
}
|
|
|
|
// Add the value to the current transform operation.
|
|
transformValue->append(createPrimitiveNumericValue(a));
|
|
|
|
a = args->next();
|
|
if (!a)
|
|
break;
|
|
if (a->unit != CSSParserValue::Operator || a->iValue != ',')
|
|
return nullptr;
|
|
a = args->next();
|
|
|
|
argNumber++;
|
|
}
|
|
|
|
return transformValue.release();
|
|
}
|
|
|
|
void BisonCSSParser::ensureLineEndings()
|
|
{
|
|
if (!m_lineEndings)
|
|
m_lineEndings = lineEndings(*m_source);
|
|
}
|
|
|
|
CSSParserSelector* BisonCSSParser::createFloatingSelectorWithTagName(const QualifiedName& tagQName)
|
|
{
|
|
CSSParserSelector* selector = new CSSParserSelector(tagQName);
|
|
m_floatingSelectors.append(selector);
|
|
return selector;
|
|
}
|
|
|
|
CSSParserSelector* BisonCSSParser::createFloatingSelector()
|
|
{
|
|
CSSParserSelector* selector = new CSSParserSelector;
|
|
m_floatingSelectors.append(selector);
|
|
return selector;
|
|
}
|
|
|
|
PassOwnPtr<CSSParserSelector> BisonCSSParser::sinkFloatingSelector(CSSParserSelector* selector)
|
|
{
|
|
if (selector) {
|
|
size_t index = m_floatingSelectors.reverseFind(selector);
|
|
ASSERT(index != kNotFound);
|
|
m_floatingSelectors.remove(index);
|
|
}
|
|
return adoptPtr(selector);
|
|
}
|
|
|
|
Vector<OwnPtr<CSSParserSelector> >* BisonCSSParser::createFloatingSelectorVector()
|
|
{
|
|
Vector<OwnPtr<CSSParserSelector> >* selectorVector = new Vector<OwnPtr<CSSParserSelector> >;
|
|
m_floatingSelectorVectors.append(selectorVector);
|
|
return selectorVector;
|
|
}
|
|
|
|
PassOwnPtr<Vector<OwnPtr<CSSParserSelector> > > BisonCSSParser::sinkFloatingSelectorVector(Vector<OwnPtr<CSSParserSelector> >* selectorVector)
|
|
{
|
|
if (selectorVector) {
|
|
size_t index = m_floatingSelectorVectors.reverseFind(selectorVector);
|
|
ASSERT(index != kNotFound);
|
|
m_floatingSelectorVectors.remove(index);
|
|
}
|
|
return adoptPtr(selectorVector);
|
|
}
|
|
|
|
CSSParserValueList* BisonCSSParser::createFloatingValueList()
|
|
{
|
|
CSSParserValueList* list = new CSSParserValueList;
|
|
m_floatingValueLists.append(list);
|
|
return list;
|
|
}
|
|
|
|
PassOwnPtr<CSSParserValueList> BisonCSSParser::sinkFloatingValueList(CSSParserValueList* list)
|
|
{
|
|
if (list) {
|
|
size_t index = m_floatingValueLists.reverseFind(list);
|
|
ASSERT(index != kNotFound);
|
|
m_floatingValueLists.remove(index);
|
|
}
|
|
return adoptPtr(list);
|
|
}
|
|
|
|
CSSParserFunction* BisonCSSParser::createFloatingFunction()
|
|
{
|
|
CSSParserFunction* function = new CSSParserFunction;
|
|
m_floatingFunctions.append(function);
|
|
return function;
|
|
}
|
|
|
|
CSSParserFunction* BisonCSSParser::createFloatingFunction(const CSSParserString& name, PassOwnPtr<CSSParserValueList> args)
|
|
{
|
|
CSSParserFunction* function = createFloatingFunction();
|
|
function->name = name;
|
|
function->args = args;
|
|
return function;
|
|
}
|
|
|
|
PassOwnPtr<CSSParserFunction> BisonCSSParser::sinkFloatingFunction(CSSParserFunction* function)
|
|
{
|
|
if (function) {
|
|
size_t index = m_floatingFunctions.reverseFind(function);
|
|
ASSERT(index != kNotFound);
|
|
m_floatingFunctions.remove(index);
|
|
}
|
|
return adoptPtr(function);
|
|
}
|
|
|
|
CSSParserValue& BisonCSSParser::sinkFloatingValue(CSSParserValue& value)
|
|
{
|
|
if (value.unit == CSSParserValue::Function) {
|
|
size_t index = m_floatingFunctions.reverseFind(value.function);
|
|
ASSERT(index != kNotFound);
|
|
m_floatingFunctions.remove(index);
|
|
}
|
|
return value;
|
|
}
|
|
|
|
StyleRuleBase* BisonCSSParser::createSupportsRule(bool conditionIsSupported, RuleList* rules)
|
|
{
|
|
m_allowImportRules = m_allowNamespaceDeclarations = false;
|
|
|
|
RefPtr<CSSRuleSourceData> data = popSupportsRuleData();
|
|
RefPtr<StyleRuleSupports> rule = nullptr;
|
|
String conditionText;
|
|
unsigned conditionOffset = data->ruleHeaderRange.start + 9;
|
|
unsigned conditionLength = data->ruleHeaderRange.length() - 9;
|
|
|
|
if (m_tokenizer.is8BitSource())
|
|
conditionText = String(m_tokenizer.m_dataStart8.get() + conditionOffset, conditionLength).stripWhiteSpace();
|
|
else
|
|
conditionText = String(m_tokenizer.m_dataStart16.get() + conditionOffset, conditionLength).stripWhiteSpace();
|
|
|
|
if (rules) {
|
|
rule = StyleRuleSupports::create(conditionText, conditionIsSupported, *rules);
|
|
} else {
|
|
RuleList emptyRules;
|
|
rule = StyleRuleSupports::create(conditionText, conditionIsSupported, emptyRules);
|
|
}
|
|
|
|
StyleRuleSupports* result = rule.get();
|
|
m_parsedRules.append(rule.release());
|
|
|
|
return result;
|
|
}
|
|
|
|
void BisonCSSParser::markSupportsRuleHeaderStart()
|
|
{
|
|
if (!m_supportsRuleDataStack)
|
|
m_supportsRuleDataStack = adoptPtr(new RuleSourceDataList());
|
|
|
|
RefPtr<CSSRuleSourceData> data = CSSRuleSourceData::create(CSSRuleSourceData::SUPPORTS_RULE);
|
|
data->ruleHeaderRange.start = m_tokenizer.tokenStartOffset();
|
|
m_supportsRuleDataStack->append(data);
|
|
}
|
|
|
|
void BisonCSSParser::markSupportsRuleHeaderEnd()
|
|
{
|
|
ASSERT(m_supportsRuleDataStack && !m_supportsRuleDataStack->isEmpty());
|
|
|
|
if (m_tokenizer.is8BitSource())
|
|
m_supportsRuleDataStack->last()->ruleHeaderRange.end = m_tokenizer.tokenStart<LChar>() - m_tokenizer.m_dataStart8.get();
|
|
else
|
|
m_supportsRuleDataStack->last()->ruleHeaderRange.end = m_tokenizer.tokenStart<UChar>() - m_tokenizer.m_dataStart16.get();
|
|
}
|
|
|
|
PassRefPtr<CSSRuleSourceData> BisonCSSParser::popSupportsRuleData()
|
|
{
|
|
ASSERT(m_supportsRuleDataStack && !m_supportsRuleDataStack->isEmpty());
|
|
RefPtr<CSSRuleSourceData> data = m_supportsRuleDataStack->last();
|
|
m_supportsRuleDataStack->removeLast();
|
|
return data.release();
|
|
}
|
|
|
|
BisonCSSParser::RuleList* BisonCSSParser::createRuleList()
|
|
{
|
|
OwnPtr<RuleList> list = adoptPtr(new RuleList);
|
|
RuleList* listPtr = list.get();
|
|
|
|
m_parsedRuleLists.append(list.release());
|
|
return listPtr;
|
|
}
|
|
|
|
BisonCSSParser::RuleList* BisonCSSParser::appendRule(RuleList* ruleList, StyleRuleBase* rule)
|
|
{
|
|
if (rule) {
|
|
if (!ruleList)
|
|
ruleList = createRuleList();
|
|
ruleList->append(rule);
|
|
}
|
|
return ruleList;
|
|
}
|
|
|
|
template <typename CharacterType>
|
|
ALWAYS_INLINE static void makeLower(const CharacterType* input, CharacterType* output, unsigned length)
|
|
{
|
|
// FIXME: If we need Unicode lowercasing here, then we probably want the real kind
|
|
// that can potentially change the length of the string rather than the character
|
|
// by character kind. If we don't need Unicode lowercasing, it would be good to
|
|
// simplify this function.
|
|
|
|
if (charactersAreAllASCII(input, length)) {
|
|
// Fast case for all-ASCII.
|
|
for (unsigned i = 0; i < length; i++)
|
|
output[i] = toASCIILower(input[i]);
|
|
} else {
|
|
for (unsigned i = 0; i < length; i++)
|
|
output[i] = Unicode::toLower(input[i]);
|
|
}
|
|
}
|
|
|
|
void BisonCSSParser::tokenToLowerCase(CSSParserString& token)
|
|
{
|
|
// Since it's our internal token, we know that we created it out
|
|
// of our writable work buffers. Therefore the const_cast is just
|
|
// ugly and not a potential crash.
|
|
size_t length = token.length();
|
|
if (token.is8Bit()) {
|
|
makeLower(token.characters8(), const_cast<LChar*>(token.characters8()), length);
|
|
} else {
|
|
makeLower(token.characters16(), const_cast<UChar*>(token.characters16()), length);
|
|
}
|
|
}
|
|
|
|
void BisonCSSParser::endInvalidRuleHeader()
|
|
{
|
|
if (m_ruleHeaderType == CSSRuleSourceData::UNKNOWN_RULE)
|
|
return;
|
|
|
|
CSSParserLocation location;
|
|
location.lineNumber = m_tokenizer.m_lineNumber;
|
|
location.offset = m_ruleHeaderStartOffset;
|
|
if (m_tokenizer.is8BitSource())
|
|
location.token.init(m_tokenizer.m_dataStart8.get() + m_ruleHeaderStartOffset, 0);
|
|
else
|
|
location.token.init(m_tokenizer.m_dataStart16.get() + m_ruleHeaderStartOffset, 0);
|
|
|
|
reportError(location, m_ruleHeaderType == CSSRuleSourceData::STYLE_RULE ? InvalidSelectorCSSError : InvalidRuleCSSError);
|
|
|
|
endRuleHeader();
|
|
}
|
|
|
|
StyleRuleBase* BisonCSSParser::createStyleRule(Vector<OwnPtr<CSSParserSelector> >* selectors)
|
|
{
|
|
StyleRule* result = 0;
|
|
if (selectors) {
|
|
m_allowImportRules = m_allowNamespaceDeclarations = false;
|
|
RefPtr<StyleRule> rule = StyleRule::create();
|
|
rule->parserAdoptSelectorVector(*selectors);
|
|
rule->setProperties(createStylePropertySet());
|
|
result = rule.get();
|
|
m_parsedRules.append(rule.release());
|
|
}
|
|
clearProperties();
|
|
return result;
|
|
}
|
|
|
|
StyleRuleBase* BisonCSSParser::createFontFaceRule()
|
|
{
|
|
m_allowImportRules = m_allowNamespaceDeclarations = false;
|
|
for (unsigned i = 0; i < m_parsedProperties.size(); ++i) {
|
|
CSSProperty& property = m_parsedProperties[i];
|
|
if (property.id() == CSSPropertyFontVariant && property.value()->isPrimitiveValue())
|
|
property.wrapValueInCommaSeparatedList();
|
|
else if (property.id() == CSSPropertyFontFamily && (!property.value()->isValueList() || toCSSValueList(property.value())->length() != 1)) {
|
|
// Unlike font-family property, font-family descriptor in @font-face rule
|
|
// has to be a value list with exactly one family name. It cannot have a
|
|
// have 'initial' value and cannot 'inherit' from parent.
|
|
// See http://dev.w3.org/csswg/css3-fonts/#font-family-desc
|
|
clearProperties();
|
|
return 0;
|
|
}
|
|
}
|
|
RefPtr<StyleRuleFontFace> rule = StyleRuleFontFace::create();
|
|
rule->setProperties(createStylePropertySet());
|
|
clearProperties();
|
|
StyleRuleFontFace* result = rule.get();
|
|
m_parsedRules.append(rule.release());
|
|
return result;
|
|
}
|
|
|
|
CSSParserSelector* BisonCSSParser::rewriteSpecifiersWithNamespaceIfNeeded(CSSParserSelector* specifiers)
|
|
{
|
|
if (m_defaultNamespace != starAtom)
|
|
return rewriteSpecifiersWithElementName(nullAtom, starAtom, specifiers, /*tagIsForNamespaceRule*/true);
|
|
return specifiers;
|
|
}
|
|
|
|
CSSParserSelector* BisonCSSParser::rewriteSpecifiersWithElementName(const AtomicString& namespacePrefix, const AtomicString& elementName, CSSParserSelector* specifiers, bool tagIsForNamespaceRule)
|
|
{
|
|
QualifiedName tag(elementName);
|
|
|
|
// *:host never matches, so we can't discard the * otherwise we can't tell the
|
|
// difference between *:host and just :host.
|
|
if (tag == anyName && !specifiers->hasHostPseudoSelector())
|
|
return specifiers;
|
|
specifiers->prependTagSelector(tag, tagIsForNamespaceRule);
|
|
return specifiers;
|
|
}
|
|
|
|
CSSParserSelector* BisonCSSParser::rewriteSpecifiers(CSSParserSelector* specifiers, CSSParserSelector* newSpecifier)
|
|
{
|
|
specifiers->appendTagHistory(sinkFloatingSelector(newSpecifier));
|
|
return specifiers;
|
|
}
|
|
|
|
void BisonCSSParser::startDeclarationsForMarginBox()
|
|
{
|
|
m_numParsedPropertiesBeforeMarginBox = m_parsedProperties.size();
|
|
}
|
|
|
|
void BisonCSSParser::endDeclarationsForMarginBox()
|
|
{
|
|
rollbackLastProperties(m_parsedProperties.size() - m_numParsedPropertiesBeforeMarginBox);
|
|
m_numParsedPropertiesBeforeMarginBox = INVALID_NUM_PARSED_PROPERTIES;
|
|
}
|
|
|
|
void BisonCSSParser::startRule()
|
|
{
|
|
if (!m_observer)
|
|
return;
|
|
|
|
ASSERT(m_ruleHasHeader);
|
|
m_ruleHasHeader = false;
|
|
}
|
|
|
|
void BisonCSSParser::endRule(bool valid)
|
|
{
|
|
if (!m_observer)
|
|
return;
|
|
|
|
if (m_ruleHasHeader)
|
|
m_observer->endRuleBody(m_tokenizer.safeUserStringTokenOffset(), !valid);
|
|
m_ruleHasHeader = true;
|
|
}
|
|
|
|
void BisonCSSParser::startRuleHeader(CSSRuleSourceData::Type ruleType)
|
|
{
|
|
m_ruleHeaderType = ruleType;
|
|
m_ruleHeaderStartOffset = m_tokenizer.safeUserStringTokenOffset();
|
|
m_ruleHeaderStartLineNumber = m_tokenizer.m_tokenStartLineNumber;
|
|
if (m_observer) {
|
|
ASSERT(!m_ruleHasHeader);
|
|
m_observer->startRuleHeader(ruleType, m_ruleHeaderStartOffset);
|
|
m_ruleHasHeader = true;
|
|
}
|
|
}
|
|
|
|
void BisonCSSParser::endRuleHeader()
|
|
{
|
|
ASSERT(m_ruleHeaderType != CSSRuleSourceData::UNKNOWN_RULE);
|
|
m_ruleHeaderType = CSSRuleSourceData::UNKNOWN_RULE;
|
|
if (m_observer) {
|
|
ASSERT(m_ruleHasHeader);
|
|
m_observer->endRuleHeader(m_tokenizer.safeUserStringTokenOffset());
|
|
}
|
|
}
|
|
|
|
void BisonCSSParser::startSelector()
|
|
{
|
|
if (m_observer)
|
|
m_observer->startSelector(m_tokenizer.safeUserStringTokenOffset());
|
|
}
|
|
|
|
void BisonCSSParser::endSelector()
|
|
{
|
|
if (m_observer)
|
|
m_observer->endSelector(m_tokenizer.safeUserStringTokenOffset());
|
|
}
|
|
|
|
void BisonCSSParser::startRuleBody()
|
|
{
|
|
if (m_observer)
|
|
m_observer->startRuleBody(m_tokenizer.safeUserStringTokenOffset());
|
|
}
|
|
|
|
void BisonCSSParser::startProperty()
|
|
{
|
|
if (m_observer)
|
|
m_observer->startProperty(m_tokenizer.safeUserStringTokenOffset());
|
|
}
|
|
|
|
void BisonCSSParser::endProperty(bool isPropertyParsed, CSSParserError errorType)
|
|
{
|
|
m_id = CSSPropertyInvalid;
|
|
if (m_observer)
|
|
m_observer->endProperty(isPropertyParsed, m_tokenizer.safeUserStringTokenOffset(), errorType);
|
|
}
|
|
|
|
void BisonCSSParser::startEndUnknownRule()
|
|
{
|
|
if (m_observer)
|
|
m_observer->startEndUnknownRule();
|
|
}
|
|
|
|
}
|