Dereferenced NULL pointer in StyleResolver
[WebKit-https.git] / Source / WebCore / css / StyleResolver.cpp
1 /*
2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3  * Copyright (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com)
4  * Copyright (C) 2006, 2007 Nicholas Shanks (webkit@nickshanks.com)
5  * Copyright (C) 2005-2014 Apple Inc. All rights reserved.
6  * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
7  * Copyright (C) 2007, 2008 Eric Seidel <eric@webkit.org>
8  * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
9  * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
10  * Copyright (C) Research In Motion Limited 2011. All rights reserved.
11  * Copyright (C) 2012, 2013 Google Inc. All rights reserved.
12  * Copyright (C) 2014 Igalia S.L.
13  *
14  * This library is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU Library General Public
16  * License as published by the Free Software Foundation; either
17  * version 2 of the License, or (at your option) any later version.
18  *
19  * This library is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22  * Library General Public License for more details.
23  *
24  * You should have received a copy of the GNU Library General Public License
25  * along with this library; see the file COPYING.LIB.  If not, write to
26  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
27  * Boston, MA 02110-1301, USA.
28  */
29
30 #include "config.h"
31 #include "StyleResolver.h"
32
33 #include "CSSBorderImage.h"
34 #include "CSSCalculationValue.h"
35 #include "CSSCursorImageValue.h"
36 #include "CSSCustomPropertyValue.h"
37 #include "CSSDefaultStyleSheets.h"
38 #include "CSSFilterImageValue.h"
39 #include "CSSFontFaceRule.h"
40 #include "CSSFontFeatureValue.h"
41 #include "CSSFontSelector.h"
42 #include "CSSFontValue.h"
43 #include "CSSFunctionValue.h"
44 #include "CSSInheritedValue.h"
45 #include "CSSInitialValue.h"
46 #include "CSSKeyframeRule.h"
47 #include "CSSKeyframesRule.h"
48 #include "CSSLineBoxContainValue.h"
49 #include "CSSPageRule.h"
50 #include "CSSParser.h"
51 #include "CSSPrimitiveValueMappings.h"
52 #include "CSSPropertyNames.h"
53 #include "CSSReflectValue.h"
54 #include "CSSSelector.h"
55 #include "CSSSelectorList.h"
56 #include "CSSShadowValue.h"
57 #include "CSSStyleRule.h"
58 #include "CSSSupportsRule.h"
59 #include "CSSTimingFunctionValue.h"
60 #include "CSSValueList.h"
61 #include "CSSValuePool.h"
62 #include "CSSVariableDependentValue.h"
63 #include "CachedImage.h"
64 #include "CachedResourceLoader.h"
65 #include "CachedSVGDocument.h"
66 #include "CachedSVGDocumentReference.h"
67 #include "CalculationValue.h"
68 #include "ContentData.h"
69 #include "Counter.h"
70 #include "CounterContent.h"
71 #include "CursorList.h"
72 #include "ElementRuleCollector.h"
73 #include "FilterOperation.h"
74 #include "Frame.h"
75 #include "FrameSelection.h"
76 #include "FrameView.h"
77 #include "HTMLDocument.h"
78 #include "HTMLIFrameElement.h"
79 #include "HTMLInputElement.h"
80 #include "HTMLMarqueeElement.h"
81 #include "HTMLNames.h"
82 #include "HTMLOptGroupElement.h"
83 #include "HTMLOptionElement.h"
84 #include "HTMLProgressElement.h"
85 #include "HTMLSlotElement.h"
86 #include "HTMLStyleElement.h"
87 #include "HTMLTableElement.h"
88 #include "HTMLTextAreaElement.h"
89 #include "InspectorInstrumentation.h"
90 #include "KeyframeList.h"
91 #include "LinkHash.h"
92 #include "LocaleToScriptMapping.h"
93 #include "MathMLNames.h"
94 #include "MediaList.h"
95 #include "MediaQueryEvaluator.h"
96 #include "NodeRenderStyle.h"
97 #include "Page.h"
98 #include "PageRuleCollector.h"
99 #include "Pair.h"
100 #include "PseudoElement.h"
101 #include "QuotesData.h"
102 #include "Rect.h"
103 #include "RenderGrid.h"
104 #include "RenderRegion.h"
105 #include "RenderScrollbar.h"
106 #include "RenderScrollbarTheme.h"
107 #include "RenderStyleConstants.h"
108 #include "RenderTheme.h"
109 #include "RenderView.h"
110 #include "RuleSet.h"
111 #include "SVGDocument.h"
112 #include "SVGDocumentExtensions.h"
113 #include "SVGFontFaceElement.h"
114 #include "SVGNames.h"
115 #include "SVGSVGElement.h"
116 #include "SVGURIReference.h"
117 #include "SecurityOrigin.h"
118 #include "Settings.h"
119 #include "ShadowData.h"
120 #include "ShadowRoot.h"
121 #include "StyleBuilder.h"
122 #include "StyleCachedImage.h"
123 #include "StyleFontSizeFunctions.h"
124 #include "StyleGeneratedImage.h"
125 #include "StylePendingImage.h"
126 #include "StyleProperties.h"
127 #include "StylePropertyShorthand.h"
128 #include "StyleRule.h"
129 #include "StyleRuleImport.h"
130 #include "StyleScrollSnapPoints.h"
131 #include "StyleSheetContents.h"
132 #include "StyleSheetList.h"
133 #include "Text.h"
134 #include "TransformFunctions.h"
135 #include "TransformOperations.h"
136 #include "UserAgentStyleSheets.h"
137 #include "ViewportStyleResolver.h"
138 #include "VisitedLinkState.h"
139 #include "WebKitCSSFilterValue.h"
140 #include "WebKitCSSRegionRule.h"
141 #include "WebKitCSSTransformValue.h"
142 #include "WebKitFontFamilyNames.h"
143 #include "XMLNames.h"
144 #include <bitset>
145 #include <wtf/StdLibExtras.h>
146 #include <wtf/TemporaryChange.h>
147 #include <wtf/Vector.h>
148 #include <wtf/text/AtomicStringHash.h>
149
150 #if ENABLE(CSS_GRID_LAYOUT)
151 #include "CSSGridLineNamesValue.h"
152 #include "CSSGridTemplateAreasValue.h"
153 #endif
154
155 #if ENABLE(CSS_IMAGE_SET)
156 #include "CSSImageSetValue.h"
157 #include "StyleCachedImageSet.h"
158 #endif
159
160 #if ENABLE(DASHBOARD_SUPPORT)
161 #include "DashboardRegion.h"
162 #endif
163
164 #if ENABLE(VIDEO_TRACK)
165 #include "WebVTTElement.h"
166 #endif
167
168 #if ENABLE(CSS_SCROLL_SNAP)
169 #include "LengthRepeat.h"
170 #endif
171
172 namespace WebCore {
173
174 using namespace HTMLNames;
175
176 static const CSSPropertyID lastHighPriorityProperty = CSSPropertyFontSynthesis;
177 static const CSSPropertyID firstLowPriorityProperty = static_cast<CSSPropertyID>(lastHighPriorityProperty + 1);
178
179 static void extractDirectionAndWritingMode(const RenderStyle&, const StyleResolver::MatchResult&, TextDirection&, WritingMode&);
180
181 inline void StyleResolver::State::cacheBorderAndBackground()
182 {
183     m_hasUAAppearance = m_style->hasAppearance();
184     if (m_hasUAAppearance) {
185         m_borderData = m_style->border();
186         m_backgroundData = *m_style->backgroundLayers();
187         m_backgroundColor = m_style->backgroundColor();
188     }
189 }
190
191 inline void StyleResolver::State::clear()
192 {
193     m_element = nullptr;
194     m_parentStyle = nullptr;
195     m_ownedParentStyle = nullptr;
196     m_regionForStyling = nullptr;
197     m_pendingResources = nullptr;
198     m_cssToLengthConversionData = CSSToLengthConversionData();
199 }
200
201 void StyleResolver::MatchResult::addMatchedProperties(const StyleProperties& properties, StyleRule* rule, unsigned linkMatchType, PropertyWhitelistType propertyWhitelistType, unsigned treeContextOrdinal)
202 {
203     m_matchedProperties.grow(m_matchedProperties.size() + 1);
204     StyleResolver::MatchedProperties& newProperties = m_matchedProperties.last();
205     newProperties.properties = const_cast<StyleProperties*>(&properties);
206     newProperties.linkMatchType = linkMatchType;
207     newProperties.whitelistType = propertyWhitelistType;
208     newProperties.treeContextOrdinal = treeContextOrdinal;
209     matchedRules.append(rule);
210
211     // Ordinal is relative to the currently matched element
212     if (treeContextOrdinal)
213         isCacheable = false;
214
215     if (isCacheable) {
216         for (unsigned i = 0, count = properties.propertyCount(); i < count; ++i) {
217             // Currently the property cache only copy the non-inherited values and resolve
218             // the inherited ones.
219             // Here we define some exception were we have to resolve some properties that are not inherited
220             // by default. If those exceptions become too common on the web, it should be possible
221             // to build a list of exception to resolve instead of completely disabling the cache.
222
223             StyleProperties::PropertyReference current = properties.propertyAt(i);
224             if (!current.isInherited()) {
225                 // If the property value is explicitly inherited, we need to apply further non-inherited properties
226                 // as they might override the value inherited here. For this reason we don't allow declarations with
227                 // explicitly inherited properties to be cached.
228                 const CSSValue& value = *current.value();
229                 if (value.isInheritedValue()) {
230                     isCacheable = false;
231                     break;
232                 }
233
234                 // The value currentColor has implicitely the same side effect. It depends on the value of color,
235                 // which is an inherited value, making the non-inherited property implicitly inherited.
236                 if (is<CSSPrimitiveValue>(value) && downcast<CSSPrimitiveValue>(value).getValueID() == CSSValueCurrentcolor) {
237                     isCacheable = false;
238                     break;
239                 }
240
241                 if (value.isVariableDependentValue()) {
242                     isCacheable = false;
243                     break;
244                 }
245             }
246         }
247     }
248 }
249
250 StyleResolver::StyleResolver(Document& document)
251     : m_matchedPropertiesCacheAdditionsSinceLastSweep(0)
252     , m_matchedPropertiesCacheSweepTimer(*this, &StyleResolver::sweepMatchedPropertiesCache)
253     , m_document(document)
254     , m_matchAuthorAndUserStyles(m_document.settings() ? m_document.settings()->authorAndUserStylesEnabled() : true)
255 #if ENABLE(CSS_DEVICE_ADAPTATION)
256     , m_viewportStyleResolver(ViewportStyleResolver::create(&document))
257 #endif
258     , m_styleMap(this)
259 {
260     Element* root = m_document.documentElement();
261
262     CSSDefaultStyleSheets::initDefaultStyle(root);
263
264     // construct document root element default style. this is needed
265     // to evaluate media queries that contain relative constraints, like "screen and (max-width: 10em)"
266     // This is here instead of constructor, because when constructor is run,
267     // document doesn't have documentElement
268     // NOTE: this assumes that element that gets passed to styleForElement -call
269     // is always from the document that owns the style selector
270     FrameView* view = m_document.view();
271     if (view)
272         m_mediaQueryEvaluator = MediaQueryEvaluator { view->mediaType() };
273     else
274         m_mediaQueryEvaluator = MediaQueryEvaluator { "all" };
275
276     if (root)
277         m_rootDefaultStyle = styleForElement(*root, m_document.renderStyle(), MatchOnlyUserAgentRules).renderStyle;
278
279     if (m_rootDefaultStyle && view)
280         m_mediaQueryEvaluator = MediaQueryEvaluator { view->mediaType(), m_document, m_rootDefaultStyle.get() };
281
282     m_ruleSets.resetAuthorStyle();
283
284     m_ruleSets.initUserStyle(m_document.extensionStyleSheets(), m_mediaQueryEvaluator, *this);
285
286 #if ENABLE(SVG_FONTS)
287     if (m_document.svgExtensions()) {
288         const HashSet<SVGFontFaceElement*>& svgFontFaceElements = m_document.svgExtensions()->svgFontFaceElements();
289         for (auto* svgFontFaceElement : svgFontFaceElements)
290             m_document.fontSelector().addFontFaceRule(svgFontFaceElement->fontFaceRule(), svgFontFaceElement->isInUserAgentShadowTree());
291     }
292 #endif
293 }
294
295 void StyleResolver::appendAuthorStyleSheets(const Vector<RefPtr<CSSStyleSheet>>& styleSheets)
296 {
297     m_ruleSets.appendAuthorStyleSheets(styleSheets, &m_mediaQueryEvaluator, m_inspectorCSSOMWrappers, this);
298
299     document().fontSelector().buildCompleted();
300
301     if (auto renderView = document().renderView())
302         renderView->style().fontCascade().update(&document().fontSelector());
303
304 #if ENABLE(CSS_DEVICE_ADAPTATION)
305     viewportStyleResolver()->resolve();
306 #endif
307 }
308
309 // This is a simplified style setting function for keyframe styles
310 void StyleResolver::addKeyframeStyle(Ref<StyleRuleKeyframes>&& rule)
311 {
312     AtomicString s(rule->name());
313     m_keyframesRuleMap.set(s.impl(), WTFMove(rule));
314 }
315
316 StyleResolver::~StyleResolver()
317 {
318     RELEASE_ASSERT(!m_inLoadPendingImages);
319
320 #if ENABLE(CSS_DEVICE_ADAPTATION)
321     m_viewportStyleResolver->clearDocument();
322 #endif
323 }
324
325 void StyleResolver::sweepMatchedPropertiesCache()
326 {
327     // Look for cache entries containing a style declaration with a single ref and remove them.
328     // This may happen when an element attribute mutation causes it to generate a new inlineStyle()
329     // or presentationAttributeStyle(), potentially leaving this cache with the last ref on the old one.
330     Vector<unsigned, 16> toRemove;
331     MatchedPropertiesCache::iterator it = m_matchedPropertiesCache.begin();
332     MatchedPropertiesCache::iterator end = m_matchedPropertiesCache.end();
333     for (; it != end; ++it) {
334         Vector<MatchedProperties>& matchedProperties = it->value.matchedProperties;
335         for (size_t i = 0; i < matchedProperties.size(); ++i) {
336             if (matchedProperties[i].properties->hasOneRef()) {
337                 toRemove.append(it->key);
338                 break;
339             }
340         }
341     }
342     for (size_t i = 0; i < toRemove.size(); ++i)
343         m_matchedPropertiesCache.remove(toRemove[i]);
344
345     m_matchedPropertiesCacheAdditionsSinceLastSweep = 0;
346 }
347
348 StyleResolver::State::State(const Element& element, const RenderStyle* parentStyle, const RenderStyle* documentElementStyle, const RenderRegion* regionForStyling, const SelectorFilter* selectorFilter)
349     : m_element(&element)
350     , m_parentStyle(parentStyle)
351     , m_regionForStyling(regionForStyling)
352     , m_elementLinkState(element.document().visitedLinkState().determineLinkState(element))
353     , m_selectorFilter(selectorFilter)
354 {
355     bool resetStyleInheritance = hasShadowRootParent(element) && downcast<ShadowRoot>(element.parentNode())->resetStyleInheritance();
356     if (resetStyleInheritance)
357         m_parentStyle = nullptr;
358
359     auto& document = element.document();
360     auto* documentElement = document.documentElement();
361     if (!documentElement || documentElement == &element)
362         m_rootElementStyle = document.renderStyle();
363     else
364         m_rootElementStyle = documentElementStyle ? documentElementStyle : documentElement->renderStyle();
365
366     updateConversionData();
367 }
368
369 inline void StyleResolver::State::updateConversionData()
370 {
371     m_cssToLengthConversionData = CSSToLengthConversionData(m_style.get(), m_rootElementStyle, m_element ? document().renderView() : nullptr);
372 }
373
374 inline void StyleResolver::State::setStyle(std::unique_ptr<RenderStyle> style)
375 {
376     m_style = WTFMove(style);
377     updateConversionData();
378 }
379
380 void StyleResolver::State::setParentStyle(std::unique_ptr<RenderStyle> parentStyle)
381 {
382     m_ownedParentStyle = WTFMove(parentStyle);
383     m_parentStyle = m_ownedParentStyle.get();
384 }
385
386 Style::PendingResources& StyleResolver::State::ensurePendingResources()
387 {
388     if (!m_pendingResources)
389         m_pendingResources = std::make_unique<Style::PendingResources>();
390     return *m_pendingResources;
391 }
392
393 static inline bool isAtShadowBoundary(const Element& element)
394 {
395     auto* parentNode = element.parentNode();
396     return parentNode && parentNode->isShadowRoot();
397 }
398
399 ElementStyle StyleResolver::styleForElement(const Element& element, const RenderStyle* parentStyle, RuleMatchingBehavior matchingBehavior, const RenderRegion* regionForStyling, const SelectorFilter* selectorFilter)
400 {
401     RELEASE_ASSERT(!m_inLoadPendingImages);
402
403     m_state = State(element, parentStyle, m_overrideDocumentElementStyle, regionForStyling, selectorFilter);
404     State& state = m_state;
405
406     if (state.parentStyle()) {
407         state.setStyle(RenderStyle::createPtr());
408         state.style()->inheritFrom(state.parentStyle(), isAtShadowBoundary(element) ? RenderStyle::AtShadowBoundary : RenderStyle::NotAtShadowBoundary);
409     } else {
410         state.setStyle(defaultStyleForElement());
411         state.setParentStyle(RenderStyle::clonePtr(*state.style()));
412     }
413
414     auto& style = *state.style();
415
416     if (element.isLink()) {
417         style.setIsLink(true);
418         EInsideLink linkState = state.elementLinkState();
419         if (linkState != NotInsideLink) {
420             bool forceVisited = InspectorInstrumentation::forcePseudoState(element, CSSSelector::PseudoClassVisited);
421             if (forceVisited)
422                 linkState = InsideVisitedLink;
423         }
424         style.setInsideLink(linkState);
425     }
426
427     CSSDefaultStyleSheets::ensureDefaultStyleSheetsForElement(element);
428
429     ElementRuleCollector collector(element, m_ruleSets, m_state.selectorFilter());
430     collector.setRegionForStyling(regionForStyling);
431     collector.setMedium(&m_mediaQueryEvaluator);
432
433     if (matchingBehavior == MatchOnlyUserAgentRules)
434         collector.matchUARules();
435     else
436         collector.matchAllRules(m_matchAuthorAndUserStyles, matchingBehavior != MatchAllRulesExcludingSMIL);
437
438     if (collector.matchedPseudoElementIds())
439         style.setHasPseudoStyles(collector.matchedPseudoElementIds());
440
441     // This is required for style sharing.
442     if (collector.didMatchUncommonAttributeSelector())
443         style.setUnique();
444
445     auto elementStyleRelations = Style::commitRelationsToRenderStyle(style, element, collector.styleRelations());
446
447     applyMatchedProperties(collector.matchedResult(), element);
448
449     // Clean up our style object's display and text decorations (among other fixups).
450     adjustRenderStyle(*state.style(), *state.parentStyle(), &element);
451
452     if (state.style()->hasViewportUnits())
453         document().setHasStyleWithViewportUnits();
454
455     state.clear(); // Clear out for the next resolve.
456
457     return { state.takeStyle(), WTFMove(elementStyleRelations) };
458 }
459
460 std::unique_ptr<RenderStyle> StyleResolver::styleForKeyframe(const RenderStyle* elementStyle, const StyleKeyframe* keyframe, KeyframeValue& keyframeValue)
461 {
462     RELEASE_ASSERT(!m_inLoadPendingImages);
463
464     MatchResult result;
465     result.addMatchedProperties(keyframe->properties());
466
467     ASSERT(!m_state.style());
468
469     State& state = m_state;
470
471     // Create the style
472     state.setStyle(RenderStyle::clonePtr(*elementStyle));
473     state.setParentStyle(RenderStyle::clonePtr(*elementStyle));
474
475     TextDirection direction;
476     WritingMode writingMode;
477     extractDirectionAndWritingMode(*state.style(), result, direction, writingMode);
478
479     // We don't need to bother with !important. Since there is only ever one
480     // decl, there's nothing to override. So just add the first properties.
481     CascadedProperties cascade(direction, writingMode);
482     cascade.addNormalMatches(result, 0, result.matchedProperties().size() - 1);
483     
484     // Resolve custom properties first.
485     applyCascadedProperties(cascade, CSSPropertyCustom, CSSPropertyCustom, &result);
486
487     applyCascadedProperties(cascade, firstCSSProperty, lastHighPriorityProperty, &result);
488
489     // If our font got dirtied, update it now.
490     updateFont();
491
492     // Now do rest of the properties.
493     applyCascadedProperties(cascade, firstLowPriorityProperty, lastCSSProperty, &result);
494
495     // If our font got dirtied by one of the non-essential font props, update it a second time.
496     updateFont();
497
498     cascade.applyDeferredProperties(*this, &result);
499
500     adjustRenderStyle(*state.style(), *state.parentStyle(), nullptr);
501
502     // Start loading resources referenced by this style.
503     loadPendingResources();
504     
505     // Add all the animating properties to the keyframe.
506     unsigned propertyCount = keyframe->properties().propertyCount();
507     for (unsigned i = 0; i < propertyCount; ++i) {
508         CSSPropertyID property = keyframe->properties().propertyAt(i).id();
509         // Timing-function within keyframes is special, because it is not animated; it just
510         // describes the timing function between this keyframe and the next.
511         if (property != CSSPropertyWebkitAnimationTimingFunction && property != CSSPropertyAnimationTimingFunction)
512             keyframeValue.addProperty(property);
513     }
514
515     return state.takeStyle();
516 }
517
518 void StyleResolver::keyframeStylesForAnimation(const Element& element, const RenderStyle* elementStyle, KeyframeList& list)
519 {
520     list.clear();
521
522     // Get the keyframesRule for this name.
523     if (list.animationName().isEmpty())
524         return;
525
526     m_keyframesRuleMap.checkConsistency();
527
528     KeyframesRuleMap::iterator it = m_keyframesRuleMap.find(list.animationName().impl());
529     if (it == m_keyframesRuleMap.end())
530         return;
531
532     const StyleRuleKeyframes* keyframesRule = it->value.get();
533
534     auto* keyframes = &keyframesRule->keyframes();
535     Vector<Ref<StyleKeyframe>> newKeyframesIfNecessary;
536
537     bool hasDuplicateKeys = false;
538     HashSet<double> keyframeKeys;
539     for (auto& keyframe : *keyframes) {
540         for (auto key : keyframe->keys()) {
541             if (!keyframeKeys.add(key)) {
542                 hasDuplicateKeys = true;
543                 break;
544             }
545         }
546         if (hasDuplicateKeys)
547             break;
548     }
549
550     // FIXME: If HashMaps could have Ref<> as value types, we wouldn't need
551     // to copy the HashMap into a Vector.
552     if (hasDuplicateKeys) {
553         // Merge duplicate key times.
554         HashMap<double, RefPtr<StyleKeyframe>> keyframesMap;
555
556         for (auto& originalKeyframe : keyframesRule->keyframes()) {
557             for (auto key : originalKeyframe->keys()) {
558                 if (auto keyframe = keyframesMap.get(key))
559                     keyframe->mutableProperties().mergeAndOverrideOnConflict(originalKeyframe->properties());
560                 else {
561                     auto styleKeyframe = StyleKeyframe::create(MutableStyleProperties::create());
562                     styleKeyframe.ptr()->setKey(key);
563                     styleKeyframe.ptr()->mutableProperties().mergeAndOverrideOnConflict(originalKeyframe->properties());
564                     keyframesMap.set(key, styleKeyframe.ptr());
565                 }
566             }
567         }
568
569         for (auto& keyframe : keyframesMap.values())
570             newKeyframesIfNecessary.append(*keyframe.get());
571
572         keyframes = &newKeyframesIfNecessary;
573     }
574
575     // Construct and populate the style for each keyframe.
576     for (auto& keyframe : *keyframes) {
577         // Apply the declaration to the style. This is a simplified version of the logic in styleForElement.
578         m_state = State(element, nullptr);
579
580         // Add this keyframe style to all the indicated key times
581         for (auto key : keyframe->keys()) {
582             KeyframeValue keyframeValue(0, nullptr);
583             keyframeValue.setStyle(styleForKeyframe(elementStyle, keyframe.ptr(), keyframeValue));
584             keyframeValue.setKey(key);
585             list.insert(WTFMove(keyframeValue));
586         }
587     }
588
589     // If the 0% keyframe is missing, create it (but only if there is at least one other keyframe).
590     int initialListSize = list.size();
591     if (initialListSize > 0 && list[0].key()) {
592         static StyleKeyframe* zeroPercentKeyframe;
593         if (!zeroPercentKeyframe) {
594             zeroPercentKeyframe = &StyleKeyframe::create(MutableStyleProperties::create()).leakRef();
595             zeroPercentKeyframe->setKey(0);
596         }
597         KeyframeValue keyframeValue(0, nullptr);
598         keyframeValue.setStyle(styleForKeyframe(elementStyle, zeroPercentKeyframe, keyframeValue));
599         list.insert(WTFMove(keyframeValue));
600     }
601
602     // If the 100% keyframe is missing, create it (but only if there is at least one other keyframe).
603     if (initialListSize > 0 && (list[list.size() - 1].key() != 1)) {
604         static StyleKeyframe* hundredPercentKeyframe;
605         if (!hundredPercentKeyframe) {
606             hundredPercentKeyframe = &StyleKeyframe::create(MutableStyleProperties::create()).leakRef();
607             hundredPercentKeyframe->setKey(1);
608         }
609         KeyframeValue keyframeValue(1, nullptr);
610         keyframeValue.setStyle(styleForKeyframe(elementStyle, hundredPercentKeyframe, keyframeValue));
611         list.insert(WTFMove(keyframeValue));
612     }
613 }
614
615 std::unique_ptr<RenderStyle> StyleResolver::pseudoStyleForElement(const Element& element, const PseudoStyleRequest& pseudoStyleRequest, const RenderStyle& parentStyle)
616 {
617     m_state = State(element, &parentStyle);
618
619     State& state = m_state;
620
621     if (m_state.parentStyle()) {
622         state.setStyle(RenderStyle::createPtr());
623         state.style()->inheritFrom(m_state.parentStyle());
624     } else {
625         state.setStyle(defaultStyleForElement());
626         state.setParentStyle(RenderStyle::clonePtr(*state.style()));
627     }
628
629     // Since we don't use pseudo-elements in any of our quirk/print user agent rules, don't waste time walking
630     // those rules.
631
632     // Check UA, user and author rules.
633     ElementRuleCollector collector(element, m_ruleSets, m_state.selectorFilter());
634     collector.setPseudoStyleRequest(pseudoStyleRequest);
635     collector.setMedium(&m_mediaQueryEvaluator);
636     collector.matchUARules();
637
638     if (m_matchAuthorAndUserStyles) {
639         collector.matchUserRules(false);
640         collector.matchAuthorRules(false);
641     }
642
643     ASSERT(!collector.matchedPseudoElementIds());
644
645     if (collector.matchedResult().matchedProperties().isEmpty())
646         return nullptr;
647
648     state.style()->setStyleType(pseudoStyleRequest.pseudoId);
649
650     applyMatchedProperties(collector.matchedResult(), element);
651
652     // Clean up our style object's display and text decorations (among other fixups).
653     adjustRenderStyle(*state.style(), *m_state.parentStyle(), nullptr);
654
655     if (state.style()->hasViewportUnits())
656         document().setHasStyleWithViewportUnits();
657
658     // Start loading resources referenced by this style.
659     loadPendingResources();
660
661     // Now return the style.
662     return state.takeStyle();
663 }
664
665 std::unique_ptr<RenderStyle> StyleResolver::styleForPage(int pageIndex)
666 {
667     RELEASE_ASSERT(!m_inLoadPendingImages);
668
669     auto* documentElement = m_document.documentElement();
670     if (!documentElement)
671         return RenderStyle::createPtr();
672
673     m_state = State(*documentElement, m_document.renderStyle());
674
675     m_state.setStyle(RenderStyle::createPtr());
676     m_state.style()->inheritFrom(m_state.rootElementStyle());
677
678     PageRuleCollector collector(m_state, m_ruleSets);
679     collector.matchAllPageRules(pageIndex);
680
681     MatchResult& result = collector.matchedResult();
682
683     TextDirection direction;
684     WritingMode writingMode;
685     extractDirectionAndWritingMode(*m_state.style(), result, direction, writingMode);
686
687     CascadedProperties cascade(direction, writingMode);
688     cascade.addNormalMatches(result, 0, result.matchedProperties().size() - 1);
689
690     // Resolve custom properties first.
691     applyCascadedProperties(cascade, CSSPropertyCustom, CSSPropertyCustom, &result);
692
693     applyCascadedProperties(cascade, firstCSSProperty, lastHighPriorityProperty, &result);
694
695     // If our font got dirtied, update it now.
696     updateFont();
697
698     applyCascadedProperties(cascade, firstLowPriorityProperty, lastCSSProperty, &result);
699
700     cascade.applyDeferredProperties(*this, &result);
701
702     // Start loading resources referenced by this style.
703     loadPendingResources();
704
705     // Now return the style.
706     return m_state.takeStyle();
707 }
708
709 std::unique_ptr<RenderStyle> StyleResolver::defaultStyleForElement()
710 {
711     m_state.setStyle(RenderStyle::createPtr());
712     // Make sure our fonts are initialized if we don't inherit them from our parent style.
713     initializeFontStyle(documentSettings());
714     if (documentSettings())
715         m_state.style()->fontCascade().update(&document().fontSelector());
716     else
717         m_state.style()->fontCascade().update(nullptr);
718
719     return m_state.takeStyle();
720 }
721
722 static void addIntrinsicMargins(RenderStyle& style)
723 {
724     // Intrinsic margin value.
725     const int intrinsicMargin = 2 * style.effectiveZoom();
726
727     // FIXME: Using width/height alone and not also dealing with min-width/max-width is flawed.
728     // FIXME: Using "hasQuirk" to decide the margin wasn't set is kind of lame.
729     if (style.width().isIntrinsicOrAuto()) {
730         if (style.marginLeft().hasQuirk())
731             style.setMarginLeft(Length(intrinsicMargin, Fixed));
732         if (style.marginRight().hasQuirk())
733             style.setMarginRight(Length(intrinsicMargin, Fixed));
734     }
735
736     if (style.height().isAuto()) {
737         if (style.marginTop().hasQuirk())
738             style.setMarginTop(Length(intrinsicMargin, Fixed));
739         if (style.marginBottom().hasQuirk())
740             style.setMarginBottom(Length(intrinsicMargin, Fixed));
741     }
742 }
743
744 static EDisplay equivalentBlockDisplay(EDisplay display, bool isFloating, bool strictParsing)
745 {
746     switch (display) {
747     case BLOCK:
748     case TABLE:
749     case BOX:
750     case FLEX:
751     case WEBKIT_FLEX:
752 #if ENABLE(CSS_GRID_LAYOUT)
753     case GRID:
754 #endif
755         return display;
756
757     case LIST_ITEM:
758         // It is a WinIE bug that floated list items lose their bullets, so we'll emulate the quirk, but only in quirks mode.
759         if (!strictParsing && isFloating)
760             return BLOCK;
761         return display;
762     case INLINE_TABLE:
763         return TABLE;
764     case INLINE_BOX:
765         return BOX;
766     case INLINE_FLEX:
767     case WEBKIT_INLINE_FLEX:
768         return FLEX;
769 #if ENABLE(CSS_GRID_LAYOUT)
770     case INLINE_GRID:
771         return GRID;
772 #endif
773
774     case INLINE:
775     case COMPACT:
776     case INLINE_BLOCK:
777     case TABLE_ROW_GROUP:
778     case TABLE_HEADER_GROUP:
779     case TABLE_FOOTER_GROUP:
780     case TABLE_ROW:
781     case TABLE_COLUMN_GROUP:
782     case TABLE_COLUMN:
783     case TABLE_CELL:
784     case TABLE_CAPTION:
785     case CONTENTS:
786         return BLOCK;
787     case NONE:
788         ASSERT_NOT_REACHED();
789         return NONE;
790     }
791     ASSERT_NOT_REACHED();
792     return BLOCK;
793 }
794
795 // CSS requires text-decoration to be reset at each DOM element for tables, 
796 // inline blocks, inline tables, shadow DOM crossings, floating elements,
797 // and absolute or relatively positioned elements.
798 static bool doesNotInheritTextDecoration(const RenderStyle& style, const Element* element)
799 {
800     return style.display() == TABLE || style.display() == INLINE_TABLE
801         || style.display() == INLINE_BLOCK || style.display() == INLINE_BOX || (element && isAtShadowBoundary(*element))
802         || style.isFloating() || style.hasOutOfFlowPosition();
803 }
804
805 #if ENABLE(ACCELERATED_OVERFLOW_SCROLLING)
806 static bool isScrollableOverflow(EOverflow overflow)
807 {
808     return overflow == OSCROLL || overflow == OAUTO || overflow == OOVERLAY;
809 }
810 #endif
811
812 void StyleResolver::adjustStyleForInterCharacterRuby()
813 {
814     RenderStyle* style = m_state.style();
815     if (style->rubyPosition() != RubyPositionInterCharacter || !m_state.element() || !m_state.element()->hasTagName(rtTag))
816         return;
817     style->setTextAlign(CENTER);
818     if (style->isHorizontalWritingMode())
819         style->setWritingMode(LeftToRightWritingMode);
820 }
821
822 void StyleResolver::adjustRenderStyle(RenderStyle& style, const RenderStyle& parentStyle, const Element* element)
823 {
824     // Cache our original display.
825     style.setOriginalDisplay(style.display());
826
827     if (style.display() != NONE) {
828         if (style.display() == CONTENTS) {
829             // FIXME: Enable for all elements.
830             bool elementSupportsDisplayContents = false;
831             elementSupportsDisplayContents = is<HTMLSlotElement>(element);
832             if (!elementSupportsDisplayContents)
833                 style.setDisplay(INLINE);
834         }
835         if (element) {
836             // If we have a <td> that specifies a float property, in quirks mode we just drop the float
837             // property.
838             // Sites also commonly use display:inline/block on <td>s and <table>s. In quirks mode we force
839             // these tags to retain their display types.
840             if (document().inQuirksMode()) {
841                 if (element->hasTagName(tdTag)) {
842                     style.setDisplay(TABLE_CELL);
843                     style.setFloating(NoFloat);
844                 } else if (is<HTMLTableElement>(*element))
845                     style.setDisplay(style.isDisplayInlineType() ? INLINE_TABLE : TABLE);
846             }
847
848             if (element->hasTagName(tdTag) || element->hasTagName(thTag)) {
849                 if (style.whiteSpace() == KHTML_NOWRAP) {
850                     // Figure out if we are really nowrapping or if we should just
851                     // use normal instead. If the width of the cell is fixed, then
852                     // we don't actually use NOWRAP.
853                     if (style.width().isFixed())
854                         style.setWhiteSpace(NORMAL);
855                     else
856                         style.setWhiteSpace(NOWRAP);
857                 }
858             }
859
860             // Tables never support the -webkit-* values for text-align and will reset back to the default.
861             if (is<HTMLTableElement>(*element) && (style.textAlign() == WEBKIT_LEFT || style.textAlign() == WEBKIT_CENTER || style.textAlign() == WEBKIT_RIGHT))
862                 style.setTextAlign(TASTART);
863
864             // Frames and framesets never honor position:relative or position:absolute. This is necessary to
865             // fix a crash where a site tries to position these objects. They also never honor display.
866             if (element->hasTagName(frameTag) || element->hasTagName(framesetTag)) {
867                 style.setPosition(StaticPosition);
868                 style.setDisplay(BLOCK);
869             }
870
871             // Ruby text does not support float or position. This might change with evolution of the specification.
872             if (element->hasTagName(rtTag)) {
873                 style.setPosition(StaticPosition);
874                 style.setFloating(NoFloat);
875             }
876
877             // FIXME: We shouldn't be overriding start/-webkit-auto like this. Do it in html.css instead.
878             // Table headers with a text-align of -webkit-auto will change the text-align to center.
879             if (element->hasTagName(thTag) && style.textAlign() == TASTART)
880                 style.setTextAlign(CENTER);
881
882             if (element->hasTagName(legendTag))
883                 style.setDisplay(BLOCK);
884         }
885
886         // Absolute/fixed positioned elements, floating elements and the document element need block-like outside display.
887         if (style.hasOutOfFlowPosition() || style.isFloating() || (element && element->document().documentElement() == element))
888             style.setDisplay(equivalentBlockDisplay(style.display(), style.isFloating(), !document().inQuirksMode()));
889
890         // FIXME: Don't support this mutation for pseudo styles like first-letter or first-line, since it's not completely
891         // clear how that should work.
892         if (style.display() == INLINE && style.styleType() == NOPSEUDO && style.writingMode() != parentStyle.writingMode())
893             style.setDisplay(INLINE_BLOCK);
894
895         // After performing the display mutation, check table rows. We do not honor position:relative or position:sticky on
896         // table rows or cells. This has been established for position:relative in CSS2.1 (and caused a crash in containingBlock()
897         // on some sites).
898         if ((style.display() == TABLE_HEADER_GROUP || style.display() == TABLE_ROW_GROUP
899             || style.display() == TABLE_FOOTER_GROUP || style.display() == TABLE_ROW)
900             && style.position() == RelativePosition)
901             style.setPosition(StaticPosition);
902
903         // writing-mode does not apply to table row groups, table column groups, table rows, and table columns.
904         // FIXME: Table cells should be allowed to be perpendicular or flipped with respect to the table, though.
905         if (style.display() == TABLE_COLUMN || style.display() == TABLE_COLUMN_GROUP || style.display() == TABLE_FOOTER_GROUP
906             || style.display() == TABLE_HEADER_GROUP || style.display() == TABLE_ROW || style.display() == TABLE_ROW_GROUP
907             || style.display() == TABLE_CELL)
908             style.setWritingMode(parentStyle.writingMode());
909
910         // FIXME: Since we don't support block-flow on flexible boxes yet, disallow setting
911         // of block-flow to anything other than TopToBottomWritingMode.
912         // https://bugs.webkit.org/show_bug.cgi?id=46418 - Flexible box support.
913         if (style.writingMode() != TopToBottomWritingMode && (style.display() == BOX || style.display() == INLINE_BOX))
914             style.setWritingMode(TopToBottomWritingMode);
915
916         if (parentStyle.isDisplayFlexibleOrGridBox()) {
917             style.setFloating(NoFloat);
918             style.setDisplay(equivalentBlockDisplay(style.display(), style.isFloating(), !document().inQuirksMode()));
919         }
920     }
921
922     // Make sure our z-index value is only applied if the object is positioned.
923     if (style.position() == StaticPosition && !parentStyle.isDisplayFlexibleOrGridBox())
924         style.setHasAutoZIndex();
925
926     // Auto z-index becomes 0 for the root element and transparent objects. This prevents
927     // cases where objects that should be blended as a single unit end up with a non-transparent
928     // object wedged in between them. Auto z-index also becomes 0 for objects that specify transforms/masks/reflections.
929     if (style.hasAutoZIndex()) {
930         if ((element && element->document().documentElement() == element)
931             || style.opacity() < 1.0f
932             || style.hasTransformRelatedProperty()
933             || style.hasMask()
934             || style.clipPath()
935             || style.boxReflect()
936             || style.hasFilter()
937 #if ENABLE(FILTERS_LEVEL_2)
938             || style.hasBackdropFilter()
939 #endif
940             || style.hasBlendMode()
941             || style.hasIsolation()
942             || style.position() == StickyPosition
943             || (style.position() == FixedPosition && documentSettings() && documentSettings()->fixedPositionCreatesStackingContext())
944             || style.hasFlowFrom()
945             || style.willChangeCreatesStackingContext())
946             style.setZIndex(0);
947     }
948
949     if (element) {
950         // Textarea considers overflow visible as auto.
951         if (is<HTMLTextAreaElement>(*element)) {
952             style.setOverflowX(style.overflowX() == OVISIBLE ? OAUTO : style.overflowX());
953             style.setOverflowY(style.overflowY() == OVISIBLE ? OAUTO : style.overflowY());
954         }
955
956         // Disallow -webkit-user-modify on :pseudo and ::pseudo elements.
957         if (!element->shadowPseudoId().isNull())
958             style.setUserModify(READ_ONLY);
959
960         // For now, <marquee> requires an overflow clip to work properly.
961         if (is<HTMLMarqueeElement>(*element)) {
962             style.setOverflowX(OHIDDEN);
963             style.setOverflowY(OHIDDEN);
964         }
965     }
966
967     if (doesNotInheritTextDecoration(style, element))
968         style.setTextDecorationsInEffect(style.textDecoration());
969     else
970         style.addToTextDecorationsInEffect(style.textDecoration());
971
972     // If either overflow value is not visible, change to auto.
973     if (style.overflowX() == OVISIBLE && style.overflowY() != OVISIBLE) {
974         // FIXME: Once we implement pagination controls, overflow-x should default to hidden
975         // if overflow-y is set to -webkit-paged-x or -webkit-page-y. For now, we'll let it
976         // default to auto so we can at least scroll through the pages.
977         style.setOverflowX(OAUTO);
978     } else if (style.overflowY() == OVISIBLE && style.overflowX() != OVISIBLE)
979         style.setOverflowY(OAUTO);
980
981     // Call setStylesForPaginationMode() if a pagination mode is set for any non-root elements. If these
982     // styles are specified on a root element, then they will be incorporated in
983     // Style::createForDocument().
984     if ((style.overflowY() == OPAGEDX || style.overflowY() == OPAGEDY) && !(element && (element->hasTagName(htmlTag) || element->hasTagName(bodyTag))))
985         style.setColumnStylesFromPaginationMode(WebCore::paginationModeForRenderStyle(style));
986
987     // Table rows, sections and the table itself will support overflow:hidden and will ignore scroll/auto.
988     // FIXME: Eventually table sections will support auto and scroll.
989     if (style.display() == TABLE || style.display() == INLINE_TABLE
990         || style.display() == TABLE_ROW_GROUP || style.display() == TABLE_ROW) {
991         if (style.overflowX() != OVISIBLE && style.overflowX() != OHIDDEN)
992             style.setOverflowX(OVISIBLE);
993         if (style.overflowY() != OVISIBLE && style.overflowY() != OHIDDEN)
994             style.setOverflowY(OVISIBLE);
995     }
996
997     // Menulists should have visible overflow
998     if (style.appearance() == MenulistPart) {
999         style.setOverflowX(OVISIBLE);
1000         style.setOverflowY(OVISIBLE);
1001     }
1002
1003 #if ENABLE(ACCELERATED_OVERFLOW_SCROLLING)
1004     // Touch overflow scrolling creates a stacking context.
1005     if (style.hasAutoZIndex() && style.useTouchOverflowScrolling() && (isScrollableOverflow(style.overflowX()) || isScrollableOverflow(style.overflowY())))
1006         style.setZIndex(0);
1007 #endif
1008
1009     // Cull out any useless layers and also repeat patterns into additional layers.
1010     style.adjustBackgroundLayers();
1011     style.adjustMaskLayers();
1012
1013     // Do the same for animations and transitions.
1014     style.adjustAnimations();
1015     style.adjustTransitions();
1016
1017     // Important: Intrinsic margins get added to controls before the theme has adjusted the style, since the theme will
1018     // alter fonts and heights/widths.
1019     if (is<HTMLFormControlElement>(element) && style.fontSize() >= 11) {
1020         // Don't apply intrinsic margins to image buttons. The designer knows how big the images are,
1021         // so we have to treat all image buttons as though they were explicitly sized.
1022         if (!is<HTMLInputElement>(*element) || !downcast<HTMLInputElement>(*element).isImageButton())
1023             addIntrinsicMargins(style);
1024     }
1025
1026     // Let the theme also have a crack at adjusting the style.
1027     if (style.hasAppearance())
1028         RenderTheme::defaultTheme()->adjustStyle(*this, style, element, m_state.hasUAAppearance(), m_state.borderData(), m_state.backgroundData(), m_state.backgroundColor());
1029
1030     // If we have first-letter pseudo style, do not share this style.
1031     if (style.hasPseudoStyle(FIRST_LETTER))
1032         style.setUnique();
1033
1034     // FIXME: when dropping the -webkit prefix on transform-style, we should also have opacity < 1 cause flattening.
1035     if (style.preserves3D() && (style.overflowX() != OVISIBLE
1036         || style.overflowY() != OVISIBLE
1037         || style.hasClip()
1038         || style.clipPath()
1039         || style.hasFilter()
1040 #if ENABLE(FILTERS_LEVEL_2)
1041         || style.hasBackdropFilter()
1042 #endif
1043         || style.hasBlendMode()))
1044         style.setTransformStyle3D(TransformStyle3DFlat);
1045
1046     if (is<SVGElement>(element)) {
1047         // Only the root <svg> element in an SVG document fragment tree honors css position
1048         if (!(element->hasTagName(SVGNames::svgTag) && element->parentNode() && !element->parentNode()->isSVGElement()))
1049             style.setPosition(RenderStyle::initialPosition());
1050
1051         // RenderSVGRoot handles zooming for the whole SVG subtree, so foreignObject content should
1052         // not be scaled again.
1053         if (element->hasTagName(SVGNames::foreignObjectTag))
1054             style.setEffectiveZoom(RenderStyle::initialZoom());
1055
1056         // SVG text layout code expects us to be a block-level style element.
1057         if ((element->hasTagName(SVGNames::foreignObjectTag) || element->hasTagName(SVGNames::textTag)) && style.isDisplayInlineType())
1058             style.setDisplay(BLOCK);
1059     }
1060 }
1061
1062 bool StyleResolver::checkRegionStyle(const Element* regionElement)
1063 {
1064     unsigned rulesSize = m_ruleSets.authorStyle().regionSelectorsAndRuleSets().size();
1065     for (unsigned i = 0; i < rulesSize; ++i) {
1066         ASSERT(m_ruleSets.authorStyle().regionSelectorsAndRuleSets().at(i).ruleSet.get());
1067         if (checkRegionSelector(m_ruleSets.authorStyle().regionSelectorsAndRuleSets().at(i).selector, regionElement))
1068             return true;
1069     }
1070
1071     if (m_ruleSets.userStyle()) {
1072         rulesSize = m_ruleSets.userStyle()->regionSelectorsAndRuleSets().size();
1073         for (unsigned i = 0; i < rulesSize; ++i) {
1074             ASSERT(m_ruleSets.userStyle()->regionSelectorsAndRuleSets().at(i).ruleSet.get());
1075             if (checkRegionSelector(m_ruleSets.userStyle()->regionSelectorsAndRuleSets().at(i).selector, regionElement))
1076                 return true;
1077         }
1078     }
1079
1080     return false;
1081 }
1082
1083 static void checkForOrientationChange(RenderStyle* style)
1084 {
1085     FontOrientation fontOrientation;
1086     NonCJKGlyphOrientation glyphOrientation;
1087     std::tie(fontOrientation, glyphOrientation) = style->fontAndGlyphOrientation();
1088
1089     const auto& fontDescription = style->fontDescription();
1090     if (fontDescription.orientation() == fontOrientation && fontDescription.nonCJKGlyphOrientation() == glyphOrientation)
1091         return;
1092
1093     auto newFontDescription = fontDescription;
1094     newFontDescription.setNonCJKGlyphOrientation(glyphOrientation);
1095     newFontDescription.setOrientation(fontOrientation);
1096     style->setFontDescription(newFontDescription);
1097 }
1098
1099 void StyleResolver::updateFont()
1100 {
1101     if (!m_state.fontDirty())
1102         return;
1103
1104     RenderStyle* style = m_state.style();
1105 #if ENABLE(IOS_TEXT_AUTOSIZING)
1106     checkForTextSizeAdjust(style);
1107 #endif
1108     checkForGenericFamilyChange(style, m_state.parentStyle());
1109     checkForZoomChange(style, m_state.parentStyle());
1110     checkForOrientationChange(style);
1111     style->fontCascade().update(&document().fontSelector());
1112     if (m_state.fontSizeHasViewportUnits())
1113         style->setHasViewportUnits(true);
1114     m_state.setFontDirty(false);
1115 }
1116
1117 Vector<RefPtr<StyleRule>> StyleResolver::styleRulesForElement(const Element* element, unsigned rulesToInclude)
1118 {
1119     return pseudoStyleRulesForElement(element, NOPSEUDO, rulesToInclude);
1120 }
1121
1122 Vector<RefPtr<StyleRule>> StyleResolver::pseudoStyleRulesForElement(const Element* element, PseudoId pseudoId, unsigned rulesToInclude)
1123 {
1124     if (!element || !element->document().haveStylesheetsLoaded())
1125         return Vector<RefPtr<StyleRule>>();
1126
1127     m_state = State(*element, nullptr);
1128
1129     ElementRuleCollector collector(*element, m_ruleSets, m_state.selectorFilter());
1130     collector.setMode(SelectorChecker::Mode::CollectingRules);
1131     collector.setPseudoStyleRequest(PseudoStyleRequest(pseudoId));
1132     collector.setMedium(&m_mediaQueryEvaluator);
1133
1134     if (rulesToInclude & UAAndUserCSSRules) {
1135         // First we match rules from the user agent sheet.
1136         collector.matchUARules();
1137         
1138         // Now we check user sheet rules.
1139         if (m_matchAuthorAndUserStyles)
1140             collector.matchUserRules(rulesToInclude & EmptyCSSRules);
1141     }
1142
1143     if (m_matchAuthorAndUserStyles && (rulesToInclude & AuthorCSSRules)) {
1144         collector.setSameOriginOnly(!(rulesToInclude & CrossOriginCSSRules));
1145
1146         // Check the rules in author sheets.
1147         collector.matchAuthorRules(rulesToInclude & EmptyCSSRules);
1148     }
1149
1150     return collector.matchedRuleList();
1151 }
1152
1153 static bool shouldApplyPropertyInParseOrder(CSSPropertyID propertyID)
1154 {
1155     switch (propertyID) {
1156     case CSSPropertyWebkitBackgroundClip:
1157     case CSSPropertyBackgroundClip:
1158     case CSSPropertyWebkitBackgroundOrigin:
1159     case CSSPropertyBackgroundOrigin:
1160     case CSSPropertyWebkitBackgroundSize:
1161     case CSSPropertyBackgroundSize:
1162     case CSSPropertyWebkitBorderImage:
1163     case CSSPropertyBorderImage:
1164     case CSSPropertyBorderImageSlice:
1165     case CSSPropertyBorderImageSource:
1166     case CSSPropertyBorderImageOutset:
1167     case CSSPropertyBorderImageRepeat:
1168     case CSSPropertyBorderImageWidth:
1169     case CSSPropertyWebkitBoxShadow:
1170     case CSSPropertyBoxShadow:
1171     case CSSPropertyWebkitTextDecoration:
1172     case CSSPropertyWebkitTextDecorationLine:
1173     case CSSPropertyWebkitTextDecorationStyle:
1174     case CSSPropertyWebkitTextDecorationColor:
1175     case CSSPropertyWebkitTextDecorationSkip:
1176     case CSSPropertyWebkitTextUnderlinePosition:
1177     case CSSPropertyTextDecoration:
1178         return true;
1179     default:
1180         return false;
1181     }
1182 }
1183
1184 static bool elementTypeHasAppearanceFromUAStyle(const Element& element)
1185 {
1186     // NOTE: This is just a hard-coded list of elements that have some -webkit-appearance value in html.css
1187     const auto& localName = element.localName();
1188     return localName == HTMLNames::inputTag
1189         || localName == HTMLNames::textareaTag
1190         || localName == HTMLNames::buttonTag
1191         || localName == HTMLNames::progressTag
1192         || localName == HTMLNames::selectTag
1193         || localName == HTMLNames::meterTag
1194         || localName == HTMLNames::isindexTag;
1195 }
1196
1197 unsigned StyleResolver::computeMatchedPropertiesHash(const MatchedProperties* properties, unsigned size)
1198 {
1199     return StringHasher::hashMemory(properties, sizeof(MatchedProperties) * size);
1200 }
1201
1202 bool operator==(const StyleResolver::MatchRanges& a, const StyleResolver::MatchRanges& b)
1203 {
1204     return a.firstUARule == b.firstUARule
1205         && a.lastUARule == b.lastUARule
1206         && a.firstAuthorRule == b.firstAuthorRule
1207         && a.lastAuthorRule == b.lastAuthorRule
1208         && a.firstUserRule == b.firstUserRule
1209         && a.lastUserRule == b.lastUserRule;
1210 }
1211
1212 bool operator!=(const StyleResolver::MatchRanges& a, const StyleResolver::MatchRanges& b)
1213 {
1214     return !(a == b);
1215 }
1216
1217 bool operator==(const StyleResolver::MatchedProperties& a, const StyleResolver::MatchedProperties& b)
1218 {
1219     return a.properties == b.properties && a.linkMatchType == b.linkMatchType;
1220 }
1221
1222 bool operator!=(const StyleResolver::MatchedProperties& a, const StyleResolver::MatchedProperties& b)
1223 {
1224     return !(a == b);
1225 }
1226
1227 const StyleResolver::MatchedPropertiesCacheItem* StyleResolver::findFromMatchedPropertiesCache(unsigned hash, const MatchResult& matchResult)
1228 {
1229     ASSERT(hash);
1230
1231     MatchedPropertiesCache::iterator it = m_matchedPropertiesCache.find(hash);
1232     if (it == m_matchedPropertiesCache.end())
1233         return nullptr;
1234     MatchedPropertiesCacheItem& cacheItem = it->value;
1235
1236     size_t size = matchResult.matchedProperties().size();
1237     if (size != cacheItem.matchedProperties.size())
1238         return nullptr;
1239     for (size_t i = 0; i < size; ++i) {
1240         if (matchResult.matchedProperties()[i] != cacheItem.matchedProperties[i])
1241             return nullptr;
1242     }
1243     if (cacheItem.ranges != matchResult.ranges)
1244         return nullptr;
1245     return &cacheItem;
1246 }
1247
1248 void StyleResolver::addToMatchedPropertiesCache(const RenderStyle* style, const RenderStyle* parentStyle, unsigned hash, const MatchResult& matchResult)
1249 {
1250     static const unsigned matchedDeclarationCacheAdditionsBetweenSweeps = 100;
1251     if (++m_matchedPropertiesCacheAdditionsSinceLastSweep >= matchedDeclarationCacheAdditionsBetweenSweeps
1252         && !m_matchedPropertiesCacheSweepTimer.isActive()) {
1253         static const unsigned matchedDeclarationCacheSweepTimeInSeconds = 60;
1254         m_matchedPropertiesCacheSweepTimer.startOneShot(matchedDeclarationCacheSweepTimeInSeconds);
1255     }
1256
1257     ASSERT(hash);
1258     MatchedPropertiesCacheItem cacheItem;
1259     cacheItem.matchedProperties.appendVector(matchResult.matchedProperties());
1260     cacheItem.ranges = matchResult.ranges;
1261     // Note that we don't cache the original RenderStyle instance. It may be further modified.
1262     // The RenderStyle in the cache is really just a holder for the substructures and never used as-is.
1263     cacheItem.renderStyle = RenderStyle::clonePtr(*style);
1264     cacheItem.parentRenderStyle = RenderStyle::clonePtr(*parentStyle);
1265     m_matchedPropertiesCache.add(hash, WTFMove(cacheItem));
1266 }
1267
1268 void StyleResolver::invalidateMatchedPropertiesCache()
1269 {
1270     m_matchedPropertiesCache.clear();
1271 }
1272
1273 void StyleResolver::clearCachedPropertiesAffectedByViewportUnits()
1274 {
1275     Vector<unsigned, 16> toRemove;
1276     for (auto& cacheKeyValue : m_matchedPropertiesCache) {
1277         if (cacheKeyValue.value.renderStyle->hasViewportUnits())
1278             toRemove.append(cacheKeyValue.key);
1279     }
1280     for (auto key : toRemove)
1281         m_matchedPropertiesCache.remove(key);
1282 }
1283
1284 static bool isCacheableInMatchedPropertiesCache(const Element& element, const RenderStyle* style, const RenderStyle* parentStyle)
1285 {
1286     // FIXME: Writing mode and direction properties modify state when applying to document element by calling
1287     // Document::setWritingMode/DirectionSetOnDocumentElement. We can't skip the applying by caching.
1288     if (&element == element.document().documentElement())
1289         return false;
1290     // content:attr() value depends on the element it is being applied to.
1291     if (style->hasAttrContent() || (style->styleType() != NOPSEUDO && parentStyle->hasAttrContent()))
1292         return false;
1293     if (style->hasAppearance())
1294         return false;
1295     if (style->zoom() != RenderStyle::initialZoom())
1296         return false;
1297     if (style->writingMode() != RenderStyle::initialWritingMode() || style->direction() != RenderStyle::initialDirection())
1298         return false;
1299     // The cache assumes static knowledge about which properties are inherited.
1300     if (style->hasExplicitlyInheritedProperties())
1301         return false;
1302     return true;
1303 }
1304
1305 void extractDirectionAndWritingMode(const RenderStyle& style, const StyleResolver::MatchResult& matchResult, TextDirection& direction, WritingMode& writingMode)
1306 {
1307     direction = style.direction();
1308     writingMode = style.writingMode();
1309
1310     bool hadImportantWebkitWritingMode = false;
1311     bool hadImportantDirection = false;
1312
1313     for (const auto& matchedProperties : matchResult.matchedProperties()) {
1314         for (unsigned i = 0, count = matchedProperties.properties->propertyCount(); i < count; ++i) {
1315             auto property = matchedProperties.properties->propertyAt(i);
1316             if (!property.value()->isPrimitiveValue())
1317                 continue;
1318             switch (property.id()) {
1319             case CSSPropertyWebkitWritingMode:
1320                 if (!hadImportantWebkitWritingMode || property.isImportant()) {
1321                     writingMode = downcast<CSSPrimitiveValue>(*property.value());
1322                     hadImportantWebkitWritingMode = property.isImportant();
1323                 }
1324                 break;
1325             case CSSPropertyDirection:
1326                 if (!hadImportantDirection || property.isImportant()) {
1327                     direction = downcast<CSSPrimitiveValue>(*property.value());
1328                     hadImportantDirection = property.isImportant();
1329                 }
1330                 break;
1331             default:
1332                 break;
1333             }
1334         }
1335     }
1336 }
1337
1338 void StyleResolver::applyMatchedProperties(const MatchResult& matchResult, const Element& element, ShouldUseMatchedPropertiesCache shouldUseMatchedPropertiesCache)
1339 {
1340     State& state = m_state;
1341     unsigned cacheHash = shouldUseMatchedPropertiesCache && matchResult.isCacheable ? computeMatchedPropertiesHash(matchResult.matchedProperties().data(), matchResult.matchedProperties().size()) : 0;
1342     bool applyInheritedOnly = false;
1343     const MatchedPropertiesCacheItem* cacheItem = nullptr;
1344     if (cacheHash && (cacheItem = findFromMatchedPropertiesCache(cacheHash, matchResult))
1345         && isCacheableInMatchedPropertiesCache(element, state.style(), state.parentStyle())) {
1346         // We can build up the style by copying non-inherited properties from an earlier style object built using the same exact
1347         // style declarations. We then only need to apply the inherited properties, if any, as their values can depend on the 
1348         // element context. This is fast and saves memory by reusing the style data structures.
1349         state.style()->copyNonInheritedFrom(cacheItem->renderStyle.get());
1350         if (state.parentStyle()->inheritedDataShared(cacheItem->parentRenderStyle.get()) && !isAtShadowBoundary(element)) {
1351             EInsideLink linkStatus = state.style()->insideLink();
1352             // If the cache item parent style has identical inherited properties to the current parent style then the
1353             // resulting style will be identical too. We copy the inherited properties over from the cache and are done.
1354             state.style()->inheritFrom(cacheItem->renderStyle.get());
1355
1356             // Unfortunately the link status is treated like an inherited property. We need to explicitly restore it.
1357             state.style()->setInsideLink(linkStatus);
1358             return;
1359         }
1360         applyInheritedOnly = true; 
1361     }
1362
1363     // Directional properties (*-before/after) are aliases that depend on the TextDirection and WritingMode.
1364     // These must be resolved before we can begin the property cascade.
1365     TextDirection direction;
1366     WritingMode writingMode;
1367     extractDirectionAndWritingMode(*state.style(), matchResult, direction, writingMode);
1368
1369     if (elementTypeHasAppearanceFromUAStyle(*state.element())) {
1370         // FIXME: This is such a hack.
1371         // Find out if there's a -webkit-appearance property in effect from the UA sheet.
1372         // If so, we cache the border and background styles so that RenderTheme::adjustStyle()
1373         // can look at them later to figure out if this is a styled form control or not.
1374         CascadedProperties cascade(direction, writingMode);
1375         cascade.addNormalMatches(matchResult, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly);
1376         cascade.addImportantMatches(matchResult, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly);
1377
1378         applyCascadedProperties(cascade, CSSPropertyWebkitRubyPosition, CSSPropertyWebkitRubyPosition, &matchResult);
1379         adjustStyleForInterCharacterRuby();
1380     
1381         // Resolve custom variables first.
1382         applyCascadedProperties(cascade, CSSPropertyCustom, CSSPropertyCustom, &matchResult);
1383
1384         // Start by applying properties that other properties may depend on.
1385         applyCascadedProperties(cascade, firstCSSProperty, lastHighPriorityProperty, &matchResult);
1386     
1387         updateFont();
1388         applyCascadedProperties(cascade, firstLowPriorityProperty, lastCSSProperty, &matchResult);
1389
1390         state.cacheBorderAndBackground();
1391     }
1392
1393     CascadedProperties cascade(direction, writingMode);
1394     cascade.addNormalMatches(matchResult, 0, matchResult.matchedProperties().size() - 1, applyInheritedOnly);
1395     cascade.addImportantMatches(matchResult, matchResult.ranges.firstAuthorRule, matchResult.ranges.lastAuthorRule, applyInheritedOnly);
1396     cascade.addImportantMatches(matchResult, matchResult.ranges.firstUserRule, matchResult.ranges.lastUserRule, applyInheritedOnly);
1397     cascade.addImportantMatches(matchResult, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly);
1398     
1399     // Resolve custom properties first.
1400     applyCascadedProperties(cascade, CSSPropertyCustom, CSSPropertyCustom, &matchResult);
1401
1402     applyCascadedProperties(cascade, CSSPropertyWebkitRubyPosition, CSSPropertyWebkitRubyPosition, &matchResult);
1403     
1404     // Adjust the font size to be smaller if ruby-position is inter-character.
1405     adjustStyleForInterCharacterRuby();
1406
1407     // Start by applying properties that other properties may depend on.
1408     applyCascadedProperties(cascade, firstCSSProperty, lastHighPriorityProperty, &matchResult);
1409
1410     // If the effective zoom value changes, we can't use the matched properties cache. Start over.
1411     if (cacheItem && cacheItem->renderStyle->effectiveZoom() != state.style()->effectiveZoom())
1412         return applyMatchedProperties(matchResult, element, DoNotUseMatchedPropertiesCache);
1413
1414     // If our font got dirtied, update it now.
1415     updateFont();
1416
1417     // If the font changed, we can't use the matched properties cache. Start over.
1418     if (cacheItem && cacheItem->renderStyle->fontDescription() != state.style()->fontDescription())
1419         return applyMatchedProperties(matchResult, element, DoNotUseMatchedPropertiesCache);
1420
1421     // Apply properties that no other properties depend on.
1422     applyCascadedProperties(cascade, firstLowPriorityProperty, lastCSSProperty, &matchResult);
1423
1424     // Finally, some properties must be applied in the order they were parsed.
1425     // There are some CSS properties that affect the same RenderStyle values,
1426     // so to preserve behavior, we queue them up during cascade and flush here.
1427     cascade.applyDeferredProperties(*this, &matchResult);
1428
1429     // Start loading resources referenced by this style.
1430     loadPendingResources();
1431     
1432     ASSERT(!state.fontDirty());
1433     
1434     if (cacheItem || !cacheHash)
1435         return;
1436     if (!isCacheableInMatchedPropertiesCache(*state.element(), state.style(), state.parentStyle()))
1437         return;
1438     addToMatchedPropertiesCache(state.style(), state.parentStyle(), cacheHash, matchResult);
1439 }
1440
1441 void StyleResolver::applyPropertyToStyle(CSSPropertyID id, CSSValue* value, std::unique_ptr<RenderStyle> style)
1442 {
1443     m_state = State();
1444     m_state.setParentStyle(RenderStyle::clonePtr(*style));
1445     m_state.setStyle(WTFMove(style));
1446     applyPropertyToCurrentStyle(id, value);
1447 }
1448
1449 void StyleResolver::applyPropertyToCurrentStyle(CSSPropertyID id, CSSValue* value)
1450 {
1451     if (value)
1452         applyProperty(id, value);
1453 }
1454
1455 inline bool isValidVisitedLinkProperty(CSSPropertyID id)
1456 {
1457     switch (id) {
1458     case CSSPropertyBackgroundColor:
1459     case CSSPropertyBorderLeftColor:
1460     case CSSPropertyBorderRightColor:
1461     case CSSPropertyBorderTopColor:
1462     case CSSPropertyBorderBottomColor:
1463     case CSSPropertyColor:
1464     case CSSPropertyOutlineColor:
1465     case CSSPropertyColumnRuleColor:
1466     case CSSPropertyWebkitTextDecorationColor:
1467     case CSSPropertyWebkitTextEmphasisColor:
1468     case CSSPropertyWebkitTextFillColor:
1469     case CSSPropertyWebkitTextStrokeColor:
1470     case CSSPropertyFill:
1471     case CSSPropertyStroke:
1472         return true;
1473     default:
1474         break;
1475     }
1476
1477     return false;
1478 }
1479
1480 // http://dev.w3.org/csswg/css3-regions/#the-at-region-style-rule
1481 // FIXME: add incremental support for other region styling properties.
1482 inline bool StyleResolver::isValidRegionStyleProperty(CSSPropertyID id)
1483 {
1484     switch (id) {
1485     case CSSPropertyBackgroundColor:
1486     case CSSPropertyColor:
1487         return true;
1488     default:
1489         break;
1490     }
1491
1492     return false;
1493 }
1494
1495 #if ENABLE(VIDEO_TRACK)
1496 inline bool StyleResolver::isValidCueStyleProperty(CSSPropertyID id)
1497 {
1498     switch (id) {
1499     case CSSPropertyBackground:
1500     case CSSPropertyBackgroundAttachment:
1501     case CSSPropertyBackgroundClip:
1502     case CSSPropertyBackgroundColor:
1503     case CSSPropertyBackgroundImage:
1504     case CSSPropertyBackgroundOrigin:
1505     case CSSPropertyBackgroundPosition:
1506     case CSSPropertyBackgroundPositionX:
1507     case CSSPropertyBackgroundPositionY:
1508     case CSSPropertyBackgroundRepeat:
1509     case CSSPropertyBackgroundRepeatX:
1510     case CSSPropertyBackgroundRepeatY:
1511     case CSSPropertyBackgroundSize:
1512     case CSSPropertyColor:
1513     case CSSPropertyFont:
1514     case CSSPropertyFontFamily:
1515     case CSSPropertyFontSize:
1516     case CSSPropertyFontStyle:
1517     case CSSPropertyFontVariantCaps:
1518     case CSSPropertyFontWeight:
1519     case CSSPropertyLineHeight:
1520     case CSSPropertyOpacity:
1521     case CSSPropertyOutline:
1522     case CSSPropertyOutlineColor:
1523     case CSSPropertyOutlineOffset:
1524     case CSSPropertyOutlineStyle:
1525     case CSSPropertyOutlineWidth:
1526     case CSSPropertyVisibility:
1527     case CSSPropertyWhiteSpace:
1528     case CSSPropertyTextDecoration:
1529     case CSSPropertyTextShadow:
1530     case CSSPropertyBorderStyle:
1531         return true;
1532     default:
1533         break;
1534     }
1535     return false;
1536 }
1537 #endif
1538 // SVG handles zooming in a different way compared to CSS. The whole document is scaled instead
1539 // of each individual length value in the render style / tree. CSSPrimitiveValue::computeLength*()
1540 // multiplies each resolved length with the zoom multiplier - so for SVG we need to disable that.
1541 // Though all CSS values that can be applied to outermost <svg> elements (width/height/border/padding...)
1542 // need to respect the scaling. RenderBox (the parent class of RenderSVGRoot) grabs values like
1543 // width/height/border/padding/... from the RenderStyle -> for SVG these values would never scale,
1544 // if we'd pass a 1.0 zoom factor everyhwere. So we only pass a zoom factor of 1.0 for specific
1545 // properties that are NOT allowed to scale within a zoomed SVG document (letter/word-spacing/font-size).
1546 bool StyleResolver::useSVGZoomRules()
1547 {
1548     return m_state.element() && m_state.element()->isSVGElement();
1549 }
1550
1551 // Scale with/height properties on inline SVG root.
1552 bool StyleResolver::useSVGZoomRulesForLength()
1553 {
1554     return is<SVGElement>(m_state.element()) && !(is<SVGSVGElement>(*m_state.element()) && m_state.element()->parentNode());
1555 }
1556
1557 StyleResolver::CascadedProperties* StyleResolver::cascadedPropertiesForRollback(const MatchResult& matchResult)
1558 {
1559     ASSERT(cascadeLevel() != UserAgentLevel);
1560     
1561     TextDirection direction;
1562     WritingMode writingMode;
1563     extractDirectionAndWritingMode(*state().style(), matchResult, direction, writingMode);
1564
1565     if (cascadeLevel() == AuthorLevel) {
1566         CascadedProperties* authorRollback = state().authorRollback();
1567         if (authorRollback)
1568             return authorRollback;
1569         
1570         auto newAuthorRollback(std::make_unique<CascadedProperties>(direction, writingMode));
1571         
1572         // This special rollback cascade contains UA rules and user rules but no author rules.
1573         newAuthorRollback->addNormalMatches(matchResult, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, false);
1574         newAuthorRollback->addNormalMatches(matchResult, matchResult.ranges.firstUserRule, matchResult.ranges.lastUserRule, false);
1575         newAuthorRollback->addImportantMatches(matchResult, matchResult.ranges.firstUserRule, matchResult.ranges.lastUserRule, false);
1576         newAuthorRollback->addImportantMatches(matchResult, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, false);
1577     
1578         state().setAuthorRollback(newAuthorRollback);
1579         return state().authorRollback();
1580     }
1581     
1582     if (cascadeLevel() == UserLevel) {
1583         CascadedProperties* userRollback = state().userRollback();
1584         if (userRollback)
1585             return userRollback;
1586         
1587         auto newUserRollback(std::make_unique<CascadedProperties>(direction, writingMode));
1588         
1589         // This special rollback cascade contains only UA rules.
1590         newUserRollback->addNormalMatches(matchResult, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, false);
1591         newUserRollback->addImportantMatches(matchResult, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, false);
1592     
1593         state().setUserRollback(newUserRollback);
1594         return state().userRollback();
1595     }
1596     
1597     return nullptr;
1598 }
1599
1600 void StyleResolver::applyProperty(CSSPropertyID id, CSSValue* value, SelectorChecker::LinkMatchMask linkMatchMask, const MatchResult* matchResult)
1601 {
1602     ASSERT_WITH_MESSAGE(!isShorthandCSSProperty(id), "Shorthand property id = %d wasn't expanded at parsing time", id);
1603
1604     State& state = m_state;
1605     
1606     RefPtr<CSSValue> valueToApply = value;
1607     if (value->isVariableDependentValue()) {
1608         valueToApply = resolvedVariableValue(id, *downcast<CSSVariableDependentValue>(value));
1609         if (!valueToApply) {
1610             if (CSSProperty::isInheritedProperty(id))
1611                 valueToApply = CSSValuePool::singleton().createInheritedValue();
1612             else
1613                 valueToApply = CSSValuePool::singleton().createExplicitInitialValue();
1614         }
1615     }
1616
1617     if (CSSProperty::isDirectionAwareProperty(id)) {
1618         CSSPropertyID newId = CSSProperty::resolveDirectionAwareProperty(id, state.style()->direction(), state.style()->writingMode());
1619         ASSERT(newId != id);
1620         return applyProperty(newId, valueToApply.get(), linkMatchMask, matchResult);
1621     }
1622     
1623     CSSValue* valueToCheckForInheritInitial = valueToApply.get();
1624     CSSCustomPropertyValue* customPropertyValue = nullptr;
1625     
1626     if (id == CSSPropertyCustom) {
1627         customPropertyValue = &downcast<CSSCustomPropertyValue>(*valueToApply);
1628         valueToCheckForInheritInitial = customPropertyValue->value().get();
1629     }
1630
1631     bool isInherit = state.parentStyle() && valueToCheckForInheritInitial->isInheritedValue();
1632     bool isInitial = valueToCheckForInheritInitial->isInitialValue() || (!state.parentStyle() && valueToCheckForInheritInitial->isInheritedValue());
1633     
1634     bool isUnset = valueToCheckForInheritInitial->isUnsetValue();
1635     bool isRevert = valueToCheckForInheritInitial->isRevertValue();
1636
1637     if (isRevert) {
1638         if (cascadeLevel() == UserAgentLevel || !matchResult)
1639             isUnset = true;
1640         else {
1641             // Fetch the correct rollback object from the state, building it if necessary.
1642             // This requires having the original MatchResult available.
1643             auto* rollback = cascadedPropertiesForRollback(*matchResult);
1644             ASSERT(rollback);
1645
1646             // With the cascade built, we need to obtain the property and apply it. If the property is
1647             // not present, then we behave like "unset." Otherwise we apply the property instead of
1648             // our own.
1649             if (customPropertyValue) {
1650                 if (rollback->hasCustomProperty(customPropertyValue->name())) {
1651                     auto property = rollback->customProperty(customPropertyValue->name());
1652                     if (property.cssValue[linkMatchMask])
1653                         applyProperty(property.id, property.cssValue[linkMatchMask], linkMatchMask, matchResult);
1654                     return;
1655                 }
1656             } else if (rollback->hasProperty(id)) {
1657                 auto& property = rollback->property(id);
1658                 if (property.cssValue[linkMatchMask])
1659                     applyProperty(property.id, property.cssValue[linkMatchMask], linkMatchMask, matchResult);
1660                 return;
1661             }
1662         
1663             isUnset = true;
1664         }
1665     }
1666     
1667     if (isUnset) {
1668         if (CSSProperty::isInheritedProperty(id))
1669             isInherit = true;
1670         else
1671             isInitial = true;
1672     }
1673
1674     ASSERT(!isInherit || !isInitial); // isInherit -> !isInitial && isInitial -> !isInherit
1675
1676     if (!state.applyPropertyToRegularStyle() && (!state.applyPropertyToVisitedLinkStyle() || !isValidVisitedLinkProperty(id))) {
1677         // Limit the properties that can be applied to only the ones honored by :visited.
1678         return;
1679     }
1680
1681     if (isInherit && !CSSProperty::isInheritedProperty(id))
1682         state.style()->setHasExplicitlyInheritedProperties();
1683     
1684     if (id == CSSPropertyCustom) {
1685         CSSCustomPropertyValue* customProperty = &downcast<CSSCustomPropertyValue>(*valueToApply);
1686         if (isInherit) {
1687             RefPtr<CSSValue> customVal = state.parentStyle()->getCustomPropertyValue(customProperty->name());
1688             if (!customVal)
1689                 customVal = CSSCustomPropertyValue::createInvalid();
1690             state.style()->setCustomPropertyValue(customProperty->name(), customVal);
1691         } else if (isInitial)
1692             state.style()->setCustomPropertyValue(customProperty->name(), CSSCustomPropertyValue::createInvalid());
1693         else
1694             state.style()->setCustomPropertyValue(customProperty->name(), customProperty->value());
1695         return;
1696     }
1697
1698     // Use the generated StyleBuilder.
1699     StyleBuilder::applyProperty(id, *this, *valueToApply, isInitial, isInherit);
1700 }
1701
1702 RefPtr<CSSValue> StyleResolver::resolvedVariableValue(CSSPropertyID propID, const CSSVariableDependentValue& value)
1703 {
1704     CSSParser parser(m_state.document());
1705     return parser.parseVariableDependentValue(propID, value, m_state.style()->customProperties(), m_state.style()->direction(), m_state.style()->writingMode());
1706 }
1707
1708 RefPtr<StyleImage> StyleResolver::styleImage(CSSPropertyID property, CSSValue& value)
1709 {
1710     if (is<CSSImageValue>(value))
1711         return cachedOrPendingFromValue(property, downcast<CSSImageValue>(value));
1712
1713     if (is<CSSImageGeneratorValue>(value)) {
1714         if (is<CSSGradientValue>(value))
1715             return generatedOrPendingFromValue(property, *downcast<CSSGradientValue>(value).gradientWithStylesResolved(this));
1716         return generatedOrPendingFromValue(property, downcast<CSSImageGeneratorValue>(value));
1717     }
1718
1719 #if ENABLE(CSS_IMAGE_SET)
1720     if (is<CSSImageSetValue>(value))
1721         return setOrPendingFromValue(property, downcast<CSSImageSetValue>(value));
1722 #endif
1723
1724     if (is<CSSCursorImageValue>(value))
1725         return cursorOrPendingFromValue(property, downcast<CSSCursorImageValue>(value));
1726
1727     return nullptr;
1728 }
1729
1730 Ref<StyleImage> StyleResolver::cachedOrPendingFromValue(CSSPropertyID property, CSSImageValue& value)
1731 {
1732     Ref<StyleImage> image = value.cachedOrPendingImage();
1733     if (image->isPendingImage())
1734         m_state.ensurePendingResources().pendingImages.set(property, &value);
1735     return image;
1736 }
1737
1738 Ref<StyleImage> StyleResolver::generatedOrPendingFromValue(CSSPropertyID property, CSSImageGeneratorValue& value)
1739 {
1740     if (is<CSSFilterImageValue>(value)) {
1741         // FilterImage needs to calculate FilterOperations.
1742         downcast<CSSFilterImageValue>(value).createFilterOperations(this);
1743     }
1744
1745     if (value.isPending()) {
1746         m_state.ensurePendingResources().pendingImages.set(property, &value);
1747         return StylePendingImage::create(&value);
1748     }
1749     return StyleGeneratedImage::create(value);
1750 }
1751
1752 #if ENABLE(CSS_IMAGE_SET)
1753 RefPtr<StyleImage> StyleResolver::setOrPendingFromValue(CSSPropertyID property, CSSImageSetValue& value)
1754 {
1755     RefPtr<StyleImage> image = value.cachedOrPendingImageSet(document());
1756     if (image && image->isPendingImage())
1757         m_state.ensurePendingResources().pendingImages.set(property, &value);
1758     return image;
1759 }
1760 #endif
1761
1762 RefPtr<StyleImage> StyleResolver::cursorOrPendingFromValue(CSSPropertyID property, CSSCursorImageValue& value)
1763 {
1764     RefPtr<StyleImage> image = value.cachedOrPendingImage(document());
1765     if (image && image->isPendingImage())
1766         m_state.ensurePendingResources().pendingImages.set(property, &value);
1767     return image;
1768 }
1769
1770 #if ENABLE(IOS_TEXT_AUTOSIZING)
1771 void StyleResolver::checkForTextSizeAdjust(RenderStyle* style)
1772 {
1773     if (style->textSizeAdjust().isAuto())
1774         return;
1775
1776     auto newFontDescription = style->fontDescription();
1777     if (!style->textSizeAdjust().isNone())
1778         newFontDescription.setComputedSize(newFontDescription.specifiedSize() * style->textSizeAdjust().multiplier());
1779     else
1780         newFontDescription.setComputedSize(newFontDescription.specifiedSize());
1781     style->setFontDescription(newFontDescription);
1782 }
1783 #endif
1784
1785 void StyleResolver::checkForZoomChange(RenderStyle* style, const RenderStyle* parentStyle)
1786 {
1787     if (!parentStyle)
1788         return;
1789     
1790     if (style->effectiveZoom() == parentStyle->effectiveZoom() && style->textZoom() == parentStyle->textZoom())
1791         return;
1792
1793     const auto& childFont = style->fontDescription();
1794     auto newFontDescription = childFont;
1795     setFontSize(newFontDescription, childFont.specifiedSize());
1796     style->setFontDescription(newFontDescription);
1797 }
1798
1799 void StyleResolver::checkForGenericFamilyChange(RenderStyle* style, const RenderStyle* parentStyle)
1800 {
1801     const auto& childFont = style->fontDescription();
1802
1803     if (childFont.isAbsoluteSize() || !parentStyle)
1804         return;
1805
1806     const auto& parentFont = parentStyle->fontDescription();
1807     if (childFont.useFixedDefaultSize() == parentFont.useFixedDefaultSize())
1808         return;
1809     // We know the parent is monospace or the child is monospace, and that font
1810     // size was unspecified. We want to scale our font size as appropriate.
1811     // If the font uses a keyword size, then we refetch from the table rather than
1812     // multiplying by our scale factor.
1813     float size;
1814     if (CSSValueID sizeIdentifier = childFont.keywordSizeAsIdentifier())
1815         size = Style::fontSizeForKeyword(sizeIdentifier, childFont.useFixedDefaultSize(), document());
1816     else {
1817         Settings* settings = documentSettings();
1818         float fixedScaleFactor = (settings && settings->defaultFixedFontSize() && settings->defaultFontSize())
1819             ? static_cast<float>(settings->defaultFixedFontSize()) / settings->defaultFontSize()
1820             : 1;
1821         size = parentFont.useFixedDefaultSize() ?
1822                 childFont.specifiedSize() / fixedScaleFactor :
1823                 childFont.specifiedSize() * fixedScaleFactor;
1824     }
1825
1826     auto newFontDescription = childFont;
1827     setFontSize(newFontDescription, size);
1828     style->setFontDescription(newFontDescription);
1829 }
1830
1831 void StyleResolver::initializeFontStyle(Settings* settings)
1832 {
1833     FontCascadeDescription fontDescription;
1834     if (settings)
1835         fontDescription.setRenderingMode(settings->fontRenderingMode());
1836     fontDescription.setOneFamily(standardFamily);
1837     fontDescription.setKeywordSizeFromIdentifier(CSSValueMedium);
1838     setFontSize(fontDescription, Style::fontSizeForKeyword(CSSValueMedium, false, document()));
1839     setFontDescription(fontDescription);
1840 }
1841
1842 void StyleResolver::setFontSize(FontCascadeDescription& fontDescription, float size)
1843 {
1844     fontDescription.setSpecifiedSize(size);
1845     fontDescription.setComputedSize(Style::computedFontSizeFromSpecifiedSize(size, fontDescription.isAbsoluteSize(), useSVGZoomRules(), m_state.style(), document()));
1846 }
1847
1848 static Color colorForCSSValue(CSSValueID cssValueId)
1849 {
1850     struct ColorValue {
1851         CSSValueID cssValueId;
1852         RGBA32 color;
1853     };
1854
1855     static const ColorValue colorValues[] = {
1856         { CSSValueAqua, 0xFF00FFFF },
1857         { CSSValueBlack, 0xFF000000 },
1858         { CSSValueBlue, 0xFF0000FF },
1859         { CSSValueFuchsia, 0xFFFF00FF },
1860         { CSSValueGray, 0xFF808080 },
1861         { CSSValueGreen, 0xFF008000  },
1862         { CSSValueGrey, 0xFF808080 },
1863         { CSSValueLime, 0xFF00FF00 },
1864         { CSSValueMaroon, 0xFF800000 },
1865         { CSSValueNavy, 0xFF000080 },
1866         { CSSValueOlive, 0xFF808000  },
1867         { CSSValueOrange, 0xFFFFA500 },
1868         { CSSValuePurple, 0xFF800080 },
1869         { CSSValueRed, 0xFFFF0000 },
1870         { CSSValueSilver, 0xFFC0C0C0 },
1871         { CSSValueTeal, 0xFF008080  },
1872         { CSSValueTransparent, 0x00000000 },
1873         { CSSValueWhite, 0xFFFFFFFF },
1874         { CSSValueYellow, 0xFFFFFF00 },
1875         { CSSValueInvalid, CSSValueInvalid }
1876     };
1877
1878     for (const ColorValue* col = colorValues; col->cssValueId; ++col) {
1879         if (col->cssValueId == cssValueId)
1880             return col->color;
1881     }
1882     return RenderTheme::defaultTheme()->systemColor(cssValueId);
1883 }
1884
1885 bool StyleResolver::colorFromPrimitiveValueIsDerivedFromElement(const CSSPrimitiveValue& value)
1886 {
1887     int ident = value.getValueID();
1888     switch (ident) {
1889     case CSSValueWebkitText:
1890     case CSSValueWebkitLink:
1891     case CSSValueWebkitActivelink:
1892     case CSSValueCurrentcolor:
1893         return true;
1894     default:
1895         return false;
1896     }
1897 }
1898
1899 Color StyleResolver::colorFromPrimitiveValue(const CSSPrimitiveValue& value, bool forVisitedLink) const
1900 {
1901     if (value.isRGBColor())
1902         return Color(value.getRGBA32Value());
1903
1904     const State& state = m_state;
1905     CSSValueID ident = value.getValueID();
1906     switch (ident) {
1907     case 0:
1908         return Color();
1909     case CSSValueWebkitText:
1910         return state.document().textColor();
1911     case CSSValueWebkitLink:
1912         return (state.element()->isLink() && forVisitedLink) ? state.document().visitedLinkColor() : state.document().linkColor();
1913     case CSSValueWebkitActivelink:
1914         return state.document().activeLinkColor();
1915     case CSSValueWebkitFocusRingColor:
1916         return RenderTheme::focusRingColor();
1917     case CSSValueCurrentcolor:
1918         return state.style()->color();
1919     default:
1920         return colorForCSSValue(ident);
1921     }
1922 }
1923
1924 void StyleResolver::addViewportDependentMediaQueryResult(const MediaQueryExpression& expression, bool result)
1925 {
1926     m_viewportDependentMediaQueryResults.append(MediaQueryResult { expression, result });
1927 }
1928
1929 bool StyleResolver::hasMediaQueriesAffectedByViewportChange() const
1930 {
1931     for (auto& result : m_viewportDependentMediaQueryResults) {
1932         if (m_mediaQueryEvaluator.evaluate(result.expression) != result.result)
1933             return true;
1934     }
1935     return false;
1936 }
1937
1938 static FilterOperation::OperationType filterOperationForType(WebKitCSSFilterValue::FilterOperationType type)
1939 {
1940     switch (type) {
1941     case WebKitCSSFilterValue::ReferenceFilterOperation:
1942         return FilterOperation::REFERENCE;
1943     case WebKitCSSFilterValue::GrayscaleFilterOperation:
1944         return FilterOperation::GRAYSCALE;
1945     case WebKitCSSFilterValue::SepiaFilterOperation:
1946         return FilterOperation::SEPIA;
1947     case WebKitCSSFilterValue::SaturateFilterOperation:
1948         return FilterOperation::SATURATE;
1949     case WebKitCSSFilterValue::HueRotateFilterOperation:
1950         return FilterOperation::HUE_ROTATE;
1951     case WebKitCSSFilterValue::InvertFilterOperation:
1952         return FilterOperation::INVERT;
1953     case WebKitCSSFilterValue::OpacityFilterOperation:
1954         return FilterOperation::OPACITY;
1955     case WebKitCSSFilterValue::BrightnessFilterOperation:
1956         return FilterOperation::BRIGHTNESS;
1957     case WebKitCSSFilterValue::ContrastFilterOperation:
1958         return FilterOperation::CONTRAST;
1959     case WebKitCSSFilterValue::BlurFilterOperation:
1960         return FilterOperation::BLUR;
1961     case WebKitCSSFilterValue::DropShadowFilterOperation:
1962         return FilterOperation::DROP_SHADOW;
1963     case WebKitCSSFilterValue::UnknownFilterOperation:
1964         return FilterOperation::NONE;
1965     }
1966     return FilterOperation::NONE;
1967 }
1968
1969 bool StyleResolver::createFilterOperations(const CSSValue& inValue, FilterOperations& outOperations)
1970 {
1971     State& state = m_state;
1972     ASSERT(outOperations.isEmpty());
1973     
1974     if (is<CSSPrimitiveValue>(inValue)) {
1975         auto& primitiveValue = downcast<CSSPrimitiveValue>(inValue);
1976         if (primitiveValue.getValueID() == CSSValueNone)
1977             return true;
1978     }
1979     
1980     if (!is<CSSValueList>(inValue))
1981         return false;
1982
1983     FilterOperations operations;
1984     for (auto& currentValue : downcast<CSSValueList>(inValue)) {
1985         if (!is<WebKitCSSFilterValue>(currentValue.get()))
1986             continue;
1987
1988         auto& filterValue = downcast<WebKitCSSFilterValue>(currentValue.get());
1989         FilterOperation::OperationType operationType = filterOperationForType(filterValue.operationType());
1990
1991         if (operationType == FilterOperation::REFERENCE) {
1992             if (filterValue.length() != 1)
1993                 continue;
1994             auto& argument = *filterValue.itemWithoutBoundsCheck(0);
1995
1996             if (!is<CSSPrimitiveValue>(argument))
1997                 continue;
1998
1999             auto& primitiveValue = downcast<CSSPrimitiveValue>(argument);
2000             String cssUrl = primitiveValue.getStringValue();
2001             URL url = m_state.document().completeURL(cssUrl);
2002
2003             RefPtr<ReferenceFilterOperation> operation = ReferenceFilterOperation::create(cssUrl, url.fragmentIdentifier());
2004             if (SVGURIReference::isExternalURIReference(cssUrl, m_state.document()))
2005                 state.ensurePendingResources().pendingSVGFilters.append(operation);
2006
2007             operations.operations().append(operation);
2008             continue;
2009         }
2010
2011         // Check that all parameters are primitive values, with the
2012         // exception of drop shadow which has a CSSShadowValue parameter.
2013         const CSSPrimitiveValue* firstValue = nullptr;
2014         if (operationType != FilterOperation::DROP_SHADOW) {
2015             bool haveNonPrimitiveValue = false;
2016             for (unsigned j = 0; j < filterValue.length(); ++j) {
2017                 if (!is<CSSPrimitiveValue>(*filterValue.itemWithoutBoundsCheck(j))) {
2018                     haveNonPrimitiveValue = true;
2019                     break;
2020                 }
2021             }
2022             if (haveNonPrimitiveValue)
2023                 continue;
2024             if (filterValue.length())
2025                 firstValue = downcast<CSSPrimitiveValue>(filterValue.itemWithoutBoundsCheck(0));
2026         }
2027
2028         switch (filterValue.operationType()) {
2029         case WebKitCSSFilterValue::GrayscaleFilterOperation:
2030         case WebKitCSSFilterValue::SepiaFilterOperation:
2031         case WebKitCSSFilterValue::SaturateFilterOperation: {
2032             double amount = 1;
2033             if (filterValue.length() == 1) {
2034                 amount = firstValue->getDoubleValue();
2035                 if (firstValue->isPercentage())
2036                     amount /= 100;
2037             }
2038
2039             operations.operations().append(BasicColorMatrixFilterOperation::create(amount, operationType));
2040             break;
2041         }
2042         case WebKitCSSFilterValue::HueRotateFilterOperation: {
2043             double angle = 0;
2044             if (filterValue.length() == 1)
2045                 angle = firstValue->computeDegrees();
2046
2047             operations.operations().append(BasicColorMatrixFilterOperation::create(angle, operationType));
2048             break;
2049         }
2050         case WebKitCSSFilterValue::InvertFilterOperation:
2051         case WebKitCSSFilterValue::BrightnessFilterOperation:
2052         case WebKitCSSFilterValue::ContrastFilterOperation:
2053         case WebKitCSSFilterValue::OpacityFilterOperation: {
2054             double amount = (filterValue.operationType() == WebKitCSSFilterValue::BrightnessFilterOperation) ? 0 : 1;
2055             if (filterValue.length() == 1) {
2056                 amount = firstValue->getDoubleValue();
2057                 if (firstValue->isPercentage())
2058                     amount /= 100;
2059             }
2060
2061             operations.operations().append(BasicComponentTransferFilterOperation::create(amount, operationType));
2062             break;
2063         }
2064         case WebKitCSSFilterValue::BlurFilterOperation: {
2065             Length stdDeviation = Length(0, Fixed);
2066             if (filterValue.length() >= 1)
2067                 stdDeviation = convertToFloatLength(firstValue, state.cssToLengthConversionData());
2068             if (stdDeviation.isUndefined())
2069                 return false;
2070
2071             operations.operations().append(BlurFilterOperation::create(stdDeviation));
2072             break;
2073         }
2074         case WebKitCSSFilterValue::DropShadowFilterOperation: {
2075             if (filterValue.length() != 1)
2076                 return false;
2077
2078             auto& cssValue = *filterValue.itemWithoutBoundsCheck(0);
2079             if (!is<CSSShadowValue>(cssValue))
2080                 continue;
2081
2082             auto& item = downcast<CSSShadowValue>(cssValue);
2083             int x = item.x->computeLength<int>(state.cssToLengthConversionData());
2084             int y = item.y->computeLength<int>(state.cssToLengthConversionData());
2085             IntPoint location(x, y);
2086             int blur = item.blur ? item.blur->computeLength<int>(state.cssToLengthConversionData()) : 0;
2087             Color color;
2088             if (item.color)
2089                 color = colorFromPrimitiveValue(*item.color);
2090
2091             operations.operations().append(DropShadowFilterOperation::create(location, blur, color.isValid() ? color : Color::transparent));
2092             break;
2093         }
2094         case WebKitCSSFilterValue::UnknownFilterOperation:
2095         default:
2096             ASSERT_NOT_REACHED();
2097             break;
2098         }
2099     }
2100
2101     outOperations = operations;
2102     return true;
2103 }
2104
2105 void StyleResolver::loadPendingResources()
2106 {
2107     ASSERT(style());
2108     if (!style())
2109         return;
2110
2111     RELEASE_ASSERT(!m_inLoadPendingImages);
2112     TemporaryChange<bool> changeInLoadPendingImages(m_inLoadPendingImages, true);
2113
2114     if (auto pendingResources = state().takePendingResources())
2115         Style::loadPendingResources(*pendingResources, document(), *style(), m_state.element());
2116 }
2117
2118 inline StyleResolver::MatchedProperties::MatchedProperties()
2119     : possiblyPaddedMember(nullptr)
2120 {
2121 }
2122
2123 StyleResolver::MatchedProperties::~MatchedProperties()
2124 {
2125 }
2126
2127 StyleResolver::CascadedProperties::CascadedProperties(TextDirection direction, WritingMode writingMode)
2128     : m_direction(direction)
2129     , m_writingMode(writingMode)
2130 {
2131 }
2132
2133 inline bool StyleResolver::CascadedProperties::hasProperty(CSSPropertyID id) const
2134 {
2135     ASSERT(id < m_propertyIsPresent.size());
2136     return m_propertyIsPresent[id];
2137 }
2138
2139 inline StyleResolver::CascadedProperties::Property& StyleResolver::CascadedProperties::property(CSSPropertyID id)
2140 {
2141     return m_properties[id];
2142 }
2143
2144 inline bool StyleResolver::CascadedProperties::hasCustomProperty(const String& name) const
2145 {
2146     return m_customProperties.contains(name);
2147 }
2148
2149 inline StyleResolver::CascadedProperties::Property StyleResolver::CascadedProperties::customProperty(const String& name) const
2150 {
2151     return m_customProperties.get(name);
2152 }
2153
2154 void StyleResolver::CascadedProperties::setPropertyInternal(Property& property, CSSPropertyID id, CSSValue& cssValue, unsigned linkMatchType, CascadeLevel cascadeLevel)
2155 {
2156     ASSERT(linkMatchType <= SelectorChecker::MatchAll);
2157     property.id = id;
2158     property.level = cascadeLevel;
2159     if (linkMatchType == SelectorChecker::MatchAll) {
2160         property.cssValue[0] = &cssValue;
2161         property.cssValue[SelectorChecker::MatchLink] = &cssValue;
2162         property.cssValue[SelectorChecker::MatchVisited] = &cssValue;
2163     } else
2164         property.cssValue[linkMatchType] = &cssValue;
2165 }
2166
2167 void StyleResolver::CascadedProperties::set(CSSPropertyID id, CSSValue& cssValue, unsigned linkMatchType, CascadeLevel cascadeLevel)
2168 {
2169     if (CSSProperty::isDirectionAwareProperty(id))
2170         id = CSSProperty::resolveDirectionAwareProperty(id, m_direction, m_writingMode);
2171
2172     ASSERT(!shouldApplyPropertyInParseOrder(id));
2173
2174     auto& property = m_properties[id];
2175     ASSERT(id < m_propertyIsPresent.size());
2176     if (id == CSSPropertyCustom) {
2177         m_propertyIsPresent.set(id);
2178         const auto& customValue = downcast<CSSCustomPropertyValue>(cssValue);
2179         bool hasValue = customProperties().contains(customValue.name());
2180         if (!hasValue) {
2181             Property property;
2182             property.id = id;
2183             memset(property.cssValue, 0, sizeof(property.cssValue));
2184             setPropertyInternal(property, id, cssValue, linkMatchType, cascadeLevel);
2185             customProperties().set(customValue.name(), property);
2186         } else {
2187             Property property = customProperties().get(customValue.name());
2188             setPropertyInternal(property, id, cssValue, linkMatchType, cascadeLevel);
2189             customProperties().set(customValue.name(), property);
2190         }
2191         return;
2192     }
2193     
2194     if (!m_propertyIsPresent[id])
2195         memset(property.cssValue, 0, sizeof(property.cssValue));
2196     m_propertyIsPresent.set(id);
2197     setPropertyInternal(property, id, cssValue, linkMatchType, cascadeLevel);
2198 }
2199
2200 void StyleResolver::CascadedProperties::setDeferred(CSSPropertyID id, CSSValue& cssValue, unsigned linkMatchType, CascadeLevel cascadeLevel)
2201 {
2202     ASSERT(!CSSProperty::isDirectionAwareProperty(id));
2203     ASSERT(shouldApplyPropertyInParseOrder(id));
2204
2205     Property property;
2206     memset(property.cssValue, 0, sizeof(property.cssValue));
2207     setPropertyInternal(property, id, cssValue, linkMatchType, cascadeLevel);
2208     m_deferredProperties.append(property);
2209 }
2210
2211 void StyleResolver::CascadedProperties::addStyleProperties(const StyleProperties& properties, bool isImportant, bool inheritedOnly, PropertyWhitelistType propertyWhitelistType, unsigned linkMatchType, CascadeLevel cascadeLevel)
2212 {
2213     for (unsigned i = 0, count = properties.propertyCount(); i < count; ++i) {
2214         auto current = properties.propertyAt(i);
2215         if (isImportant != current.isImportant())
2216             continue;
2217         if (inheritedOnly && !current.isInherited()) {
2218             // We apply the inherited properties only when using the property cache.
2219             // A match with a value that is explicitely inherited should never have been cached.
2220             ASSERT(!current.value()->isInheritedValue());
2221             continue;
2222         }
2223         CSSPropertyID propertyID = current.id();
2224
2225         if (propertyWhitelistType == PropertyWhitelistRegion && !StyleResolver::isValidRegionStyleProperty(propertyID))
2226             continue;
2227 #if ENABLE(VIDEO_TRACK)
2228         if (propertyWhitelistType == PropertyWhitelistCue && !StyleResolver::isValidCueStyleProperty(propertyID))
2229             continue;
2230 #endif
2231
2232         if (shouldApplyPropertyInParseOrder(propertyID))
2233             setDeferred(propertyID, *current.value(), linkMatchType, cascadeLevel);
2234         else
2235             set(propertyID, *current.value(), linkMatchType, cascadeLevel);
2236     }
2237 }
2238
2239 static CascadeLevel cascadeLevelForIndex(const StyleResolver::MatchResult& matchResult, int index)
2240 {
2241     if (index >= matchResult.ranges.firstUARule && index <= matchResult.ranges.lastUARule)
2242         return UserAgentLevel;
2243     if (index >= matchResult.ranges.firstUserRule && index <= matchResult.ranges.lastUserRule)
2244         return UserLevel;
2245     return AuthorLevel;
2246 }
2247
2248 void StyleResolver::CascadedProperties::addMatch(const MatchResult& matchResult, unsigned index, bool isImportant, bool inheritedOnly)
2249 {
2250     const MatchedProperties& matchedProperties = matchResult.matchedProperties()[index];
2251
2252     auto propertyWhitelistType = static_cast<PropertyWhitelistType>(matchedProperties.whitelistType);
2253     auto cascadeLevel = cascadeLevelForIndex(matchResult, index);
2254
2255     addStyleProperties(*matchedProperties.properties, isImportant, inheritedOnly, propertyWhitelistType, matchedProperties.linkMatchType, cascadeLevel);
2256 }
2257
2258 void StyleResolver::CascadedProperties::addNormalMatches(const MatchResult& matchResult, int startIndex, int endIndex, bool inheritedOnly)
2259 {
2260     if (startIndex == -1)
2261         return;
2262
2263     for (int i = startIndex; i <= endIndex; ++i)
2264         addMatch(matchResult, i, false, inheritedOnly);
2265 }
2266
2267 static bool hasImportantProperties(const StyleProperties& properties)
2268 {
2269     for (unsigned i = 0, count = properties.propertyCount(); i < count; ++i) {
2270         if (properties.propertyAt(i).isImportant())
2271             return true;
2272     }
2273     return false;
2274 }
2275
2276 void StyleResolver::CascadedProperties::addImportantMatches(const MatchResult& matchResult, int startIndex, int endIndex, bool inheritedOnly)
2277 {
2278     if (startIndex == -1)
2279         return;
2280
2281     struct IndexAndOrdinal {
2282         int index;
2283         unsigned ordinal;
2284     };
2285     Vector<IndexAndOrdinal> shadowTreeMatches;
2286
2287     for (int i = startIndex; i <= endIndex; ++i) {
2288         const MatchedProperties& matchedProperties = matchResult.matchedProperties()[i];
2289
2290         if (!hasImportantProperties(*matchedProperties.properties))
2291             continue;
2292
2293         if (matchedProperties.treeContextOrdinal) {
2294             shadowTreeMatches.append({ i, matchedProperties.treeContextOrdinal });
2295             continue;
2296         }
2297
2298         addMatch(matchResult, i, true, inheritedOnly);
2299     }
2300
2301     if (shadowTreeMatches.isEmpty())
2302         return;
2303
2304     // For !important properties a later shadow tree wins.
2305     // Match results are sorted in reverse tree context order so this is not needed for normal properties.
2306     std::stable_sort(shadowTreeMatches.begin(), shadowTreeMatches.end(), [] (const IndexAndOrdinal& a, const IndexAndOrdinal& b) {
2307         return a.ordinal < b.ordinal;
2308     });
2309
2310     for (auto& match : shadowTreeMatches)
2311         addMatch(matchResult, match.index, true, inheritedOnly);
2312 }
2313
2314 void StyleResolver::CascadedProperties::applyDeferredProperties(StyleResolver& resolver, const MatchResult* matchResult)
2315 {
2316     for (auto& property : m_deferredProperties)
2317         property.apply(resolver, matchResult);
2318 }
2319
2320 void StyleResolver::CascadedProperties::Property::apply(StyleResolver& resolver, const MatchResult* matchResult)
2321 {
2322     State& state = resolver.state();
2323     state.setCascadeLevel(level);
2324
2325     if (cssValue[SelectorChecker::MatchDefault]) {
2326         state.setApplyPropertyToRegularStyle(true);
2327         state.setApplyPropertyToVisitedLinkStyle(false);
2328         resolver.applyProperty(id, cssValue[SelectorChecker::MatchDefault], SelectorChecker::MatchDefault, matchResult);
2329     }
2330
2331     if (state.style()->insideLink() == NotInsideLink)
2332         return;
2333
2334     if (cssValue[SelectorChecker::MatchLink]) {
2335         state.setApplyPropertyToRegularStyle(true);
2336         state.setApplyPropertyToVisitedLinkStyle(false);
2337         resolver.applyProperty(id, cssValue[SelectorChecker::MatchLink], SelectorChecker::MatchLink, matchResult);
2338     }
2339
2340     if (cssValue[SelectorChecker::MatchVisited]) {
2341         state.setApplyPropertyToRegularStyle(false);
2342         state.setApplyPropertyToVisitedLinkStyle(true);
2343         resolver.applyProperty(id, cssValue[SelectorChecker::MatchVisited], SelectorChecker::MatchVisited, matchResult);
2344     }
2345
2346     state.setApplyPropertyToRegularStyle(true);
2347     state.setApplyPropertyToVisitedLinkStyle(false);
2348 }
2349
2350 void StyleResolver::applyCascadedProperties(CascadedProperties& cascade, int firstProperty, int lastProperty, const MatchResult* matchResult)
2351 {
2352     for (int id = firstProperty; id <= lastProperty; ++id) {
2353         CSSPropertyID propertyID = static_cast<CSSPropertyID>(id);
2354         if (!cascade.hasProperty(propertyID))
2355             continue;
2356         if (propertyID == CSSPropertyCustom) {
2357             HashMap<AtomicString, CascadedProperties::Property>::iterator end = cascade.customProperties().end();
2358             for (HashMap<AtomicString, CascadedProperties::Property>::iterator it = cascade.customProperties().begin(); it != end; ++it)
2359                 it->value.apply(*this, matchResult);
2360             continue;
2361         }
2362         auto& property = cascade.property(propertyID);
2363         ASSERT(!shouldApplyPropertyInParseOrder(propertyID));
2364         property.apply(*this, matchResult);
2365     }
2366     
2367     if (firstProperty == CSSPropertyCustom)
2368         m_state.style()->checkVariablesInCustomProperties();
2369 }
2370
2371 } // namespace WebCore