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 "RuntimeEnabledFeatures.h" |
48 | #include "Settings.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 AtomicString& 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, ApplyCascadedPropertyState& state) |
181 | { |
182 | ASSERT((propID == CSSPropertyCustom && value.isCustomPropertyValue()) || (propID != CSSPropertyCustom && !value.isCustomPropertyValue())); |
183 | auto& style = *state.styleResolver->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(state); |
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, StyleRule::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(state); |
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 = state.styleResolver->document().getCSSRegisteredCustomPropertySet().get(name); |
226 | auto& syntax = registered ? registered->syntax : "*" ; |
227 | auto resolvedData = valueWithReferences.resolveVariableReferences(state); |
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 | state.styleResolver->applyCascadedProperties(id, id, state); |
238 | |
239 | return CSSPropertyParser::parseTypedCustomPropertyValue(name, syntax, resolvedData->tokens(), *state.styleResolver, 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 | StringBuilder builder; |
250 | builder.appendLiteral("@font-face { " ); |
251 | builder.append(getPropertyNameString(propertyID)); |
252 | builder.appendLiteral(" : " ); |
253 | builder.append(propertyValue); |
254 | builder.appendLiteral("; }" ); |
255 | RefPtr<StyleRuleBase> rule = parseRule(context, nullptr, builder.toString()); |
256 | if (!rule || !rule->isFontFaceRule()) |
257 | return nullptr; |
258 | return downcast<StyleRuleFontFace>(*rule.get()).properties().getPropertyCSSValue(propertyID); |
259 | } |
260 | |
261 | } |
262 | |