| Index: Source/core/css/resolver/SharedStyleFinder.cpp
|
| diff --git a/Source/core/css/resolver/SharedStyleFinder.cpp b/Source/core/css/resolver/SharedStyleFinder.cpp
|
| index d3899ad104264c3fedf910cce73c48442e7ecf42..ee83ce26fadc855efcfe5b60788b01e685bf38d4 100644
|
| --- a/Source/core/css/resolver/SharedStyleFinder.cpp
|
| +++ b/Source/core/css/resolver/SharedStyleFinder.cpp
|
| @@ -56,11 +56,64 @@ namespace WebCore {
|
|
|
| using namespace HTMLNames;
|
|
|
| +static const unsigned cStyleSearchThreshold = 10;
|
| +static const unsigned cStyleSearchLevelThreshold = 10;
|
| +
|
| static inline bool parentElementPreventsSharing(const Element* parentElement)
|
| {
|
| + if (!parentElement)
|
| + return false;
|
| return parentElement->hasFlagsSetDuringStylingOfChildren();
|
| }
|
|
|
| +Node* SharedStyleFinder::locateCousinList(Element* parent, unsigned& visitedNodeCount) const
|
| +{
|
| + if (visitedNodeCount >= cStyleSearchThreshold * cStyleSearchLevelThreshold)
|
| + return 0;
|
| + if (!parent || !parent->isStyledElement())
|
| + return 0;
|
| + if (parent->hasScopedHTMLStyleChild())
|
| + return 0;
|
| + if (parent->inlineStyle())
|
| + return 0;
|
| + if (parent->isSVGElement() && toSVGElement(parent)->animatedSMILStyleProperties())
|
| + return 0;
|
| + if (parent->hasID() && m_features.idsInRules.contains(parent->idForStyleResolution().impl()))
|
| + return 0;
|
| + if (isShadowHost(parent) && parent->shadow()->containsActiveStyles())
|
| + return 0;
|
| +
|
| + RenderStyle* parentStyle = parent->renderStyle();
|
| + unsigned subcount = 0;
|
| + Node* thisCousin = parent;
|
| + Node* currentNode = parent->previousSibling();
|
| +
|
| + // Reserve the tries for this level. This effectively makes sure that the algorithm
|
| + // will never go deeper than cStyleSearchLevelThreshold levels into recursion.
|
| + visitedNodeCount += cStyleSearchThreshold;
|
| + while (thisCousin) {
|
| + while (currentNode) {
|
| + ++subcount;
|
| + if (!currentNode->hasScopedHTMLStyleChild() && currentNode->renderStyle() == parentStyle && currentNode->lastChild()
|
| + && currentNode->isElementNode() && !parentElementPreventsSharing(toElement(currentNode))
|
| + && !toElement(currentNode)->shadow()
|
| + ) {
|
| + // Adjust for unused reserved tries.
|
| + visitedNodeCount -= cStyleSearchThreshold - subcount;
|
| + return currentNode->lastChild();
|
| + }
|
| + if (subcount >= cStyleSearchThreshold)
|
| + return 0;
|
| + currentNode = currentNode->previousSibling();
|
| + }
|
| + currentNode = locateCousinList(thisCousin->parentElement(), visitedNodeCount);
|
| + thisCousin = currentNode;
|
| + }
|
| +
|
| + return 0;
|
| +}
|
| +
|
| +
|
| bool SharedStyleFinder::canShareStyleWithControl(const ElementResolveContext& context, Element* element) const
|
| {
|
| if (!element->hasTagName(inputTag) || !context.element()->hasTagName(inputTag))
|
| @@ -161,16 +214,9 @@ bool SharedStyleFinder::sharingCandidateHasIdenticalStyleAffectingAttributes(con
|
|
|
| bool SharedStyleFinder::canShareStyleWithElement(const ElementResolveContext& context, Element* element) const
|
| {
|
| - if (context.element() == element)
|
| - return false;
|
| - Element* parent = element->parentElement();
|
| RenderStyle* style = element->renderStyle();
|
| if (!style)
|
| return false;
|
| - if (!parent)
|
| - return false;
|
| - if (context.element()->parentElement()->renderStyle() != parent->renderStyle())
|
| - return false;
|
| if (style->unique())
|
| return false;
|
| if (style->hasUniquePseudoStyle())
|
| @@ -250,24 +296,22 @@ bool SharedStyleFinder::canShareStyleWithElement(const ElementResolveContext& co
|
| return false;
|
| }
|
|
|
| - if (context.element()->parentElement() != parent) {
|
| - if (!parent->isStyledElement())
|
| - return false;
|
| - if (parent->hasScopedHTMLStyleChild())
|
| - return false;
|
| - if (parent->inlineStyle())
|
| - return false;
|
| - if (parent->isSVGElement() && toSVGElement(parent)->animatedSMILStyleProperties())
|
| - return false;
|
| - if (parent->hasID() && m_features.idsInRules.contains(parent->idForStyleResolution().impl()))
|
| - return false;
|
| - if (parentElementPreventsSharing(parent))
|
| - return false;
|
| - }
|
| -
|
| return true;
|
| }
|
|
|
| +inline Element* SharedStyleFinder::findSiblingForStyleSharing(const ElementResolveContext& context, Node* node, unsigned& count) const
|
| +{
|
| + for (; node; node = node->previousSibling()) {
|
| + if (!node->isStyledElement())
|
| + continue;
|
| + if (canShareStyleWithElement(context, toElement(node)))
|
| + break;
|
| + if (count++ == cStyleSearchThreshold)
|
| + return 0;
|
| + }
|
| + return toElement(node);
|
| +}
|
| +
|
| #ifdef STYLE_STATS
|
| Element* SharedStyleFinder::searchDocumentForSharedStyle(const ElementResolveContext& context) const
|
| {
|
| @@ -279,28 +323,10 @@ Element* SharedStyleFinder::searchDocumentForSharedStyle(const ElementResolveCon
|
| }
|
| #endif
|
|
|
| -inline Element* SharedStyleFinder::findElementForStyleSharing(const ElementResolveContext& context) const
|
| -{
|
| - StyleSharingList& styleSharingList = m_styleResolver->styleSharingList();
|
| - for (StyleSharingList::iterator iter = styleSharingList.begin(); iter != styleSharingList.end(); ++iter) {
|
| - if (canShareStyleWithElement(context, *iter)) {
|
| - Element* element = *iter;
|
| - if (iter != styleSharingList.begin()) {
|
| - // Move the element to the front of the LRU
|
| - styleSharingList.remove(iter);
|
| - styleSharingList.prepend(element);
|
| - }
|
| - return element;
|
| - }
|
| - }
|
| - m_styleResolver->addToStyleSharingList(context.element());
|
| - return 0;
|
| -}
|
| -
|
| RenderStyle* SharedStyleFinder::locateSharedStyle(const ElementResolveContext& context, RenderStyle* newStyle)
|
| {
|
| STYLE_STATS_ADD_SEARCH();
|
| - if (!context.element() || !context.element()->isStyledElement() || !context.element()->parentElement())
|
| + if (!context.element() || !context.element()->isStyledElement())
|
| return 0;
|
|
|
| // If the element has inline style it is probably unique.
|
| @@ -344,7 +370,17 @@ RenderStyle* SharedStyleFinder::locateSharedStyle(const ElementResolveContext& c
|
| // FIXME: This should be an explicit out parameter, instead of a member variable.
|
| m_elementAffectedByClassRules = context.element() && context.element()->hasClass() && classNamesAffectedByRules(context.element()->classNames());
|
|
|
| - Element* shareElement = findElementForStyleSharing(context);
|
| + // Check previous siblings and their cousins.
|
| + unsigned count = 0;
|
| + unsigned visitedNodeCount = 0;
|
| + Element* shareElement = 0;
|
| + Node* cousinList = context.element()->previousSibling();
|
| + while (cousinList) {
|
| + shareElement = findSiblingForStyleSharing(context, cousinList, count);
|
| + if (shareElement)
|
| + break;
|
| + cousinList = locateCousinList(cousinList->parentElement(), visitedNodeCount);
|
| + }
|
|
|
| #ifdef STYLE_STATS
|
| // FIXME: these stats don't to into account whether or not sibling/attribute
|
|
|