Chromium Code Reviews| 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 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 49 #include "core/html/track/WebVTTElement.h" | 49 #include "core/html/track/WebVTTElement.h" |
| 50 #include "core/rendering/style/RenderStyle.h" | 50 #include "core/rendering/style/RenderStyle.h" |
| 51 #include "core/svg/SVGElement.h" | 51 #include "core/svg/SVGElement.h" |
| 52 #include "wtf/HashSet.h" | 52 #include "wtf/HashSet.h" |
| 53 #include "wtf/text/AtomicString.h" | 53 #include "wtf/text/AtomicString.h" |
| 54 | 54 |
| 55 namespace WebCore { | 55 namespace WebCore { |
| 56 | 56 |
| 57 using namespace HTMLNames; | 57 using namespace HTMLNames; |
| 58 | 58 |
| 59 static const unsigned cStyleSearchThreshold = 10; | |
| 60 static const unsigned cStyleSearchLevelThreshold = 10; | |
| 61 | |
| 62 static inline bool parentElementPreventsSharing(const Element* parentElement) | 59 static inline bool parentElementPreventsSharing(const Element* parentElement) |
| 63 { | 60 { |
| 64 if (!parentElement) | |
| 65 return false; | |
| 66 return parentElement->hasFlagsSetDuringStylingOfChildren(); | 61 return parentElement->hasFlagsSetDuringStylingOfChildren(); |
| 67 } | 62 } |
| 68 | 63 |
| 69 Node* SharedStyleFinder::locateCousinList(Element* parent, unsigned& visitedNode Count) const | |
| 70 { | |
| 71 if (visitedNodeCount >= cStyleSearchThreshold * cStyleSearchLevelThreshold) | |
| 72 return 0; | |
| 73 if (!parent || !parent->isStyledElement()) | |
| 74 return 0; | |
| 75 if (parent->hasScopedHTMLStyleChild()) | |
| 76 return 0; | |
| 77 if (parent->inlineStyle()) | |
| 78 return 0; | |
| 79 if (parent->isSVGElement() && toSVGElement(parent)->animatedSMILStylePropert ies()) | |
| 80 return 0; | |
| 81 if (parent->hasID() && m_features.idsInRules.contains(parent->idForStyleReso lution().impl())) | |
| 82 return 0; | |
| 83 if (isShadowHost(parent) && parent->shadow()->containsActiveStyles()) | |
| 84 return 0; | |
| 85 | |
| 86 RenderStyle* parentStyle = parent->renderStyle(); | |
| 87 unsigned subcount = 0; | |
| 88 Node* thisCousin = parent; | |
| 89 Node* currentNode = parent->previousSibling(); | |
| 90 | |
| 91 // Reserve the tries for this level. This effectively makes sure that the al gorithm | |
| 92 // will never go deeper than cStyleSearchLevelThreshold levels into recursio n. | |
| 93 visitedNodeCount += cStyleSearchThreshold; | |
| 94 while (thisCousin) { | |
| 95 while (currentNode) { | |
| 96 ++subcount; | |
| 97 if (!currentNode->hasScopedHTMLStyleChild() && currentNode->renderSt yle() == parentStyle && currentNode->lastChild() | |
| 98 && currentNode->isElementNode() && !parentElementPreventsSharing (toElement(currentNode)) | |
| 99 && !toElement(currentNode)->shadow() | |
| 100 ) { | |
| 101 // Adjust for unused reserved tries. | |
| 102 visitedNodeCount -= cStyleSearchThreshold - subcount; | |
| 103 return currentNode->lastChild(); | |
| 104 } | |
| 105 if (subcount >= cStyleSearchThreshold) | |
| 106 return 0; | |
| 107 currentNode = currentNode->previousSibling(); | |
| 108 } | |
| 109 currentNode = locateCousinList(thisCousin->parentElement(), visitedNodeC ount); | |
| 110 thisCousin = currentNode; | |
| 111 } | |
| 112 | |
| 113 return 0; | |
| 114 } | |
| 115 | |
| 116 | |
| 117 bool SharedStyleFinder::canShareStyleWithControl(const ElementResolveContext& co ntext, Element* element) const | 64 bool SharedStyleFinder::canShareStyleWithControl(const ElementResolveContext& co ntext, Element* element) const |
| 118 { | 65 { |
| 119 if (!element->hasTagName(inputTag) || !context.element()->hasTagName(inputTa g)) | 66 if (!element->hasTagName(inputTag) || !context.element()->hasTagName(inputTa g)) |
| 120 return false; | 67 return false; |
| 121 | 68 |
| 122 HTMLInputElement* thisInputElement = toHTMLInputElement(element); | 69 HTMLInputElement* thisInputElement = toHTMLInputElement(element); |
| 123 HTMLInputElement* otherInputElement = toHTMLInputElement(context.element()); | 70 HTMLInputElement* otherInputElement = toHTMLInputElement(context.element()); |
| 124 if (thisInputElement->elementData() != otherInputElement->elementData()) { | 71 if (thisInputElement->elementData() != otherInputElement->elementData()) { |
| 125 if (thisInputElement->fastGetAttribute(typeAttr) != otherInputElement->f astGetAttribute(typeAttr)) | 72 if (thisInputElement->fastGetAttribute(typeAttr) != otherInputElement->f astGetAttribute(typeAttr)) |
| 126 return false; | 73 return false; |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 207 if (context.element()->hasTagName(progressTag)) { | 154 if (context.element()->hasTagName(progressTag)) { |
| 208 if (context.element()->shouldAppearIndeterminate() != sharingCandidate-> shouldAppearIndeterminate()) | 155 if (context.element()->shouldAppearIndeterminate() != sharingCandidate-> shouldAppearIndeterminate()) |
| 209 return false; | 156 return false; |
| 210 } | 157 } |
| 211 | 158 |
| 212 return true; | 159 return true; |
| 213 } | 160 } |
| 214 | 161 |
| 215 bool SharedStyleFinder::canShareStyleWithElement(const ElementResolveContext& co ntext, Element* element) const | 162 bool SharedStyleFinder::canShareStyleWithElement(const ElementResolveContext& co ntext, Element* element) const |
| 216 { | 163 { |
| 164 if (context.element() == element) | |
| 165 return false; | |
| 166 Element* parent = element->parentElement(); | |
| 217 RenderStyle* style = element->renderStyle(); | 167 RenderStyle* style = element->renderStyle(); |
| 218 if (!style) | 168 if (!style) |
| 219 return false; | 169 return false; |
| 170 if (!parent) | |
| 171 return false; | |
| 172 if (context.element()->parentElement()->renderStyle() != parent->renderStyle ()) | |
| 173 return false; | |
| 220 if (style->unique()) | 174 if (style->unique()) |
| 221 return false; | 175 return false; |
| 222 if (style->hasUniquePseudoStyle()) | 176 if (style->hasUniquePseudoStyle()) |
| 223 return false; | 177 return false; |
| 224 if (element->tagQName() != context.element()->tagQName()) | 178 if (element->tagQName() != context.element()->tagQName()) |
| 225 return false; | 179 return false; |
| 226 if (element->inlineStyle()) | 180 if (element->inlineStyle()) |
| 227 return false; | 181 return false; |
| 228 if (element->needsStyleRecalc()) | 182 if (element->needsStyleRecalc()) |
| 229 return false; | 183 return false; |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 289 return false; | 243 return false; |
| 290 | 244 |
| 291 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()) |
| 292 return false; | 246 return false; |
| 293 | 247 |
| 294 if (FullscreenElementStack* fullscreen = FullscreenElementStack::fromIfExist s(context.document())) { | 248 if (FullscreenElementStack* fullscreen = FullscreenElementStack::fromIfExist s(context.document())) { |
| 295 if (element == fullscreen->webkitCurrentFullScreenElement() || context.e lement() == fullscreen->webkitCurrentFullScreenElement()) | 249 if (element == fullscreen->webkitCurrentFullScreenElement() || context.e lement() == fullscreen->webkitCurrentFullScreenElement()) |
| 296 return false; | 250 return false; |
| 297 } | 251 } |
| 298 | 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 | |
| 299 return true; | 268 return true; |
| 300 } | 269 } |
| 301 | 270 |
| 302 inline Element* SharedStyleFinder::findSiblingForStyleSharing(const ElementResol veContext& context, Node* node, unsigned& count) const | |
| 303 { | |
| 304 for (; node; node = node->previousSibling()) { | |
| 305 if (!node->isStyledElement()) | |
| 306 continue; | |
| 307 if (canShareStyleWithElement(context, toElement(node))) | |
| 308 break; | |
| 309 if (count++ == cStyleSearchThreshold) | |
| 310 return 0; | |
| 311 } | |
| 312 return toElement(node); | |
| 313 } | |
| 314 | |
| 315 #ifdef STYLE_STATS | 271 #ifdef STYLE_STATS |
| 316 Element* SharedStyleFinder::searchDocumentForSharedStyle(const ElementResolveCon text& context) const | 272 Element* SharedStyleFinder::searchDocumentForSharedStyle(const ElementResolveCon text& context) const |
| 317 { | 273 { |
| 318 for (Element* element = context.element()->document()->documentElement(); el ement; element = ElementTraversal::next(element)) { | 274 for (Element* element = context.element()->document()->documentElement(); el ement; element = ElementTraversal::next(element)) { |
| 319 if (canShareStyleWithElement(context, element)) | 275 if (canShareStyleWithElement(context, element)) |
| 320 return element; | 276 return element; |
| 321 } | 277 } |
| 322 return 0; | 278 return 0; |
| 323 } | 279 } |
| 324 #endif | 280 #endif |
| 325 | 281 |
| 282 inline Element* SharedStyleFinder::findElementForStyleSharing(const ElementResol veContext& context) const | |
| 283 { | |
| 284 StyleSharingList& styleSharingList = m_styleResolver->styleSharingList(); | |
| 285 for (StyleSharingList::iterator iter = styleSharingList.begin(); iter != sty leSharingList.end(); ++iter) { | |
|
esprehn
2013/08/20 00:48:01
I think we usually use "it" for iterators.
| |
| 286 if (canShareStyleWithElement(context, iter->get())) { | |
|
esprehn
2013/08/20 00:48:01
if (!...)
continue;
would make this nicer since
leviw_travelin_and_unemployed
2013/08/20 00:54:09
Sure.
| |
| 287 Element* element = iter->get(); | |
| 288 if (iter != styleSharingList.begin()) { | |
| 289 // Move the element to the front of the LRU | |
| 290 styleSharingList.remove(iter); | |
| 291 styleSharingList.prepend(element); | |
| 292 } | |
| 293 return element; | |
| 294 } | |
| 295 } | |
| 296 m_styleResolver->addToStyleSharingList(context.element()); | |
| 297 return 0; | |
| 298 } | |
| 299 | |
| 326 RenderStyle* SharedStyleFinder::locateSharedStyle(const ElementResolveContext& c ontext, RenderStyle* newStyle) | 300 RenderStyle* SharedStyleFinder::locateSharedStyle(const ElementResolveContext& c ontext, RenderStyle* newStyle) |
| 327 { | 301 { |
| 328 STYLE_STATS_ADD_SEARCH(); | 302 STYLE_STATS_ADD_SEARCH(); |
| 329 if (!context.element() || !context.element()->isStyledElement()) | 303 if (!context.element() || !context.element()->isStyledElement() || !context. element()->parentElement()) |
| 330 return 0; | 304 return 0; |
| 331 | 305 |
| 332 // If the element has inline style it is probably unique. | 306 // If the element has inline style it is probably unique. |
| 333 if (context.element()->inlineStyle()) | 307 if (context.element()->inlineStyle()) |
| 334 return 0; | 308 return 0; |
| 335 if (context.element()->isSVGElement() && toSVGElement(context.element())->an imatedSMILStyleProperties()) | 309 if (context.element()->isSVGElement() && toSVGElement(context.element())->an imatedSMILStyleProperties()) |
| 336 return 0; | 310 return 0; |
| 337 // Ids stop style sharing if they show up in the stylesheets. | 311 // Ids stop style sharing if they show up in the stylesheets. |
| 338 if (context.element()->hasID() && m_features.idsInRules.contains(context.ele ment()->idForStyleResolution().impl())) | 312 if (context.element()->hasID() && m_features.idsInRules.contains(context.ele ment()->idForStyleResolution().impl())) |
| 339 return 0; | 313 return 0; |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 363 return 0; | 337 return 0; |
| 364 if (isShadowHost(context.element()) && context.element()->shadow()->contains ActiveStyles()) | 338 if (isShadowHost(context.element()) && context.element()->shadow()->contains ActiveStyles()) |
| 365 return 0; | 339 return 0; |
| 366 | 340 |
| 367 STYLE_STATS_ADD_ELEMENT_ELIGIBLE_FOR_SHARING(); | 341 STYLE_STATS_ADD_ELEMENT_ELIGIBLE_FOR_SHARING(); |
| 368 | 342 |
| 369 // Cache whether context.element() is affected by any known class selectors. | 343 // Cache whether context.element() is affected by any known class selectors. |
| 370 // FIXME: This should be an explicit out parameter, instead of a member vari able. | 344 // FIXME: This should be an explicit out parameter, instead of a member vari able. |
| 371 m_elementAffectedByClassRules = context.element() && context.element()->hasC lass() && classNamesAffectedByRules(context.element()->classNames()); | 345 m_elementAffectedByClassRules = context.element() && context.element()->hasC lass() && classNamesAffectedByRules(context.element()->classNames()); |
| 372 | 346 |
| 373 // Check previous siblings and their cousins. | 347 Element* shareElement = findElementForStyleSharing(context); |
| 374 unsigned count = 0; | |
| 375 unsigned visitedNodeCount = 0; | |
| 376 Element* shareElement = 0; | |
| 377 Node* cousinList = context.element()->previousSibling(); | |
| 378 while (cousinList) { | |
| 379 shareElement = findSiblingForStyleSharing(context, cousinList, count); | |
| 380 if (shareElement) | |
| 381 break; | |
| 382 cousinList = locateCousinList(cousinList->parentElement(), visitedNodeCo unt); | |
| 383 } | |
| 384 | 348 |
| 385 #ifdef STYLE_STATS | 349 #ifdef STYLE_STATS |
| 386 // FIXME: these stats don't to into account whether or not sibling/attribute | 350 // FIXME: these stats don't to into account whether or not sibling/attribute |
| 387 // rules prevent these nodes from actually sharing | 351 // rules prevent these nodes from actually sharing |
| 388 if (shareElement) { | 352 if (shareElement) { |
| 389 STYLE_STATS_ADD_SEARCH_FOUND_SIBLING_FOR_SHARING(); | 353 STYLE_STATS_ADD_SEARCH_FOUND_SIBLING_FOR_SHARING(); |
| 390 } else { | 354 } else { |
| 391 shareElement = searchDocumentForSharedStyle(context); | 355 shareElement = searchDocumentForSharedStyle(context); |
| 392 if (shareElement) | 356 if (shareElement) |
| 393 STYLE_STATS_ADD_SEARCH_MISSED_SHARING(); | 357 STYLE_STATS_ADD_SEARCH_MISSED_SHARING(); |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 406 if (m_styleResolver->styleSharingCandidateMatchesRuleSet(context, newStyle, m_uncommonAttributeRuleSet)) | 370 if (m_styleResolver->styleSharingCandidateMatchesRuleSet(context, newStyle, m_uncommonAttributeRuleSet)) |
| 407 return 0; | 371 return 0; |
| 408 // Tracking child index requires unique style for each node. This may get se t by the sibling rule match above. | 372 // Tracking child index requires unique style for each node. This may get se t by the sibling rule match above. |
| 409 if (parentElementPreventsSharing(context.element()->parentElement())) | 373 if (parentElementPreventsSharing(context.element()->parentElement())) |
| 410 return 0; | 374 return 0; |
| 411 STYLE_STATS_ADD_STYLE_SHARED(); | 375 STYLE_STATS_ADD_STYLE_SHARED(); |
| 412 return shareElement->renderStyle(); | 376 return shareElement->renderStyle(); |
| 413 } | 377 } |
| 414 | 378 |
| 415 } | 379 } |
| OLD | NEW |