Add release assert for selectedIndex in WebKit::WebPopupMenu::show()
[WebKit-https.git] / Source / WebCore / css / parser / CSSParser.cpp
1 /*
2  * Copyright (C) 2003 Lars Knoll (knoll@kde.org)
3  * Copyright (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com)
4  * Copyright (C) 2004-2016 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.torchmobile.com/)
8  * Copyright (C) 2012, 2013 Adobe Systems Incorporated. All rights reserved.
9  * Copyright (C) 2012 Intel Corporation. All rights reserved.
10  * Copyright (C) 2014 Google Inc. All rights reserved.
11  *
12  * This library is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU Library General Public
14  * License as published by the Free Software Foundation; either
15  * version 2 of the License, or (at your option) any later version.
16  *
17  * This library is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  * Library General Public License for more details.
21  *
22  * You should have received a copy of the GNU Library General Public License
23  * along with this library; see the file COPYING.LIB.  If not, write to
24  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
25  * Boston, MA 02110-1301, USA.
26  */
27
28 #include "config.h"
29 #include "CSSParser.h"
30
31 #include "CSSCustomPropertyValue.h"
32 #include "CSSKeyframeRule.h"
33 #include "CSSParserFastPaths.h"
34 #include "CSSParserImpl.h"
35 #include "CSSPendingSubstitutionValue.h"
36 #include "CSSPropertyParser.h"
37 #include "CSSSelectorParser.h"
38 #include "CSSSupportsParser.h"
39 #include "CSSTokenizer.h"
40 #include "CSSVariableData.h"
41 #include "CSSVariableReferenceValue.h"
42 #include "Document.h"
43 #include "Element.h"
44 #include "Page.h"
45 #include "RenderStyle.h"
46 #include "RenderTheme.h"
47 #include "Settings.h"
48 #include "StyleBuilder.h"
49 #include "StyleColor.h"
50 #include "StyleResolver.h"
51 #include "StyleRule.h"
52 #include "StyleSheetContents.h"
53 #include <wtf/NeverDestroyed.h>
54 #include <wtf/text/StringBuilder.h>
55
56 namespace WebCore {
57
58 CSSParser::CSSParser(const CSSParserContext& context)
59     : m_context(context)
60 {
61 }
62
63 CSSParser::~CSSParser() = default;
64
65 void CSSParser::parseSheet(StyleSheetContents* sheet, const String& string, RuleParsing ruleParsing)
66 {
67     return CSSParserImpl::parseStyleSheet(string, m_context, sheet, ruleParsing);
68 }
69
70 void CSSParser::parseSheetForInspector(const CSSParserContext& context, StyleSheetContents* sheet, const String& string, CSSParserObserver& observer)
71 {
72     return CSSParserImpl::parseStyleSheetForInspector(string, context, sheet, observer);
73 }
74
75 RefPtr<StyleRuleBase> CSSParser::parseRule(const CSSParserContext& context, StyleSheetContents* sheet, const String& string)
76 {
77     return CSSParserImpl::parseRule(string, context, sheet, CSSParserImpl::AllowImportRules);
78 }
79
80 RefPtr<StyleRuleKeyframe> CSSParser::parseKeyframeRule(const String& string)
81 {
82     RefPtr<StyleRuleBase> keyframe = CSSParserImpl::parseRule(string, m_context, nullptr, CSSParserImpl::KeyframeRules);
83     return downcast<StyleRuleKeyframe>(keyframe.get());
84 }
85
86 bool CSSParser::parseSupportsCondition(const String& condition)
87 {
88     CSSParserImpl parser(m_context, condition);
89     return CSSSupportsParser::supportsCondition(parser.tokenizer()->tokenRange(), parser, CSSSupportsParser::ForWindowCSS) == CSSSupportsParser::Supported;
90 }
91
92 Color CSSParser::parseColor(const String& string, bool strict)
93 {
94     if (string.isEmpty())
95         return Color();
96     
97     // Try named colors first.
98     Color namedColor { string };
99     if (namedColor.isValid())
100         return namedColor;
101     
102     // Try the fast path to parse hex and rgb.
103     RefPtr<CSSValue> value = CSSParserFastPaths::parseColor(string, strict ? HTMLStandardMode : HTMLQuirksMode);
104     
105     // If that fails, try the full parser.
106     if (!value)
107         value = parseSingleValue(CSSPropertyColor, string, strictCSSParserContext());
108     if (!value || !value->isPrimitiveValue())
109         return Color();
110     const auto& primitiveValue = downcast<CSSPrimitiveValue>(*value);
111     if (!primitiveValue.isRGBColor())
112         return Color();
113     return primitiveValue.color();
114 }
115
116 Color CSSParser::parseSystemColor(const String& string, const CSSParserContext* context)
117 {
118     CSSValueID id = cssValueKeywordID(string);
119     if (!StyleColor::isSystemColor(id))
120         return Color();
121
122     OptionSet<StyleColor::Options> options;
123     if (context && context->useSystemAppearance)
124         options.add(StyleColor::Options::UseSystemAppearance);
125     return RenderTheme::singleton().systemColor(id, options);
126 }
127
128 RefPtr<CSSValue> CSSParser::parseSingleValue(CSSPropertyID propertyID, const String& string, const CSSParserContext& context)
129 {
130     if (string.isEmpty())
131         return nullptr;
132     if (RefPtr<CSSValue> value = CSSParserFastPaths::maybeParseValue(propertyID, string, context.mode))
133         return value;
134     CSSTokenizer tokenizer(string);
135     return CSSPropertyParser::parseSingleValue(propertyID, tokenizer.tokenRange(), context);
136 }
137
138 CSSParser::ParseResult CSSParser::parseValue(MutableStyleProperties& declaration, CSSPropertyID propertyID, const String& string, bool important, const CSSParserContext& context)
139 {
140     ASSERT(!string.isEmpty());
141     RefPtr<CSSValue> value = CSSParserFastPaths::maybeParseValue(propertyID, string, context.mode);
142     if (value)
143         return declaration.addParsedProperty(CSSProperty(propertyID, WTFMove(value), important)) ? CSSParser::ParseResult::Changed : CSSParser::ParseResult::Unchanged;
144
145     CSSParser parser(context);
146     return parser.parseValue(declaration, propertyID, string, important);
147 }
148
149 CSSParser::ParseResult CSSParser::parseCustomPropertyValue(MutableStyleProperties& declaration, const AtomString& propertyName, const String& string, bool important, const CSSParserContext& context)
150 {
151     return CSSParserImpl::parseCustomPropertyValue(&declaration, propertyName, string, important, context);
152 }
153
154 CSSParser::ParseResult CSSParser::parseValue(MutableStyleProperties& declaration, CSSPropertyID propertyID, const String& string, bool important)
155 {
156     return CSSParserImpl::parseValue(&declaration, propertyID, string, important, m_context);
157 }
158
159 void CSSParser::parseSelector(const String& string, CSSSelectorList& selectorList)
160 {
161     CSSTokenizer tokenizer(string);
162     selectorList = CSSSelectorParser::parseSelector(tokenizer.tokenRange(), m_context, nullptr);
163 }
164
165 Ref<ImmutableStyleProperties> CSSParser::parseInlineStyleDeclaration(const String& string, const Element* element)
166 {
167     return CSSParserImpl::parseInlineStyleDeclaration(string, element);
168 }
169
170 bool CSSParser::parseDeclaration(MutableStyleProperties& declaration, const String& string)
171 {
172     return CSSParserImpl::parseDeclarationList(&declaration, string, m_context);
173 }
174
175 void CSSParser::parseDeclarationForInspector(const CSSParserContext& context, const String& string, CSSParserObserver& observer)
176 {
177     CSSParserImpl::parseDeclarationListForInspector(string, context, observer);
178 }
179
180 RefPtr<CSSValue> CSSParser::parseValueWithVariableReferences(CSSPropertyID propID, const CSSValue& value, Style::BuilderState& builderState)
181 {
182     ASSERT((propID == CSSPropertyCustom && value.isCustomPropertyValue()) || (propID != CSSPropertyCustom && !value.isCustomPropertyValue()));
183     auto& style = builderState.style();
184     auto direction = style.direction();
185     auto writingMode = style.writingMode();
186
187     if (value.isPendingSubstitutionValue()) {
188         // FIXME: Should have a resolvedShorthands cache to stop this from being done
189         // over and over for each longhand value.
190         const CSSPendingSubstitutionValue& pendingSubstitution = downcast<CSSPendingSubstitutionValue>(value);
191         CSSPropertyID shorthandID = pendingSubstitution.shorthandPropertyId();
192         if (CSSProperty::isDirectionAwareProperty(shorthandID))
193             shorthandID = CSSProperty::resolveDirectionAwareProperty(shorthandID, direction, writingMode);
194         CSSVariableReferenceValue* shorthandValue = pendingSubstitution.shorthandValue();
195
196         auto resolvedData = shorthandValue->resolveVariableReferences(builderState);
197         if (!resolvedData)
198             return nullptr;
199         Vector<CSSParserToken> resolvedTokens = resolvedData->tokens();
200         
201         ParsedPropertyVector parsedProperties;
202         if (!CSSPropertyParser::parseValue(shorthandID, false, resolvedTokens, m_context, parsedProperties, StyleRuleType::Style))
203             return nullptr;
204         
205         for (auto& property : parsedProperties) {
206             if (property.id() == propID)
207                 return property.value();
208         }
209         
210         return nullptr;
211     }
212
213     if (value.isVariableReferenceValue()) {
214         const CSSVariableReferenceValue& valueWithReferences = downcast<CSSVariableReferenceValue>(value);
215         auto resolvedData = valueWithReferences.resolveVariableReferences(builderState);
216         if (!resolvedData)
217             return nullptr;
218         return CSSPropertyParser::parseSingleValue(propID, resolvedData->tokens(), m_context);
219     }
220
221     const auto& customPropValue = downcast<CSSCustomPropertyValue>(value);
222     const auto& valueWithReferences = WTF::get<Ref<CSSVariableReferenceValue>>(customPropValue.value()).get();
223
224     auto& name = downcast<CSSCustomPropertyValue>(value).name();
225     auto* registered = builderState.document().getCSSRegisteredCustomPropertySet().get(name);
226     auto& syntax = registered ? registered->syntax : "*";
227     auto resolvedData = valueWithReferences.resolveVariableReferences(builderState);
228
229     if (!resolvedData)
230         return nullptr;
231
232     // FIXME handle REM cycles.
233     HashSet<CSSPropertyID> dependencies;
234     CSSPropertyParser::collectParsedCustomPropertyValueDependencies(syntax, false, dependencies, resolvedData->tokens(), m_context);
235
236     for (auto id : dependencies)
237         builderState.builder().applyProperty(id);
238
239     return CSSPropertyParser::parseTypedCustomPropertyValue(name, syntax, resolvedData->tokens(), builderState, m_context);
240 }
241
242 std::unique_ptr<Vector<double>> CSSParser::parseKeyframeKeyList(const String& selector)
243 {
244     return CSSParserImpl::parseKeyframeKeyList(selector);
245 }
246
247 RefPtr<CSSValue> CSSParser::parseFontFaceDescriptor(CSSPropertyID propertyID, const String& propertyValue, const CSSParserContext& context)
248 {
249     String string = makeString("@font-face { ", getPropertyNameString(propertyID), " : ", propertyValue, "; }");
250     RefPtr<StyleRuleBase> rule = parseRule(context, nullptr, string);
251     if (!rule || !rule->isFontFaceRule())
252         return nullptr;
253     return downcast<StyleRuleFontFace>(*rule.get()).properties().getPropertyCSSValue(propertyID);
254 }
255
256 }