1/*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 *           (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com)
4 * Copyright (C) 2006, 2007 Nicholas Shanks (webkit@nickshanks.com)
5 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 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 Google Inc. All rights reserved.
12 *
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Library General Public
15 * License as published by the Free Software Foundation; either
16 * version 2 of the License, or (at your option) any later version.
17 *
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21 * Library General Public License for more details.
22 *
23 * You should have received a copy of the GNU Library General Public License
24 * along with this library; see the file COPYING.LIB.  If not, write to
25 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
26 * Boston, MA 02110-1301, USA.
27 */
28
29#include "config.h"
30#include "StyleResolver.h"
31
32#include "Attribute.h"
33#include "CSSBorderImage.h"
34#include "CSSCalculationValue.h"
35#include "CSSCursorImageValue.h"
36#include "CSSDefaultStyleSheets.h"
37#include "CSSFontFaceRule.h"
38#include "CSSFontSelector.h"
39#include "CSSLineBoxContainValue.h"
40#include "CSSPageRule.h"
41#include "CSSParser.h"
42#include "CSSPrimitiveValueMappings.h"
43#include "CSSPropertyNames.h"
44#include "CSSReflectValue.h"
45#include "CSSSelector.h"
46#include "CSSSelectorList.h"
47#include "CSSStyleRule.h"
48#include "CSSSupportsRule.h"
49#include "CSSTimingFunctionValue.h"
50#include "CSSValueList.h"
51#if ENABLE(CSS_VARIABLES)
52#include "CSSVariableValue.h"
53#endif
54#include "CachedImage.h"
55#include "CalculationValue.h"
56#include "ContentData.h"
57#include "ContextFeatures.h"
58#include "Counter.h"
59#include "CounterContent.h"
60#include "CursorList.h"
61#include "DeprecatedStyleBuilder.h"
62#include "DocumentStyleSheetCollection.h"
63#include "ElementRuleCollector.h"
64#include "ElementShadow.h"
65#include "FontFeatureValue.h"
66#include "FontValue.h"
67#include "Frame.h"
68#include "FrameSelection.h"
69#include "FrameView.h"
70#include "HTMLDocument.h"
71#include "HTMLIFrameElement.h"
72#include "HTMLInputElement.h"
73#include "HTMLNames.h"
74#include "HTMLOptionElement.h"
75#include "HTMLProgressElement.h"
76#include "HTMLStyleElement.h"
77#include "HTMLTextAreaElement.h"
78#include "InsertionPoint.h"
79#include "InspectorInstrumentation.h"
80#include "KeyframeList.h"
81#include "LinkHash.h"
82#include "LocaleToScriptMapping.h"
83#include "MathMLNames.h"
84#include "MediaList.h"
85#include "MediaQueryEvaluator.h"
86#include "NodeRenderStyle.h"
87#include "NodeRenderingContext.h"
88#include "Page.h"
89#include "PageRuleCollector.h"
90#include "Pair.h"
91#include "QuotesData.h"
92#include "Rect.h"
93#include "RenderRegion.h"
94#include "RenderScrollbar.h"
95#include "RenderScrollbarTheme.h"
96#include "RenderStyleConstants.h"
97#include "RenderTheme.h"
98#include "RenderView.h"
99#include "RuleSet.h"
100#include "SVGDocumentExtensions.h"
101#include "SVGFontFaceElement.h"
102#include "SecurityOrigin.h"
103#include "SelectorCheckerFastPath.h"
104#include "Settings.h"
105#include "ShadowData.h"
106#include "ShadowRoot.h"
107#include "ShadowValue.h"
108#include "StyleCachedImage.h"
109#include "StyleGeneratedImage.h"
110#include "StylePendingImage.h"
111#include "StylePropertySet.h"
112#include "StylePropertyShorthand.h"
113#include "StyleRule.h"
114#include "StyleRuleImport.h"
115#include "StyleSheetContents.h"
116#include "StyleSheetList.h"
117#include "Text.h"
118#include "TransformFunctions.h"
119#include "TransformOperations.h"
120#include "UserAgentStyleSheets.h"
121#include "ViewportStyleResolver.h"
122#include "VisitedLinkState.h"
123#include "WebKitCSSKeyframeRule.h"
124#include "WebKitCSSKeyframesRule.h"
125#include "WebKitCSSRegionRule.h"
126#include "WebKitCSSTransformValue.h"
127#include "WebKitFontFamilyNames.h"
128#include "XMLNames.h"
129#include <wtf/StdLibExtras.h>
130#include <wtf/Vector.h>
131
132#if ENABLE(CSS_FILTERS)
133#include "FilterOperation.h"
134#include "WebKitCSSFilterValue.h"
135#endif
136
137#if ENABLE(DASHBOARD_SUPPORT)
138#include "DashboardRegion.h"
139#endif
140
141#if ENABLE(SVG)
142#include "CachedSVGDocument.h"
143#include "CachedSVGDocumentReference.h"
144#include "SVGDocument.h"
145#include "SVGElement.h"
146#include "SVGNames.h"
147#include "SVGURIReference.h"
148#include "WebKitCSSSVGDocumentValue.h"
149#endif
150
151#if ENABLE(CSS_SHADERS)
152#include "CustomFilterArrayParameter.h"
153#include "CustomFilterColorParameter.h"
154#include "CustomFilterConstants.h"
155#include "CustomFilterNumberParameter.h"
156#include "CustomFilterOperation.h"
157#include "CustomFilterParameter.h"
158#include "CustomFilterProgramInfo.h"
159#include "CustomFilterTransformParameter.h"
160#include "StyleCachedShader.h"
161#include "StyleCustomFilterProgram.h"
162#include "StyleCustomFilterProgramCache.h"
163#include "StylePendingShader.h"
164#include "StyleShader.h"
165#include "WebKitCSSMixFunctionValue.h"
166#include "WebKitCSSShaderValue.h"
167#endif
168
169#if ENABLE(CSS_IMAGE_SET)
170#include "CSSImageSetValue.h"
171#include "StyleCachedImageSet.h"
172#endif
173
174#if ENABLE(VIDEO_TRACK)
175#include "WebVTTElement.h"
176#endif
177
178using namespace std;
179
180namespace WebCore {
181
182using namespace HTMLNames;
183
184#define HANDLE_INHERIT(prop, Prop) \
185if (isInherit) { \
186    m_state.style()->set##Prop(m_state.parentStyle()->prop()); \
187    return; \
188}
189
190#define HANDLE_INHERIT_AND_INITIAL(prop, Prop) \
191HANDLE_INHERIT(prop, Prop) \
192if (isInitial) { \
193    m_state.style()->set##Prop(RenderStyle::initial##Prop()); \
194    return; \
195}
196
197RenderStyle* StyleResolver::s_styleNotYetAvailable;
198
199inline void StyleResolver::State::cacheBorderAndBackground()
200{
201    m_hasUAAppearance = m_style->hasAppearance();
202    if (m_hasUAAppearance) {
203        m_borderData = m_style->border();
204        m_backgroundData = *m_style->backgroundLayers();
205        m_backgroundColor = m_style->backgroundColor();
206    }
207}
208
209inline void StyleResolver::State::clear()
210{
211    m_element = 0;
212    m_styledElement = 0;
213    m_parentStyle = 0;
214    m_parentNode = 0;
215    m_regionForStyling = 0;
216    m_pendingImageProperties.clear();
217#if ENABLE(CSS_SHADERS)
218    m_hasPendingShaders = false;
219#endif
220#if ENABLE(CSS_FILTERS) && ENABLE(SVG)
221    m_pendingSVGDocuments.clear();
222#endif
223}
224
225void StyleResolver::MatchResult::addMatchedProperties(const StylePropertySet* properties, StyleRule* rule, unsigned linkMatchType, PropertyWhitelistType propertyWhitelistType)
226{
227    matchedProperties.grow(matchedProperties.size() + 1);
228    StyleResolver::MatchedProperties& newProperties = matchedProperties.last();
229    newProperties.properties = const_cast<StylePropertySet*>(properties);
230    newProperties.linkMatchType = linkMatchType;
231    newProperties.whitelistType = propertyWhitelistType;
232    matchedRules.append(rule);
233}
234
235StyleResolver::StyleResolver(Document* document, bool matchAuthorAndUserStyles)
236    : m_matchedPropertiesCacheAdditionsSinceLastSweep(0)
237    , m_matchedPropertiesCacheSweepTimer(this, &StyleResolver::sweepMatchedPropertiesCache)
238    , m_document(document)
239    , m_matchAuthorAndUserStyles(matchAuthorAndUserStyles)
240    , m_fontSelector(CSSFontSelector::create(document))
241#if ENABLE(CSS_DEVICE_ADAPTATION)
242    , m_viewportStyleResolver(ViewportStyleResolver::create(document))
243#endif
244    , m_deprecatedStyleBuilder(DeprecatedStyleBuilder::sharedStyleBuilder())
245    , m_styleMap(this)
246{
247    Element* root = document->documentElement();
248
249    CSSDefaultStyleSheets::initDefaultStyle(root);
250
251    // construct document root element default style. this is needed
252    // to evaluate media queries that contain relative constraints, like "screen and (max-width: 10em)"
253    // This is here instead of constructor, because when constructor is run,
254    // document doesn't have documentElement
255    // NOTE: this assumes that element that gets passed to styleForElement -call
256    // is always from the document that owns the style selector
257    FrameView* view = document->view();
258    if (view)
259        m_medium = adoptPtr(new MediaQueryEvaluator(view->mediaType()));
260    else
261        m_medium = adoptPtr(new MediaQueryEvaluator("all"));
262
263    if (root)
264        m_rootDefaultStyle = styleForElement(root, 0, DisallowStyleSharing, MatchOnlyUserAgentRules);
265
266    if (m_rootDefaultStyle && view)
267        m_medium = adoptPtr(new MediaQueryEvaluator(view->mediaType(), view->frame(), m_rootDefaultStyle.get()));
268
269    m_ruleSets.resetAuthorStyle();
270
271    DocumentStyleSheetCollection* styleSheetCollection = document->styleSheetCollection();
272    m_ruleSets.initUserStyle(styleSheetCollection, *m_medium, *this);
273
274#if ENABLE(SVG_FONTS)
275    if (document->svgExtensions()) {
276        const HashSet<SVGFontFaceElement*>& svgFontFaceElements = document->svgExtensions()->svgFontFaceElements();
277        HashSet<SVGFontFaceElement*>::const_iterator end = svgFontFaceElements.end();
278        for (HashSet<SVGFontFaceElement*>::const_iterator it = svgFontFaceElements.begin(); it != end; ++it)
279            fontSelector()->addFontFaceRule((*it)->fontFaceRule());
280    }
281#endif
282
283    appendAuthorStyleSheets(0, styleSheetCollection->activeAuthorStyleSheets());
284}
285
286void StyleResolver::appendAuthorStyleSheets(unsigned firstNew, const Vector<RefPtr<CSSStyleSheet> >& styleSheets)
287{
288    m_ruleSets.appendAuthorStyleSheets(firstNew, styleSheets, m_medium.get(), m_inspectorCSSOMWrappers, document()->isViewSource(), this);
289    if (document()->renderer() && document()->renderer()->style())
290        document()->renderer()->style()->font().update(fontSelector());
291
292#if ENABLE(CSS_DEVICE_ADAPTATION)
293    viewportStyleResolver()->resolve();
294#endif
295}
296
297void StyleResolver::pushParentElement(Element* parent)
298{
299    const ContainerNode* parentsParent = parent->parentOrShadowHostElement();
300
301    // We are not always invoked consistently. For example, script execution can cause us to enter
302    // style recalc in the middle of tree building. We may also be invoked from somewhere within the tree.
303    // Reset the stack in this case, or if we see a new root element.
304    // Otherwise just push the new parent.
305    if (!parentsParent || m_selectorFilter.parentStackIsEmpty())
306        m_selectorFilter.setupParentStack(parent);
307    else
308        m_selectorFilter.pushParent(parent);
309
310    // Note: We mustn't skip ShadowRoot nodes for the scope stack.
311    if (m_scopeResolver)
312        m_scopeResolver->push(parent, parent->parentOrShadowHostNode());
313}
314
315void StyleResolver::popParentElement(Element* parent)
316{
317    // Note that we may get invoked for some random elements in some wacky cases during style resolve.
318    // Pause maintaining the stack in this case.
319    if (m_selectorFilter.parentStackIsConsistent(parent))
320        m_selectorFilter.popParent();
321    if (m_scopeResolver)
322        m_scopeResolver->pop(parent);
323}
324
325void StyleResolver::pushParentShadowRoot(const ShadowRoot* shadowRoot)
326{
327    ASSERT(shadowRoot->host());
328    if (m_scopeResolver)
329        m_scopeResolver->push(shadowRoot, shadowRoot->host());
330}
331
332void StyleResolver::popParentShadowRoot(const ShadowRoot* shadowRoot)
333{
334    ASSERT(shadowRoot->host());
335    if (m_scopeResolver)
336        m_scopeResolver->pop(shadowRoot);
337}
338
339// This is a simplified style setting function for keyframe styles
340void StyleResolver::addKeyframeStyle(PassRefPtr<StyleRuleKeyframes> rule)
341{
342    AtomicString s(rule->name());
343    m_keyframesRuleMap.set(s.impl(), rule);
344}
345
346StyleResolver::~StyleResolver()
347{
348    m_fontSelector->clearDocument();
349
350#if ENABLE(CSS_DEVICE_ADAPTATION)
351    m_viewportStyleResolver->clearDocument();
352#endif
353}
354
355void StyleResolver::sweepMatchedPropertiesCache(Timer<StyleResolver>*)
356{
357    // Look for cache entries containing a style declaration with a single ref and remove them.
358    // This may happen when an element attribute mutation causes it to generate a new inlineStyle()
359    // or presentationAttributeStyle(), potentially leaving this cache with the last ref on the old one.
360    Vector<unsigned, 16> toRemove;
361    MatchedPropertiesCache::iterator it = m_matchedPropertiesCache.begin();
362    MatchedPropertiesCache::iterator end = m_matchedPropertiesCache.end();
363    for (; it != end; ++it) {
364        Vector<MatchedProperties>& matchedProperties = it->value.matchedProperties;
365        for (size_t i = 0; i < matchedProperties.size(); ++i) {
366            if (matchedProperties[i].properties->hasOneRef()) {
367                toRemove.append(it->key);
368                break;
369            }
370        }
371    }
372    for (size_t i = 0; i < toRemove.size(); ++i)
373        m_matchedPropertiesCache.remove(toRemove[i]);
374
375    m_matchedPropertiesCacheAdditionsSinceLastSweep = 0;
376}
377
378inline bool StyleResolver::styleSharingCandidateMatchesHostRules()
379{
380#if ENABLE(SHADOW_DOM)
381    return m_scopeResolver && m_scopeResolver->styleSharingCandidateMatchesHostRules(m_state.element());
382#else
383    return false;
384#endif
385}
386
387bool StyleResolver::classNamesAffectedByRules(const SpaceSplitString& classNames) const
388{
389    for (unsigned i = 0; i < classNames.size(); ++i) {
390        if (m_ruleSets.features().classesInRules.contains(classNames[i].impl()))
391            return true;
392    }
393    return false;
394}
395
396inline void StyleResolver::State::initElement(Element* e)
397{
398    m_element = e;
399    m_styledElement = e && e->isStyledElement() ? static_cast<StyledElement*>(e) : 0;
400    m_elementLinkState = e ? e->document()->visitedLinkState()->determineLinkState(e) : NotInsideLink;
401}
402
403inline void StyleResolver::initElement(Element* e)
404{
405    if (m_state.element() != e) {
406        m_state.initElement(e);
407        if (e && e == e->document()->documentElement()) {
408            e->document()->setDirectionSetOnDocumentElement(false);
409            e->document()->setWritingModeSetOnDocumentElement(false);
410        }
411    }
412}
413
414inline void StyleResolver::State::initForStyleResolve(Document* document, Element* e, RenderStyle* parentStyle, RenderRegion* regionForStyling)
415{
416    m_regionForStyling = regionForStyling;
417
418    if (e) {
419        NodeRenderingContext context(e);
420        m_parentNode = context.parentNodeForRenderingAndStyle();
421        m_parentStyle = context.resetStyleInheritance() ? 0 :
422            parentStyle ? parentStyle :
423            m_parentNode ? m_parentNode->renderStyle() : 0;
424        m_distributedToInsertionPoint = context.insertionPoint();
425    } else {
426        m_parentNode = 0;
427        m_parentStyle = parentStyle;
428        m_distributedToInsertionPoint = false;
429    }
430
431    Node* docElement = e ? e->document()->documentElement() : 0;
432    RenderStyle* docStyle = document->renderStyle();
433    m_rootElementStyle = docElement && e != docElement ? docElement->renderStyle() : docStyle;
434
435    m_style = 0;
436    m_pendingImageProperties.clear();
437    m_fontDirty = false;
438}
439
440static const unsigned cStyleSearchThreshold = 10;
441static const unsigned cStyleSearchLevelThreshold = 10;
442
443static inline bool parentElementPreventsSharing(const Element* parentElement)
444{
445    if (!parentElement)
446        return false;
447    return parentElement->hasFlagsSetDuringStylingOfChildren();
448}
449
450Node* StyleResolver::locateCousinList(Element* parent, unsigned& visitedNodeCount) const
451{
452    if (visitedNodeCount >= cStyleSearchThreshold * cStyleSearchLevelThreshold)
453        return 0;
454    if (!parent || !parent->isStyledElement())
455        return 0;
456    if (parent->hasScopedHTMLStyleChild())
457        return 0;
458    StyledElement* p = static_cast<StyledElement*>(parent);
459    if (p->inlineStyle())
460        return 0;
461#if ENABLE(SVG)
462    if (p->isSVGElement() && toSVGElement(p)->animatedSMILStyleProperties())
463        return 0;
464#endif
465    if (p->hasID() && m_ruleSets.features().idsInRules.contains(p->idForStyleResolution().impl()))
466        return 0;
467
468    RenderStyle* parentStyle = p->renderStyle();
469    unsigned subcount = 0;
470    Node* thisCousin = p;
471    Node* currentNode = p->previousSibling();
472
473    // Reserve the tries for this level. This effectively makes sure that the algorithm
474    // will never go deeper than cStyleSearchLevelThreshold levels into recursion.
475    visitedNodeCount += cStyleSearchThreshold;
476    while (thisCousin) {
477        while (currentNode) {
478            ++subcount;
479            if (currentNode->renderStyle() == parentStyle && currentNode->lastChild()
480                && currentNode->isElementNode() && !parentElementPreventsSharing(toElement(currentNode))
481#if ENABLE(SHADOW_DOM)
482                && !toElement(currentNode)->shadow()
483#endif
484                ) {
485                // Adjust for unused reserved tries.
486                visitedNodeCount -= cStyleSearchThreshold - subcount;
487                return currentNode->lastChild();
488            }
489            if (subcount >= cStyleSearchThreshold)
490                return 0;
491            currentNode = currentNode->previousSibling();
492        }
493        currentNode = locateCousinList(thisCousin->parentElement(), visitedNodeCount);
494        thisCousin = currentNode;
495    }
496
497    return 0;
498}
499
500bool StyleResolver::styleSharingCandidateMatchesRuleSet(RuleSet* ruleSet)
501{
502    if (!ruleSet)
503        return false;
504
505    ElementRuleCollector collector(this, m_state);
506    return collector.hasAnyMatchingRules(ruleSet);
507}
508
509bool StyleResolver::canShareStyleWithControl(StyledElement* element) const
510{
511    const State& state = m_state;
512    HTMLInputElement* thisInputElement = element->toInputElement();
513    HTMLInputElement* otherInputElement = state.element()->toInputElement();
514
515    if (!thisInputElement || !otherInputElement)
516        return false;
517
518    if (thisInputElement->elementData() != otherInputElement->elementData()) {
519        if (thisInputElement->fastGetAttribute(typeAttr) != otherInputElement->fastGetAttribute(typeAttr))
520            return false;
521        if (thisInputElement->fastGetAttribute(readonlyAttr) != otherInputElement->fastGetAttribute(readonlyAttr))
522            return false;
523    }
524
525    if (thisInputElement->isAutofilled() != otherInputElement->isAutofilled())
526        return false;
527    if (thisInputElement->shouldAppearChecked() != otherInputElement->shouldAppearChecked())
528        return false;
529    if (thisInputElement->shouldAppearIndeterminate() != otherInputElement->shouldAppearIndeterminate())
530        return false;
531    if (thisInputElement->isRequired() != otherInputElement->isRequired())
532        return false;
533
534    if (element->isDisabledFormControl() != state.element()->isDisabledFormControl())
535        return false;
536
537    if (element->isDefaultButtonForForm() != state.element()->isDefaultButtonForForm())
538        return false;
539
540    if (state.document()->containsValidityStyleRules()) {
541        bool willValidate = element->willValidate();
542
543        if (willValidate != state.element()->willValidate())
544            return false;
545
546        if (willValidate && (element->isValidFormControlElement() != state.element()->isValidFormControlElement()))
547            return false;
548
549        if (element->isInRange() != state.element()->isInRange())
550            return false;
551
552        if (element->isOutOfRange() != state.element()->isOutOfRange())
553            return false;
554    }
555
556    return true;
557}
558
559static inline bool elementHasDirectionAuto(Element* element)
560{
561    // FIXME: This line is surprisingly hot, we may wish to inline hasDirectionAuto into StyleResolver.
562    return element->isHTMLElement() && toHTMLElement(element)->hasDirectionAuto();
563}
564
565bool StyleResolver::sharingCandidateHasIdenticalStyleAffectingAttributes(StyledElement* sharingCandidate) const
566{
567    const State& state = m_state;
568    if (state.element()->elementData() == sharingCandidate->elementData())
569        return true;
570    if (state.element()->fastGetAttribute(XMLNames::langAttr) != sharingCandidate->fastGetAttribute(XMLNames::langAttr))
571        return false;
572    if (state.element()->fastGetAttribute(langAttr) != sharingCandidate->fastGetAttribute(langAttr))
573        return false;
574
575    if (!state.elementAffectedByClassRules()) {
576        if (sharingCandidate->hasClass() && classNamesAffectedByRules(sharingCandidate->classNames()))
577            return false;
578    } else if (sharingCandidate->hasClass()) {
579#if ENABLE(SVG)
580        // SVG elements require a (slow!) getAttribute comparision because "class" is an animatable attribute for SVG.
581        if (state.element()->isSVGElement()) {
582            if (state.element()->getAttribute(classAttr) != sharingCandidate->getAttribute(classAttr))
583                return false;
584        } else {
585#endif
586            if (state.element()->classNames() != sharingCandidate->classNames())
587                return false;
588#if ENABLE(SVG)
589        }
590#endif
591    } else
592        return false;
593
594    if (state.styledElement()->presentationAttributeStyle() != sharingCandidate->presentationAttributeStyle())
595        return false;
596
597#if ENABLE(PROGRESS_ELEMENT)
598    if (state.element()->hasTagName(progressTag)) {
599        if (state.element()->shouldAppearIndeterminate() != sharingCandidate->shouldAppearIndeterminate())
600            return false;
601    }
602#endif
603
604    return true;
605}
606
607bool StyleResolver::canShareStyleWithElement(StyledElement* element) const
608{
609    RenderStyle* style = element->renderStyle();
610    const State& state = m_state;
611
612    if (!style)
613        return false;
614    if (style->unique())
615        return false;
616    if (style->hasUniquePseudoStyle())
617        return false;
618    if (element->tagQName() != state.element()->tagQName())
619        return false;
620    if (element->inlineStyle())
621        return false;
622    if (element->needsStyleRecalc())
623        return false;
624#if ENABLE(SVG)
625    if (element->isSVGElement() && toSVGElement(element)->animatedSMILStyleProperties())
626        return false;
627#endif
628    if (element->isLink() != state.element()->isLink())
629        return false;
630    if (element->hovered() != state.element()->hovered())
631        return false;
632    if (element->active() != state.element()->active())
633        return false;
634    if (element->focused() != state.element()->focused())
635        return false;
636    if (element->shadowPseudoId() != state.element()->shadowPseudoId())
637        return false;
638    if (element == element->document()->cssTarget())
639        return false;
640    if (!sharingCandidateHasIdenticalStyleAffectingAttributes(element))
641        return false;
642    if (element->additionalPresentationAttributeStyle() != state.styledElement()->additionalPresentationAttributeStyle())
643        return false;
644
645    if (element->hasID() && m_ruleSets.features().idsInRules.contains(element->idForStyleResolution().impl()))
646        return false;
647    if (element->hasScopedHTMLStyleChild())
648        return false;
649
650    // FIXME: We should share style for option and optgroup whenever possible.
651    // Before doing so, we need to resolve issues in HTMLSelectElement::recalcListItems
652    // and RenderMenuList::setText. See also https://bugs.webkit.org/show_bug.cgi?id=88405
653    if (element->hasTagName(optionTag) || element->hasTagName(optgroupTag))
654        return false;
655
656    bool isControl = element->isFormControlElement();
657
658    if (isControl != state.element()->isFormControlElement())
659        return false;
660
661    if (isControl && !canShareStyleWithControl(element))
662        return false;
663
664    if (style->transitions() || style->animations())
665        return false;
666
667#if USE(ACCELERATED_COMPOSITING)
668    // Turn off style sharing for elements that can gain layers for reasons outside of the style system.
669    // See comments in RenderObject::setStyle().
670    if (element->hasTagName(iframeTag) || element->hasTagName(frameTag) || element->hasTagName(embedTag) || element->hasTagName(objectTag) || element->hasTagName(appletTag) || element->hasTagName(canvasTag)
671#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
672        // With proxying, the media elements are backed by a RenderEmbeddedObject.
673        || element->hasTagName(videoTag) || element->hasTagName(audioTag)
674#endif
675        )
676        return false;
677#endif
678
679    if (elementHasDirectionAuto(element))
680        return false;
681
682    if (element->isLink() && state.elementLinkState() != style->insideLink())
683        return false;
684
685#if ENABLE(VIDEO_TRACK)
686    // Deny sharing styles between WebVTT and non-WebVTT nodes.
687    if (element->isWebVTTElement() != state.element()->isWebVTTElement())
688        return false;
689
690    if (element->isWebVTTElement() && state.element()->isWebVTTElement() && toWebVTTElement(element)->isPastNode() != toWebVTTElement(state.element())->isPastNode())
691        return false;
692#endif
693
694#if ENABLE(FULLSCREEN_API)
695    if (element == element->document()->webkitCurrentFullScreenElement() || state.element() == state.document()->webkitCurrentFullScreenElement())
696        return false;
697#endif
698    return true;
699}
700
701inline StyledElement* StyleResolver::findSiblingForStyleSharing(Node* node, unsigned& count) const
702{
703    for (; node; node = node->previousSibling()) {
704        if (!node->isStyledElement())
705            continue;
706        if (canShareStyleWithElement(static_cast<StyledElement*>(node)))
707            break;
708        if (count++ == cStyleSearchThreshold)
709            return 0;
710    }
711    return static_cast<StyledElement*>(node);
712}
713
714RenderStyle* StyleResolver::locateSharedStyle()
715{
716    State& state = m_state;
717    if (!state.styledElement() || !state.parentStyle())
718        return 0;
719
720    // If the element has inline style it is probably unique.
721    if (state.styledElement()->inlineStyle())
722        return 0;
723#if ENABLE(SVG)
724    if (state.styledElement()->isSVGElement() && toSVGElement(state.styledElement())->animatedSMILStyleProperties())
725        return 0;
726#endif
727    // Ids stop style sharing if they show up in the stylesheets.
728    if (state.styledElement()->hasID() && m_ruleSets.features().idsInRules.contains(state.styledElement()->idForStyleResolution().impl()))
729        return 0;
730    if (parentElementPreventsSharing(state.element()->parentElement()))
731        return 0;
732    if (state.styledElement()->hasScopedHTMLStyleChild())
733        return 0;
734    if (state.element() == state.document()->cssTarget())
735        return 0;
736    if (elementHasDirectionAuto(state.element()))
737        return 0;
738
739    // Cache whether state.element is affected by any known class selectors.
740    // FIXME: This shouldn't be a member variable. The style sharing code could be factored out of StyleResolver.
741    state.setElementAffectedByClassRules(state.element() && state.element()->hasClass() && classNamesAffectedByRules(state.element()->classNames()));
742
743    // Check previous siblings and their cousins.
744    unsigned count = 0;
745    unsigned visitedNodeCount = 0;
746    StyledElement* shareElement = 0;
747    Node* cousinList = state.styledElement()->previousSibling();
748    while (cousinList) {
749        shareElement = findSiblingForStyleSharing(cousinList, count);
750        if (shareElement)
751            break;
752        cousinList = locateCousinList(cousinList->parentElement(), visitedNodeCount);
753    }
754
755    // If we have exhausted all our budget or our cousins.
756    if (!shareElement)
757        return 0;
758
759    // Can't share if sibling rules apply. This is checked at the end as it should rarely fail.
760    if (styleSharingCandidateMatchesRuleSet(m_ruleSets.sibling()))
761        return 0;
762    // Can't share if attribute rules apply.
763    if (styleSharingCandidateMatchesRuleSet(m_ruleSets.uncommonAttribute()))
764        return 0;
765    // Can't share if @host @-rules apply.
766    if (styleSharingCandidateMatchesHostRules())
767        return 0;
768    // Tracking child index requires unique style for each node. This may get set by the sibling rule match above.
769    if (parentElementPreventsSharing(state.element()->parentElement()))
770        return 0;
771    return shareElement->renderStyle();
772}
773
774static void getFontAndGlyphOrientation(const RenderStyle* style, FontOrientation& fontOrientation, NonCJKGlyphOrientation& glyphOrientation)
775{
776    if (style->isHorizontalWritingMode()) {
777        fontOrientation = Horizontal;
778        glyphOrientation = NonCJKGlyphOrientationVerticalRight;
779        return;
780    }
781
782    switch (style->textOrientation()) {
783    case TextOrientationVerticalRight:
784        fontOrientation = Vertical;
785        glyphOrientation = NonCJKGlyphOrientationVerticalRight;
786        return;
787    case TextOrientationUpright:
788        fontOrientation = Vertical;
789        glyphOrientation = NonCJKGlyphOrientationUpright;
790        return;
791    case TextOrientationSideways:
792        if (style->writingMode() == LeftToRightWritingMode) {
793            // FIXME: This should map to sideways-left, which is not supported yet.
794            fontOrientation = Vertical;
795            glyphOrientation = NonCJKGlyphOrientationVerticalRight;
796            return;
797        }
798        fontOrientation = Horizontal;
799        glyphOrientation = NonCJKGlyphOrientationVerticalRight;
800        return;
801    case TextOrientationSidewaysRight:
802        fontOrientation = Horizontal;
803        glyphOrientation = NonCJKGlyphOrientationVerticalRight;
804        return;
805    default:
806        ASSERT_NOT_REACHED();
807        fontOrientation = Horizontal;
808        glyphOrientation = NonCJKGlyphOrientationVerticalRight;
809        return;
810    }
811}
812
813PassRefPtr<RenderStyle> StyleResolver::styleForDocument(Document* document, CSSFontSelector* fontSelector)
814{
815    Frame* frame = document->frame();
816
817    // HTML5 states that seamless iframes should replace default CSS values
818    // with values inherited from the containing iframe element. However,
819    // some values (such as the case of designMode = "on") still need to
820    // be set by this "document style".
821    RefPtr<RenderStyle> documentStyle = RenderStyle::create();
822    bool seamlessWithParent = document->shouldDisplaySeamlesslyWithParent();
823    if (seamlessWithParent) {
824        RenderStyle* iframeStyle = document->seamlessParentIFrame()->renderStyle();
825        if (iframeStyle)
826            documentStyle->inheritFrom(iframeStyle);
827    }
828
829    // FIXME: It's not clear which values below we want to override in the seamless case!
830    documentStyle->setDisplay(BLOCK);
831    if (!seamlessWithParent) {
832        documentStyle->setRTLOrdering(document->visuallyOrdered() ? VisualOrder : LogicalOrder);
833        documentStyle->setZoom(frame && !document->printing() ? frame->pageZoomFactor() : 1);
834        documentStyle->setPageScaleTransform(frame ? frame->frameScaleFactor() : 1);
835        documentStyle->setLocale(document->contentLanguage());
836    }
837    // This overrides any -webkit-user-modify inherited from the parent iframe.
838    documentStyle->setUserModify(document->inDesignMode() ? READ_WRITE : READ_ONLY);
839
840    Element* docElement = document->documentElement();
841    RenderObject* docElementRenderer = docElement ? docElement->renderer() : 0;
842    if (docElementRenderer) {
843        // Use the direction and writing-mode of the body to set the
844        // viewport's direction and writing-mode unless the property is set on the document element.
845        // If there is no body, then use the document element.
846        RenderObject* bodyRenderer = document->body() ? document->body()->renderer() : 0;
847        if (bodyRenderer && !document->writingModeSetOnDocumentElement())
848            documentStyle->setWritingMode(bodyRenderer->style()->writingMode());
849        else
850            documentStyle->setWritingMode(docElementRenderer->style()->writingMode());
851        if (bodyRenderer && !document->directionSetOnDocumentElement())
852            documentStyle->setDirection(bodyRenderer->style()->direction());
853        else
854            documentStyle->setDirection(docElementRenderer->style()->direction());
855    }
856
857    if (frame) {
858        if (FrameView* frameView = frame->view()) {
859            const Pagination& pagination = frameView->pagination();
860            if (pagination.mode != Pagination::Unpaginated) {
861                documentStyle->setColumnStylesFromPaginationMode(pagination.mode);
862                documentStyle->setColumnGap(pagination.gap);
863                if (RenderView* view = document->renderView()) {
864                    if (view->hasColumns())
865                        view->updateColumnInfoFromStyle(documentStyle.get());
866                }
867            }
868        }
869    }
870
871    // Seamless iframes want to inherit their font from their parent iframe, so early return before setting the font.
872    if (seamlessWithParent)
873        return documentStyle.release();
874
875    FontDescription fontDescription;
876    fontDescription.setScript(localeToScriptCodeForFontSelection(documentStyle->locale()));
877    if (Settings* settings = document->settings()) {
878        fontDescription.setUsePrinterFont(document->printing() || !settings->screenFontSubstitutionEnabled());
879        fontDescription.setRenderingMode(settings->fontRenderingMode());
880        const AtomicString& standardFont = settings->standardFontFamily(fontDescription.script());
881        if (!standardFont.isEmpty()) {
882            fontDescription.setGenericFamily(FontDescription::StandardFamily);
883            fontDescription.setOneFamily(standardFont);
884        }
885        fontDescription.setKeywordSize(CSSValueMedium - CSSValueXxSmall + 1);
886        int size = StyleResolver::fontSizeForKeyword(document, CSSValueMedium, false);
887        fontDescription.setSpecifiedSize(size);
888        bool useSVGZoomRules = document->isSVGDocument();
889        fontDescription.setComputedSize(StyleResolver::getComputedSizeFromSpecifiedSize(document, documentStyle.get(), fontDescription.isAbsoluteSize(), size, useSVGZoomRules));
890    } else
891        fontDescription.setUsePrinterFont(document->printing());
892
893    FontOrientation fontOrientation;
894    NonCJKGlyphOrientation glyphOrientation;
895    getFontAndGlyphOrientation(documentStyle.get(), fontOrientation, glyphOrientation);
896    fontDescription.setOrientation(fontOrientation);
897    fontDescription.setNonCJKGlyphOrientation(glyphOrientation);
898
899    documentStyle->setFontDescription(fontDescription);
900    documentStyle->font().update(fontSelector);
901
902    return documentStyle.release();
903}
904
905static inline bool isAtShadowBoundary(const Element* element)
906{
907    if (!element)
908        return false;
909    ContainerNode* parentNode = element->parentNode();
910    return parentNode && parentNode->isShadowRoot();
911}
912
913PassRefPtr<RenderStyle> StyleResolver::styleForElement(Element* element, RenderStyle* defaultParent,
914    StyleSharingBehavior sharingBehavior, RuleMatchingBehavior matchingBehavior, RenderRegion* regionForStyling)
915{
916    // Once an element has a renderer, we don't try to destroy it, since otherwise the renderer
917    // will vanish if a style recalc happens during loading.
918    if (sharingBehavior == AllowStyleSharing && !element->document()->haveStylesheetsLoaded() && !element->renderer()) {
919        if (!s_styleNotYetAvailable) {
920            s_styleNotYetAvailable = RenderStyle::create().leakRef();
921            s_styleNotYetAvailable->setDisplay(NONE);
922            s_styleNotYetAvailable->font().update(m_fontSelector);
923        }
924        element->document()->setHasNodesWithPlaceholderStyle();
925        return s_styleNotYetAvailable;
926    }
927
928    State& state = m_state;
929    initElement(element);
930    state.initForStyleResolve(document(), element, defaultParent, regionForStyling);
931    if (sharingBehavior == AllowStyleSharing && !state.distributedToInsertionPoint()) {
932        RenderStyle* sharedStyle = locateSharedStyle();
933        if (sharedStyle) {
934            state.clear();
935            return sharedStyle;
936        }
937    }
938
939    if (state.parentStyle()) {
940        state.setStyle(RenderStyle::create());
941        state.style()->inheritFrom(state.parentStyle(), isAtShadowBoundary(element) ? RenderStyle::AtShadowBoundary : RenderStyle::NotAtShadowBoundary);
942    } else {
943        state.setStyle(defaultStyleForElement());
944        state.setParentStyle(RenderStyle::clone(state.style()));
945    }
946    // contenteditable attribute (implemented by -webkit-user-modify) should
947    // be propagated from shadow host to distributed node.
948    if (state.distributedToInsertionPoint()) {
949        if (Element* parent = element->parentElement()) {
950            if (RenderStyle* styleOfShadowHost = parent->renderStyle())
951                state.style()->setUserModify(styleOfShadowHost->userModify());
952        }
953    }
954
955    if (element->isLink()) {
956        state.style()->setIsLink(true);
957        EInsideLink linkState = state.elementLinkState();
958        if (linkState != NotInsideLink) {
959            bool forceVisited = InspectorInstrumentation::forcePseudoState(element, CSSSelector::PseudoVisited);
960            if (forceVisited)
961                linkState = InsideVisitedLink;
962        }
963        state.style()->setInsideLink(linkState);
964    }
965
966    bool needsCollection = false;
967    CSSDefaultStyleSheets::ensureDefaultStyleSheetsForElement(element, needsCollection);
968    if (needsCollection)
969        m_ruleSets.collectFeatures(document()->isViewSource(), m_scopeResolver.get());
970
971    ElementRuleCollector collector(this, state);
972    collector.setRegionForStyling(regionForStyling);
973    collector.setMedium(m_medium.get());
974
975    if (matchingBehavior == MatchOnlyUserAgentRules)
976        collector.matchUARules();
977    else
978        collector.matchAllRules(m_matchAuthorAndUserStyles, matchingBehavior != MatchAllRulesExcludingSMIL);
979
980    applyMatchedProperties(collector.matchedResult(), element);
981
982    // Clean up our style object's display and text decorations (among other fixups).
983    adjustRenderStyle(state.style(), state.parentStyle(), element);
984
985    state.clear(); // Clear out for the next resolve.
986
987    document()->didAccessStyleResolver();
988
989    // Now return the style.
990    return state.takeStyle();
991}
992
993PassRefPtr<RenderStyle> StyleResolver::styleForKeyframe(const RenderStyle* elementStyle, const StyleKeyframe* keyframe, KeyframeValue& keyframeValue)
994{
995    MatchResult result;
996    if (keyframe->properties())
997        result.addMatchedProperties(keyframe->properties());
998
999    ASSERT(!m_state.style());
1000
1001    State& state = m_state;
1002
1003    // Create the style
1004    state.setStyle(RenderStyle::clone(elementStyle));
1005    state.setLineHeightValue(0);
1006
1007    // We don't need to bother with !important. Since there is only ever one
1008    // decl, there's nothing to override. So just add the first properties.
1009    bool inheritedOnly = false;
1010    if (keyframe->properties())
1011        applyMatchedProperties<HighPriorityProperties>(result, false, 0, result.matchedProperties.size() - 1, inheritedOnly);
1012
1013    // If our font got dirtied, go ahead and update it now.
1014    updateFont();
1015
1016    // Line-height is set when we are sure we decided on the font-size
1017    if (state.lineHeightValue())
1018        applyProperty(CSSPropertyLineHeight, state.lineHeightValue());
1019
1020    // Now do rest of the properties.
1021    if (keyframe->properties())
1022        applyMatchedProperties<LowPriorityProperties>(result, false, 0, result.matchedProperties.size() - 1, inheritedOnly);
1023
1024    // If our font got dirtied by one of the non-essential font props,
1025    // go ahead and update it a second time.
1026    updateFont();
1027
1028    // Start loading resources referenced by this style.
1029    loadPendingResources();
1030
1031    // Add all the animating properties to the keyframe.
1032    if (const StylePropertySet* styleDeclaration = keyframe->properties()) {
1033        unsigned propertyCount = styleDeclaration->propertyCount();
1034        for (unsigned i = 0; i < propertyCount; ++i) {
1035            CSSPropertyID property = styleDeclaration->propertyAt(i).id();
1036            // Timing-function within keyframes is special, because it is not animated; it just
1037            // describes the timing function between this keyframe and the next.
1038            if (property != CSSPropertyWebkitAnimationTimingFunction)
1039                keyframeValue.addProperty(property);
1040        }
1041    }
1042
1043    document()->didAccessStyleResolver();
1044
1045    return state.takeStyle();
1046}
1047
1048void StyleResolver::keyframeStylesForAnimation(Element* e, const RenderStyle* elementStyle, KeyframeList& list)
1049{
1050    list.clear();
1051
1052    // Get the keyframesRule for this name
1053    if (!e || list.animationName().isEmpty())
1054        return;
1055
1056    m_keyframesRuleMap.checkConsistency();
1057
1058    KeyframesRuleMap::iterator it = m_keyframesRuleMap.find(list.animationName().impl());
1059    if (it == m_keyframesRuleMap.end())
1060        return;
1061
1062    const StyleRuleKeyframes* keyframesRule = it->value.get();
1063
1064    // Construct and populate the style for each keyframe
1065    const Vector<RefPtr<StyleKeyframe> >& keyframes = keyframesRule->keyframes();
1066    for (unsigned i = 0; i < keyframes.size(); ++i) {
1067        // Apply the declaration to the style. This is a simplified version of the logic in styleForElement
1068        initElement(e);
1069        m_state.initForStyleResolve(document(), e);
1070
1071        const StyleKeyframe* keyframe = keyframes[i].get();
1072
1073        KeyframeValue keyframeValue(0, 0);
1074        keyframeValue.setStyle(styleForKeyframe(elementStyle, keyframe, keyframeValue));
1075
1076        // Add this keyframe style to all the indicated key times
1077        Vector<float> keys;
1078        keyframe->getKeys(keys);
1079        for (size_t keyIndex = 0; keyIndex < keys.size(); ++keyIndex) {
1080            keyframeValue.setKey(keys[keyIndex]);
1081            list.insert(keyframeValue);
1082        }
1083    }
1084
1085    // If the 0% keyframe is missing, create it (but only if there is at least one other keyframe)
1086    int initialListSize = list.size();
1087    if (initialListSize > 0 && list[0].key()) {
1088        static StyleKeyframe* zeroPercentKeyframe;
1089        if (!zeroPercentKeyframe) {
1090            zeroPercentKeyframe = StyleKeyframe::create().leakRef();
1091            zeroPercentKeyframe->setKeyText("0%");
1092        }
1093        KeyframeValue keyframeValue(0, 0);
1094        keyframeValue.setStyle(styleForKeyframe(elementStyle, zeroPercentKeyframe, keyframeValue));
1095        list.insert(keyframeValue);
1096    }
1097
1098    // If the 100% keyframe is missing, create it (but only if there is at least one other keyframe)
1099    if (initialListSize > 0 && (list[list.size() - 1].key() != 1)) {
1100        static StyleKeyframe* hundredPercentKeyframe;
1101        if (!hundredPercentKeyframe) {
1102            hundredPercentKeyframe = StyleKeyframe::create().leakRef();
1103            hundredPercentKeyframe->setKeyText("100%");
1104        }
1105        KeyframeValue keyframeValue(1, 0);
1106        keyframeValue.setStyle(styleForKeyframe(elementStyle, hundredPercentKeyframe, keyframeValue));
1107        list.insert(keyframeValue);
1108    }
1109}
1110
1111PassRefPtr<RenderStyle> StyleResolver::pseudoStyleForElement(Element* e, const PseudoStyleRequest& pseudoStyleRequest, RenderStyle* parentStyle)
1112{
1113    ASSERT(parentStyle);
1114    if (!e)
1115        return 0;
1116
1117    State& state = m_state;
1118
1119    initElement(e);
1120
1121    state.initForStyleResolve(document(), e, parentStyle);
1122
1123    if (m_state.parentStyle()) {
1124        state.setStyle(RenderStyle::create());
1125        state.style()->inheritFrom(m_state.parentStyle());
1126    } else {
1127        state.setStyle(defaultStyleForElement());
1128        state.setParentStyle(RenderStyle::clone(state.style()));
1129    }
1130
1131    // Since we don't use pseudo-elements in any of our quirk/print user agent rules, don't waste time walking
1132    // those rules.
1133
1134    // Check UA, user and author rules.
1135    ElementRuleCollector collector(this, state);
1136    collector.setPseudoStyleRequest(pseudoStyleRequest);
1137    collector.setMedium(m_medium.get());
1138    collector.matchUARules();
1139
1140    if (m_matchAuthorAndUserStyles) {
1141        collector.matchUserRules(false);
1142        collector.matchAuthorRules(false);
1143    }
1144
1145    if (collector.matchedResult().matchedProperties.isEmpty())
1146        return 0;
1147
1148    state.style()->setStyleType(pseudoStyleRequest.pseudoId);
1149
1150    applyMatchedProperties(collector.matchedResult(), e);
1151
1152    // Clean up our style object's display and text decorations (among other fixups).
1153    adjustRenderStyle(state.style(), m_state.parentStyle(), 0);
1154
1155    // Start loading resources referenced by this style.
1156    loadPendingResources();
1157
1158    document()->didAccessStyleResolver();
1159
1160    // Now return the style.
1161    return state.takeStyle();
1162}
1163
1164PassRefPtr<RenderStyle> StyleResolver::styleForPage(int pageIndex)
1165{
1166    m_state.initForStyleResolve(document(), document()->documentElement()); // m_rootElementStyle will be set to the document style.
1167
1168    m_state.setStyle(RenderStyle::create());
1169    m_state.style()->inheritFrom(m_state.rootElementStyle());
1170
1171    PageRuleCollector collector(m_state, m_ruleSets);
1172    collector.matchAllPageRules(pageIndex);
1173    m_state.setLineHeightValue(0);
1174    bool inheritedOnly = false;
1175
1176    MatchResult& result = collector.matchedResult();
1177#if ENABLE(CSS_VARIABLES)
1178    applyMatchedProperties<VariableDefinitions>(result, false, 0, result.matchedProperties.size() - 1, inheritedOnly);
1179#endif
1180    applyMatchedProperties<HighPriorityProperties>(result, false, 0, result.matchedProperties.size() - 1, inheritedOnly);
1181
1182    // If our font got dirtied, go ahead and update it now.
1183    updateFont();
1184
1185    // Line-height is set when we are sure we decided on the font-size.
1186    if (m_state.lineHeightValue())
1187        applyProperty(CSSPropertyLineHeight, m_state.lineHeightValue());
1188
1189    applyMatchedProperties<LowPriorityProperties>(result, false, 0, result.matchedProperties.size() - 1, inheritedOnly);
1190
1191    // Start loading resources referenced by this style.
1192    loadPendingResources();
1193
1194    document()->didAccessStyleResolver();
1195
1196    // Now return the style.
1197    return m_state.takeStyle();
1198}
1199
1200PassRefPtr<RenderStyle> StyleResolver::defaultStyleForElement()
1201{
1202    m_state.setStyle(RenderStyle::create());
1203    // Make sure our fonts are initialized if we don't inherit them from our parent style.
1204    if (Settings* settings = documentSettings()) {
1205        initializeFontStyle(settings);
1206        m_state.style()->font().update(fontSelector());
1207    } else
1208        m_state.style()->font().update(0);
1209
1210    return m_state.takeStyle();
1211}
1212
1213PassRefPtr<RenderStyle> StyleResolver::styleForText(Text* textNode)
1214{
1215    ASSERT(textNode);
1216
1217    NodeRenderingContext context(textNode);
1218    Node* parentNode = context.parentNodeForRenderingAndStyle();
1219    return context.resetStyleInheritance() || !parentNode || !parentNode->renderStyle() ?
1220        defaultStyleForElement() : parentNode->renderStyle();
1221}
1222
1223static void addIntrinsicMargins(RenderStyle* style)
1224{
1225    // Intrinsic margin value.
1226    const int intrinsicMargin = 2 * style->effectiveZoom();
1227
1228    // FIXME: Using width/height alone and not also dealing with min-width/max-width is flawed.
1229    // FIXME: Using "quirk" to decide the margin wasn't set is kind of lame.
1230    if (style->width().isIntrinsicOrAuto()) {
1231        if (style->marginLeft().quirk())
1232            style->setMarginLeft(Length(intrinsicMargin, Fixed));
1233        if (style->marginRight().quirk())
1234            style->setMarginRight(Length(intrinsicMargin, Fixed));
1235    }
1236
1237    if (style->height().isAuto()) {
1238        if (style->marginTop().quirk())
1239            style->setMarginTop(Length(intrinsicMargin, Fixed));
1240        if (style->marginBottom().quirk())
1241            style->setMarginBottom(Length(intrinsicMargin, Fixed));
1242    }
1243}
1244
1245static EDisplay equivalentBlockDisplay(EDisplay display, bool isFloating, bool strictParsing)
1246{
1247    switch (display) {
1248    case BLOCK:
1249    case TABLE:
1250    case BOX:
1251    case FLEX:
1252    case GRID:
1253        return display;
1254
1255    case LIST_ITEM:
1256        // It is a WinIE bug that floated list items lose their bullets, so we'll emulate the quirk, but only in quirks mode.
1257        if (!strictParsing && isFloating)
1258            return BLOCK;
1259        return display;
1260    case INLINE_TABLE:
1261        return TABLE;
1262    case INLINE_BOX:
1263        return BOX;
1264    case INLINE_FLEX:
1265        return FLEX;
1266    case INLINE_GRID:
1267        return GRID;
1268
1269    case INLINE:
1270    case RUN_IN:
1271    case COMPACT:
1272    case INLINE_BLOCK:
1273    case TABLE_ROW_GROUP:
1274    case TABLE_HEADER_GROUP:
1275    case TABLE_FOOTER_GROUP:
1276    case TABLE_ROW:
1277    case TABLE_COLUMN_GROUP:
1278    case TABLE_COLUMN:
1279    case TABLE_CELL:
1280    case TABLE_CAPTION:
1281        return BLOCK;
1282    case NONE:
1283        ASSERT_NOT_REACHED();
1284        return NONE;
1285    }
1286    ASSERT_NOT_REACHED();
1287    return BLOCK;
1288}
1289
1290// CSS requires text-decoration to be reset at each DOM element for tables,
1291// inline blocks, inline tables, run-ins, shadow DOM crossings, floating elements,
1292// and absolute or relatively positioned elements.
1293static bool doesNotInheritTextDecoration(RenderStyle* style, Element* e)
1294{
1295    return style->display() == TABLE || style->display() == INLINE_TABLE || style->display() == RUN_IN
1296        || style->display() == INLINE_BLOCK || style->display() == INLINE_BOX || isAtShadowBoundary(e)
1297        || style->isFloating() || style->hasOutOfFlowPosition();
1298}
1299
1300static bool isDisplayFlexibleBox(EDisplay display)
1301{
1302    return display == FLEX || display == INLINE_FLEX;
1303}
1304
1305void StyleResolver::adjustRenderStyle(RenderStyle* style, RenderStyle* parentStyle, Element *e)
1306{
1307    ASSERT(parentStyle);
1308
1309    // Cache our original display.
1310    style->setOriginalDisplay(style->display());
1311
1312    if (style->display() != NONE) {
1313        // If we have a <td> that specifies a float property, in quirks mode we just drop the float
1314        // property.
1315        // Sites also commonly use display:inline/block on <td>s and <table>s. In quirks mode we force
1316        // these tags to retain their display types.
1317        if (document()->inQuirksMode() && e) {
1318            if (e->hasTagName(tdTag)) {
1319                style->setDisplay(TABLE_CELL);
1320                style->setFloating(NoFloat);
1321            } else if (e->hasTagName(tableTag))
1322                style->setDisplay(style->isDisplayInlineType() ? INLINE_TABLE : TABLE);
1323        }
1324
1325        if (e && (e->hasTagName(tdTag) || e->hasTagName(thTag))) {
1326            if (style->whiteSpace() == KHTML_NOWRAP) {
1327                // Figure out if we are really nowrapping or if we should just
1328                // use normal instead. If the width of the cell is fixed, then
1329                // we don't actually use NOWRAP.
1330                if (style->width().isFixed())
1331                    style->setWhiteSpace(NORMAL);
1332                else
1333                    style->setWhiteSpace(NOWRAP);
1334            }
1335        }
1336
1337        // Tables never support the -webkit-* values for text-align and will reset back to the default.
1338        if (e && e->hasTagName(tableTag) && (style->textAlign() == WEBKIT_LEFT || style->textAlign() == WEBKIT_CENTER || style->textAlign() == WEBKIT_RIGHT))
1339            style->setTextAlign(TASTART);
1340
1341        // Frames and framesets never honor position:relative or position:absolute. This is necessary to
1342        // fix a crash where a site tries to position these objects. They also never honor display.
1343        if (e && (e->hasTagName(frameTag) || e->hasTagName(framesetTag))) {
1344            style->setPosition(StaticPosition);
1345            style->setDisplay(BLOCK);
1346        }
1347
1348        // Ruby text does not support float or position. This might change with evolution of the specification.
1349        if (e && e->hasTagName(rtTag)) {
1350            style->setPosition(StaticPosition);
1351            style->setFloating(NoFloat);
1352        }
1353
1354        // FIXME: We shouldn't be overriding start/-webkit-auto like this. Do it in html.css instead.
1355        // Table headers with a text-align of -webkit-auto will change the text-align to center.
1356        if (e && e->hasTagName(thTag) && style->textAlign() == TASTART)
1357            style->setTextAlign(CENTER);
1358
1359        if (e && e->hasTagName(legendTag))
1360            style->setDisplay(BLOCK);
1361
1362        // Absolute/fixed positioned elements, floating elements and the document element need block-like outside display.
1363        if (style->hasOutOfFlowPosition() || style->isFloating() || (e && e->document()->documentElement() == e))
1364            style->setDisplay(equivalentBlockDisplay(style->display(), style->isFloating(), !document()->inQuirksMode()));
1365
1366        // FIXME: Don't support this mutation for pseudo styles like first-letter or first-line, since it's not completely
1367        // clear how that should work.
1368        if (style->display() == INLINE && style->styleType() == NOPSEUDO && style->writingMode() != parentStyle->writingMode())
1369            style->setDisplay(INLINE_BLOCK);
1370
1371        // After performing the display mutation, check table rows. We do not honor position:relative or position:sticky on
1372        // table rows or cells. This has been established for position:relative in CSS2.1 (and caused a crash in containingBlock()
1373        // on some sites).
1374        if ((style->display() == TABLE_HEADER_GROUP || style->display() == TABLE_ROW_GROUP
1375            || style->display() == TABLE_FOOTER_GROUP || style->display() == TABLE_ROW)
1376            && style->hasInFlowPosition())
1377            style->setPosition(StaticPosition);
1378
1379        // writing-mode does not apply to table row groups, table column groups, table rows, and table columns.
1380        // FIXME: Table cells should be allowed to be perpendicular or flipped with respect to the table, though.
1381        if (style->display() == TABLE_COLUMN || style->display() == TABLE_COLUMN_GROUP || style->display() == TABLE_FOOTER_GROUP
1382            || style->display() == TABLE_HEADER_GROUP || style->display() == TABLE_ROW || style->display() == TABLE_ROW_GROUP
1383            || style->display() == TABLE_CELL)
1384            style->setWritingMode(parentStyle->writingMode());
1385
1386        // FIXME: Since we don't support block-flow on flexible boxes yet, disallow setting
1387        // of block-flow to anything other than TopToBottomWritingMode.
1388        // https://bugs.webkit.org/show_bug.cgi?id=46418 - Flexible box support.
1389        if (style->writingMode() != TopToBottomWritingMode && (style->display() == BOX || style->display() == INLINE_BOX))
1390            style->setWritingMode(TopToBottomWritingMode);
1391
1392        if (isDisplayFlexibleBox(parentStyle->display())) {
1393            style->setFloating(NoFloat);
1394            style->setDisplay(equivalentBlockDisplay(style->display(), style->isFloating(), !document()->inQuirksMode()));
1395        }
1396
1397#if ENABLE(DIALOG_ELEMENT)
1398        // Per the spec, position 'static' and 'relative' in the top layer compute to 'absolute'.
1399        if (e && e->isInTopLayer() && (style->position() == StaticPosition || style->position() == RelativePosition)) {
1400            style->setPosition(AbsolutePosition);
1401            style->setDisplay(BLOCK);
1402        }
1403#endif
1404    }
1405
1406    // Make sure our z-index value is only applied if the object is positioned.
1407    if (style->position() == StaticPosition && !isDisplayFlexibleBox(parentStyle->display()))
1408        style->setHasAutoZIndex();
1409
1410    // Auto z-index becomes 0 for the root element and transparent objects. This prevents
1411    // cases where objects that should be blended as a single unit end up with a non-transparent
1412    // object wedged in between them. Auto z-index also becomes 0 for objects that specify transforms/masks/reflections.
1413    if (style->hasAutoZIndex() && ((e && e->document()->documentElement() == e)
1414        || style->opacity() < 1.0f
1415        || style->hasTransformRelatedProperty()
1416        || style->hasMask()
1417        || style->clipPath()
1418        || style->boxReflect()
1419        || style->hasFilter()
1420        || style->hasBlendMode()
1421        || style->position() == StickyPosition
1422        || (style->position() == FixedPosition && e && e->document()->page() && e->document()->page()->settings()->fixedPositionCreatesStackingContext())
1423#if ENABLE(ACCELERATED_OVERFLOW_SCROLLING)
1424        // Touch overflow scrolling creates a stacking context.
1425        || ((style->overflowX() != OHIDDEN || style->overflowY() != OHIDDEN) && style->useTouchOverflowScrolling())
1426#endif
1427#if ENABLE(DIALOG_ELEMENT)
1428        || (e && e->isInTopLayer())
1429#endif
1430        ))
1431        style->setZIndex(0);
1432
1433    // Textarea considers overflow visible as auto.
1434    if (e && e->hasTagName(textareaTag)) {
1435        style->setOverflowX(style->overflowX() == OVISIBLE ? OAUTO : style->overflowX());
1436        style->setOverflowY(style->overflowY() == OVISIBLE ? OAUTO : style->overflowY());
1437    }
1438
1439    if (doesNotInheritTextDecoration(style, e))
1440        style->setTextDecorationsInEffect(style->textDecoration());
1441    else
1442        style->addToTextDecorationsInEffect(style->textDecoration());
1443
1444    // If either overflow value is not visible, change to auto.
1445    if (style->overflowX() == OMARQUEE && style->overflowY() != OMARQUEE)
1446        style->setOverflowY(OMARQUEE);
1447    else if (style->overflowY() == OMARQUEE && style->overflowX() != OMARQUEE)
1448        style->setOverflowX(OMARQUEE);
1449    else if (style->overflowX() == OVISIBLE && style->overflowY() != OVISIBLE) {
1450        // FIXME: Once we implement pagination controls, overflow-x should default to hidden
1451        // if overflow-y is set to -webkit-paged-x or -webkit-page-y. For now, we'll let it
1452        // default to auto so we can at least scroll through the pages.
1453        style->setOverflowX(OAUTO);
1454    } else if (style->overflowY() == OVISIBLE && style->overflowX() != OVISIBLE)
1455        style->setOverflowY(OAUTO);
1456
1457    // Call setStylesForPaginationMode() if a pagination mode is set for any non-root elements. If these
1458    // styles are specified on a root element, then they will be incorporated in
1459    // StyleResolver::styleForDocument().
1460    if ((style->overflowY() == OPAGEDX || style->overflowY() == OPAGEDY) && !(e && (e->hasTagName(htmlTag) || e->hasTagName(bodyTag))))
1461        style->setColumnStylesFromPaginationMode(WebCore::paginationModeForRenderStyle(style));
1462
1463    // Table rows, sections and the table itself will support overflow:hidden and will ignore scroll/auto.
1464    // FIXME: Eventually table sections will support auto and scroll.
1465    if (style->display() == TABLE || style->display() == INLINE_TABLE
1466        || style->display() == TABLE_ROW_GROUP || style->display() == TABLE_ROW) {
1467        if (style->overflowX() != OVISIBLE && style->overflowX() != OHIDDEN)
1468            style->setOverflowX(OVISIBLE);
1469        if (style->overflowY() != OVISIBLE && style->overflowY() != OHIDDEN)
1470            style->setOverflowY(OVISIBLE);
1471    }
1472
1473    // Menulists should have visible overflow
1474    if (style->appearance() == MenulistPart) {
1475        style->setOverflowX(OVISIBLE);
1476        style->setOverflowY(OVISIBLE);
1477    }
1478
1479    // Cull out any useless layers and also repeat patterns into additional layers.
1480    style->adjustBackgroundLayers();
1481    style->adjustMaskLayers();
1482
1483    // Do the same for animations and transitions.
1484    style->adjustAnimations();
1485    style->adjustTransitions();
1486
1487    // Important: Intrinsic margins get added to controls before the theme has adjusted the style, since the theme will
1488    // alter fonts and heights/widths.
1489    if (e && e->isFormControlElement() && style->fontSize() >= 11) {
1490        // Don't apply intrinsic margins to image buttons. The designer knows how big the images are,
1491        // so we have to treat all image buttons as though they were explicitly sized.
1492        if (!e->hasTagName(inputTag) || !static_cast<HTMLInputElement*>(e)->isImageButton())
1493            addIntrinsicMargins(style);
1494    }
1495
1496    // Let the theme also have a crack at adjusting the style.
1497    if (style->hasAppearance())
1498        RenderTheme::defaultTheme()->adjustStyle(this, style, e, m_state.hasUAAppearance(), m_state.borderData(), m_state.backgroundData(), m_state.backgroundColor());
1499
1500    // If we have first-letter pseudo style, do not share this style.
1501    if (style->hasPseudoStyle(FIRST_LETTER))
1502        style->setUnique();
1503
1504    // FIXME: when dropping the -webkit prefix on transform-style, we should also have opacity < 1 cause flattening.
1505    if (style->preserves3D() && (style->overflowX() != OVISIBLE
1506        || style->overflowY() != OVISIBLE
1507        || style->hasFilter()))
1508        style->setTransformStyle3D(TransformStyle3DFlat);
1509
1510    // Seamless iframes behave like blocks. Map their display to inline-block when marked inline.
1511    if (e && e->hasTagName(iframeTag) && style->display() == INLINE && toHTMLIFrameElement(e)->shouldDisplaySeamlessly())
1512        style->setDisplay(INLINE_BLOCK);
1513
1514#if ENABLE(SVG)
1515    if (e && e->isSVGElement()) {
1516        // Spec: http://www.w3.org/TR/SVG/masking.html#OverflowProperty
1517        if (style->overflowY() == OSCROLL)
1518            style->setOverflowY(OHIDDEN);
1519        else if (style->overflowY() == OAUTO)
1520            style->setOverflowY(OVISIBLE);
1521
1522        if (style->overflowX() == OSCROLL)
1523            style->setOverflowX(OHIDDEN);
1524        else if (style->overflowX() == OAUTO)
1525            style->setOverflowX(OVISIBLE);
1526
1527        // Only the root <svg> element in an SVG document fragment tree honors css position
1528        if (!(e->hasTagName(SVGNames::svgTag) && e->parentNode() && !e->parentNode()->isSVGElement()))
1529            style->setPosition(RenderStyle::initialPosition());
1530
1531        // RenderSVGRoot handles zooming for the whole SVG subtree, so foreignObject content should
1532        // not be scaled again.
1533        if (e->hasTagName(SVGNames::foreignObjectTag))
1534            style->setEffectiveZoom(RenderStyle::initialZoom());
1535    }
1536#endif
1537}
1538
1539bool StyleResolver::checkRegionStyle(Element* regionElement)
1540{
1541    // FIXME (BUG 72472): We don't add @-webkit-region rules of scoped style sheets for the moment,
1542    // so all region rules are global by default. Verify whether that can stand or needs changing.
1543
1544    unsigned rulesSize = m_ruleSets.authorStyle()->m_regionSelectorsAndRuleSets.size();
1545    for (unsigned i = 0; i < rulesSize; ++i) {
1546        ASSERT(m_ruleSets.authorStyle()->m_regionSelectorsAndRuleSets.at(i).ruleSet.get());
1547        if (checkRegionSelector(m_ruleSets.authorStyle()->m_regionSelectorsAndRuleSets.at(i).selector, regionElement))
1548            return true;
1549    }
1550
1551    if (m_ruleSets.userStyle()) {
1552        rulesSize = m_ruleSets.userStyle()->m_regionSelectorsAndRuleSets.size();
1553        for (unsigned i = 0; i < rulesSize; ++i) {
1554            ASSERT(m_ruleSets.userStyle()->m_regionSelectorsAndRuleSets.at(i).ruleSet.get());
1555            if (checkRegionSelector(m_ruleSets.userStyle()->m_regionSelectorsAndRuleSets.at(i).selector, regionElement))
1556                return true;
1557        }
1558    }
1559
1560    return false;
1561}
1562
1563static void checkForOrientationChange(RenderStyle* style)
1564{
1565    FontOrientation fontOrientation;
1566    NonCJKGlyphOrientation glyphOrientation;
1567    getFontAndGlyphOrientation(style, fontOrientation, glyphOrientation);
1568
1569    const FontDescription& fontDescription = style->fontDescription();
1570    if (fontDescription.orientation() == fontOrientation && fontDescription.nonCJKGlyphOrientation() == glyphOrientation)
1571        return;
1572
1573    FontDescription newFontDescription(fontDescription);
1574    newFontDescription.setNonCJKGlyphOrientation(glyphOrientation);
1575    newFontDescription.setOrientation(fontOrientation);
1576    style->setFontDescription(newFontDescription);
1577}
1578
1579void StyleResolver::updateFont()
1580{
1581    if (!m_state.fontDirty())
1582        return;
1583
1584    RenderStyle* style = m_state.style();
1585    checkForGenericFamilyChange(style, m_state.parentStyle());
1586    checkForZoomChange(style, m_state.parentStyle());
1587    checkForOrientationChange(style);
1588    style->font().update(m_fontSelector);
1589    m_state.setFontDirty(false);
1590}
1591
1592Vector<RefPtr<StyleRuleBase> > StyleResolver::styleRulesForElement(Element* e, unsigned rulesToInclude)
1593{
1594    return pseudoStyleRulesForElement(e, NOPSEUDO, rulesToInclude);
1595}
1596
1597Vector<RefPtr<StyleRuleBase> > StyleResolver::pseudoStyleRulesForElement(Element* e, PseudoId pseudoId, unsigned rulesToInclude)
1598{
1599    if (!e || !e->document()->haveStylesheetsLoaded())
1600        return Vector<RefPtr<StyleRuleBase> >();
1601
1602    initElement(e);
1603    m_state.initForStyleResolve(document(), e, 0);
1604
1605    ElementRuleCollector collector(this, m_state);
1606    collector.setMode(SelectorChecker::CollectingRules);
1607    collector.setPseudoStyleRequest(PseudoStyleRequest(pseudoId));
1608    collector.setMedium(m_medium.get());
1609
1610    if (rulesToInclude & UAAndUserCSSRules) {
1611        // First we match rules from the user agent sheet.
1612        collector.matchUARules();
1613
1614        // Now we check user sheet rules.
1615        if (m_matchAuthorAndUserStyles)
1616            collector.matchUserRules(rulesToInclude & EmptyCSSRules);
1617    }
1618
1619    if (m_matchAuthorAndUserStyles && (rulesToInclude & AuthorCSSRules)) {
1620        collector.setSameOriginOnly(!(rulesToInclude & CrossOriginCSSRules));
1621
1622        // Check the rules in author sheets.
1623        collector.matchAuthorRules(rulesToInclude & EmptyCSSRules);
1624    }
1625
1626    return collector.matchedRuleList();
1627}
1628
1629// -------------------------------------------------------------------------------------
1630// this is mostly boring stuff on how to apply a certain rule to the renderstyle...
1631
1632Length StyleResolver::convertToIntLength(const CSSPrimitiveValue* primitiveValue, const RenderStyle* style, const RenderStyle* rootStyle, double multiplier)
1633{
1634    return primitiveValue ? primitiveValue->convertToLength<FixedIntegerConversion | PercentConversion | CalculatedConversion | FractionConversion | ViewportPercentageConversion>(style, rootStyle, multiplier) : Length(Undefined);
1635}
1636
1637Length StyleResolver::convertToFloatLength(const CSSPrimitiveValue* primitiveValue, const RenderStyle* style, const RenderStyle* rootStyle, double multiplier)
1638{
1639    return primitiveValue ? primitiveValue->convertToLength<FixedFloatConversion | PercentConversion | CalculatedConversion | FractionConversion | ViewportPercentageConversion>(style, rootStyle, multiplier) : Length(Undefined);
1640}
1641
1642template <StyleResolver::StyleApplicationPass pass>
1643void StyleResolver::applyProperties(const StylePropertySet* properties, StyleRule* rule, bool isImportant, bool inheritedOnly, PropertyWhitelistType propertyWhitelistType)
1644{
1645    ASSERT((propertyWhitelistType != PropertyWhitelistRegion) || m_state.regionForStyling());
1646    InspectorInstrumentationCookie cookie = InspectorInstrumentation::willProcessRule(document(), rule, this);
1647
1648    unsigned propertyCount = properties->propertyCount();
1649    for (unsigned i = 0; i < propertyCount; ++i) {
1650        StylePropertySet::PropertyReference current = properties->propertyAt(i);
1651        if (isImportant != current.isImportant())
1652            continue;
1653        if (inheritedOnly && !current.isInherited()) {
1654            // If the property value is explicitly inherited, we need to apply further non-inherited properties
1655            // as they might override the value inherited here. For this reason we don't allow declarations with
1656            // explicitly inherited properties to be cached.
1657            ASSERT(!current.value()->isInheritedValue());
1658            continue;
1659        }
1660        CSSPropertyID property = current.id();
1661
1662        if (propertyWhitelistType == PropertyWhitelistRegion && !StyleResolver::isValidRegionStyleProperty(property))
1663            continue;
1664#if ENABLE(VIDEO_TRACK)
1665        if (propertyWhitelistType == PropertyWhitelistCue && !StyleResolver::isValidCueStyleProperty(property))
1666            continue;
1667#endif
1668        switch (pass) {
1669#if ENABLE(CSS_VARIABLES)
1670        case VariableDefinitions:
1671            COMPILE_ASSERT(CSSPropertyVariable < firstCSSProperty, CSS_variable_is_before_first_property);
1672            if (property == CSSPropertyVariable)
1673                applyProperty(current.id(), current.value());
1674            break;
1675#endif
1676        case HighPriorityProperties:
1677            COMPILE_ASSERT(firstCSSProperty == CSSPropertyColor, CSS_color_is_first_property);
1678            COMPILE_ASSERT(CSSPropertyZoom == CSSPropertyColor + 17, CSS_zoom_is_end_of_first_prop_range);
1679            COMPILE_ASSERT(CSSPropertyLineHeight == CSSPropertyZoom + 1, CSS_line_height_is_after_zoom);
1680#if ENABLE(CSS_VARIABLES)
1681            if (property == CSSPropertyVariable)
1682                continue;
1683#endif
1684            // give special priority to font-xxx, color properties, etc
1685            if (property < CSSPropertyLineHeight)
1686                applyProperty(current.id(), current.value());
1687            // we apply line-height later
1688            else if (property == CSSPropertyLineHeight)
1689                m_state.setLineHeightValue(current.value());
1690            break;
1691        case LowPriorityProperties:
1692            if (property > CSSPropertyLineHeight)
1693                applyProperty(current.id(), current.value());
1694        }
1695    }
1696    InspectorInstrumentation::didProcessRule(cookie);
1697}
1698
1699template <StyleResolver::StyleApplicationPass pass>
1700void StyleResolver::applyMatchedProperties(const MatchResult& matchResult, bool isImportant, int startIndex, int endIndex, bool inheritedOnly)
1701{
1702    if (startIndex == -1)
1703        return;
1704
1705    State& state = m_state;
1706    if (state.style()->insideLink() != NotInsideLink) {
1707        for (int i = startIndex; i <= endIndex; ++i) {
1708            const MatchedProperties& matchedProperties = matchResult.matchedProperties[i];
1709            unsigned linkMatchType = matchedProperties.linkMatchType;
1710            // FIXME: It would be nicer to pass these as arguments but that requires changes in many places.
1711            state.setApplyPropertyToRegularStyle(linkMatchType & SelectorChecker::MatchLink);
1712            state.setApplyPropertyToVisitedLinkStyle(linkMatchType & SelectorChecker::MatchVisited);
1713
1714            applyProperties<pass>(matchedProperties.properties.get(), matchResult.matchedRules[i], isImportant, inheritedOnly, static_cast<PropertyWhitelistType>(matchedProperties.whitelistType));
1715        }
1716        state.setApplyPropertyToRegularStyle(true);
1717        state.setApplyPropertyToVisitedLinkStyle(false);
1718        return;
1719    }
1720    for (int i = startIndex; i <= endIndex; ++i) {
1721        const MatchedProperties& matchedProperties = matchResult.matchedProperties[i];
1722        applyProperties<pass>(matchedProperties.properties.get(), matchResult.matchedRules[i], isImportant, inheritedOnly, static_cast<PropertyWhitelistType>(matchedProperties.whitelistType));
1723    }
1724}
1725
1726unsigned StyleResolver::computeMatchedPropertiesHash(const MatchedProperties* properties, unsigned size)
1727{
1728
1729    return StringHasher::hashMemory(properties, sizeof(MatchedProperties) * size);
1730}
1731
1732bool operator==(const StyleResolver::MatchRanges& a, const StyleResolver::MatchRanges& b)
1733{
1734    return a.firstUARule == b.firstUARule
1735        && a.lastUARule == b.lastUARule
1736        && a.firstAuthorRule == b.firstAuthorRule
1737        && a.lastAuthorRule == b.lastAuthorRule
1738        && a.firstUserRule == b.firstUserRule
1739        && a.lastUserRule == b.lastUserRule;
1740}
1741
1742bool operator!=(const StyleResolver::MatchRanges& a, const StyleResolver::MatchRanges& b)
1743{
1744    return !(a == b);
1745}
1746
1747bool operator==(const StyleResolver::MatchedProperties& a, const StyleResolver::MatchedProperties& b)
1748{
1749    return a.properties == b.properties && a.linkMatchType == b.linkMatchType;
1750}
1751
1752bool operator!=(const StyleResolver::MatchedProperties& a, const StyleResolver::MatchedProperties& b)
1753{
1754    return !(a == b);
1755}
1756
1757const StyleResolver::MatchedPropertiesCacheItem* StyleResolver::findFromMatchedPropertiesCache(unsigned hash, const MatchResult& matchResult)
1758{
1759    ASSERT(hash);
1760
1761    MatchedPropertiesCache::iterator it = m_matchedPropertiesCache.find(hash);
1762    if (it == m_matchedPropertiesCache.end())
1763        return 0;
1764    MatchedPropertiesCacheItem& cacheItem = it->value;
1765
1766    size_t size = matchResult.matchedProperties.size();
1767    if (size != cacheItem.matchedProperties.size())
1768        return 0;
1769    for (size_t i = 0; i < size; ++i) {
1770        if (matchResult.matchedProperties[i] != cacheItem.matchedProperties[i])
1771            return 0;
1772    }
1773    if (cacheItem.ranges != matchResult.ranges)
1774        return 0;
1775    return &cacheItem;
1776}
1777
1778void StyleResolver::addToMatchedPropertiesCache(const RenderStyle* style, const RenderStyle* parentStyle, unsigned hash, const MatchResult& matchResult)
1779{
1780    static const unsigned matchedDeclarationCacheAdditionsBetweenSweeps = 100;
1781    if (++m_matchedPropertiesCacheAdditionsSinceLastSweep >= matchedDeclarationCacheAdditionsBetweenSweeps
1782        && !m_matchedPropertiesCacheSweepTimer.isActive()) {
1783        static const unsigned matchedDeclarationCacheSweepTimeInSeconds = 60;
1784        m_matchedPropertiesCacheSweepTimer.startOneShot(matchedDeclarationCacheSweepTimeInSeconds);
1785    }
1786
1787    ASSERT(hash);
1788    MatchedPropertiesCacheItem cacheItem;
1789    cacheItem.matchedProperties.appendVector(matchResult.matchedProperties);
1790    cacheItem.ranges = matchResult.ranges;
1791    // Note that we don't cache the original RenderStyle instance. It may be further modified.
1792    // The RenderStyle in the cache is really just a holder for the substructures and never used as-is.
1793    cacheItem.renderStyle = RenderStyle::clone(style);
1794    cacheItem.parentRenderStyle = RenderStyle::clone(parentStyle);
1795    m_matchedPropertiesCache.add(hash, cacheItem);
1796}
1797
1798void StyleResolver::invalidateMatchedPropertiesCache()
1799{
1800    m_matchedPropertiesCache.clear();
1801}
1802
1803static bool isCacheableInMatchedPropertiesCache(const Element* element, const RenderStyle* style, const RenderStyle* parentStyle)
1804{
1805    // FIXME: CSSPropertyWebkitWritingMode modifies state when applying to document element. We can't skip the applying by caching.
1806    if (element == element->document()->documentElement() && element->document()->writingModeSetOnDocumentElement())
1807        return false;
1808    if (style->unique() || (style->styleType() != NOPSEUDO && parentStyle->unique()))
1809        return false;
1810    if (style->hasAppearance())
1811        return false;
1812    if (style->zoom() != RenderStyle::initialZoom())
1813        return false;
1814    if (style->writingMode() != RenderStyle::initialWritingMode())
1815        return false;
1816    // The cache assumes static knowledge about which properties are inherited.
1817    if (parentStyle->hasExplicitlyInheritedProperties())
1818        return false;
1819    return true;
1820}
1821
1822void StyleResolver::applyMatchedProperties(const MatchResult& matchResult, const Element* element)
1823{
1824    ASSERT(element);
1825    State& state = m_state;
1826    unsigned cacheHash = matchResult.isCacheable ? computeMatchedPropertiesHash(matchResult.matchedProperties.data(), matchResult.matchedProperties.size()) : 0;
1827    bool applyInheritedOnly = false;
1828    const MatchedPropertiesCacheItem* cacheItem = 0;
1829    if (cacheHash && (cacheItem = findFromMatchedPropertiesCache(cacheHash, matchResult))) {
1830        // We can build up the style by copying non-inherited properties from an earlier style object built using the same exact
1831        // style declarations. We then only need to apply the inherited properties, if any, as their values can depend on the
1832        // element context. This is fast and saves memory by reusing the style data structures.
1833        state.style()->copyNonInheritedFrom(cacheItem->renderStyle.get());
1834        if (state.parentStyle()->inheritedDataShared(cacheItem->parentRenderStyle.get()) && !isAtShadowBoundary(element)) {
1835            EInsideLink linkStatus = state.style()->insideLink();
1836            // If the cache item parent style has identical inherited properties to the current parent style then the
1837            // resulting style will be identical too. We copy the inherited properties over from the cache and are done.
1838            state.style()->inheritFrom(cacheItem->renderStyle.get());
1839
1840            // Unfortunately the link status is treated like an inherited property. We need to explicitly restore it.
1841            state.style()->setInsideLink(linkStatus);
1842            return;
1843        }
1844        applyInheritedOnly = true;
1845    }
1846
1847#if ENABLE(CSS_VARIABLES)
1848    // First apply all variable definitions, as they may be used during application of later properties.
1849    applyMatchedProperties<VariableDefinitions>(matchResult, false, 0, matchResult.matchedProperties.size() - 1, applyInheritedOnly);
1850    applyMatchedProperties<VariableDefinitions>(matchResult, true, matchResult.ranges.firstAuthorRule, matchResult.ranges.lastAuthorRule, applyInheritedOnly);
1851    applyMatchedProperties<VariableDefinitions>(matchResult, true, matchResult.ranges.firstUserRule, matchResult.ranges.lastUserRule, applyInheritedOnly);
1852    applyMatchedProperties<VariableDefinitions>(matchResult, true, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly);
1853#endif
1854
1855    // Now we have all of the matched rules in the appropriate order. Walk the rules and apply
1856    // high-priority properties first, i.e., those properties that other properties depend on.
1857    // The order is (1) high-priority not important, (2) high-priority important, (3) normal not important
1858    // and (4) normal important.
1859    state.setLineHeightValue(0);
1860    applyMatchedProperties<HighPriorityProperties>(matchResult, false, 0, matchResult.matchedProperties.size() - 1, applyInheritedOnly);
1861    applyMatchedProperties<HighPriorityProperties>(matchResult, true, matchResult.ranges.firstAuthorRule, matchResult.ranges.lastAuthorRule, applyInheritedOnly);
1862    applyMatchedProperties<HighPriorityProperties>(matchResult, true, matchResult.ranges.firstUserRule, matchResult.ranges.lastUserRule, applyInheritedOnly);
1863    applyMatchedProperties<HighPriorityProperties>(matchResult, true, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly);
1864
1865    if (cacheItem && cacheItem->renderStyle->effectiveZoom() != state.style()->effectiveZoom()) {
1866        state.setFontDirty(true);
1867        applyInheritedOnly = false;
1868    }
1869
1870    // If our font got dirtied, go ahead and update it now.
1871    updateFont();
1872
1873    // Line-height is set when we are sure we decided on the font-size.
1874    if (state.lineHeightValue())
1875        applyProperty(CSSPropertyLineHeight, state.lineHeightValue());
1876
1877    // Many properties depend on the font. If it changes we just apply all properties.
1878    if (cacheItem && cacheItem->renderStyle->fontDescription() != state.style()->fontDescription())
1879        applyInheritedOnly = false;
1880
1881    // Now do the normal priority UA properties.
1882    applyMatchedProperties<LowPriorityProperties>(matchResult, false, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly);
1883
1884    // Cache our border and background so that we can examine them later.
1885    state.cacheBorderAndBackground();
1886
1887    // Now do the author and user normal priority properties and all the !important properties.
1888    applyMatchedProperties<LowPriorityProperties>(matchResult, false, matchResult.ranges.lastUARule + 1, matchResult.matchedProperties.size() - 1, applyInheritedOnly);
1889    applyMatchedProperties<LowPriorityProperties>(matchResult, true, matchResult.ranges.firstAuthorRule, matchResult.ranges.lastAuthorRule, applyInheritedOnly);
1890    applyMatchedProperties<LowPriorityProperties>(matchResult, true, matchResult.ranges.firstUserRule, matchResult.ranges.lastUserRule, applyInheritedOnly);
1891    applyMatchedProperties<LowPriorityProperties>(matchResult, true, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly);
1892
1893    // Start loading resources referenced by this style.
1894    loadPendingResources();
1895
1896    ASSERT(!state.fontDirty());
1897
1898    if (cacheItem || !cacheHash)
1899        return;
1900    if (!isCacheableInMatchedPropertiesCache(state.element(), state.style(), state.parentStyle()))
1901        return;
1902    addToMatchedPropertiesCache(state.style(), state.parentStyle(), cacheHash, matchResult);
1903}
1904
1905void StyleResolver::applyPropertyToStyle(CSSPropertyID id, CSSValue* value, RenderStyle* style)
1906{
1907    initElement(0);
1908    m_state.initForStyleResolve(document(), 0, style);
1909    m_state.setStyle(style);
1910    applyPropertyToCurrentStyle(id, value);
1911}
1912
1913void StyleResolver::applyPropertyToCurrentStyle(CSSPropertyID id, CSSValue* value)
1914{
1915    if (value)
1916        applyProperty(id, value);
1917}
1918
1919inline bool isValidVisitedLinkProperty(CSSPropertyID id)
1920{
1921    switch (id) {
1922    case CSSPropertyBackgroundColor:
1923    case CSSPropertyBorderLeftColor:
1924    case CSSPropertyBorderRightColor:
1925    case CSSPropertyBorderTopColor:
1926    case CSSPropertyBorderBottomColor:
1927    case CSSPropertyColor:
1928    case CSSPropertyOutlineColor:
1929    case CSSPropertyWebkitColumnRuleColor:
1930#if ENABLE(CSS3_TEXT)
1931    case CSSPropertyWebkitTextDecorationColor:
1932#endif // CSS3_TEXT
1933    case CSSPropertyWebkitTextEmphasisColor:
1934    case CSSPropertyWebkitTextFillColor:
1935    case CSSPropertyWebkitTextStrokeColor:
1936#if ENABLE(SVG)
1937    case CSSPropertyFill:
1938    case CSSPropertyStroke:
1939#endif
1940        return true;
1941    default:
1942        break;
1943    }
1944
1945    return false;
1946}
1947
1948// http://dev.w3.org/csswg/css3-regions/#the-at-region-style-rule
1949// FIXME: add incremental support for other region styling properties.
1950inline bool StyleResolver::isValidRegionStyleProperty(CSSPropertyID id)
1951{
1952    switch (id) {
1953    case CSSPropertyBackgroundColor:
1954    case CSSPropertyColor:
1955        return true;
1956    default:
1957        break;
1958    }
1959
1960    return false;
1961}
1962
1963#if ENABLE(VIDEO_TRACK)
1964inline bool StyleResolver::isValidCueStyleProperty(CSSPropertyID id)
1965{
1966    switch (id) {
1967    case CSSPropertyBackground:
1968    case CSSPropertyBackgroundAttachment:
1969    case CSSPropertyBackgroundClip:
1970    case CSSPropertyBackgroundColor:
1971    case CSSPropertyBackgroundImage:
1972    case CSSPropertyBackgroundOrigin:
1973    case CSSPropertyBackgroundPosition:
1974    case CSSPropertyBackgroundPositionX:
1975    case CSSPropertyBackgroundPositionY:
1976    case CSSPropertyBackgroundRepeat:
1977    case CSSPropertyBackgroundRepeatX:
1978    case CSSPropertyBackgroundRepeatY:
1979    case CSSPropertyBackgroundSize:
1980    case CSSPropertyColor:
1981    case CSSPropertyFont:
1982    case CSSPropertyFontFamily:
1983    case CSSPropertyFontSize:
1984    case CSSPropertyFontStyle:
1985    case CSSPropertyFontVariant:
1986    case CSSPropertyFontWeight:
1987    case CSSPropertyLineHeight:
1988    case CSSPropertyOpacity:
1989    case CSSPropertyOutline:
1990    case CSSPropertyOutlineColor:
1991    case CSSPropertyOutlineOffset:
1992    case CSSPropertyOutlineStyle:
1993    case CSSPropertyOutlineWidth:
1994    case CSSPropertyVisibility:
1995    case CSSPropertyWhiteSpace:
1996    case CSSPropertyTextDecoration:
1997    case CSSPropertyTextShadow:
1998    case CSSPropertyBorderStyle:
1999        return true;
2000    default:
2001        break;
2002    }
2003    return false;
2004}
2005#endif
2006// SVG handles zooming in a different way compared to CSS. The whole document is scaled instead
2007// of each individual length value in the render style / tree. CSSPrimitiveValue::computeLength*()
2008// multiplies each resolved length with the zoom multiplier - so for SVG we need to disable that.
2009// Though all CSS values that can be applied to outermost <svg> elements (width/height/border/padding...)
2010// need to respect the scaling. RenderBox (the parent class of RenderSVGRoot) grabs values like
2011// width/height/border/padding/... from the RenderStyle -> for SVG these values would never scale,
2012// if we'd pass a 1.0 zoom factor everyhwere. So we only pass a zoom factor of 1.0 for specific
2013// properties that are NOT allowed to scale within a zoomed SVG document (letter/word-spacing/font-size).
2014bool StyleResolver::useSVGZoomRules()
2015{
2016    return m_state.element() && m_state.element()->isSVGElement();
2017}
2018
2019static bool createGridTrackBreadth(CSSPrimitiveValue* primitiveValue, const StyleResolver::State& state, Length& workingLength)
2020{
2021    if (primitiveValue->getIdent() == CSSValueWebkitMinContent) {
2022        workingLength = Length(MinContent);
2023        return true;
2024    }
2025
2026    if (primitiveValue->getIdent() == CSSValueWebkitMaxContent) {
2027        workingLength = Length(MaxContent);
2028        return true;
2029    }
2030
2031    workingLength = primitiveValue->convertToLength<FixedIntegerConversion | PercentConversion | ViewportPercentageConversion | AutoConversion>(state.style(), state.rootElementStyle(), state.style()->effectiveZoom());
2032    if (workingLength.isUndefined())
2033        return false;
2034
2035    if (primitiveValue->isLength())
2036        workingLength.setQuirk(primitiveValue->isQuirkValue());
2037
2038    return true;
2039}
2040
2041static bool createGridTrackSize(CSSValue* value, GridTrackSize& trackSize, const StyleResolver::State& state)
2042{
2043    if (!value->isPrimitiveValue())
2044        return false;
2045
2046    CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value);
2047    Pair* minMaxTrackBreadth = primitiveValue->getPairValue();
2048    if (!minMaxTrackBreadth) {
2049        Length workingLength;
2050        if (!createGridTrackBreadth(primitiveValue, state, workingLength))
2051            return false;
2052
2053        trackSize.setLength(workingLength);
2054        return true;
2055    }
2056
2057    Length minTrackBreadth;
2058    Length maxTrackBreadth;
2059    if (!createGridTrackBreadth(minMaxTrackBreadth->first(), state, minTrackBreadth) || !createGridTrackBreadth(minMaxTrackBreadth->second(), state, maxTrackBreadth))
2060        return false;
2061
2062    trackSize.setMinMax(minTrackBreadth, maxTrackBreadth);
2063    return true;
2064}
2065
2066static bool createGridTrackList(CSSValue* value, Vector<GridTrackSize>& trackSizes, const StyleResolver::State& state)
2067{
2068    // Handle 'none'.
2069    if (value->isPrimitiveValue()) {
2070        CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value);
2071        return primitiveValue->getIdent() == CSSValueNone;
2072    }
2073
2074    if (!value->isValueList())
2075        return false;
2076
2077    for (CSSValueListIterator i = value; i.hasMore(); i.advance()) {
2078        CSSValue* currValue = i.value();
2079        GridTrackSize trackSize;
2080        if (!createGridTrackSize(currValue, trackSize, state))
2081            return false;
2082
2083        trackSizes.append(trackSize);
2084    }
2085    return true;
2086}
2087
2088
2089static bool createGridPosition(CSSValue* value, GridPosition& position)
2090{
2091    // For now, we only accept: <integer> | 'auto'
2092    if (!value->isPrimitiveValue())
2093        return false;
2094
2095    CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value);
2096    if (primitiveValue->getIdent() == CSSValueAuto)
2097        return true;
2098
2099    ASSERT_WITH_SECURITY_IMPLICATION(primitiveValue->isNumber());
2100    position.setIntegerPosition(primitiveValue->getIntValue());
2101    return true;
2102}
2103
2104#if ENABLE(CSS_VARIABLES)
2105static bool hasVariableReference(CSSValue* value)
2106{
2107    if (value->isPrimitiveValue()) {
2108        CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value);
2109        return primitiveValue->hasVariableReference();
2110    }
2111
2112    if (value->isCalculationValue())
2113        return static_cast<CSSCalcValue*>(value)->hasVariableReference();
2114
2115    if (value->isReflectValue()) {
2116        CSSReflectValue* reflectValue = static_cast<CSSReflectValue*>(value);
2117        CSSPrimitiveValue* direction = reflectValue->direction();
2118        CSSPrimitiveValue* offset = reflectValue->offset();
2119        CSSValue* mask = reflectValue->mask();
2120        return (direction && hasVariableReference(direction)) || (offset && hasVariableReference(offset)) || (mask && hasVariableReference(mask));
2121    }
2122
2123    for (CSSValueListIterator i = value; i.hasMore(); i.advance()) {
2124        if (hasVariableReference(i.value()))
2125            return true;
2126    }
2127
2128    return false;
2129}
2130
2131void StyleResolver::resolveVariables(CSSPropertyID id, CSSValue* value, Vector<std::pair<CSSPropertyID, String> >& knownExpressions)
2132{
2133    std::pair<CSSPropertyID, String> expression(id, value->serializeResolvingVariables(*m_state.style()->variables()));
2134
2135    if (knownExpressions.contains(expression))
2136        return; // cycle detected.
2137
2138    knownExpressions.append(expression);
2139
2140    // FIXME: It would be faster not to re-parse from strings, but for now CSS property validation lives inside the parser so we do it there.
2141    RefPtr<MutableStylePropertySet> resultSet = MutableStylePropertySet::create();
2142    if (!CSSParser::parseValue(resultSet.get(), id, expression.second, false, document()))
2143        return; // expression failed to parse.
2144
2145    for (unsigned i = 0; i < resultSet->propertyCount(); i++) {
2146        StylePropertySet::PropertyReference property = resultSet->propertyAt(i);
2147        if (property.id() != CSSPropertyVariable && hasVariableReference(property.value()))
2148            resolveVariables(property.id(), property.value(), knownExpressions);
2149        else
2150            applyProperty(property.id(), property.value());
2151    }
2152}
2153#endif
2154
2155void StyleResolver::applyProperty(CSSPropertyID id, CSSValue* value)
2156{
2157#if ENABLE(CSS_VARIABLES)
2158    if (id != CSSPropertyVariable && hasVariableReference(value)) {
2159        Vector<std::pair<CSSPropertyID, String> > knownExpressions;
2160        resolveVariables(id, value, knownExpressions);
2161        return;
2162    }
2163#endif
2164
2165    // CSS variables don't resolve shorthands at parsing time, so this should be *after* handling variables.
2166    ASSERT_WITH_MESSAGE(!isExpandedShorthand(id), "Shorthand property id = %d wasn't expanded at parsing time", id);
2167
2168    State& state = m_state;
2169    bool isInherit = state.parentNode() && value->isInheritedValue();
2170    bool isInitial = value->isInitialValue() || (!state.parentNode() && value->isInheritedValue());
2171
2172    ASSERT(!isInherit || !isInitial); // isInherit -> !isInitial && isInitial -> !isInherit
2173    ASSERT(!isInherit || (state.parentNode() && state.parentStyle())); // isInherit -> (state.parentNode() && state.parentStyle())
2174
2175    if (!state.applyPropertyToRegularStyle() && (!state.applyPropertyToVisitedLinkStyle() || !isValidVisitedLinkProperty(id))) {
2176        // Limit the properties that can be applied to only the ones honored by :visited.
2177        return;
2178    }
2179
2180    if (isInherit && !state.parentStyle()->hasExplicitlyInheritedProperties() && !CSSProperty::isInheritedProperty(id))
2181        state.parentStyle()->setHasExplicitlyInheritedProperties();
2182
2183#if ENABLE(CSS_VARIABLES)
2184    if (id == CSSPropertyVariable) {
2185        ASSERT_WITH_SECURITY_IMPLICATION(value->isVariableValue());
2186        CSSVariableValue* variable = static_cast<CSSVariableValue*>(value);
2187        ASSERT(!variable->name().isEmpty());
2188        ASSERT(!variable->value().isEmpty());
2189        state.style()->setVariable(variable->name(), variable->value());
2190        return;
2191    }
2192#endif
2193
2194    // Check lookup table for implementations and use when available.
2195    const PropertyHandler& handler = m_deprecatedStyleBuilder.propertyHandler(id);
2196    if (handler.isValid()) {
2197        if (isInherit)
2198            handler.applyInheritValue(id, this);
2199        else if (isInitial)
2200            handler.applyInitialValue(id, this);
2201        else
2202            handler.applyValue(id, this, value);
2203        return;
2204    }
2205
2206    CSSPrimitiveValue* primitiveValue = value->isPrimitiveValue() ? static_cast<CSSPrimitiveValue*>(value) : 0;
2207
2208    float zoomFactor = state.style()->effectiveZoom();
2209
2210    // What follows is a list that maps the CSS properties into their corresponding front-end
2211    // RenderStyle values.
2212    switch (id) {
2213    // lists
2214    case CSSPropertyContent:
2215        // list of string, uri, counter, attr, i
2216        {
2217            // FIXME: In CSS3, it will be possible to inherit content. In CSS2 it is not. This
2218            // note is a reminder that eventually "inherit" needs to be supported.
2219
2220            if (isInitial) {
2221                state.style()->clearContent();
2222                return;
2223            }
2224
2225            if (!value->isValueList())
2226                return;
2227
2228            bool didSet = false;
2229            for (CSSValueListIterator i = value; i.hasMore(); i.advance()) {
2230                CSSValue* item = i.value();
2231                if (item->isImageGeneratorValue()) {
2232                    if (item->isGradientValue())
2233                        state.style()->setContent(StyleGeneratedImage::create(static_cast<CSSGradientValue*>(item)->gradientWithStylesResolved(this).get()), didSet);
2234                    else
2235                        state.style()->setContent(StyleGeneratedImage::create(static_cast<CSSImageGeneratorValue*>(item)), didSet);
2236                    didSet = true;
2237#if ENABLE(CSS_IMAGE_SET)
2238                } else if (item->isImageSetValue()) {
2239                    state.style()->setContent(setOrPendingFromValue(CSSPropertyContent, static_cast<CSSImageSetValue*>(item)), didSet);
2240                    didSet = true;
2241#endif
2242                }
2243
2244                if (item->isImageValue()) {
2245                    state.style()->setContent(cachedOrPendingFromValue(CSSPropertyContent, static_cast<CSSImageValue*>(item)), didSet);
2246                    didSet = true;
2247                    continue;
2248                }
2249
2250                if (!item->isPrimitiveValue())
2251                    continue;
2252
2253                CSSPrimitiveValue* contentValue = static_cast<CSSPrimitiveValue*>(item);
2254
2255                if (contentValue->isString()) {
2256                    state.style()->setContent(contentValue->getStringValue().impl(), didSet);
2257                    didSet = true;
2258                } else if (contentValue->isAttr()) {
2259                    // FIXME: Can a namespace be specified for an attr(foo)?
2260                    if (state.style()->styleType() == NOPSEUDO)
2261                        state.style()->setUnique();
2262                    else
2263                        state.parentStyle()->setUnique();
2264                    QualifiedName attr(nullAtom, contentValue->getStringValue().impl(), nullAtom);
2265                    const AtomicString& value = state.element()->getAttribute(attr);
2266                    state.style()->setContent(value.isNull() ? emptyAtom : value.impl(), didSet);
2267                    didSet = true;
2268                    // register the fact that the attribute value affects the style
2269                    m_ruleSets.features().attrsInRules.add(attr.localName().impl());
2270                } else if (contentValue->isCounter()) {
2271                    Counter* counterValue = contentValue->getCounterValue();
2272                    EListStyleType listStyleType = NoneListStyle;
2273                    int listStyleIdent = counterValue->listStyleIdent();
2274                    if (listStyleIdent != CSSValueNone)
2275                        listStyleType = static_cast<EListStyleType>(listStyleIdent - CSSValueDisc);
2276                    OwnPtr<CounterContent> counter = adoptPtr(new CounterContent(counterValue->identifier(), listStyleType, counterValue->separator()));
2277                    state.style()->setContent(counter.release(), didSet);
2278                    didSet = true;
2279                } else {
2280                    switch (contentValue->getIdent()) {
2281                    case CSSValueOpenQuote:
2282                        state.style()->setContent(OPEN_QUOTE, didSet);
2283                        didSet = true;
2284                        break;
2285                    case CSSValueCloseQuote:
2286                        state.style()->setContent(CLOSE_QUOTE, didSet);
2287                        didSet = true;
2288                        break;
2289                    case CSSValueNoOpenQuote:
2290                        state.style()->setContent(NO_OPEN_QUOTE, didSet);
2291                        didSet = true;
2292                        break;
2293                    case CSSValueNoCloseQuote:
2294                        state.style()->setContent(NO_CLOSE_QUOTE, didSet);
2295                        didSet = true;
2296                        break;
2297                    default:
2298                        // normal and none do not have any effect.
2299                        { }
2300                    }
2301                }
2302            }
2303            if (!didSet)
2304                state.style()->clearContent();
2305            return;
2306        }
2307    case CSSPropertyQuotes:
2308        if (isInherit) {
2309            state.style()->setQuotes(state.parentStyle()->quotes());
2310            return;
2311        }
2312        if (isInitial) {
2313            state.style()->setQuotes(0);
2314            return;
2315        }
2316        if (value->isValueList()) {
2317            CSSValueList* list = static_cast<CSSValueList*>(value);
2318            Vector<std::pair<String, String> > quotes;
2319            for (size_t i = 0; i < list->length(); i += 2) {
2320                CSSValue* first = list->itemWithoutBoundsCheck(i);
2321                // item() returns null if out of bounds so this is safe.
2322                CSSValue* second = list->item(i + 1);
2323                if (!second)
2324                    continue;
2325                ASSERT_WITH_SECURITY_IMPLICATION(first->isPrimitiveValue());
2326                ASSERT_WITH_SECURITY_IMPLICATION(second->isPrimitiveValue());
2327                String startQuote = static_cast<CSSPrimitiveValue*>(first)->getStringValue();
2328                String endQuote = static_cast<CSSPrimitiveValue*>(second)->getStringValue();
2329                quotes.append(std::make_pair(startQuote, endQuote));
2330            }
2331            state.style()->setQuotes(QuotesData::create(quotes));
2332            return;
2333        }
2334        if (primitiveValue) {
2335            if (primitiveValue->getIdent() == CSSValueNone)
2336                state.style()->setQuotes(QuotesData::create(Vector<std::pair<String, String> >()));
2337        }
2338        return;
2339    // Shorthand properties.
2340    case CSSPropertyFont:
2341        if (isInherit) {
2342            FontDescription fontDescription = state.parentStyle()->fontDescription();
2343            state.style()->setLineHeight(state.parentStyle()->specifiedLineHeight());
2344            state.setLineHeightValue(0);
2345            setFontDescription(fontDescription);
2346        } else if (isInitial) {
2347            Settings* settings = documentSettings();
2348            ASSERT(settings); // If we're doing style resolution, this document should always be in a frame and thus have settings
2349            if (!settings)
2350                return;
2351            initializeFontStyle(settings);
2352        } else if (primitiveValue) {
2353            state.style()->setLineHeight(RenderStyle::initialLineHeight());
2354            state.setLineHeightValue(0);
2355
2356            FontDescription fontDescription;
2357            RenderTheme::defaultTheme()->systemFont(primitiveValue->getIdent(), fontDescription);
2358
2359            // Double-check and see if the theme did anything. If not, don't bother updating the font.
2360            if (fontDescription.isAbsoluteSize()) {
2361                // Make sure the rendering mode and printer font settings are updated.
2362                Settings* settings = documentSettings();
2363                ASSERT(settings); // If we're doing style resolution, this document should always be in a frame and thus have settings
2364                if (!settings)
2365                    return;
2366                fontDescription.setRenderingMode(settings->fontRenderingMode());
2367                fontDescription.setUsePrinterFont(document()->printing() || !settings->screenFontSubstitutionEnabled());
2368
2369                // Handle the zoom factor.
2370                fontDescription.setComputedSize(getComputedSizeFromSpecifiedSize(document(), state.style(), fontDescription.isAbsoluteSize(), fontDescription.specifiedSize(), useSVGZoomRules()));
2371                setFontDescription(fontDescription);
2372            }
2373        } else if (value->isFontValue()) {
2374            FontValue* font = static_cast<FontValue*>(value);
2375            if (!font->style || !font->variant || !font->weight
2376                || !font->size || !font->lineHeight || !font->family)
2377                return;
2378            applyProperty(CSSPropertyFontStyle, font->style.get());
2379            applyProperty(CSSPropertyFontVariant, font->variant.get());
2380            applyProperty(CSSPropertyFontWeight, font->weight.get());
2381            // The previous properties can dirty our font but they don't try to read the font's
2382            // properties back, which is safe. However if font-size is using the 'ex' unit, it will
2383            // need query the dirtied font's x-height to get the computed size. To be safe in this
2384            // case, let's just update the font now.
2385            updateFont();
2386            applyProperty(CSSPropertyFontSize, font->size.get());
2387
2388            state.setLineHeightValue(font->lineHeight.get());
2389
2390            applyProperty(CSSPropertyFontFamily, font->family.get());
2391        }
2392        return;
2393
2394    case CSSPropertyBackground:
2395    case CSSPropertyBackgroundPosition:
2396    case CSSPropertyBackgroundRepeat:
2397    case CSSPropertyBorder:
2398    case CSSPropertyBorderBottom:
2399    case CSSPropertyBorderColor:
2400    case CSSPropertyBorderImage:
2401    case CSSPropertyBorderLeft:
2402    case CSSPropertyBorderRadius:
2403    case CSSPropertyBorderRight:
2404    case CSSPropertyBorderSpacing:
2405    case CSSPropertyBorderStyle:
2406    case CSSPropertyBorderTop:
2407    case CSSPropertyBorderWidth:
2408    case CSSPropertyListStyle:
2409    case CSSPropertyMargin:
2410    case CSSPropertyOutline:
2411    case CSSPropertyOverflow:
2412    case CSSPropertyPadding:
2413    case CSSPropertyTransition:
2414    case CSSPropertyWebkitAnimation:
2415    case CSSPropertyWebkitBorderAfter:
2416    case CSSPropertyWebkitBorderBefore:
2417    case CSSPropertyWebkitBorderEnd:
2418    case CSSPropertyWebkitBorderStart:
2419    case CSSPropertyWebkitBorderRadius:
2420    case CSSPropertyWebkitColumns:
2421    case CSSPropertyWebkitColumnRule:
2422    case CSSPropertyWebkitFlex:
2423    case CSSPropertyWebkitFlexFlow:
2424    case CSSPropertyWebkitGridColumn:
2425    case CSSPropertyWebkitGridRow:
2426    case CSSPropertyWebkitMarginCollapse:
2427    case CSSPropertyWebkitMarquee:
2428    case CSSPropertyWebkitMask:
2429    case CSSPropertyWebkitMaskPosition:
2430    case CSSPropertyWebkitMaskRepeat:
2431    case CSSPropertyWebkitTextEmphasis:
2432    case CSSPropertyWebkitTextStroke:
2433    case CSSPropertyWebkitTransition:
2434    case CSSPropertyWebkitTransformOrigin:
2435        ASSERT(isExpandedShorthand(id));
2436        ASSERT_NOT_REACHED();
2437        break;
2438
2439    // CSS3 Properties
2440    case CSSPropertyTextShadow:
2441    case CSSPropertyBoxShadow:
2442    case CSSPropertyWebkitBoxShadow: {
2443        if (isInherit) {
2444            if (id == CSSPropertyTextShadow)
2445                return state.style()->setTextShadow(state.parentStyle()->textShadow() ? adoptPtr(new ShadowData(*state.parentStyle()->textShadow())) : nullptr);
2446            return state.style()->setBoxShadow(state.parentStyle()->boxShadow() ? adoptPtr(new ShadowData(*state.parentStyle()->boxShadow())) : nullptr);
2447        }
2448        if (isInitial || primitiveValue) // initial | none
2449            return id == CSSPropertyTextShadow ? state.style()->setTextShadow(nullptr) : state.style()->setBoxShadow(nullptr);
2450
2451        if (!value->isValueList())
2452            return;
2453
2454        for (CSSValueListIterator i = value; i.hasMore(); i.advance()) {
2455            CSSValue* currValue = i.value();
2456            if (!currValue->isShadowValue())
2457                continue;
2458            ShadowValue* item = static_cast<ShadowValue*>(currValue);
2459            int x = item->x->computeLength<int>(state.style(), state.rootElementStyle(), zoomFactor);
2460            int y = item->y->computeLength<int>(state.style(), state.rootElementStyle(), zoomFactor);
2461            int blur = item->blur ? item->blur->computeLength<int>(state.style(), state.rootElementStyle(), zoomFactor) : 0;
2462            int spread = item->spread ? item->spread->computeLength<int>(state.style(), state.rootElementStyle(), zoomFactor) : 0;
2463            ShadowStyle shadowStyle = item->style && item->style->getIdent() == CSSValueInset ? Inset : Normal;
2464            Color color;
2465            if (item->color)
2466                color = colorFromPrimitiveValue(item->color.get());
2467            else if (state.style())
2468                color = state.style()->color();
2469
2470            OwnPtr<ShadowData> shadowData = adoptPtr(new ShadowData(IntPoint(x, y), blur, spread, shadowStyle, id == CSSPropertyWebkitBoxShadow, color.isValid() ? color : Color::transparent));
2471            if (id == CSSPropertyTextShadow)
2472                state.style()->setTextShadow(shadowData.release(), i.index()); // add to the list if this is not the first entry
2473            else
2474                state.style()->setBoxShadow(shadowData.release(), i.index()); // add to the list if this is not the first entry
2475        }
2476        return;
2477    }
2478    case CSSPropertyWebkitBoxReflect: {
2479        HANDLE_INHERIT_AND_INITIAL(boxReflect, BoxReflect)
2480        if (primitiveValue) {
2481            state.style()->setBoxReflect(RenderStyle::initialBoxReflect());
2482            return;
2483        }
2484
2485        if (!value->isReflectValue())
2486            return;
2487
2488        CSSReflectValue* reflectValue = static_cast<CSSReflectValue*>(value);
2489        RefPtr<StyleReflection> reflection = StyleReflection::create();
2490        reflection->setDirection(*reflectValue->direction());
2491        if (reflectValue->offset())
2492            reflection->setOffset(reflectValue->offset()->convertToLength<FixedIntegerConversion | PercentConversion | CalculatedConversion>(state.style(), state.rootElementStyle(), zoomFactor));
2493        NinePieceImage mask;
2494        mask.setMaskDefaults();
2495        m_styleMap.mapNinePieceImage(id, reflectValue->mask(), mask);
2496        reflection->setMask(mask);
2497
2498        state.style()->setBoxReflect(reflection.release());
2499        return;
2500    }
2501    case CSSPropertySrc: // Only used in @font-face rules.
2502        return;
2503    case CSSPropertyUnicodeRange: // Only used in @font-face rules.
2504        return;
2505    case CSSPropertyWebkitLocale: {
2506        HANDLE_INHERIT_AND_INITIAL(locale, Locale);
2507        if (!primitiveValue)
2508            return;
2509        if (primitiveValue->getIdent() == CSSValueAuto)
2510            state.style()->setLocale(nullAtom);
2511        else
2512            state.style()->setLocale(primitiveValue->getStringValue());
2513        FontDescription fontDescription = state.style()->fontDescription();
2514        fontDescription.setScript(localeToScriptCodeForFontSelection(state.style()->locale()));
2515        setFontDescription(fontDescription);
2516        return;
2517    }
2518#if ENABLE(DASHBOARD_SUPPORT)
2519    case CSSPropertyWebkitDashboardRegion:
2520    {
2521        HANDLE_INHERIT_AND_INITIAL(dashboardRegions, DashboardRegions)
2522        if (!primitiveValue)
2523            return;
2524
2525        if (primitiveValue->getIdent() == CSSValueNone) {
2526            state.style()->setDashboardRegions(RenderStyle::noneDashboardRegions());
2527            return;
2528        }
2529
2530        DashboardRegion* region = primitiveValue->getDashboardRegionValue();
2531        if (!region)
2532            return;
2533
2534        DashboardRegion* first = region;
2535        while (region) {
2536            Length top = convertToIntLength(region->top(), state.style(), state.rootElementStyle());
2537            Length right = convertToIntLength(region->right(), state.style(), state.rootElementStyle());
2538            Length bottom = convertToIntLength(region->bottom(), state.style(), state.rootElementStyle());
2539            Length left = convertToIntLength(region->left(), state.style(), state.rootElementStyle());
2540
2541            if (top.isUndefined())
2542                top = Length();
2543            if (right.isUndefined())
2544                right = Length();
2545            if (bottom.isUndefined())
2546                bottom = Length();
2547            if (left.isUndefined())
2548                left = Length();
2549
2550            if (region->m_isCircle)
2551                state.style()->setDashboardRegion(StyleDashboardRegion::Circle, region->m_label, top, right, bottom, left, region == first ? false : true);
2552            else if (region->m_isRectangle)
2553                state.style()->setDashboardRegion(StyleDashboardRegion::Rectangle, region->m_label, top, right, bottom, left, region == first ? false : true);
2554            region = region->m_next.get();
2555        }
2556
2557        state.document()->setHasAnnotatedRegions(true);
2558
2559        return;
2560    }
2561#endif
2562#if ENABLE(DRAGGABLE_REGION)
2563    case CSSPropertyWebkitAppRegion: {
2564        if (!primitiveValue || !primitiveValue->getIdent())
2565            return;
2566        state.style()->setDraggableRegionMode(primitiveValue->getIdent() == CSSValueDrag ? DraggableRegionDrag : DraggableRegionNoDrag);
2567        state.document()->setHasAnnotatedRegions(true);
2568        return;
2569    }
2570#endif
2571    case CSSPropertyWebkitTextStrokeWidth: {
2572        HANDLE_INHERIT_AND_INITIAL(textStrokeWidth, TextStrokeWidth)
2573        float width = 0;
2574        switch (primitiveValue->getIdent()) {
2575        case CSSValueThin:
2576        case CSSValueMedium:
2577        case CSSValueThick: {
2578            double result = 1.0 / 48;
2579            if (primitiveValue->getIdent() == CSSValueMedium)
2580                result *= 3;
2581            else if (primitiveValue->getIdent() == CSSValueThick)
2582                result *= 5;
2583            width = CSSPrimitiveValue::create(result, CSSPrimitiveValue::CSS_EMS)->computeLength<float>(state.style(), state.rootElementStyle(), zoomFactor);
2584            break;
2585        }
2586        default:
2587            width = primitiveValue->computeLength<float>(state.style(), state.rootElementStyle(), zoomFactor);
2588            break;
2589        }
2590        state.style()->setTextStrokeWidth(width);
2591        return;
2592    }
2593    case CSSPropertyWebkitTransform: {
2594        HANDLE_INHERIT_AND_INITIAL(transform, Transform);
2595        TransformOperations operations;
2596        transformsForValue(state.style(), state.rootElementStyle(), value, operations);
2597        state.style()->setTransform(operations);
2598        return;
2599    }
2600    case CSSPropertyWebkitPerspective: {
2601        HANDLE_INHERIT_AND_INITIAL(perspective, Perspective)
2602
2603        if (!primitiveValue)
2604            return;
2605
2606        if (primitiveValue->getIdent() == CSSValueNone) {
2607            state.style()->setPerspective(0);
2608            return;
2609        }
2610
2611        float perspectiveValue;
2612        if (primitiveValue->isLength())
2613            perspectiveValue = primitiveValue->computeLength<float>(state.style(), state.rootElementStyle(), zoomFactor);
2614        else if (primitiveValue->isNumber()) {
2615            // For backward compatibility, treat valueless numbers as px.
2616            perspectiveValue = CSSPrimitiveValue::create(primitiveValue->getDoubleValue(), CSSPrimitiveValue::CSS_PX)->computeLength<float>(state.style(), state.rootElementStyle(), zoomFactor);
2617        } else
2618            return;
2619
2620        if (perspectiveValue >= 0.0f)
2621            state.style()->setPerspective(perspectiveValue);
2622        return;
2623    }
2624#if ENABLE(TOUCH_EVENTS)
2625    case CSSPropertyWebkitTapHighlightColor: {
2626        HANDLE_INHERIT_AND_INITIAL(tapHighlightColor, TapHighlightColor);
2627        if (!primitiveValue)
2628            break;
2629
2630        Color col = colorFromPrimitiveValue(primitiveValue);
2631        state.style()->setTapHighlightColor(col);
2632        return;
2633    }
2634#endif
2635#if ENABLE(ACCELERATED_OVERFLOW_SCROLLING)
2636    case CSSPropertyWebkitOverflowScrolling: {
2637        HANDLE_INHERIT_AND_INITIAL(useTouchOverflowScrolling, UseTouchOverflowScrolling);
2638        if (!primitiveValue)
2639            break;
2640        state.style()->setUseTouchOverflowScrolling(primitiveValue->getIdent() == CSSValueTouch);
2641        return;
2642    }
2643#endif
2644    case CSSPropertyInvalid:
2645        return;
2646    // Directional properties are resolved by resolveDirectionAwareProperty() before the switch.
2647    case CSSPropertyWebkitBorderEndColor:
2648    case CSSPropertyWebkitBorderEndStyle:
2649    case CSSPropertyWebkitBorderEndWidth:
2650    case CSSPropertyWebkitBorderStartColor:
2651    case CSSPropertyWebkitBorderStartStyle:
2652    case CSSPropertyWebkitBorderStartWidth:
2653    case CSSPropertyWebkitBorderBeforeColor:
2654    case CSSPropertyWebkitBorderBeforeStyle:
2655    case CSSPropertyWebkitBorderBeforeWidth:
2656    case CSSPropertyWebkitBorderAfterColor:
2657    case CSSPropertyWebkitBorderAfterStyle:
2658    case CSSPropertyWebkitBorderAfterWidth:
2659    case CSSPropertyWebkitMarginEnd:
2660    case CSSPropertyWebkitMarginStart:
2661    case CSSPropertyWebkitMarginBefore:
2662    case CSSPropertyWebkitMarginAfter:
2663    case CSSPropertyWebkitMarginBeforeCollapse:
2664    case CSSPropertyWebkitMarginTopCollapse:
2665    case CSSPropertyWebkitMarginAfterCollapse:
2666    case CSSPropertyWebkitMarginBottomCollapse:
2667    case CSSPropertyWebkitPaddingEnd:
2668    case CSSPropertyWebkitPaddingStart:
2669    case CSSPropertyWebkitPaddingBefore:
2670    case CSSPropertyWebkitPaddingAfter:
2671    case CSSPropertyWebkitLogicalWidth:
2672    case CSSPropertyWebkitLogicalHeight:
2673    case CSSPropertyWebkitMinLogicalWidth:
2674    case CSSPropertyWebkitMinLogicalHeight:
2675    case CSSPropertyWebkitMaxLogicalWidth:
2676    case CSSPropertyWebkitMaxLogicalHeight:
2677    {
2678        CSSPropertyID newId = CSSProperty::resolveDirectionAwareProperty(id, state.style()->direction(), state.style()->writingMode());
2679        ASSERT(newId != id);
2680        return applyProperty(newId, value);
2681    }
2682    case CSSPropertyFontStretch:
2683    case CSSPropertyPage:
2684    case CSSPropertyTextLineThrough:
2685    case CSSPropertyTextLineThroughColor:
2686    case CSSPropertyTextLineThroughMode:
2687    case CSSPropertyTextLineThroughStyle:
2688    case CSSPropertyTextLineThroughWidth:
2689    case CSSPropertyTextOverline:
2690    case CSSPropertyTextOverlineColor:
2691    case CSSPropertyTextOverlineMode:
2692    case CSSPropertyTextOverlineStyle:
2693    case CSSPropertyTextOverlineWidth:
2694    case CSSPropertyTextUnderline:
2695    case CSSPropertyTextUnderlineColor:
2696    case CSSPropertyTextUnderlineMode:
2697    case CSSPropertyTextUnderlineStyle:
2698    case CSSPropertyTextUnderlineWidth:
2699    case CSSPropertyWebkitFontSizeDelta:
2700    case CSSPropertyWebkitTextDecorationsInEffect:
2701        return;
2702
2703    // CSS Text Layout Module Level 3: Vertical writing support
2704    case CSSPropertyWebkitWritingMode: {
2705        HANDLE_INHERIT_AND_INITIAL(writingMode, WritingMode);
2706
2707        if (primitiveValue)
2708            setWritingMode(*primitiveValue);
2709
2710        // FIXME: It is not ok to modify document state while applying style.
2711        if (state.element() && state.element() == state.document()->documentElement())
2712            state.document()->setWritingModeSetOnDocumentElement(true);
2713        return;
2714    }
2715
2716    case CSSPropertyWebkitTextOrientation: {
2717        HANDLE_INHERIT_AND_INITIAL(textOrientation, TextOrientation);
2718
2719        if (primitiveValue)
2720            setTextOrientation(*primitiveValue);
2721
2722        return;
2723    }
2724
2725    case CSSPropertyWebkitLineBoxContain: {
2726        HANDLE_INHERIT_AND_INITIAL(lineBoxContain, LineBoxContain)
2727        if (primitiveValue && primitiveValue->getIdent() == CSSValueNone) {
2728            state.style()->setLineBoxContain(LineBoxContainNone);
2729            return;
2730        }
2731
2732        if (!value->isCSSLineBoxContainValue())
2733            return;
2734
2735        CSSLineBoxContainValue* lineBoxContainValue = static_cast<CSSLineBoxContainValue*>(value);
2736        state.style()->setLineBoxContain(lineBoxContainValue->value());
2737        return;
2738    }
2739
2740    // CSS Fonts Module Level 3
2741    case CSSPropertyWebkitFontFeatureSettings: {
2742        if (primitiveValue && primitiveValue->getIdent() == CSSValueNormal) {
2743            setFontDescription(state.style()->fontDescription().makeNormalFeatureSettings());
2744            return;
2745        }
2746
2747        if (!value->isValueList())
2748            return;
2749
2750        FontDescription fontDescription = state.style()->fontDescription();
2751        CSSValueList* list = static_cast<CSSValueList*>(value);
2752        RefPtr<FontFeatureSettings> settings = FontFeatureSettings::create();
2753        int len = list->length();
2754        for (int i = 0; i < len; ++i) {
2755            CSSValue* item = list->itemWithoutBoundsCheck(i);
2756            if (!item->isFontFeatureValue())
2757                continue;
2758            FontFeatureValue* feature = static_cast<FontFeatureValue*>(item);
2759            settings->append(FontFeature(feature->tag(), feature->value()));
2760        }
2761        fontDescription.setFeatureSettings(settings.release());
2762        setFontDescription(fontDescription);
2763        return;
2764    }
2765
2766#if ENABLE(CSS_FILTERS)
2767    case CSSPropertyWebkitFilter: {
2768        HANDLE_INHERIT_AND_INITIAL(filter, Filter);
2769        FilterOperations operations;
2770        if (createFilterOperations(value, state.style(), state.rootElementStyle(), operations))
2771            state.style()->setFilter(operations);
2772        return;
2773    }
2774#endif
2775    case CSSPropertyWebkitGridAutoColumns: {
2776        GridTrackSize trackSize;
2777        if (!createGridTrackSize(value, trackSize, state))
2778            return;
2779        state.style()->setGridAutoColumns(trackSize);
2780        return;
2781    }
2782    case CSSPropertyWebkitGridAutoRows: {
2783        GridTrackSize trackSize;
2784        if (!createGridTrackSize(value, trackSize, state))
2785            return;
2786        state.style()->setGridAutoRows(trackSize);
2787        return;
2788    }
2789    case CSSPropertyWebkitGridColumns: {
2790        Vector<GridTrackSize> trackSizes;
2791        if (!createGridTrackList(value, trackSizes, state))
2792            return;
2793        state.style()->setGridColumns(trackSizes);
2794        return;
2795    }
2796    case CSSPropertyWebkitGridRows: {
2797        Vector<GridTrackSize> trackSizes;
2798        if (!createGridTrackList(value, trackSizes, state))
2799            return;
2800        state.style()->setGridRows(trackSizes);
2801        return;
2802    }
2803
2804    case CSSPropertyWebkitGridStart: {
2805        GridPosition startPosition;
2806        if (!createGridPosition(value, startPosition))
2807            return;
2808        state.style()->setGridItemStart(startPosition);
2809        return;
2810    }
2811    case CSSPropertyWebkitGridEnd: {
2812        GridPosition endPosition;
2813        if (!createGridPosition(value, endPosition))
2814            return;
2815        state.style()->setGridItemEnd(endPosition);
2816        return;
2817    }
2818
2819    case CSSPropertyWebkitGridBefore: {
2820        GridPosition beforePosition;
2821        if (!createGridPosition(value, beforePosition))
2822            return;
2823        state.style()->setGridItemBefore(beforePosition);
2824        return;
2825    }
2826    case CSSPropertyWebkitGridAfter: {
2827        GridPosition afterPosition;
2828        if (!createGridPosition(value, afterPosition))
2829            return;
2830        state.style()->setGridItemAfter(afterPosition);
2831        return;
2832    }
2833
2834    // These properties are aliased and DeprecatedStyleBuilder already applied the property on the prefixed version.
2835    case CSSPropertyTransitionDelay:
2836    case CSSPropertyTransitionDuration:
2837    case CSSPropertyTransitionProperty:
2838    case CSSPropertyTransitionTimingFunction:
2839        return;
2840    // These properties are implemented in the DeprecatedStyleBuilder lookup table.
2841    case CSSPropertyBackgroundAttachment:
2842    case CSSPropertyBackgroundClip:
2843    case CSSPropertyBackgroundColor:
2844    case CSSPropertyBackgroundImage:
2845    case CSSPropertyBackgroundOrigin:
2846    case CSSPropertyBackgroundPositionX:
2847    case CSSPropertyBackgroundPositionY:
2848    case CSSPropertyBackgroundRepeatX:
2849    case CSSPropertyBackgroundRepeatY:
2850    case CSSPropertyBackgroundSize:
2851    case CSSPropertyBorderBottomColor:
2852    case CSSPropertyBorderBottomLeftRadius:
2853    case CSSPropertyBorderBottomRightRadius:
2854    case CSSPropertyBorderBottomStyle:
2855    case CSSPropertyBorderBottomWidth:
2856    case CSSPropertyBorderCollapse:
2857    case CSSPropertyBorderImageOutset:
2858    case CSSPropertyBorderImageRepeat:
2859    case CSSPropertyBorderImageSlice:
2860    case CSSPropertyBorderImageSource:
2861    case CSSPropertyBorderImageWidth:
2862    case CSSPropertyBorderLeftColor:
2863    case CSSPropertyBorderLeftStyle:
2864    case CSSPropertyBorderLeftWidth:
2865    case CSSPropertyBorderRightColor:
2866    case CSSPropertyBorderRightStyle:
2867    case CSSPropertyBorderRightWidth:
2868    case CSSPropertyBorderTopColor:
2869    case CSSPropertyBorderTopLeftRadius:
2870    case CSSPropertyBorderTopRightRadius:
2871    case CSSPropertyBorderTopStyle:
2872    case CSSPropertyBorderTopWidth:
2873    case CSSPropertyBottom:
2874    case CSSPropertyBoxSizing:
2875    case CSSPropertyCaptionSide:
2876    case CSSPropertyClear:
2877    case CSSPropertyClip:
2878    case CSSPropertyColor:
2879    case CSSPropertyCounterIncrement:
2880    case CSSPropertyCounterReset:
2881    case CSSPropertyCursor:
2882    case CSSPropertyDirection:
2883    case CSSPropertyDisplay:
2884    case CSSPropertyEmptyCells:
2885    case CSSPropertyFloat:
2886    case CSSPropertyFontSize:
2887    case CSSPropertyFontStyle:
2888    case CSSPropertyFontVariant:
2889    case CSSPropertyFontWeight:
2890    case CSSPropertyHeight:
2891#if ENABLE(CSS_IMAGE_ORIENTATION)
2892    case CSSPropertyImageOrientation:
2893#endif
2894    case CSSPropertyImageRendering:
2895#if ENABLE(CSS_IMAGE_RESOLUTION)
2896    case CSSPropertyImageResolution:
2897#endif
2898    case CSSPropertyLeft:
2899    case CSSPropertyLetterSpacing:
2900    case CSSPropertyLineHeight:
2901    case CSSPropertyListStyleImage:
2902    case CSSPropertyListStylePosition:
2903    case CSSPropertyListStyleType:
2904    case CSSPropertyMarginBottom:
2905    case CSSPropertyMarginLeft:
2906    case CSSPropertyMarginRight:
2907    case CSSPropertyMarginTop:
2908    case CSSPropertyMaxHeight:
2909    case CSSPropertyMaxWidth:
2910    case CSSPropertyMinHeight:
2911    case CSSPropertyMinWidth:
2912    case CSSPropertyOpacity:
2913    case CSSPropertyOrphans:
2914    case CSSPropertyOutlineColor:
2915    case CSSPropertyOutlineOffset:
2916    case CSSPropertyOutlineStyle:
2917    case CSSPropertyOutlineWidth:
2918    case CSSPropertyOverflowWrap:
2919    case CSSPropertyOverflowX:
2920    case CSSPropertyOverflowY:
2921    case CSSPropertyPaddingBottom:
2922    case CSSPropertyPaddingLeft:
2923    case CSSPropertyPaddingRight:
2924    case CSSPropertyPaddingTop:
2925    case CSSPropertyPageBreakAfter:
2926    case CSSPropertyPageBreakBefore:
2927    case CSSPropertyPageBreakInside:
2928    case CSSPropertyPointerEvents:
2929    case CSSPropertyPosition:
2930    case CSSPropertyResize:
2931    case CSSPropertyRight:
2932    case CSSPropertySize:
2933    case CSSPropertySpeak:
2934    case CSSPropertyTabSize:
2935    case CSSPropertyTableLayout:
2936    case CSSPropertyTextAlign:
2937    case CSSPropertyTextDecoration:
2938    case CSSPropertyTextIndent:
2939    case CSSPropertyTextOverflow:
2940    case CSSPropertyTextRendering:
2941    case CSSPropertyTextTransform:
2942    case CSSPropertyTop:
2943    case CSSPropertyUnicodeBidi:
2944#if ENABLE(CSS_VARIABLES)
2945    case CSSPropertyVariable:
2946#endif
2947    case CSSPropertyVerticalAlign:
2948    case CSSPropertyVisibility:
2949    case CSSPropertyWebkitAnimationDelay:
2950    case CSSPropertyWebkitAnimationDirection:
2951    case CSSPropertyWebkitAnimationDuration:
2952    case CSSPropertyWebkitAnimationFillMode:
2953    case CSSPropertyWebkitAnimationIterationCount:
2954    case CSSPropertyWebkitAnimationName:
2955    case CSSPropertyWebkitAnimationPlayState:
2956    case CSSPropertyWebkitAnimationTimingFunction:
2957    case CSSPropertyWebkitAppearance:
2958    case CSSPropertyWebkitAspectRatio:
2959    case CSSPropertyWebkitBackfaceVisibility:
2960    case CSSPropertyWebkitBackgroundClip:
2961    case CSSPropertyWebkitBackgroundComposite:
2962    case CSSPropertyWebkitBackgroundOrigin:
2963    case CSSPropertyWebkitBackgroundSize:
2964    case CSSPropertyWebkitBorderFit:
2965    case CSSPropertyWebkitBorderHorizontalSpacing:
2966    case CSSPropertyWebkitBorderImage:
2967    case CSSPropertyWebkitBorderVerticalSpacing:
2968    case CSSPropertyWebkitBoxAlign:
2969#if ENABLE(CSS_BOX_DECORATION_BREAK)
2970    case CSSPropertyWebkitBoxDecorationBreak:
2971#endif
2972    case CSSPropertyWebkitBoxDirection:
2973    case CSSPropertyWebkitBoxFlex:
2974    case CSSPropertyWebkitBoxFlexGroup:
2975    case CSSPropertyWebkitBoxLines:
2976    case CSSPropertyWebkitBoxOrdinalGroup:
2977    case CSSPropertyWebkitBoxOrient:
2978    case CSSPropertyWebkitBoxPack:
2979    case CSSPropertyWebkitColorCorrection:
2980    case CSSPropertyWebkitColumnAxis:
2981    case CSSPropertyWebkitColumnBreakAfter:
2982    case CSSPropertyWebkitColumnBreakBefore:
2983    case CSSPropertyWebkitColumnBreakInside:
2984    case CSSPropertyWebkitColumnCount:
2985    case CSSPropertyWebkitColumnGap:
2986    case CSSPropertyWebkitColumnProgression:
2987    case CSSPropertyWebkitColumnRuleColor:
2988    case CSSPropertyWebkitColumnRuleStyle:
2989    case CSSPropertyWebkitColumnRuleWidth:
2990    case CSSPropertyWebkitColumnSpan:
2991    case CSSPropertyWebkitColumnWidth:
2992#if ENABLE(CURSOR_VISIBILITY)
2993    case CSSPropertyWebkitCursorVisibility:
2994#endif
2995    case CSSPropertyWebkitAlignContent:
2996    case CSSPropertyWebkitAlignItems:
2997    case CSSPropertyWebkitAlignSelf:
2998    case CSSPropertyWebkitFlexBasis:
2999    case CSSPropertyWebkitFlexDirection:
3000    case CSSPropertyWebkitFlexGrow:
3001    case CSSPropertyWebkitFlexShrink:
3002    case CSSPropertyWebkitFlexWrap:
3003    case CSSPropertyWebkitJustifyContent:
3004    case CSSPropertyWebkitOrder:
3005#if ENABLE(CSS_REGIONS)
3006    case CSSPropertyWebkitFlowFrom:
3007    case CSSPropertyWebkitFlowInto:
3008#endif
3009    case CSSPropertyWebkitFontKerning:
3010    case CSSPropertyWebkitFontSmoothing:
3011    case CSSPropertyWebkitFontVariantLigatures:
3012    case CSSPropertyWebkitHighlight:
3013    case CSSPropertyWebkitHyphenateCharacter:
3014    case CSSPropertyWebkitHyphenateLimitAfter:
3015    case CSSPropertyWebkitHyphenateLimitBefore:
3016    case CSSPropertyWebkitHyphenateLimitLines:
3017    case CSSPropertyWebkitHyphens:
3018    case CSSPropertyWebkitLineAlign:
3019    case CSSPropertyWebkitLineBreak:
3020    case CSSPropertyWebkitLineClamp:
3021    case CSSPropertyWebkitLineGrid:
3022    case CSSPropertyWebkitLineSnap:
3023    case CSSPropertyWebkitMarqueeDirection:
3024    case CSSPropertyWebkitMarqueeIncrement:
3025    case CSSPropertyWebkitMarqueeRepetition:
3026    case CSSPropertyWebkitMarqueeSpeed:
3027    case CSSPropertyWebkitMarqueeStyle:
3028    case CSSPropertyWebkitMaskBoxImage:
3029    case CSSPropertyWebkitMaskBoxImageOutset:
3030    case CSSPropertyWebkitMaskBoxImageRepeat:
3031    case CSSPropertyWebkitMaskBoxImageSlice:
3032    case CSSPropertyWebkitMaskBoxImageSource:
3033    case CSSPropertyWebkitMaskBoxImageWidth:
3034    case CSSPropertyWebkitMaskClip:
3035    case CSSPropertyWebkitMaskComposite:
3036    case CSSPropertyWebkitMaskImage:
3037    case CSSPropertyWebkitMaskOrigin:
3038    case CSSPropertyWebkitMaskPositionX:
3039    case CSSPropertyWebkitMaskPositionY:
3040    case CSSPropertyWebkitMaskRepeatX:
3041    case CSSPropertyWebkitMaskRepeatY:
3042    case CSSPropertyWebkitMaskSize:
3043    case CSSPropertyWebkitNbspMode:
3044    case CSSPropertyWebkitPerspectiveOrigin:
3045    case CSSPropertyWebkitPerspectiveOriginX:
3046    case CSSPropertyWebkitPerspectiveOriginY:
3047    case CSSPropertyWebkitPrintColorAdjust:
3048#if ENABLE(CSS_REGIONS)
3049    case CSSPropertyWebkitRegionBreakAfter:
3050    case CSSPropertyWebkitRegionBreakBefore:
3051    case CSSPropertyWebkitRegionBreakInside:
3052    case CSSPropertyWebkitRegionFragment:
3053#endif
3054    case CSSPropertyWebkitRtlOrdering:
3055    case CSSPropertyWebkitRubyPosition:
3056    case CSSPropertyWebkitTextCombine:
3057#if ENABLE(CSS3_TEXT)
3058    case CSSPropertyWebkitTextDecorationLine:
3059    case CSSPropertyWebkitTextDecorationStyle:
3060    case CSSPropertyWebkitTextDecorationColor:
3061    case CSSPropertyWebkitTextAlignLast:
3062    case CSSPropertyWebkitTextJustify:
3063    case CSSPropertyWebkitTextUnderlinePosition:
3064#endif // CSS3_TEXT
3065    case CSSPropertyWebkitTextEmphasisColor:
3066    case CSSPropertyWebkitTextEmphasisPosition:
3067    case CSSPropertyWebkitTextEmphasisStyle:
3068    case CSSPropertyWebkitTextFillColor:
3069    case CSSPropertyWebkitTextSecurity:
3070    case CSSPropertyWebkitTextStrokeColor:
3071    case CSSPropertyWebkitTransformOriginX:
3072    case CSSPropertyWebkitTransformOriginY:
3073    case CSSPropertyWebkitTransformOriginZ:
3074    case CSSPropertyWebkitTransformStyle:
3075    case CSSPropertyWebkitTransitionDelay:
3076    case CSSPropertyWebkitTransitionDuration:
3077    case CSSPropertyWebkitTransitionProperty:
3078    case CSSPropertyWebkitTransitionTimingFunction:
3079    case CSSPropertyWebkitUserDrag:
3080    case CSSPropertyWebkitUserModify:
3081    case CSSPropertyWebkitUserSelect:
3082    case CSSPropertyWebkitClipPath:
3083#if ENABLE(CSS_SHAPES)
3084    case CSSPropertyWebkitShapeMargin:
3085    case CSSPropertyWebkitShapePadding:
3086    case CSSPropertyWebkitShapeInside:
3087    case CSSPropertyWebkitShapeOutside:
3088#endif
3089#if ENABLE(CSS_EXCLUSIONS)
3090    case CSSPropertyWebkitWrapFlow:
3091    case CSSPropertyWebkitWrapThrough:
3092#endif
3093#if ENABLE(CSS_SHADERS)
3094    case CSSPropertyMix:
3095    case CSSPropertyParameters:
3096#endif
3097    case CSSPropertyWhiteSpace:
3098    case CSSPropertyWidows:
3099    case CSSPropertyWidth:
3100    case CSSPropertyWordBreak:
3101    case CSSPropertyWordSpacing:
3102    case CSSPropertyWordWrap:
3103    case CSSPropertyZIndex:
3104    case CSSPropertyZoom:
3105#if ENABLE(CSS_DEVICE_ADAPTATION)
3106    case CSSPropertyMaxZoom:
3107    case CSSPropertyMinZoom:
3108    case CSSPropertyOrientation:
3109    case CSSPropertyUserZoom:
3110#endif
3111        ASSERT_NOT_REACHED();
3112        return;
3113    default:
3114#if ENABLE(SVG)
3115        // Try the SVG properties
3116        applySVGProperty(id, value);
3117#endif
3118        return;
3119    }
3120}
3121
3122PassRefPtr<StyleImage> StyleResolver::styleImage(CSSPropertyID property, CSSValue* value)
3123{
3124    if (value->isImageValue())
3125        return cachedOrPendingFromValue(property, static_cast<CSSImageValue*>(value));
3126
3127    if (value->isImageGeneratorValue()) {
3128        if (value->isGradientValue())
3129            return generatedOrPendingFromValue(property, static_cast<CSSGradientValue*>(value)->gradientWithStylesResolved(this).get());
3130        return generatedOrPendingFromValue(property, static_cast<CSSImageGeneratorValue*>(value));
3131    }
3132
3133#if ENABLE(CSS_IMAGE_SET)
3134    if (value->isImageSetValue())
3135        return setOrPendingFromValue(property, static_cast<CSSImageSetValue*>(value));
3136#endif
3137
3138    if (value->isCursorImageValue())
3139        return cursorOrPendingFromValue(property, static_cast<CSSCursorImageValue*>(value));
3140
3141    return 0;
3142}
3143
3144PassRefPtr<StyleImage> StyleResolver::cachedOrPendingFromValue(CSSPropertyID property, CSSImageValue* value)
3145{
3146    RefPtr<StyleImage> image = value->cachedOrPendingImage();
3147    if (image && image->isPendingImage())
3148        m_state.pendingImageProperties().set(property, value);
3149    return image.release();
3150}
3151
3152PassRefPtr<StyleImage> StyleResolver::generatedOrPendingFromValue(CSSPropertyID property, CSSImageGeneratorValue* value)
3153{
3154    if (value->isPending()) {
3155        m_state.pendingImageProperties().set(property, value);
3156        return StylePendingImage::create(value);
3157    }
3158    return StyleGeneratedImage::create(value);
3159}
3160
3161#if ENABLE(CSS_IMAGE_SET)
3162PassRefPtr<StyleImage> StyleResolver::setOrPendingFromValue(CSSPropertyID property, CSSImageSetValue* value)
3163{
3164    RefPtr<StyleImage> image = value->cachedOrPendingImageSet(document());
3165    if (image && image->isPendingImage())
3166        m_state.pendingImageProperties().set(property, value);
3167    return image.release();
3168}
3169#endif
3170
3171PassRefPtr<StyleImage> StyleResolver::cursorOrPendingFromValue(CSSPropertyID property, CSSCursorImageValue* value)
3172{
3173    RefPtr<StyleImage> image = value->cachedOrPendingImage(document());
3174    if (image && image->isPendingImage())
3175        m_state.pendingImageProperties().set(property, value);
3176    return image.release();
3177}
3178
3179void StyleResolver::checkForZoomChange(RenderStyle* style, RenderStyle* parentStyle)
3180{
3181    if (style->effectiveZoom() == parentStyle->effectiveZoom())
3182        return;
3183
3184    const FontDescription& childFont = style->fontDescription();
3185    FontDescription newFontDescription(childFont);
3186    setFontSize(newFontDescription, childFont.specifiedSize());
3187    style->setFontDescription(newFontDescription);
3188}
3189
3190void StyleResolver::checkForGenericFamilyChange(RenderStyle* style, RenderStyle* parentStyle)
3191{
3192    const FontDescription& childFont = style->fontDescription();
3193
3194    if (childFont.isAbsoluteSize() || !parentStyle)
3195        return;
3196
3197    const FontDescription& parentFont = parentStyle->fontDescription();
3198    if (childFont.useFixedDefaultSize() == parentFont.useFixedDefaultSize())
3199        return;
3200
3201    // For now, lump all families but monospace together.
3202    if (childFont.genericFamily() != FontDescription::MonospaceFamily
3203        && parentFont.genericFamily() != FontDescription::MonospaceFamily)
3204        return;
3205
3206    // We know the parent is monospace or the child is monospace, and that font
3207    // size was unspecified. We want to scale our font size as appropriate.
3208    // If the font uses a keyword size, then we refetch from the table rather than
3209    // multiplying by our scale factor.
3210    float size;
3211    if (childFont.keywordSize())
3212        size = fontSizeForKeyword(document(), CSSValueXxSmall + childFont.keywordSize() - 1, childFont.useFixedDefaultSize());
3213    else {
3214        Settings* settings = documentSettings();
3215        float fixedScaleFactor = (settings && settings->defaultFixedFontSize() && settings->defaultFontSize())
3216            ? static_cast<float>(settings->defaultFixedFontSize()) / settings->defaultFontSize()
3217            : 1;
3218        size = parentFont.useFixedDefaultSize() ?
3219                childFont.specifiedSize() / fixedScaleFactor :
3220                childFont.specifiedSize() * fixedScaleFactor;
3221    }
3222
3223    FontDescription newFontDescription(childFont);
3224    setFontSize(newFontDescription, size);
3225    style->setFontDescription(newFontDescription);
3226}
3227
3228void StyleResolver::initializeFontStyle(Settings* settings)
3229{
3230    FontDescription fontDescription;
3231    fontDescription.setGenericFamily(FontDescription::StandardFamily);
3232    fontDescription.setRenderingMode(settings->fontRenderingMode());
3233    fontDescription.setUsePrinterFont(document()->printing() || !settings->screenFontSubstitutionEnabled());
3234    const AtomicString& standardFontFamily = documentSettings()->standardFontFamily();
3235    if (!standardFontFamily.isEmpty())
3236        fontDescription.setOneFamily(standardFontFamily);
3237    fontDescription.setKeywordSize(CSSValueMedium - CSSValueXxSmall + 1);
3238    setFontSize(fontDescription, fontSizeForKeyword(document(), CSSValueMedium, false));
3239    m_state.style()->setLineHeight(RenderStyle::initialLineHeight());
3240    m_state.setLineHeightValue(0);
3241    setFontDescription(fontDescription);
3242}
3243
3244void StyleResolver::setFontSize(FontDescription& fontDescription, float size)
3245{
3246    fontDescription.setSpecifiedSize(size);
3247    fontDescription.setComputedSize(getComputedSizeFromSpecifiedSize(document(), m_state.style(), fontDescription.isAbsoluteSize(), size, useSVGZoomRules()));
3248}
3249
3250float StyleResolver::getComputedSizeFromSpecifiedSize(Document* document, RenderStyle* style, bool isAbsoluteSize, float specifiedSize, bool useSVGZoomRules)
3251{
3252    float zoomFactor = 1.0f;
3253    if (!useSVGZoomRules) {
3254        zoomFactor = style->effectiveZoom();
3255        if (Frame* frame = document->frame())
3256            zoomFactor *= frame->textZoomFactor();
3257    }
3258
3259    return StyleResolver::getComputedSizeFromSpecifiedSize(document, zoomFactor, isAbsoluteSize, specifiedSize);
3260}
3261
3262float StyleResolver::getComputedSizeFromSpecifiedSize(Document* document, float zoomFactor, bool isAbsoluteSize, float specifiedSize, ESmartMinimumForFontSize useSmartMinimumForFontSize)
3263{
3264    // Text with a 0px font size should not be visible and therefore needs to be
3265    // exempt from minimum font size rules. Acid3 relies on this for pixel-perfect
3266    // rendering. This is also compatible with other browsers that have minimum
3267    // font size settings (e.g. Firefox).
3268    if (fabsf(specifiedSize) < std::numeric_limits<float>::epsilon())
3269        return 0.0f;
3270
3271    // We support two types of minimum font size. The first is a hard override that applies to
3272    // all fonts. This is "minSize." The second type of minimum font size is a "smart minimum"
3273    // that is applied only when the Web page can't know what size it really asked for, e.g.,
3274    // when it uses logical sizes like "small" or expresses the font-size as a percentage of
3275    // the user's default font setting.
3276
3277    // With the smart minimum, we never want to get smaller than the minimum font size to keep fonts readable.
3278    // However we always allow the page to set an explicit pixel size that is smaller,
3279    // since sites will mis-render otherwise (e.g., http://www.gamespot.com with a 9px minimum).
3280
3281    Settings* settings = document->settings();
3282    if (!settings)
3283        return 1.0f;
3284
3285    int minSize = settings->minimumFontSize();
3286    int minLogicalSize = settings->minimumLogicalFontSize();
3287    float zoomedSize = specifiedSize * zoomFactor;
3288
3289    // Apply the hard minimum first. We only apply the hard minimum if after zooming we're still too small.
3290    if (zoomedSize < minSize)
3291        zoomedSize = minSize;
3292
3293    // Now apply the "smart minimum." This minimum is also only applied if we're still too small
3294    // after zooming. The font size must either be relative to the user default or the original size
3295    // must have been acceptable. In other words, we only apply the smart minimum whenever we're positive
3296    // doing so won't disrupt the layout.
3297    if (useSmartMinimumForFontSize && zoomedSize < minLogicalSize && (specifiedSize >= minLogicalSize || !isAbsoluteSize))
3298        zoomedSize = minLogicalSize;
3299
3300    // Also clamp to a reasonable maximum to prevent insane font sizes from causing crashes on various
3301    // platforms (I'm looking at you, Windows.)
3302    return min(maximumAllowedFontSize, zoomedSize);
3303}
3304
3305const int fontSizeTableMax = 16;
3306const int fontSizeTableMin = 9;
3307const int totalKeywords = 8;
3308
3309// WinIE/Nav4 table for font sizes. Designed to match the legacy font mapping system of HTML.
3310static const int quirksFontSizeTable[fontSizeTableMax - fontSizeTableMin + 1][totalKeywords] =
3311{
3312      { 9,    9,     9,     9,    11,    14,    18,    28 },
3313      { 9,    9,     9,    10,    12,    15,    20,    31 },
3314      { 9,    9,     9,    11,    13,    17,    22,    34 },
3315      { 9,    9,    10,    12,    14,    18,    24,    37 },
3316      { 9,    9,    10,    13,    16,    20,    26,    40 }, // fixed font default (13)
3317      { 9,    9,    11,    14,    17,    21,    28,    42 },
3318      { 9,   10,    12,    15,    17,    23,    30,    45 },
3319      { 9,   10,    13,    16,    18,    24,    32,    48 } // proportional font default (16)
3320};
3321// HTML       1      2      3      4      5      6      7
3322// CSS  xxs   xs     s      m      l     xl     xxl
3323//                          |
3324//                      user pref
3325
3326// Strict mode table matches MacIE and Mozilla's settings exactly.
3327static const int strictFontSizeTable[fontSizeTableMax - fontSizeTableMin + 1][totalKeywords] =
3328{
3329      { 9,    9,     9,     9,    11,    14,    18,    27 },
3330      { 9,    9,     9,    10,    12,    15,    20,    30 },
3331      { 9,    9,    10,    11,    13,    17,    22,    33 },
3332      { 9,    9,    10,    12,    14,    18,    24,    36 },
3333      { 9,   10,    12,    13,    16,    20,    26,    39 }, // fixed font default (13)
3334      { 9,   10,    12,    14,    17,    21,    28,    42 },
3335      { 9,   10,    13,    15,    18,    23,    30,    45 },
3336      { 9,   10,    13,    16,    18,    24,    32,    48 } // proportional font default (16)
3337};
3338// HTML       1      2      3      4      5      6      7
3339// CSS  xxs   xs     s      m      l     xl     xxl
3340//                          |
3341//                      user pref
3342
3343// For values outside the range of the table, we use Todd Fahrner's suggested scale
3344// factors for each keyword value.
3345static const float fontSizeFactors[totalKeywords] = { 0.60f, 0.75f, 0.89f, 1.0f, 1.2f, 1.5f, 2.0f, 3.0f };
3346
3347float StyleResolver::fontSizeForKeyword(Document* document, int keyword, bool shouldUseFixedDefaultSize)
3348{
3349    Settings* settings = document->settings();
3350    if (!settings)
3351        return 1.0f;
3352
3353    bool quirksMode = document->inQuirksMode();
3354    int mediumSize = shouldUseFixedDefaultSize ? settings->defaultFixedFontSize() : settings->defaultFontSize();
3355    if (mediumSize >= fontSizeTableMin && mediumSize <= fontSizeTableMax) {
3356        // Look up the entry in the table.
3357        int row = mediumSize - fontSizeTableMin;
3358        int col = (keyword - CSSValueXxSmall);
3359        return quirksMode ? quirksFontSizeTable[row][col] : strictFontSizeTable[row][col];
3360    }
3361
3362    // Value is outside the range of the table. Apply the scale factor instead.
3363    float minLogicalSize = max(settings->minimumLogicalFontSize(), 1);
3364    return max(fontSizeFactors[keyword - CSSValueXxSmall]*mediumSize, minLogicalSize);
3365}
3366
3367template<typename T>
3368static int findNearestLegacyFontSize(int pixelFontSize, const T* table, int multiplier)
3369{
3370    // Ignore table[0] because xx-small does not correspond to any legacy font size.
3371    for (int i = 1; i < totalKeywords - 1; i++) {
3372        if (pixelFontSize * 2 < (table[i] + table[i + 1]) * multiplier)
3373            return i;
3374    }
3375    return totalKeywords - 1;
3376}
3377
3378int StyleResolver::legacyFontSize(Document* document, int pixelFontSize, bool shouldUseFixedDefaultSize)
3379{
3380    Settings* settings = document->settings();
3381    if (!settings)
3382        return 1;
3383
3384    bool quirksMode = document->inQuirksMode();
3385    int mediumSize = shouldUseFixedDefaultSize ? settings->defaultFixedFontSize() : settings->defaultFontSize();
3386    if (mediumSize >= fontSizeTableMin && mediumSize <= fontSizeTableMax) {
3387        int row = mediumSize - fontSizeTableMin;
3388        return findNearestLegacyFontSize<int>(pixelFontSize, quirksMode ? quirksFontSizeTable[row] : strictFontSizeTable[row], 1);
3389    }
3390
3391    return findNearestLegacyFontSize<float>(pixelFontSize, fontSizeFactors, mediumSize);
3392}
3393
3394static Color colorForCSSValue(int cssValueId)
3395{
3396    struct ColorValue {
3397        int cssValueId;
3398        RGBA32 color;
3399    };
3400
3401    static const ColorValue colorValues[] = {
3402        { CSSValueAqua, 0xFF00FFFF },
3403        { CSSValueBlack, 0xFF000000 },
3404        { CSSValueBlue, 0xFF0000FF },
3405        { CSSValueFuchsia, 0xFFFF00FF },
3406        { CSSValueGray, 0xFF808080 },
3407        { CSSValueGreen, 0xFF008000  },
3408        { CSSValueGrey, 0xFF808080 },
3409        { CSSValueLime, 0xFF00FF00 },
3410        { CSSValueMaroon, 0xFF800000 },
3411        { CSSValueNavy, 0xFF000080 },
3412        { CSSValueOlive, 0xFF808000  },
3413        { CSSValueOrange, 0xFFFFA500 },
3414        { CSSValuePurple, 0xFF800080 },
3415        { CSSValueRed, 0xFFFF0000 },
3416        { CSSValueSilver, 0xFFC0C0C0 },
3417        { CSSValueTeal, 0xFF008080  },
3418        { CSSValueTransparent, 0x00000000 },
3419        { CSSValueWhite, 0xFFFFFFFF },
3420        { CSSValueYellow, 0xFFFFFF00 },
3421        { 0, 0 }
3422    };
3423
3424    for (const ColorValue* col = colorValues; col->cssValueId; ++col) {
3425        if (col->cssValueId == cssValueId)
3426            return col->color;
3427    }
3428    return RenderTheme::defaultTheme()->systemColor(cssValueId);
3429}
3430
3431bool StyleResolver::colorFromPrimitiveValueIsDerivedFromElement(CSSPrimitiveValue* value)
3432{
3433    int ident = value->getIdent();
3434    switch (ident) {
3435    case CSSValueWebkitText:
3436    case CSSValueWebkitLink:
3437    case CSSValueWebkitActivelink:
3438    case CSSValueCurrentcolor:
3439        return true;
3440    default:
3441        return false;
3442    }
3443}
3444
3445Color StyleResolver::colorFromPrimitiveValue(CSSPrimitiveValue* value, bool forVisitedLink) const
3446{
3447    if (value->isRGBColor())
3448        return Color(value->getRGBA32Value());
3449
3450    const State& state = m_state;
3451    int ident = value->getIdent();
3452    switch (ident) {
3453    case 0:
3454        return Color();
3455    case CSSValueWebkitText:
3456        return state.document()->textColor();
3457    case CSSValueWebkitLink:
3458        return (state.element()->isLink() && forVisitedLink) ? state.document()->visitedLinkColor() : state.document()->linkColor();
3459    case CSSValueWebkitActivelink:
3460        return state.document()->activeLinkColor();
3461    case CSSValueWebkitFocusRingColor:
3462        return RenderTheme::focusRingColor();
3463    case CSSValueCurrentcolor:
3464        return state.style()->color();
3465    default:
3466        return colorForCSSValue(ident);
3467    }
3468}
3469
3470void StyleResolver::addViewportDependentMediaQueryResult(const MediaQueryExp* expr, bool result)
3471{
3472    m_viewportDependentMediaQueryResults.append(adoptPtr(new MediaQueryResult(*expr, result)));
3473}
3474
3475bool StyleResolver::affectedByViewportChange() const
3476{
3477    unsigned s = m_viewportDependentMediaQueryResults.size();
3478    for (unsigned i = 0; i < s; i++) {
3479        if (m_medium->eval(&m_viewportDependentMediaQueryResults[i]->m_expression) != m_viewportDependentMediaQueryResults[i]->m_result)
3480            return true;
3481    }
3482    return false;
3483}
3484
3485#if ENABLE(CSS_FILTERS)
3486static FilterOperation::OperationType filterOperationForType(WebKitCSSFilterValue::FilterOperationType type)
3487{
3488    switch (type) {
3489    case WebKitCSSFilterValue::ReferenceFilterOperation:
3490        return FilterOperation::REFERENCE;
3491    case WebKitCSSFilterValue::GrayscaleFilterOperation:
3492        return FilterOperation::GRAYSCALE;
3493    case WebKitCSSFilterValue::SepiaFilterOperation:
3494        return FilterOperation::SEPIA;
3495    case WebKitCSSFilterValue::SaturateFilterOperation:
3496        return FilterOperation::SATURATE;
3497    case WebKitCSSFilterValue::HueRotateFilterOperation:
3498        return FilterOperation::HUE_ROTATE;
3499    case WebKitCSSFilterValue::InvertFilterOperation:
3500        return FilterOperation::INVERT;
3501    case WebKitCSSFilterValue::OpacityFilterOperation:
3502        return FilterOperation::OPACITY;
3503    case WebKitCSSFilterValue::BrightnessFilterOperation:
3504        return FilterOperation::BRIGHTNESS;
3505    case WebKitCSSFilterValue::ContrastFilterOperation:
3506        return FilterOperation::CONTRAST;
3507    case WebKitCSSFilterValue::BlurFilterOperation:
3508        return FilterOperation::BLUR;
3509    case WebKitCSSFilterValue::DropShadowFilterOperation:
3510        return FilterOperation::DROP_SHADOW;
3511#if ENABLE(CSS_SHADERS)
3512    case WebKitCSSFilterValue::CustomFilterOperation:
3513        return FilterOperation::CUSTOM;
3514#endif
3515    case WebKitCSSFilterValue::UnknownFilterOperation:
3516        return FilterOperation::NONE;
3517    }
3518    return FilterOperation::NONE;
3519}
3520
3521#if ENABLE(CSS_FILTERS) && ENABLE(SVG)
3522void StyleResolver::loadPendingSVGDocuments()
3523{
3524    State& state = m_state;
3525
3526    // Crash reports indicate that we've seen calls to this function when our
3527    // style is NULL. We don't know exactly why this happens. Our guess is
3528    // reentering styleForElement().
3529    ASSERT(state.style());
3530    if (!state.style() || !state.style()->hasFilter() || state.pendingSVGDocuments().isEmpty())
3531        return;
3532
3533    CachedResourceLoader* cachedResourceLoader = state.document()->cachedResourceLoader();
3534    Vector<RefPtr<FilterOperation> >& filterOperations = state.style()->mutableFilter().operations();
3535    for (unsigned i = 0; i < filterOperations.size(); ++i) {
3536        RefPtr<FilterOperation> filterOperation = filterOperations.at(i);
3537        if (filterOperation->getOperationType() == FilterOperation::REFERENCE) {
3538            ReferenceFilterOperation* referenceFilter = static_cast<ReferenceFilterOperation*>(filterOperation.get());
3539
3540            WebKitCSSSVGDocumentValue* value = state.pendingSVGDocuments().get(referenceFilter);
3541            if (!value)
3542                continue;
3543            CachedSVGDocument* cachedDocument = value->load(cachedResourceLoader);
3544            if (!cachedDocument)
3545                continue;
3546
3547            // Stash the CachedSVGDocument on the reference filter.
3548            referenceFilter->setCachedSVGDocumentReference(adoptPtr(new CachedSVGDocumentReference(cachedDocument)));
3549        }
3550    }
3551    state.pendingSVGDocuments().clear();
3552}
3553#endif
3554
3555#if ENABLE(CSS_SHADERS)
3556StyleShader* StyleResolver::styleShader(CSSValue* value)
3557{
3558    if (value->isWebKitCSSShaderValue())
3559        return cachedOrPendingStyleShaderFromValue(static_cast<WebKitCSSShaderValue*>(value));
3560    return 0;
3561}
3562
3563StyleShader* StyleResolver::cachedOrPendingStyleShaderFromValue(WebKitCSSShaderValue* value)
3564{
3565    StyleShader* shader = value->cachedOrPendingShader();
3566    if (shader && shader->isPendingShader())
3567        m_state.setHasPendingShaders(true);
3568    return shader;
3569}
3570
3571PassRefPtr<CustomFilterProgram> StyleResolver::lookupCustomFilterProgram(WebKitCSSShaderValue* vertexShader, WebKitCSSShaderValue* fragmentShader,
3572    CustomFilterProgramType programType, const CustomFilterProgramMixSettings& mixSettings, CustomFilterMeshType meshType)
3573{
3574    CachedResourceLoader* cachedResourceLoader = m_state.document()->cachedResourceLoader();
3575    KURL vertexShaderURL = vertexShader ? vertexShader->completeURL(cachedResourceLoader) : KURL();
3576    KURL fragmentShaderURL = fragmentShader ? fragmentShader->completeURL(cachedResourceLoader) : KURL();
3577    RefPtr<StyleCustomFilterProgram> program;
3578    if (m_customFilterProgramCache)
3579        program = m_customFilterProgramCache->lookup(CustomFilterProgramInfo(vertexShaderURL, fragmentShaderURL, programType, mixSettings, meshType));
3580    if (!program) {
3581        // Create a new StyleCustomFilterProgram that will be resolved during the loadPendingShaders and added to the cache.
3582        program = StyleCustomFilterProgram::create(vertexShaderURL, vertexShader ? styleShader(vertexShader) : 0,
3583            fragmentShaderURL, fragmentShader ? styleShader(fragmentShader) : 0, programType, mixSettings, meshType);
3584    }
3585    return program.release();
3586}
3587
3588void StyleResolver::loadPendingShaders()
3589{
3590    // FIXME: We shouldn't have to check that style is non-null. This is a speculative fix for:
3591    // https://bugs.webkit.org/show_bug.cgi?id=117665
3592    if (!m_state.hasPendingShaders() || !m_state.style() || !m_state.style()->hasFilter())
3593        return;
3594
3595    CachedResourceLoader* cachedResourceLoader = m_state.document()->cachedResourceLoader();
3596
3597    Vector<RefPtr<FilterOperation> >& filterOperations = m_state.style()->mutableFilter().operations();
3598    for (unsigned i = 0; i < filterOperations.size(); ++i) {
3599        RefPtr<FilterOperation> filterOperation = filterOperations.at(i);
3600        if (filterOperation->getOperationType() == FilterOperation::CUSTOM) {
3601            CustomFilterOperation* customFilter = static_cast<CustomFilterOperation*>(filterOperation.get());
3602            ASSERT(customFilter->program());
3603            StyleCustomFilterProgram* program = static_cast<StyleCustomFilterProgram*>(customFilter->program());
3604            // Note that the StylePendingShaders could be already resolved to StyleCachedShaders. That's because the rule was matched before.
3605            // However, the StyleCustomFilterProgram that was initially created could have been removed from the cache in the meanwhile,
3606            // meaning that we get a new StyleCustomFilterProgram here that is not yet in the cache, but already has loaded StyleShaders.
3607            if (!program->hasPendingShaders() && program->inCache())
3608                continue;
3609            if (!m_customFilterProgramCache)
3610                m_customFilterProgramCache = adoptPtr(new StyleCustomFilterProgramCache());
3611            RefPtr<StyleCustomFilterProgram> styleProgram = m_customFilterProgramCache->lookup(program);
3612            if (styleProgram.get())
3613                customFilter->setProgram(styleProgram.release());
3614            else {
3615                if (program->vertexShader() && program->vertexShader()->isPendingShader()) {
3616                    WebKitCSSShaderValue* shaderValue = static_cast<StylePendingShader*>(program->vertexShader())->cssShaderValue();
3617                    program->setVertexShader(shaderValue->cachedShader(cachedResourceLoader));
3618                }
3619                if (program->fragmentShader() && program->fragmentShader()->isPendingShader()) {
3620                    WebKitCSSShaderValue* shaderValue = static_cast<StylePendingShader*>(program->fragmentShader())->cssShaderValue();
3621                    program->setFragmentShader(shaderValue->cachedShader(cachedResourceLoader));
3622                }
3623                m_customFilterProgramCache->add(program);
3624            }
3625        }
3626    }
3627    m_state.setHasPendingShaders(false);
3628}
3629
3630static bool sortParametersByNameComparator(const RefPtr<CustomFilterParameter>& a, const RefPtr<CustomFilterParameter>& b)
3631{
3632    return codePointCompareLessThan(a->name(), b->name());
3633}
3634
3635PassRefPtr<CustomFilterParameter> StyleResolver::parseCustomFilterArrayParameter(const String& name, CSSValueList* values, bool isArray)
3636{
3637    RefPtr<CustomFilterArrayParameter> arrayParameter = CustomFilterArrayParameter::create(name, isArray ? CustomFilterArrayParameter::ARRAY : CustomFilterArrayParameter::MATRIX);
3638    for (unsigned i = 0, length = values->length(); i < length; ++i) {
3639        CSSValue* value = values->itemWithoutBoundsCheck(i);
3640        if (!value->isPrimitiveValue())
3641            return 0;
3642        CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value);
3643        if (primitiveValue->primitiveType() != CSSPrimitiveValue::CSS_NUMBER)
3644            return 0;
3645        arrayParameter->addValue(primitiveValue->getDoubleValue());
3646    }
3647    return arrayParameter.release();
3648}
3649
3650PassRefPtr<CustomFilterParameter> StyleResolver::parseCustomFilterColorParameter(const String& name, CSSValueList* values)
3651{
3652    ASSERT(values->length());
3653    CSSPrimitiveValue* firstPrimitiveValue = static_cast<CSSPrimitiveValue*>(values->itemWithoutBoundsCheck(0));
3654    RefPtr<CustomFilterColorParameter> colorParameter = CustomFilterColorParameter::create(name);
3655    colorParameter->setColor(Color(firstPrimitiveValue->getRGBA32Value()));
3656    return colorParameter.release();
3657}
3658
3659PassRefPtr<CustomFilterParameter> StyleResolver::parseCustomFilterNumberParameter(const String& name, CSSValueList* values)
3660{
3661    RefPtr<CustomFilterNumberParameter> numberParameter = CustomFilterNumberParameter::create(name);
3662    for (unsigned i = 0; i < values->length(); ++i) {
3663        CSSValue* value = values->itemWithoutBoundsCheck(i);
3664        if (!value->isPrimitiveValue())
3665            return 0;
3666        CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(value);
3667        if (primitiveValue->primitiveType() != CSSPrimitiveValue::CSS_NUMBER)
3668            return 0;
3669        numberParameter->addValue(primitiveValue->getDoubleValue());
3670    }
3671    return numberParameter.release();
3672}
3673
3674PassRefPtr<CustomFilterParameter> StyleResolver::parseCustomFilterTransformParameter(const String& name, CSSValueList* values)
3675{
3676    RefPtr<CustomFilterTransformParameter> transformParameter = CustomFilterTransformParameter::create(name);
3677    TransformOperations operations;
3678    transformsForValue(m_state.style(), m_state.rootElementStyle(), values, operations);
3679    transformParameter->setOperations(operations);
3680    return transformParameter.release();
3681}
3682
3683PassRefPtr<CustomFilterParameter> StyleResolver::parseCustomFilterParameter(const String& name, CSSValue* parameterValue)
3684{
3685    // FIXME: Implement other parameters types parsing.
3686    // textures: https://bugs.webkit.org/show_bug.cgi?id=71442
3687    // mat2, mat3, mat4: https://bugs.webkit.org/show_bug.cgi?id=71444
3688    // Number parameters are wrapped inside a CSSValueList and all
3689    // the other functions values inherit from CSSValueList.
3690    if (!parameterValue->isValueList())
3691        return 0;
3692
3693    CSSValueList* values = static_cast<CSSValueList*>(parameterValue);
3694    if (!values->length())
3695        return 0;
3696
3697    if (parameterValue->isWebKitCSSArrayFunctionValue())
3698        return parseCustomFilterArrayParameter(name, values, true);
3699
3700    if (parameterValue->isWebKitCSSMatFunctionValue())
3701        return parseCustomFilterArrayParameter(name, values, false);
3702
3703    // If the first value of the list is a transform function,
3704    // then we could safely assume that all the remaining items
3705    // are transforms. parseCustomFilterTransformParameter will
3706    // return 0 if that assumption is incorrect.
3707    if (values->itemWithoutBoundsCheck(0)->isWebKitCSSTransformValue())
3708        return parseCustomFilterTransformParameter(name, values);
3709
3710    // We can only have arrays of colors or numbers, so use the first value to choose between those two.
3711    // We need up to 4 values (all booleans or all numbers).
3712    if (!values->itemWithoutBoundsCheck(0)->isPrimitiveValue() || values->length() > 4)
3713        return 0;
3714
3715    CSSPrimitiveValue* firstPrimitiveValue = static_cast<CSSPrimitiveValue*>(values->itemWithoutBoundsCheck(0));
3716    if (firstPrimitiveValue->primitiveType() == CSSPrimitiveValue::CSS_NUMBER)
3717        return parseCustomFilterNumberParameter(name, values);
3718
3719    if (firstPrimitiveValue->primitiveType() == CSSPrimitiveValue::CSS_RGBCOLOR)
3720        return parseCustomFilterColorParameter(name, values);
3721
3722    return 0;
3723}
3724
3725bool StyleResolver::parseCustomFilterParameterList(CSSValue* parametersValue, CustomFilterParameterList& parameterList)
3726{
3727    HashSet<String> knownParameterNames;
3728    CSSValueListIterator parameterIterator(parametersValue);
3729    for (; parameterIterator.hasMore(); parameterIterator.advance()) {
3730        if (!parameterIterator.value()->isValueList())
3731            return false;
3732        CSSValueListIterator iterator(parameterIterator.value());
3733        if (!iterator.isPrimitiveValue())
3734            return false;
3735        CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(iterator.value());
3736        if (primitiveValue->primitiveType() != CSSPrimitiveValue::CSS_STRING)
3737            return false;
3738
3739        String name = primitiveValue->getStringValue();
3740        // Do not allow duplicate parameter names.
3741        if (knownParameterNames.contains(name))
3742            return false;
3743        knownParameterNames.add(name);
3744
3745        iterator.advance();
3746
3747        if (!iterator.hasMore())
3748            return false;
3749
3750        RefPtr<CustomFilterParameter> parameter = parseCustomFilterParameter(name, iterator.value());
3751        if (!parameter)
3752            return false;
3753        parameterList.append(parameter.release());
3754    }
3755
3756    // Make sure we sort the parameters before passing them down to the CustomFilterOperation.
3757    std::sort(parameterList.begin(), parameterList.end(), sortParametersByNameComparator);
3758
3759    return true;
3760}
3761
3762PassRefPtr<CustomFilterOperation> StyleResolver::createCustomFilterOperationWithAtRuleReferenceSyntax(WebKitCSSFilterValue* filterValue)
3763{
3764    // FIXME: Implement style resolution for the custom filter at-rule reference syntax.
3765    UNUSED_PARAM(filterValue);
3766    return 0;
3767}
3768
3769PassRefPtr<CustomFilterOperation> StyleResolver::createCustomFilterOperationWithInlineSyntax(WebKitCSSFilterValue* filterValue)
3770{
3771    CSSValue* shadersValue = filterValue->itemWithoutBoundsCheck(0);
3772    ASSERT_WITH_SECURITY_IMPLICATION(shadersValue->isValueList());
3773    CSSValueList* shadersList = static_cast<CSSValueList*>(shadersValue);
3774
3775    unsigned shadersListLength = shadersList->length();
3776    ASSERT(shadersListLength);
3777
3778    WebKitCSSShaderValue* vertexShader = toWebKitCSSShaderValue(shadersList->itemWithoutBoundsCheck(0));
3779    WebKitCSSShaderValue* fragmentShader = 0;
3780    CustomFilterProgramType programType = PROGRAM_TYPE_BLENDS_ELEMENT_TEXTURE;
3781    CustomFilterProgramMixSettings mixSettings;
3782
3783    if (shadersListLength > 1) {
3784        CSSValue* fragmentShaderOrMixFunction = shadersList->itemWithoutBoundsCheck(1);
3785        if (fragmentShaderOrMixFunction->isWebKitCSSMixFunctionValue()) {
3786            WebKitCSSMixFunctionValue* mixFunction = static_cast<WebKitCSSMixFunctionValue*>(fragmentShaderOrMixFunction);
3787            CSSValueListIterator iterator(mixFunction);
3788
3789            ASSERT(mixFunction->length());
3790            fragmentShader = toWebKitCSSShaderValue(iterator.value());
3791            iterator.advance();
3792
3793            ASSERT(mixFunction->length() <= 3);
3794            while (iterator.hasMore()) {
3795                CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(iterator.value());
3796                if (CSSParser::isBlendMode(primitiveValue->getIdent()))
3797                    mixSettings.blendMode = *primitiveValue;
3798                else if (CSSParser::isCompositeOperator(primitiveValue->getIdent()))
3799                    mixSettings.compositeOperator = *primitiveValue;
3800                else
3801                    ASSERT_NOT_REACHED();
3802                iterator.advance();
3803            }
3804        } else {
3805            programType = PROGRAM_TYPE_NO_ELEMENT_TEXTURE;
3806            fragmentShader = toWebKitCSSShaderValue(fragmentShaderOrMixFunction);
3807        }
3808    }
3809
3810    if (!vertexShader && !fragmentShader)
3811        return 0;
3812
3813    unsigned meshRows = 1;
3814    unsigned meshColumns = 1;
3815    CustomFilterMeshType meshType = MeshTypeAttached;
3816
3817    CSSValue* parametersValue = 0;
3818
3819    if (filterValue->length() > 1) {
3820        CSSValueListIterator iterator(filterValue->itemWithoutBoundsCheck(1));
3821
3822        // The second value might be the mesh box or the list of parameters:
3823        // If it starts with a number or any of the mesh-box identifiers it is
3824        // the mesh-box list, if not it means it is the parameters list.
3825
3826        if (iterator.hasMore() && iterator.isPrimitiveValue()) {
3827            CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(iterator.value());
3828            if (primitiveValue->isNumber()) {
3829                // If only one integer value is specified, it will set both
3830                // the rows and the columns.
3831                meshColumns = meshRows = primitiveValue->getIntValue();
3832                iterator.advance();
3833
3834                // Try to match another number for the rows.
3835                if (iterator.hasMore() && iterator.isPrimitiveValue()) {
3836                    CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(iterator.value());
3837                    if (primitiveValue->isNumber()) {
3838                        meshRows = primitiveValue->getIntValue();
3839                        iterator.advance();
3840                    }
3841                }
3842            }
3843        }
3844
3845        if (iterator.hasMore() && iterator.isPrimitiveValue()) {
3846            CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(iterator.value());
3847            if (primitiveValue->getIdent() == CSSValueDetached) {
3848                meshType = MeshTypeDetached;
3849                iterator.advance();
3850            }
3851        }
3852
3853        if (!iterator.index()) {
3854            // If no value was consumed from the mesh value, then it is just a parameter list, meaning that we end up
3855            // having just two CSSListValues: list of shaders and list of parameters.
3856            ASSERT(filterValue->length() == 2);
3857            parametersValue = filterValue->itemWithoutBoundsCheck(1);
3858        }
3859    }
3860
3861    if (filterValue->length() > 2 && !parametersValue)
3862        parametersValue = filterValue->itemWithoutBoundsCheck(2);
3863
3864    CustomFilterParameterList parameterList;
3865    if (parametersValue && !parseCustomFilterParameterList(parametersValue, parameterList))
3866        return 0;
3867
3868    RefPtr<CustomFilterProgram> program = lookupCustomFilterProgram(vertexShader, fragmentShader, programType, mixSettings, meshType);
3869    return CustomFilterOperation::create(program.release(), parameterList, meshRows, meshColumns);
3870}
3871
3872PassRefPtr<CustomFilterOperation> StyleResolver::createCustomFilterOperation(WebKitCSSFilterValue* filterValue)
3873{
3874    ASSERT(filterValue->length());
3875    bool isAtRuleReferenceSyntax = filterValue->itemWithoutBoundsCheck(0)->isPrimitiveValue();
3876    return isAtRuleReferenceSyntax ? createCustomFilterOperationWithAtRuleReferenceSyntax(filterValue) : createCustomFilterOperationWithInlineSyntax(filterValue);
3877}
3878
3879#endif
3880
3881bool StyleResolver::createFilterOperations(CSSValue* inValue, RenderStyle* style, RenderStyle* rootStyle, FilterOperations& outOperations)
3882{
3883    ASSERT(outOperations.isEmpty());
3884
3885    if (!inValue)
3886        return false;
3887
3888    if (inValue->isPrimitiveValue()) {
3889        CSSPrimitiveValue* primitiveValue = static_cast<CSSPrimitiveValue*>(inValue);
3890        if (primitiveValue->getIdent() == CSSValueNone)
3891            return true;
3892    }
3893
3894    if (!inValue->isValueList())
3895        return false;
3896
3897    float zoomFactor = style ? style->effectiveZoom() : 1;
3898    FilterOperations operations;
3899    for (CSSValueListIterator i = inValue; i.hasMore(); i.advance()) {
3900        CSSValue* currValue = i.value();
3901        if (!currValue->isWebKitCSSFilterValue())
3902            continue;
3903
3904        WebKitCSSFilterValue* filterValue = static_cast<WebKitCSSFilterValue*>(i.value());
3905        FilterOperation::OperationType operationType = filterOperationForType(filterValue->operationType());
3906
3907#if ENABLE(CSS_SHADERS)
3908        if (operationType == FilterOperation::VALIDATED_CUSTOM) {
3909            // ValidatedCustomFilterOperation is not supposed to end up in the RenderStyle.
3910            ASSERT_NOT_REACHED();
3911            continue;
3912        }
3913        if (operationType == FilterOperation::CUSTOM) {
3914            RefPtr<CustomFilterOperation> operation = createCustomFilterOperation(filterValue);
3915            if (!operation)
3916                return false;
3917
3918            operations.operations().append(operation);
3919            continue;
3920        }
3921#endif
3922        if (operationType == FilterOperation::REFERENCE) {
3923#if ENABLE(SVG)
3924            if (filterValue->length() != 1)
3925                continue;
3926            CSSValue* argument = filterValue->itemWithoutBoundsCheck(0);
3927
3928            if (!argument->isWebKitCSSSVGDocumentValue())
3929                continue;
3930
3931            WebKitCSSSVGDocumentValue* svgDocumentValue = static_cast<WebKitCSSSVGDocumentValue*>(argument);
3932            KURL url = m_state.document()->completeURL(svgDocumentValue->url());
3933
3934            RefPtr<ReferenceFilterOperation> operation = ReferenceFilterOperation::create(svgDocumentValue->url(), url.fragmentIdentifier());
3935            if (SVGURIReference::isExternalURIReference(svgDocumentValue->url(), m_state.document())) {
3936                if (!svgDocumentValue->loadRequested())
3937                    m_state.pendingSVGDocuments().set(operation.get(), svgDocumentValue);
3938                else if (svgDocumentValue->cachedSVGDocument())
3939                    operation->setCachedSVGDocumentReference(adoptPtr(new CachedSVGDocumentReference(svgDocumentValue->cachedSVGDocument())));
3940            }
3941            operations.operations().append(operation);
3942#endif
3943            continue;
3944        }
3945
3946        // Check that all parameters are primitive values, with the
3947        // exception of drop shadow which has a ShadowValue parameter.
3948        if (operationType != FilterOperation::DROP_SHADOW) {
3949            bool haveNonPrimitiveValue = false;
3950            for (unsigned j = 0; j < filterValue->length(); ++j) {
3951                if (!filterValue->itemWithoutBoundsCheck(j)->isPrimitiveValue()) {
3952                    haveNonPrimitiveValue = true;
3953                    break;
3954                }
3955            }
3956            if (haveNonPrimitiveValue)
3957                continue;
3958        }
3959
3960        CSSPrimitiveValue* firstValue = filterValue->length() ? static_cast<CSSPrimitiveValue*>(filterValue->itemWithoutBoundsCheck(0)) : 0;
3961        switch (filterValue->operationType()) {
3962        case WebKitCSSFilterValue::GrayscaleFilterOperation:
3963        case WebKitCSSFilterValue::SepiaFilterOperation:
3964        case WebKitCSSFilterValue::SaturateFilterOperation: {
3965            double amount = 1;
3966            if (filterValue->length() == 1) {
3967                amount = firstValue->getDoubleValue();
3968                if (firstValue->isPercentage())
3969                    amount /= 100;
3970            }
3971
3972            operations.operations().append(BasicColorMatrixFilterOperation::create(amount, operationType));
3973            break;
3974        }
3975        case WebKitCSSFilterValue::HueRotateFilterOperation: {
3976            double angle = 0;
3977            if (filterValue->length() == 1)
3978                angle = firstValue->computeDegrees();
3979
3980            operations.operations().append(BasicColorMatrixFilterOperation::create(angle, operationType));
3981            break;
3982        }
3983        case WebKitCSSFilterValue::InvertFilterOperation:
3984        case WebKitCSSFilterValue::BrightnessFilterOperation:
3985        case WebKitCSSFilterValue::ContrastFilterOperation:
3986        case WebKitCSSFilterValue::OpacityFilterOperation: {
3987            double amount = (filterValue->operationType() == WebKitCSSFilterValue::BrightnessFilterOperation) ? 0 : 1;
3988            if (filterValue->length() == 1) {
3989                amount = firstValue->getDoubleValue();
3990                if (firstValue->isPercentage())
3991                    amount /= 100;
3992            }
3993
3994            operations.operations().append(BasicComponentTransferFilterOperation::create(amount, operationType));
3995            break;
3996        }
3997        case WebKitCSSFilterValue::BlurFilterOperation: {
3998            Length stdDeviation = Length(0, Fixed);
3999            if (filterValue->length() >= 1)
4000                stdDeviation = convertToFloatLength(firstValue, style, rootStyle, zoomFactor);
4001            if (stdDeviation.isUndefined())
4002                return false;
4003
4004            operations.operations().append(BlurFilterOperation::create(stdDeviation));
4005            break;
4006        }
4007        case WebKitCSSFilterValue::DropShadowFilterOperation: {
4008            if (filterValue->length() != 1)
4009                return false;
4010
4011            CSSValue* cssValue = filterValue->itemWithoutBoundsCheck(0);
4012            if (!cssValue->isShadowValue())
4013                continue;
4014
4015            ShadowValue* item = static_cast<ShadowValue*>(cssValue);
4016            IntPoint location(item->x->computeLength<int>(style, rootStyle, zoomFactor),
4017                              item->y->computeLength<int>(style, rootStyle, zoomFactor));
4018            int blur = item->blur ? item->blur->computeLength<int>(style, rootStyle, zoomFactor) : 0;
4019            Color color;
4020            if (item->color)
4021                color = colorFromPrimitiveValue(item->color.get());
4022
4023            operations.operations().append(DropShadowFilterOperation::create(location, blur, color.isValid() ? color : Color::transparent));
4024            break;
4025        }
4026        case WebKitCSSFilterValue::UnknownFilterOperation:
4027        default:
4028            ASSERT_NOT_REACHED();
4029            break;
4030        }
4031    }
4032
4033    outOperations = operations;
4034    return true;
4035}
4036
4037#endif
4038
4039PassRefPtr<StyleImage> StyleResolver::loadPendingImage(StylePendingImage* pendingImage)
4040{
4041    CachedResourceLoader* cachedResourceLoader = m_state.document()->cachedResourceLoader();
4042
4043    if (pendingImage->cssImageValue()) {
4044        CSSImageValue* imageValue = pendingImage->cssImageValue();
4045        return imageValue->cachedImage(cachedResourceLoader);
4046    }
4047
4048    if (pendingImage->cssImageGeneratorValue()) {
4049        CSSImageGeneratorValue* imageGeneratorValue = pendingImage->cssImageGeneratorValue();
4050        imageGeneratorValue->loadSubimages(cachedResourceLoader);
4051        return StyleGeneratedImage::create(imageGeneratorValue);
4052    }
4053
4054    if (pendingImage->cssCursorImageValue()) {
4055        CSSCursorImageValue* cursorImageValue = pendingImage->cssCursorImageValue();
4056        return cursorImageValue->cachedImage(cachedResourceLoader);
4057    }
4058
4059#if ENABLE(CSS_IMAGE_SET)
4060    if (pendingImage->cssImageSetValue()) {
4061        CSSImageSetValue* imageSetValue = pendingImage->cssImageSetValue();
4062        return imageSetValue->cachedImageSet(cachedResourceLoader);
4063    }
4064#endif
4065
4066    return 0;
4067}
4068
4069void StyleResolver::loadPendingImages()
4070{
4071    if (m_state.pendingImageProperties().isEmpty())
4072        return;
4073
4074    PendingImagePropertyMap::const_iterator::Keys end = m_state.pendingImageProperties().end().keys();
4075    for (PendingImagePropertyMap::const_iterator::Keys it = m_state.pendingImageProperties().begin().keys(); it != end; ++it) {
4076        CSSPropertyID currentProperty = *it;
4077
4078        switch (currentProperty) {
4079        case CSSPropertyBackgroundImage: {
4080            for (FillLayer* backgroundLayer = m_state.style()->accessBackgroundLayers(); backgroundLayer; backgroundLayer = backgroundLayer->next()) {
4081                if (backgroundLayer->image() && backgroundLayer->image()->isPendingImage())
4082                    backgroundLayer->setImage(loadPendingImage(static_cast<StylePendingImage*>(backgroundLayer->image())));
4083            }
4084            break;
4085        }
4086        case CSSPropertyContent: {
4087            for (ContentData* contentData = const_cast<ContentData*>(m_state.style()->contentData()); contentData; contentData = contentData->next()) {
4088                if (contentData->isImage()) {
4089                    StyleImage* image = static_cast<ImageContentData*>(contentData)->image();
4090                    if (image->isPendingImage()) {
4091                        RefPtr<StyleImage> loadedImage = loadPendingImage(static_cast<StylePendingImage*>(image));
4092                        if (loadedImage)
4093                            static_cast<ImageContentData*>(contentData)->setImage(loadedImage.release());
4094                    }
4095                }
4096            }
4097            break;
4098        }
4099        case CSSPropertyCursor: {
4100            if (CursorList* cursorList = m_state.style()->cursors()) {
4101                for (size_t i = 0; i < cursorList->size(); ++i) {
4102                    CursorData& currentCursor = cursorList->at(i);
4103                    if (StyleImage* image = currentCursor.image()) {
4104                        if (image->isPendingImage())
4105                            currentCursor.setImage(loadPendingImage(static_cast<StylePendingImage*>(image)));
4106                    }
4107                }
4108            }
4109            break;
4110        }
4111        case CSSPropertyListStyleImage: {
4112            if (m_state.style()->listStyleImage() && m_state.style()->listStyleImage()->isPendingImage())
4113                m_state.style()->setListStyleImage(loadPendingImage(static_cast<StylePendingImage*>(m_state.style()->listStyleImage())));
4114            break;
4115        }
4116        case CSSPropertyBorderImageSource: {
4117            if (m_state.style()->borderImageSource() && m_state.style()->borderImageSource()->isPendingImage())
4118                m_state.style()->setBorderImageSource(loadPendingImage(static_cast<StylePendingImage*>(m_state.style()->borderImageSource())));
4119            break;
4120        }
4121        case CSSPropertyWebkitBoxReflect: {
4122            if (StyleReflection* reflection = m_state.style()->boxReflect()) {
4123                const NinePieceImage& maskImage = reflection->mask();
4124                if (maskImage.image() && maskImage.image()->isPendingImage()) {
4125                    RefPtr<StyleImage> loadedImage = loadPendingImage(static_cast<StylePendingImage*>(maskImage.image()));
4126                    reflection->setMask(NinePieceImage(loadedImage.release(), maskImage.imageSlices(), maskImage.fill(), maskImage.borderSlices(), maskImage.outset(), maskImage.horizontalRule(), maskImage.verticalRule()));
4127                }
4128            }
4129            break;
4130        }
4131        case CSSPropertyWebkitMaskBoxImageSource: {
4132            if (m_state.style()->maskBoxImageSource() && m_state.style()->maskBoxImageSource()->isPendingImage())
4133                m_state.style()->setMaskBoxImageSource(loadPendingImage(static_cast<StylePendingImage*>(m_state.style()->maskBoxImageSource())));
4134            break;
4135        }
4136        case CSSPropertyWebkitMaskImage: {
4137            for (FillLayer* maskLayer = m_state.style()->accessMaskLayers(); maskLayer; maskLayer = maskLayer->next()) {
4138                if (maskLayer->image() && maskLayer->image()->isPendingImage())
4139                    maskLayer->setImage(loadPendingImage(static_cast<StylePendingImage*>(maskLayer->image())));
4140            }
4141            break;
4142        }
4143#if ENABLE(CSS_SHAPES)
4144        case CSSPropertyWebkitShapeInside:
4145            if (m_state.style()->shapeInside() && m_state.style()->shapeInside()->image() && m_state.style()->shapeInside()->image()->isPendingImage())
4146                m_state.style()->shapeInside()->setImage(loadPendingImage(static_cast<StylePendingImage*>(m_state.style()->shapeInside()->image())));
4147            break;
4148        case CSSPropertyWebkitShapeOutside:
4149            if (m_state.style()->shapeOutside() && m_state.style()->shapeOutside()->image() && m_state.style()->shapeOutside()->image()->isPendingImage())
4150                m_state.style()->shapeOutside()->setImage(loadPendingImage(static_cast<StylePendingImage*>(m_state.style()->shapeOutside()->image())));
4151            break;
4152#endif
4153        default:
4154            ASSERT_NOT_REACHED();
4155        }
4156    }
4157
4158    m_state.pendingImageProperties().clear();
4159}
4160
4161#ifndef NDEBUG
4162static bool inLoadPendingResources = false;
4163#endif
4164
4165void StyleResolver::loadPendingResources()
4166{
4167    // We've seen crashes in all three of the functions below. Some of them
4168    // indicate that style() is NULL. This NULL check will cut down on total
4169    // crashes, while the ASSERT will help us find the cause in debug builds.
4170    ASSERT(style());
4171    if (!style())
4172        return;
4173
4174#ifndef NDEBUG
4175    // Re-entering this function will probably mean trouble. Catch it in debug builds.
4176    ASSERT(!inLoadPendingResources);
4177    inLoadPendingResources = true;
4178#endif
4179
4180    // Start loading images referenced by this style.
4181    loadPendingImages();
4182
4183#if ENABLE(CSS_SHADERS)
4184    // Start loading the shaders referenced by this style.
4185    loadPendingShaders();
4186#endif
4187
4188#if ENABLE(CSS_FILTERS) && ENABLE(SVG)
4189    // Start loading the SVG Documents referenced by this style.
4190    loadPendingSVGDocuments();
4191#endif
4192
4193#ifndef NDEBUG
4194    inLoadPendingResources = false;
4195#endif
4196}
4197
4198inline StyleResolver::MatchedProperties::MatchedProperties()
4199    : possiblyPaddedMember(0)
4200{
4201}
4202
4203inline StyleResolver::MatchedProperties::~MatchedProperties()
4204{
4205}
4206
4207} // namespace WebCore
4208