Index: Source/core/css/resolver/SharedStyleFinder.cpp |
diff --git a/Source/core/css/resolver/SharedStyleFinder.cpp b/Source/core/css/resolver/SharedStyleFinder.cpp |
index 2cbc11f8bec7a4a49438de5d3018d5c837d9ff2e..aad32e73e0121d073a7c1fa85337fc2bc138e182 100644 |
--- a/Source/core/css/resolver/SharedStyleFinder.cpp |
+++ b/Source/core/css/resolver/SharedStyleFinder.cpp |
@@ -36,6 +36,7 @@ |
#include "core/dom/ContainerNode.h" |
#include "core/dom/Document.h" |
#include "core/dom/Element.h" |
+#include "core/dom/ElementTraversal.h" |
#include "core/dom/FullscreenElementStack.h" |
#include "core/dom/Node.h" |
#include "core/dom/NodeRenderStyle.h" |
@@ -55,64 +56,11 @@ 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)) |
@@ -213,9 +161,16 @@ 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()) |
@@ -295,20 +250,22 @@ bool SharedStyleFinder::canShareStyleWithElement(const ElementResolveContext& co |
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; |
+ 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 toElement(node); |
+ |
+ return true; |
} |
#ifdef STYLE_STATS |
@@ -322,45 +279,29 @@ Element* SharedStyleFinder::searchDocumentForSharedStyle(const ElementResolveCon |
} |
#endif |
+inline Element* SharedStyleFinder::findElementForStyleSharing(const ElementResolveContext& context) const |
+{ |
+ StyleSharingList& styleSharingList = m_styleResolver->styleSharingList(); |
+ for (StyleSharingList::iterator it = styleSharingList.begin(); it != styleSharingList.end(); ++it) { |
+ if (!canShareStyleWithElement(context, it->get())) |
+ continue; |
+ Element* element = it->get(); |
+ if (it != styleSharingList.begin()) { |
+ // Move the element to the front of the LRU |
+ styleSharingList.remove(it); |
+ 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()) |
- return 0; |
- // If the element has inline style it is probably unique. |
- if (context.element()->inlineStyle()) |
- return 0; |
- if (context.element()->isSVGElement() && toSVGElement(context.element())->animatedSMILStyleProperties()) |
- return 0; |
- // Ids stop style sharing if they show up in the stylesheets. |
- if (context.element()->hasID() && m_features.idsInRules.contains(context.element()->idForStyleResolution().impl())) |
- return 0; |
- // Active and hovered elements always make a chain towards the document node |
- // and no siblings or cousins will have the same state. |
- if (context.element()->hovered()) |
- return 0; |
- if (context.element()->active()) |
- return 0; |
- // There is always only one focused element. |
- if (context.element()->focused()) |
- return 0; |
- if (parentElementPreventsSharing(context.element()->parentElement())) |
- return 0; |
- if (context.element()->hasScopedHTMLStyleChild()) |
- return 0; |
- if (context.element() == context.document().cssTarget()) |
- return 0; |
- if (elementHasDirectionAuto(context.element())) |
- return 0; |
- if (context.element()->hasActiveAnimations()) |
- return 0; |
- // When a dialog is first shown, its style is mutated to center it in the |
- // viewport. So the styles can't be shared since the viewport position and |
- // size may be different each time a dialog is opened. |
- if (context.element()->hasTagName(dialogTag)) |
- return 0; |
- if (isShadowHost(context.element()) && context.element()->shadow()->containsActiveStyles()) |
+ if (!m_styleResolver->supportsStyleSharing(context.element())) |
return 0; |
STYLE_STATS_ADD_ELEMENT_ELIGIBLE_FOR_SHARING(); |
@@ -369,17 +310,7 @@ 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()); |
- // 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); |
- } |
+ Element* shareElement = findElementForStyleSharing(context); |
#ifdef STYLE_STATS |
// FIXME: these stats don't to into account whether or not sibling/attribute |