Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(28)

Side by Side Diff: Source/core/css/resolver/SharedStyleFinder.cpp

Issue 24106007: Replace style sharing cousin list search with LRU (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Updating with esprehn's changes Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « Source/core/css/resolver/SharedStyleFinder.h ('k') | Source/core/css/resolver/StyleResolver.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « Source/core/css/resolver/SharedStyleFinder.h ('k') | Source/core/css/resolver/StyleResolver.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698