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 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
48 #include "core/html/track/WebVTTElement.h" | 48 #include "core/html/track/WebVTTElement.h" |
49 #include "core/rendering/style/RenderStyle.h" | 49 #include "core/rendering/style/RenderStyle.h" |
50 #include "core/svg/SVGElement.h" | 50 #include "core/svg/SVGElement.h" |
51 #include "wtf/HashSet.h" | 51 #include "wtf/HashSet.h" |
52 #include "wtf/text/AtomicString.h" | 52 #include "wtf/text/AtomicString.h" |
53 | 53 |
54 namespace WebCore { | 54 namespace WebCore { |
55 | 55 |
56 using namespace HTMLNames; | 56 using namespace HTMLNames; |
57 | 57 |
58 static const unsigned cStyleSearchThreshold = 10; | |
59 static const unsigned cStyleSearchLevelThreshold = 10; | |
60 | |
61 static inline bool parentElementPreventsSharing(const Element* parentElement) | 58 static inline bool parentElementPreventsSharing(const Element* parentElement) |
62 { | 59 { |
63 if (!parentElement) | |
64 return false; | |
65 return parentElement->hasFlagsSetDuringStylingOfChildren(); | 60 return parentElement->hasFlagsSetDuringStylingOfChildren(); |
66 } | 61 } |
67 | 62 |
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 | 63 bool SharedStyleFinder::canShareStyleWithControl(const ElementResolveContext& co
ntext, Element* element) const |
117 { | 64 { |
118 if (!element->hasTagName(inputTag) || !context.element()->hasTagName(inputTa
g)) | 65 if (!element->hasTagName(inputTag) || !context.element()->hasTagName(inputTa
g)) |
119 return false; | 66 return false; |
120 | 67 |
121 HTMLInputElement* thisInputElement = toHTMLInputElement(element); | 68 HTMLInputElement* thisInputElement = toHTMLInputElement(element); |
122 HTMLInputElement* otherInputElement = toHTMLInputElement(context.element()); | 69 HTMLInputElement* otherInputElement = toHTMLInputElement(context.element()); |
123 if (thisInputElement->elementData() != otherInputElement->elementData()) { | 70 if (thisInputElement->elementData() != otherInputElement->elementData()) { |
124 if (thisInputElement->fastGetAttribute(typeAttr) != otherInputElement->f
astGetAttribute(typeAttr)) | 71 if (thisInputElement->fastGetAttribute(typeAttr) != otherInputElement->f
astGetAttribute(typeAttr)) |
125 return false; | 72 return false; |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
206 if (context.element()->hasTagName(progressTag)) { | 153 if (context.element()->hasTagName(progressTag)) { |
207 if (context.element()->shouldAppearIndeterminate() != sharingCandidate->
shouldAppearIndeterminate()) | 154 if (context.element()->shouldAppearIndeterminate() != sharingCandidate->
shouldAppearIndeterminate()) |
208 return false; | 155 return false; |
209 } | 156 } |
210 | 157 |
211 return true; | 158 return true; |
212 } | 159 } |
213 | 160 |
214 bool SharedStyleFinder::canShareStyleWithElement(const ElementResolveContext& co
ntext, Element* element) const | 161 bool SharedStyleFinder::canShareStyleWithElement(const ElementResolveContext& co
ntext, Element* element) const |
215 { | 162 { |
| 163 if (context.element() == element) |
| 164 return false; |
| 165 Element* parent = element->parentElement(); |
216 RenderStyle* style = element->renderStyle(); | 166 RenderStyle* style = element->renderStyle(); |
217 if (!style) | 167 if (!style) |
218 return false; | 168 return false; |
| 169 if (!parent) |
| 170 return false; |
| 171 if (context.element()->parentElement()->renderStyle() != parent->renderStyle
()) |
| 172 return false; |
219 if (style->unique()) | 173 if (style->unique()) |
220 return false; | 174 return false; |
221 if (style->hasUniquePseudoStyle()) | 175 if (style->hasUniquePseudoStyle()) |
222 return false; | 176 return false; |
223 if (element->tagQName() != context.element()->tagQName()) | 177 if (element->tagQName() != context.element()->tagQName()) |
224 return false; | 178 return false; |
225 if (element->inlineStyle()) | 179 if (element->inlineStyle()) |
226 return false; | 180 return false; |
227 if (element->needsStyleRecalc()) | 181 if (element->needsStyleRecalc()) |
228 return false; | 182 return false; |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
288 return false; | 242 return false; |
289 | 243 |
290 if (element->isWebVTTElement() && context.element()->isWebVTTElement() && to
WebVTTElement(element)->isPastNode() != toWebVTTElement(context.element())->isPa
stNode()) | 244 if (element->isWebVTTElement() && context.element()->isWebVTTElement() && to
WebVTTElement(element)->isPastNode() != toWebVTTElement(context.element())->isPa
stNode()) |
291 return false; | 245 return false; |
292 | 246 |
293 if (FullscreenElementStack* fullscreen = FullscreenElementStack::fromIfExist
s(&context.document())) { | 247 if (FullscreenElementStack* fullscreen = FullscreenElementStack::fromIfExist
s(&context.document())) { |
294 if (element == fullscreen->webkitCurrentFullScreenElement() || context.e
lement() == fullscreen->webkitCurrentFullScreenElement()) | 248 if (element == fullscreen->webkitCurrentFullScreenElement() || context.e
lement() == fullscreen->webkitCurrentFullScreenElement()) |
295 return false; | 249 return false; |
296 } | 250 } |
297 | 251 |
| 252 if (context.element()->parentElement() != parent) { |
| 253 if (!parent->isStyledElement()) |
| 254 return false; |
| 255 if (parent->hasScopedHTMLStyleChild()) |
| 256 return false; |
| 257 if (parent->inlineStyle()) |
| 258 return false; |
| 259 if (parent->isSVGElement() && toSVGElement(parent)->animatedSMILStylePro
perties()) |
| 260 return false; |
| 261 if (parent->hasID() && m_features.idsInRules.contains(parent->idForStyle
Resolution().impl())) |
| 262 return false; |
| 263 if (parentElementPreventsSharing(parent)) |
| 264 return false; |
| 265 } |
| 266 |
298 return true; | 267 return true; |
299 } | 268 } |
300 | 269 |
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 | 270 #ifdef STYLE_STATS |
315 Element* SharedStyleFinder::searchDocumentForSharedStyle(const ElementResolveCon
text& context) const | 271 Element* SharedStyleFinder::searchDocumentForSharedStyle(const ElementResolveCon
text& context) const |
316 { | 272 { |
317 for (Element* element = context.element()->document().documentElement(); ele
ment; element = ElementTraversal::next(element)) { | 273 for (Element* element = context.element()->document().documentElement(); ele
ment; element = ElementTraversal::next(element)) { |
318 if (canShareStyleWithElement(context, element)) | 274 if (canShareStyleWithElement(context, element)) |
319 return element; | 275 return element; |
320 } | 276 } |
321 return 0; | 277 return 0; |
322 } | 278 } |
323 #endif | 279 #endif |
324 | 280 |
| 281 inline Element* SharedStyleFinder::findElementForStyleSharing(const ElementResol
veContext& context) const |
| 282 { |
| 283 StyleSharingList& styleSharingList = m_styleResolver->styleSharingList(); |
| 284 for (StyleSharingList::iterator it = styleSharingList.begin(); it != styleSh
aringList.end(); ++it) { |
| 285 if (!canShareStyleWithElement(context, it->get())) |
| 286 continue; |
| 287 Element* element = it->get(); |
| 288 if (it != styleSharingList.begin()) { |
| 289 // Move the element to the front of the LRU |
| 290 styleSharingList.remove(it); |
| 291 styleSharingList.prepend(element); |
| 292 } |
| 293 return element; |
| 294 } |
| 295 m_styleResolver->addToStyleSharingList(context.element()); |
| 296 return 0; |
| 297 } |
| 298 |
325 RenderStyle* SharedStyleFinder::locateSharedStyle(const ElementResolveContext& c
ontext, RenderStyle* newStyle) | 299 RenderStyle* SharedStyleFinder::locateSharedStyle(const ElementResolveContext& c
ontext, RenderStyle* newStyle) |
326 { | 300 { |
327 STYLE_STATS_ADD_SEARCH(); | 301 STYLE_STATS_ADD_SEARCH(); |
328 if (!context.element() || !context.element()->isStyledElement()) | 302 if (!context.element() || !context.element()->isStyledElement() || !context.
element()->parentElement()) |
329 return 0; | 303 return 0; |
330 | 304 |
331 // If the element has inline style it is probably unique. | 305 // If the element has inline style it is probably unique. |
332 if (context.element()->inlineStyle()) | 306 if (context.element()->inlineStyle()) |
333 return 0; | 307 return 0; |
334 if (context.element()->isSVGElement() && toSVGElement(context.element())->an
imatedSMILStyleProperties()) | 308 if (context.element()->isSVGElement() && toSVGElement(context.element())->an
imatedSMILStyleProperties()) |
335 return 0; | 309 return 0; |
336 // Ids stop style sharing if they show up in the stylesheets. | 310 // 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())) | 311 if (context.element()->hasID() && m_features.idsInRules.contains(context.ele
ment()->idForStyleResolution().impl())) |
338 return 0; | 312 return 0; |
(...skipping 23 matching lines...) Expand all Loading... |
362 return 0; | 336 return 0; |
363 if (isShadowHost(context.element()) && context.element()->shadow()->contains
ActiveStyles()) | 337 if (isShadowHost(context.element()) && context.element()->shadow()->contains
ActiveStyles()) |
364 return 0; | 338 return 0; |
365 | 339 |
366 STYLE_STATS_ADD_ELEMENT_ELIGIBLE_FOR_SHARING(); | 340 STYLE_STATS_ADD_ELEMENT_ELIGIBLE_FOR_SHARING(); |
367 | 341 |
368 // Cache whether context.element() is affected by any known class selectors. | 342 // 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. | 343 // 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()); | 344 m_elementAffectedByClassRules = context.element() && context.element()->hasC
lass() && classNamesAffectedByRules(context.element()->classNames()); |
371 | 345 |
372 // Check previous siblings and their cousins. | 346 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 | 347 |
384 #ifdef STYLE_STATS | 348 #ifdef STYLE_STATS |
385 // FIXME: these stats don't to into account whether or not sibling/attribute | 349 // FIXME: these stats don't to into account whether or not sibling/attribute |
386 // rules prevent these nodes from actually sharing | 350 // rules prevent these nodes from actually sharing |
387 if (shareElement) { | 351 if (shareElement) { |
388 STYLE_STATS_ADD_SEARCH_FOUND_SIBLING_FOR_SHARING(); | 352 STYLE_STATS_ADD_SEARCH_FOUND_SIBLING_FOR_SHARING(); |
389 } else { | 353 } else { |
390 shareElement = searchDocumentForSharedStyle(context); | 354 shareElement = searchDocumentForSharedStyle(context); |
391 if (shareElement) | 355 if (shareElement) |
392 STYLE_STATS_ADD_SEARCH_MISSED_SHARING(); | 356 STYLE_STATS_ADD_SEARCH_MISSED_SHARING(); |
(...skipping 12 matching lines...) Expand all Loading... |
405 if (m_styleResolver->styleSharingCandidateMatchesRuleSet(context, newStyle,
m_uncommonAttributeRuleSet)) | 369 if (m_styleResolver->styleSharingCandidateMatchesRuleSet(context, newStyle,
m_uncommonAttributeRuleSet)) |
406 return 0; | 370 return 0; |
407 // Tracking child index requires unique style for each node. This may get se
t by the sibling rule match above. | 371 // 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())) | 372 if (parentElementPreventsSharing(context.element()->parentElement())) |
409 return 0; | 373 return 0; |
410 STYLE_STATS_ADD_STYLE_SHARED(); | 374 STYLE_STATS_ADD_STYLE_SHARED(); |
411 return shareElement->renderStyle(); | 375 return shareElement->renderStyle(); |
412 } | 376 } |
413 | 377 |
414 } | 378 } |
OLD | NEW |