| 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 |