Changeset 80330 in webkit


Ignore:
Timestamp:
Mar 3, 2011 11:03:55 PM (13 years ago)
Author:
eric@webkit.org
Message:

2011-03-03 Eric Seidel <eric@webkit.org>

Reviewed by Dimitri Glazkov.

Refactor createRendererIfNeeded to avoid premature nextRenderer calculation
https://bugs.webkit.org/show_bug.cgi?id=55720

There are two thing going on here:

  1. Delaying nextRenderer calculation until we actually use it, previously we would always compute nextRenderer (expensive!) even if no renderer insertion was to occur.
  2. Fix fullscreen elements to be inserted into the right place in the rendering tree. Previously they would always be the last child in their parent's list, even if that wasn't the right place.

I don't know of any way to trigger the fullscreen bug,
but I tested this with peacekeeper and saw no performance change.

Peacekeeper's domJQueryBasics is now possibly as much as 2% faster
but I don't really trust the stability of peacekeeper to begin with.

This paves the way for further improvement in our nextRenderer calculation.

  • dom/Node.cpp: (WebCore::Node::attach): (WebCore::Node::previousRenderer): (WebCore::Node::nextRenderer): (WebCore::Node::createRendererAndStyle): (WebCore::wrapWithRenderFullScreen): (WebCore::Node::createRendererIfNeeded):
  • dom/Node.h:
