| OLD | NEW | 
|    1 /* |    1 /* | 
|    2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org) |    2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org) | 
|    3  *           (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com) |    3  *           (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com) | 
|    4  * Copyright (C) 2006, 2007 Nicholas Shanks (webkit@nickshanks.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. |    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> |    6  * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org> | 
|    7  * Copyright (C) 2007, 2008 Eric Seidel <eric@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.t
     orchmobile.com/) |    8  * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.t
     orchmobile.com/) | 
|    9  * Copyright (c) 2011, Code Aurora Forum. All rights reserved. |    9  * Copyright (c) 2011, Code Aurora Forum. All rights reserved. | 
|   10  * Copyright (C) Research In Motion Limited 2011. All rights reserved. |   10  * Copyright (C) Research In Motion Limited 2011. All rights reserved. | 
| (...skipping 18 matching lines...) Expand all  Loading... | 
|   29 #include "config.h" |   29 #include "config.h" | 
|   30 #include "core/css/resolver/SharedStyleFinder.h" |   30 #include "core/css/resolver/SharedStyleFinder.h" | 
|   31  |   31  | 
|   32 #include "HTMLNames.h" |   32 #include "HTMLNames.h" | 
|   33 #include "XMLNames.h" |   33 #include "XMLNames.h" | 
|   34 #include "core/css/resolver/StyleResolver.h" |   34 #include "core/css/resolver/StyleResolver.h" | 
|   35 #include "core/css/resolver/StyleResolverState.h" |   35 #include "core/css/resolver/StyleResolverState.h" | 
|   36 #include "core/dom/ContainerNode.h" |   36 #include "core/dom/ContainerNode.h" | 
|   37 #include "core/dom/Document.h" |   37 #include "core/dom/Document.h" | 
|   38 #include "core/dom/Element.h" |   38 #include "core/dom/Element.h" | 
 |   39 #include "core/dom/ElementTraversal.h" | 
|   39 #include "core/dom/FullscreenElementStack.h" |   40 #include "core/dom/FullscreenElementStack.h" | 
|   40 #include "core/dom/Node.h" |   41 #include "core/dom/Node.h" | 
|   41 #include "core/dom/NodeRenderStyle.h" |   42 #include "core/dom/NodeRenderStyle.h" | 
|   42 #include "core/dom/QualifiedName.h" |   43 #include "core/dom/QualifiedName.h" | 
|   43 #include "core/dom/SpaceSplitString.h" |   44 #include "core/dom/SpaceSplitString.h" | 
|   44 #include "core/dom/shadow/ElementShadow.h" |   45 #include "core/dom/shadow/ElementShadow.h" | 
|   45 #include "core/html/HTMLElement.h" |   46 #include "core/html/HTMLElement.h" | 
|   46 #include "core/html/HTMLInputElement.h" |   47 #include "core/html/HTMLInputElement.h" | 
|   47 #include "core/html/HTMLOptGroupElement.h" |   48 #include "core/html/HTMLOptGroupElement.h" | 
|   48 #include "core/html/track/WebVTTElement.h" |   49 #include "core/html/track/WebVTTElement.h" | 
|   49 #include "core/rendering/style/RenderStyle.h" |   50 #include "core/rendering/style/RenderStyle.h" | 
|   50 #include "core/svg/SVGElement.h" |   51 #include "core/svg/SVGElement.h" | 
|   51 #include "wtf/HashSet.h" |   52 #include "wtf/HashSet.h" | 
|   52 #include "wtf/text/AtomicString.h" |   53 #include "wtf/text/AtomicString.h" | 
|   53  |   54  | 
|   54 namespace WebCore { |   55 namespace WebCore { | 
|   55  |   56  | 
|   56 using namespace HTMLNames; |   57 using namespace HTMLNames; | 
|   57  |   58  | 
|   58 static const unsigned cStyleSearchThreshold = 10; |  | 
|   59 static const unsigned cStyleSearchLevelThreshold = 10; |  | 
|   60  |  | 
|   61 static inline bool parentElementPreventsSharing(const Element* parentElement) |   59 static inline bool parentElementPreventsSharing(const Element* parentElement) | 
|   62 { |   60 { | 
|   63     if (!parentElement) |  | 
|   64         return false; |  | 
|   65     return parentElement->hasFlagsSetDuringStylingOfChildren(); |   61     return parentElement->hasFlagsSetDuringStylingOfChildren(); | 
|   66 } |   62 } | 
|   67  |   63  | 
|   68 Node* SharedStyleFinder::locateCousinList(Element* parent, unsigned& visitedNode
     Count) const |  | 
|   69 { |  | 
|   70     if (visitedNodeCount >= cStyleSearchThreshold * cStyleSearchLevelThreshold) |  | 
|   71         return 0; |  | 
|   72     if (!parent || !parent->isStyledElement()) |  | 
|   73         return 0; |  | 
|   74     if (parent->hasScopedHTMLStyleChild()) |  | 
|   75         return 0; |  | 
|   76     if (parent->inlineStyle()) |  | 
|   77         return 0; |  | 
|   78     if (parent->isSVGElement() && toSVGElement(parent)->animatedSMILStylePropert
     ies()) |  | 
|   79         return 0; |  | 
|   80     if (parent->hasID() && m_features.idsInRules.contains(parent->idForStyleReso
     lution().impl())) |  | 
|   81         return 0; |  | 
|   82     if (isShadowHost(parent) && parent->shadow()->containsActiveStyles()) |  | 
|   83         return 0; |  | 
|   84  |  | 
|   85     RenderStyle* parentStyle = parent->renderStyle(); |  | 
|   86     unsigned subcount = 0; |  | 
|   87     Node* thisCousin = parent; |  | 
|   88     Node* currentNode = parent->previousSibling(); |  | 
|   89  |  | 
|   90     // Reserve the tries for this level. This effectively makes sure that the al
     gorithm |  | 
|   91     // will never go deeper than cStyleSearchLevelThreshold levels into recursio
     n. |  | 
|   92     visitedNodeCount += cStyleSearchThreshold; |  | 
|   93     while (thisCousin) { |  | 
|   94         while (currentNode) { |  | 
|   95             ++subcount; |  | 
|   96             if (!currentNode->hasScopedHTMLStyleChild() && currentNode->renderSt
     yle() == parentStyle && currentNode->lastChild() |  | 
|   97                 && currentNode->isElementNode() && !parentElementPreventsSharing
     (toElement(currentNode)) |  | 
|   98                 && !toElement(currentNode)->shadow() |  | 
|   99                 ) { |  | 
|  100                 // Adjust for unused reserved tries. |  | 
|  101                 visitedNodeCount -= cStyleSearchThreshold - subcount; |  | 
|  102                 return currentNode->lastChild(); |  | 
|  103             } |  | 
|  104             if (subcount >= cStyleSearchThreshold) |  | 
|  105                 return 0; |  | 
|  106             currentNode = currentNode->previousSibling(); |  | 
|  107         } |  | 
|  108         currentNode = locateCousinList(thisCousin->parentElement(), visitedNodeC
     ount); |  | 
|  109         thisCousin = currentNode; |  | 
|  110     } |  | 
|  111  |  | 
|  112     return 0; |  | 
|  113 } |  | 
|  114  |  | 
|  115  |  | 
|  116 bool SharedStyleFinder::canShareStyleWithControl(const ElementResolveContext& co
     ntext, Element* element) const |   64 bool SharedStyleFinder::canShareStyleWithControl(const ElementResolveContext& co
     ntext, Element* element) const | 
|  117 { |   65 { | 
|  118     if (!element->hasTagName(inputTag) || !context.element()->hasTagName(inputTa
     g)) |   66     if (!element->hasTagName(inputTag) || !context.element()->hasTagName(inputTa
     g)) | 
|  119         return false; |   67         return false; | 
|  120  |   68  | 
|  121     HTMLInputElement* thisInputElement = toHTMLInputElement(element); |   69     HTMLInputElement* thisInputElement = toHTMLInputElement(element); | 
|  122     HTMLInputElement* otherInputElement = toHTMLInputElement(context.element()); |   70     HTMLInputElement* otherInputElement = toHTMLInputElement(context.element()); | 
|  123     if (thisInputElement->elementData() != otherInputElement->elementData()) { |   71     if (thisInputElement->elementData() != otherInputElement->elementData()) { | 
|  124         if (thisInputElement->fastGetAttribute(typeAttr) != otherInputElement->f
     astGetAttribute(typeAttr)) |   72         if (thisInputElement->fastGetAttribute(typeAttr) != otherInputElement->f
     astGetAttribute(typeAttr)) | 
|  125             return false; |   73             return false; | 
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  206     if (context.element()->hasTagName(progressTag)) { |  154     if (context.element()->hasTagName(progressTag)) { | 
|  207         if (context.element()->shouldAppearIndeterminate() != sharingCandidate->
     shouldAppearIndeterminate()) |  155         if (context.element()->shouldAppearIndeterminate() != sharingCandidate->
     shouldAppearIndeterminate()) | 
|  208             return false; |  156             return false; | 
|  209     } |  157     } | 
|  210  |  158  | 
|  211     return true; |  159     return true; | 
|  212 } |  160 } | 
|  213  |  161  | 
|  214 bool SharedStyleFinder::canShareStyleWithElement(const ElementResolveContext& co
     ntext, Element* element) const |  162 bool SharedStyleFinder::canShareStyleWithElement(const ElementResolveContext& co
     ntext, Element* element) const | 
|  215 { |  163 { | 
 |  164     if (context.element() == element) | 
 |  165         return false; | 
 |  166     Element* parent = element->parentElement(); | 
|  216     RenderStyle* style = element->renderStyle(); |  167     RenderStyle* style = element->renderStyle(); | 
|  217     if (!style) |  168     if (!style) | 
|  218         return false; |  169         return false; | 
 |  170     if (!parent) | 
 |  171         return false; | 
 |  172     if (context.element()->parentElement()->renderStyle() != parent->renderStyle
     ()) | 
 |  173         return false; | 
|  219     if (style->unique()) |  174     if (style->unique()) | 
|  220         return false; |  175         return false; | 
|  221     if (style->hasUniquePseudoStyle()) |  176     if (style->hasUniquePseudoStyle()) | 
|  222         return false; |  177         return false; | 
|  223     if (element->tagQName() != context.element()->tagQName()) |  178     if (element->tagQName() != context.element()->tagQName()) | 
|  224         return false; |  179         return false; | 
|  225     if (element->inlineStyle()) |  180     if (element->inlineStyle()) | 
|  226         return false; |  181         return false; | 
|  227     if (element->needsStyleRecalc()) |  182     if (element->needsStyleRecalc()) | 
|  228         return false; |  183         return false; | 
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  288         return false; |  243         return false; | 
|  289  |  244  | 
|  290     if (element->isWebVTTElement() && context.element()->isWebVTTElement() && to
     WebVTTElement(element)->isPastNode() != toWebVTTElement(context.element())->isPa
     stNode()) |  245     if (element->isWebVTTElement() && context.element()->isWebVTTElement() && to
     WebVTTElement(element)->isPastNode() != toWebVTTElement(context.element())->isPa
     stNode()) | 
|  291         return false; |  246         return false; | 
|  292  |  247  | 
|  293     if (FullscreenElementStack* fullscreen = FullscreenElementStack::fromIfExist
     s(&context.document())) { |  248     if (FullscreenElementStack* fullscreen = FullscreenElementStack::fromIfExist
     s(&context.document())) { | 
|  294         if (element == fullscreen->webkitCurrentFullScreenElement() || context.e
     lement() == fullscreen->webkitCurrentFullScreenElement()) |  249         if (element == fullscreen->webkitCurrentFullScreenElement() || context.e
     lement() == fullscreen->webkitCurrentFullScreenElement()) | 
|  295             return false; |  250             return false; | 
|  296     } |  251     } | 
|  297  |  252  | 
 |  253     if (context.element()->parentElement() != parent) { | 
 |  254         if (!parent->isStyledElement()) | 
 |  255             return false; | 
 |  256         if (parent->hasScopedHTMLStyleChild()) | 
 |  257             return false; | 
 |  258         if (parent->inlineStyle()) | 
 |  259             return false; | 
 |  260         if (parent->isSVGElement() && toSVGElement(parent)->animatedSMILStylePro
     perties()) | 
 |  261             return false; | 
 |  262         if (parent->hasID() && m_features.idsInRules.contains(parent->idForStyle
     Resolution().impl())) | 
 |  263             return false; | 
 |  264         if (parentElementPreventsSharing(parent)) | 
 |  265             return false; | 
 |  266     } | 
 |  267  | 
|  298     return true; |  268     return true; | 
|  299 } |  269 } | 
|  300  |  270  | 
|  301 inline Element* SharedStyleFinder::findSiblingForStyleSharing(const ElementResol
     veContext& context, Node* node, unsigned& count) const |  | 
|  302 { |  | 
|  303     for (; node; node = node->previousSibling()) { |  | 
|  304         if (!node->isStyledElement()) |  | 
|  305             continue; |  | 
|  306         if (canShareStyleWithElement(context, toElement(node))) |  | 
|  307             break; |  | 
|  308         if (count++ == cStyleSearchThreshold) |  | 
|  309             return 0; |  | 
|  310     } |  | 
|  311     return toElement(node); |  | 
|  312 } |  | 
|  313  |  | 
|  314 #ifdef STYLE_STATS |  271 #ifdef STYLE_STATS | 
|  315 Element* SharedStyleFinder::searchDocumentForSharedStyle(const ElementResolveCon
     text& context) const |  272 Element* SharedStyleFinder::searchDocumentForSharedStyle(const ElementResolveCon
     text& context) const | 
|  316 { |  273 { | 
|  317     for (Element* element = context.element()->document().documentElement(); ele
     ment; element = ElementTraversal::next(element)) { |  274     for (Element* element = context.element()->document().documentElement(); ele
     ment; element = ElementTraversal::next(element)) { | 
|  318         if (canShareStyleWithElement(context, element)) |  275         if (canShareStyleWithElement(context, element)) | 
|  319             return element; |  276             return element; | 
|  320     } |  277     } | 
|  321     return 0; |  278     return 0; | 
|  322 } |  279 } | 
|  323 #endif |  280 #endif | 
|  324  |  281  | 
 |  282 inline Element* SharedStyleFinder::findElementForStyleSharing(const ElementResol
     veContext& context) const | 
 |  283 { | 
 |  284     StyleSharingList& styleSharingList = m_styleResolver->styleSharingList(); | 
 |  285     for (StyleSharingList::iterator it = styleSharingList.begin(); it != styleSh
     aringList.end(); ++it) { | 
 |  286         if (!canShareStyleWithElement(context, it->get())) | 
 |  287             continue; | 
 |  288         Element* element = it->get(); | 
 |  289         if (it != styleSharingList.begin()) { | 
 |  290             // Move the element to the front of the LRU | 
 |  291             styleSharingList.remove(it); | 
 |  292             styleSharingList.prepend(element); | 
 |  293         } | 
 |  294         return element; | 
 |  295     } | 
 |  296     m_styleResolver->addToStyleSharingList(context.element()); | 
 |  297     return 0; | 
 |  298 } | 
 |  299  | 
|  325 RenderStyle* SharedStyleFinder::locateSharedStyle(const ElementResolveContext& c
     ontext, RenderStyle* newStyle) |  300 RenderStyle* SharedStyleFinder::locateSharedStyle(const ElementResolveContext& c
     ontext, RenderStyle* newStyle) | 
|  326 { |  301 { | 
|  327     STYLE_STATS_ADD_SEARCH(); |  302     STYLE_STATS_ADD_SEARCH(); | 
|  328     if (!context.element() || !context.element()->isStyledElement()) |  | 
|  329         return 0; |  | 
|  330  |  303  | 
|  331     // If the element has inline style it is probably unique. |  304     if (!m_styleResolver->supportsStyleSharing(context.element())) | 
|  332     if (context.element()->inlineStyle()) |  | 
|  333         return 0; |  | 
|  334     if (context.element()->isSVGElement() && toSVGElement(context.element())->an
     imatedSMILStyleProperties()) |  | 
|  335         return 0; |  | 
|  336     // Ids stop style sharing if they show up in the stylesheets. |  | 
|  337     if (context.element()->hasID() && m_features.idsInRules.contains(context.ele
     ment()->idForStyleResolution().impl())) |  | 
|  338         return 0; |  | 
|  339     // Active and hovered elements always make a chain towards the document node |  | 
|  340     // and no siblings or cousins will have the same state. |  | 
|  341     if (context.element()->hovered()) |  | 
|  342         return 0; |  | 
|  343     if (context.element()->active()) |  | 
|  344         return 0; |  | 
|  345     // There is always only one focused element. |  | 
|  346     if (context.element()->focused()) |  | 
|  347         return 0; |  | 
|  348     if (parentElementPreventsSharing(context.element()->parentElement())) |  | 
|  349         return 0; |  | 
|  350     if (context.element()->hasScopedHTMLStyleChild()) |  | 
|  351         return 0; |  | 
|  352     if (context.element() == context.document().cssTarget()) |  | 
|  353         return 0; |  | 
|  354     if (elementHasDirectionAuto(context.element())) |  | 
|  355         return 0; |  | 
|  356     if (context.element()->hasActiveAnimations()) |  | 
|  357         return 0; |  | 
|  358     // When a dialog is first shown, its style is mutated to center it in the |  | 
|  359     // viewport. So the styles can't be shared since the viewport position and |  | 
|  360     // size may be different each time a dialog is opened. |  | 
|  361     if (context.element()->hasTagName(dialogTag)) |  | 
|  362         return 0; |  | 
|  363     if (isShadowHost(context.element()) && context.element()->shadow()->contains
     ActiveStyles()) |  | 
|  364         return 0; |  305         return 0; | 
|  365  |  306  | 
|  366     STYLE_STATS_ADD_ELEMENT_ELIGIBLE_FOR_SHARING(); |  307     STYLE_STATS_ADD_ELEMENT_ELIGIBLE_FOR_SHARING(); | 
|  367  |  308  | 
|  368     // Cache whether context.element() is affected by any known class selectors. |  309     // Cache whether context.element() is affected by any known class selectors. | 
|  369     // FIXME: This should be an explicit out parameter, instead of a member vari
     able. |  310     // FIXME: This should be an explicit out parameter, instead of a member vari
     able. | 
|  370     m_elementAffectedByClassRules = context.element() && context.element()->hasC
     lass() && classNamesAffectedByRules(context.element()->classNames()); |  311     m_elementAffectedByClassRules = context.element() && context.element()->hasC
     lass() && classNamesAffectedByRules(context.element()->classNames()); | 
|  371  |  312  | 
|  372     // Check previous siblings and their cousins. |  313     Element* shareElement = findElementForStyleSharing(context); | 
|  373     unsigned count = 0; |  | 
|  374     unsigned visitedNodeCount = 0; |  | 
|  375     Element* shareElement = 0; |  | 
|  376     Node* cousinList = context.element()->previousSibling(); |  | 
|  377     while (cousinList) { |  | 
|  378         shareElement = findSiblingForStyleSharing(context, cousinList, count); |  | 
|  379         if (shareElement) |  | 
|  380             break; |  | 
|  381         cousinList = locateCousinList(cousinList->parentElement(), visitedNodeCo
     unt); |  | 
|  382     } |  | 
|  383  |  314  | 
|  384 #ifdef STYLE_STATS |  315 #ifdef STYLE_STATS | 
|  385     // FIXME: these stats don't to into account whether or not sibling/attribute |  316     // FIXME: these stats don't to into account whether or not sibling/attribute | 
|  386     // rules prevent these nodes from actually sharing |  317     // rules prevent these nodes from actually sharing | 
|  387     if (shareElement) { |  318     if (shareElement) { | 
|  388         STYLE_STATS_ADD_SEARCH_FOUND_SIBLING_FOR_SHARING(); |  319         STYLE_STATS_ADD_SEARCH_FOUND_SIBLING_FOR_SHARING(); | 
|  389     } else { |  320     } else { | 
|  390         shareElement = searchDocumentForSharedStyle(context); |  321         shareElement = searchDocumentForSharedStyle(context); | 
|  391         if (shareElement) |  322         if (shareElement) | 
|  392             STYLE_STATS_ADD_SEARCH_MISSED_SHARING(); |  323             STYLE_STATS_ADD_SEARCH_MISSED_SHARING(); | 
| (...skipping 12 matching lines...) Expand all  Loading... | 
|  405     if (m_styleResolver->styleSharingCandidateMatchesRuleSet(context, newStyle, 
     m_uncommonAttributeRuleSet)) |  336     if (m_styleResolver->styleSharingCandidateMatchesRuleSet(context, newStyle, 
     m_uncommonAttributeRuleSet)) | 
|  406         return 0; |  337         return 0; | 
|  407     // Tracking child index requires unique style for each node. This may get se
     t by the sibling rule match above. |  338     // Tracking child index requires unique style for each node. This may get se
     t by the sibling rule match above. | 
|  408     if (parentElementPreventsSharing(context.element()->parentElement())) |  339     if (parentElementPreventsSharing(context.element()->parentElement())) | 
|  409         return 0; |  340         return 0; | 
|  410     STYLE_STATS_ADD_STYLE_SHARED(); |  341     STYLE_STATS_ADD_STYLE_SHARED(); | 
|  411     return shareElement->renderStyle(); |  342     return shareElement->renderStyle(); | 
|  412 } |  343 } | 
|  413  |  344  | 
|  414 } |  345 } | 
| OLD | NEW |