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