Location:
trunk/Source/WebCore
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r80328 r80330  
     12011-03-03  Eric Seidel  <eric@webkit.org>
     2
     3        Reviewed by Dimitri Glazkov.
     4
     5        Refactor createRendererIfNeeded to avoid premature nextRenderer calculation
     6        https://bugs.webkit.org/show_bug.cgi?id=55720
     7
     8        There are two thing going on here:
     9        1. Delaying nextRenderer calculation until we actually use it,
     10           previously we would always compute nextRenderer (expensive!)
     11           even if no renderer insertion was to occur.
     12        2. Fix fullscreen elements to be inserted into the right place
     13           in the rendering tree.  Previously they would always be the last
     14           child in their parent's list, even if that wasn't the right place.
     15
     16        I don't know of any way to trigger the fullscreen bug,
     17        but I tested this with peacekeeper and saw no performance change.
     18
     19        Peacekeeper's domJQueryBasics is now possibly as much as 2% faster
     20        but I don't really trust the stability of peacekeeper to begin with.
     21
     22        This paves the way for further improvement in our nextRenderer calculation.
     23
     24        * dom/Node.cpp:
     25        (WebCore::Node::attach):
     26        (WebCore::Node::previousRenderer):
     27        (WebCore::Node::nextRenderer):
     28        (WebCore::Node::createRendererAndStyle):
     29        (WebCore::wrapWithRenderFullScreen):
     30        (WebCore::Node::createRendererIfNeeded):
     31        * dom/Node.h:
     32
    1332011-03-03  Ryosuke Niwa  <rniwa@webkit.org>
    234
  • trunk/Source/WebCore/dom/Node.cpp

    r79269 r80330  
    12431243    ASSERT(!renderer() || (renderer()->style() && renderer()->parent()));
    12441244
     1245    // FIXME: This is O(N^2) for the innerHTML case, where all children are replaced at once (and not attached).
    12451246    // If this node got a renderer it may be the previousRenderer() of sibling text nodes and thus affect the
    12461247    // result of Text::rendererIsNeeded() for those nodes.
     
    12861287}
    12871288
    1288 RenderObject * Node::previousRenderer()
    1289 {
    1290     for (Node *n = previousSibling(); n; n = n->previousSibling()) {
     1289RenderObject* Node::previousRenderer()
     1290{
     1291    // FIXME: We should have the same O(N^2) avoidance as nextRenderer does
     1292    // however, when I tried adding it, several tests failed.
     1293    for (Node* n = previousSibling(); n; n = n->previousSibling()) {
    12911294        if (n->renderer())
    12921295            return n->renderer();
     
    12951298}
    12961299
    1297 RenderObject * Node::nextRenderer()
    1298 {
    1299     // Avoid an O(n^2) problem with this function by not checking for nextRenderer() when the parent element hasn't even
    1300     // been attached yet.
     1300RenderObject* Node::nextRenderer()
     1301{
     1302    // Avoid an O(n^2) problem with this function by not checking for
     1303    // nextRenderer() when the parent element hasn't attached yet.
    13011304    if (parentOrHostNode() && !parentOrHostNode()->attached())
    13021305        return 0;
    13031306
    1304     for (Node *n = nextSibling(); n; n = n->nextSibling()) {
     1307    for (Node* n = nextSibling(); n; n = n->nextSibling()) {
    13051308        if (n->renderer())
    13061309            return n->renderer();
     
    13621365}
    13631366
     1367RenderObject* Node::createRendererAndStyle()
     1368{
     1369    ASSERT(!renderer());
     1370    ASSERT(document()->shouldCreateRenderers());
     1371
     1372    ContainerNode* parent = parentOrHostNode();
     1373    ASSERT(parent);
     1374    RenderObject* parentRenderer = parent->renderer();
     1375
     1376    // FIXME: Ignoring canHaveChildren() in a case of isShadowRoot() might be wrong.
     1377    // See https://bugs.webkit.org/show_bug.cgi?id=52423
     1378    if (!parentRenderer || (!parentRenderer->canHaveChildren() && !isShadowRoot()) || !parent->childShouldCreateRenderer(this))
     1379        return 0;
     1380
     1381    RefPtr<RenderStyle> style = styleForRenderer();
     1382    if (!rendererIsNeeded(style.get()))
     1383        return 0;
     1384
     1385    RenderObject* newRenderer = createRenderer(document()->renderArena(), style.get());
     1386    if (!newRenderer)
     1387        return 0;
     1388
     1389    if (!parentRenderer->isChildAllowed(newRenderer, style.get())) {
     1390        newRenderer->destroy();
     1391        return 0;
     1392    }
     1393    setRenderer(newRenderer);
     1394    newRenderer->setAnimatableStyle(style.release()); // setAnimatableStyle() can depend on renderer() already being set.
     1395    return newRenderer;
     1396}
     1397
     1398#if ENABLE(FULLSCREEN_API)
     1399static RenderFullScreen* wrapWithRenderFullScreen(RenderObject* object, Document* document)
     1400{
     1401    RenderFullScreen* fullscreenRenderer = new (document->renderArena()) RenderFullScreen(document);
     1402    fullscreenRenderer->setStyle(RenderFullScreen::createFullScreenStyle());
     1403    // It's possible that we failed to create the new render and end up wrapping nothing.
     1404    // We'll end up displaying a black screen, but Jer says this is expected.
     1405    if (object)
     1406        fullscreenRenderer->addChild(object);
     1407    document->setFullScreenRenderer(fullscreenRenderer);
     1408    return fullscreenRenderer;
     1409}
     1410#endif
     1411
    13641412void Node::createRendererIfNeeded()
    13651413{
     
    13681416
    13691417    ASSERT(!renderer());
    1370    
    1371     ContainerNode* parent = parentOrHostNode();
    1372     ASSERT(parent);
    1373    
    1374     RenderObject* parentRenderer = parent->renderer();
    1375     RenderObject* nextRenderer = this->nextRenderer();
    1376    
     1418
     1419    RenderObject* newRenderer = createRendererAndStyle();
     1420
    13771421#if ENABLE(FULLSCREEN_API)
    1378     // If this node is a fullscreen node, create a new anonymous full screen
    1379     // renderer.
    1380     if (document()->webkitIsFullScreen() && document()->webkitCurrentFullScreenElement() == this) {
    1381         RenderFullScreen* fullscreenRenderer = new (document()->renderArena()) RenderFullScreen(document());
    1382         fullscreenRenderer->setStyle(RenderFullScreen::createFullScreenStyle());
    1383         parentRenderer->addChild(fullscreenRenderer, 0);
    1384         parentRenderer = fullscreenRenderer;
    1385         nextRenderer = 0;
    1386         document()->setFullScreenRenderer(fullscreenRenderer);
    1387     }
     1422    if (document()->webkitIsFullScreen() && document()->webkitCurrentFullScreenElement() == this)
     1423        newRenderer = wrapWithRenderFullScreen(newRenderer, document());
    13881424#endif
    13891425
    1390     // FIXME: Ignoreing canHaveChildren() in a case of isShadowRoot() might be wrong.
    1391     // See https://bugs.webkit.org/show_bug.cgi?id=52423
    1392     if (parentRenderer && (parentRenderer->canHaveChildren() || isShadowRoot()) && parent->childShouldCreateRenderer(this)) {
    1393         RefPtr<RenderStyle> style = styleForRenderer();
    1394         if (rendererIsNeeded(style.get())) {
    1395             if (RenderObject* r = createRenderer(document()->renderArena(), style.get())) {
    1396                 if (!parentRenderer->isChildAllowed(r, style.get()))
    1397                     r->destroy();
    1398                 else {
    1399                     setRenderer(r);
    1400                     renderer()->setAnimatableStyle(style.release());
    1401                     parentRenderer->addChild(renderer(), nextRenderer);
    1402                 }
    1403             }
    1404         }
    1405     }
     1426    if (!newRenderer)
     1427        return;
     1428
     1429    // Note: Adding newRenderer instead of renderer(). renderer() may be a child of newRenderer.
     1430    parentOrHostNode()->renderer()->addChild(newRenderer, nextRenderer());
    14061431}
    14071432
  • trunk/Source/WebCore/dom/Node.h

    r80231 r80330  
    660660    void markAncestorsWithChildNeedsStyleRecalc();
    661661
     662    RenderObject* createRendererAndStyle();
     663
    662664    virtual void refEventTarget();
    663665    virtual void derefEventTarget();
Note: See TracChangeset for help on using the changeset viewer.