Changeset 77702 in webkit


Ignore:
Timestamp:
Feb 4, 2011 4:28:57 PM (13 years ago)
Author:
carol.szabo@nokia.com
Message:

2011-02-04 Carol Szabo <carol.szabo@nokia.com>

Reviewed by David Hyatt.

Code Changes.

CSS 2.1 failure: content-*
https://bugs.webkit.org/show_bug.cgi?id=52126

  • fast/css/counters/content-021-expected.txt: Added.
  • fast/css/counters/content-021.html: Added. This is a copy of the test with the same name from the official css test suite, adapted for DumpRenderTree.

2011-02-04 Carol Szabo <carol.szabo@nokia.com>

Reviewed by David Hyatt.

Code Changes.

CSS 2.1 failure: content-*
https://bugs.webkit.org/show_bug.cgi?id=52126

Test: fast/css/counters/content-021.html

  • rendering/CounterNode.cpp: (showCounterTree): Made parameter const because it is supposed to be so.
  • rendering/RenderCounter.cpp: (WebCore::previousInPreOrder): (WebCore::previousSiblingOrParent): (WebCore::parentElement): (WebCore::areRenderersElementsSiblings): (WebCore::nextInPreOrder): Added these local helper functions to help navigate the DOM tree enriched with :before and :after pseudo elements. (WebCore::planCounter): Fixed bug that would create a repeat counter for second and subsequent renderers associated with the same DOM element. (WebCore::findPlaceForCounter): (WebCore::makeCounterNode): Changed to use the new tree navigation functions described above instead of the Renderer Tree navigation functions. (WebCore::RenderCounter::rendererSubtreeAttached): (WebCore::RenderCounter::rendererStyleChanged): Optimized to not bother about counters until the renderers are finally attached. (showRendererTree): (showNodeTree): Debug helper functions used to debug Counter bugs.
Location:
trunk
Files:
2 added
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r77700 r77702  
     12011-02-04  Carol Szabo  <carol.szabo@nokia.com>
     2
     3        Reviewed by David Hyatt.
     4
     5        Code Changes.
     6
     7        CSS 2.1 failure: content-*
     8        https://bugs.webkit.org/show_bug.cgi?id=52126
     9
     10        * fast/css/counters/content-021-expected.txt: Added.
     11        * fast/css/counters/content-021.html: Added.
     12        This is a copy of the test with the same name from the
     13        official css test suite, adapted for DumpRenderTree.
     14
    1152011-02-04  Dimitri Glazkov  <dglazkov@chromium.org>
    216
  • trunk/Source/WebCore/ChangeLog

    r77698 r77702  
     12011-02-04  Carol Szabo  <carol.szabo@nokia.com>
     2
     3        Reviewed by David Hyatt.
     4
     5        Code Changes.
     6
     7        CSS 2.1 failure: content-*
     8        https://bugs.webkit.org/show_bug.cgi?id=52126
     9
     10        Test: fast/css/counters/content-021.html
     11
     12        * rendering/CounterNode.cpp:
     13        (showCounterTree):
     14        Made parameter const because it is supposed to be so.
     15        * rendering/RenderCounter.cpp:
     16        (WebCore::previousInPreOrder):
     17        (WebCore::previousSiblingOrParent):
     18        (WebCore::parentElement):
     19        (WebCore::areRenderersElementsSiblings):
     20        (WebCore::nextInPreOrder):
     21        Added these local helper functions to help navigate the DOM tree
     22        enriched with :before and :after pseudo elements.
     23        (WebCore::planCounter):
     24        Fixed bug that would create a repeat counter for second and
     25        subsequent renderers associated with the same DOM element.
     26        (WebCore::findPlaceForCounter):
     27        (WebCore::makeCounterNode):
     28        Changed to use the new tree navigation functions described above
     29        instead of the Renderer Tree navigation functions.
     30        (WebCore::RenderCounter::rendererSubtreeAttached):
     31        (WebCore::RenderCounter::rendererStyleChanged):
     32        Optimized to not bother about counters until the renderers are
     33        finally attached.
     34        (showRendererTree):
     35        (showNodeTree):
     36        Debug helper functions used to debug Counter bugs.
     37
    1382011-02-04  Dan Bernstein  <mitz@apple.com>
    239
  • trunk/Source/WebCore/rendering/CounterNode.cpp

    r75611 r77702  
    264264#ifndef NDEBUG
    265265
    266 void showTree(const WebCore::CounterNode* counter)
     266void showCounterTree(const WebCore::CounterNode* counter)
    267267{
    268268    if (counter)
  • trunk/Source/WebCore/rendering/CounterNode.h

    r68819 r77702  
    9595#ifndef NDEBUG
    9696// Outside the WebCore namespace for ease of invocation from gdb.
    97 void showTree(const WebCore::CounterNode*);
     97void showCounterTree(const WebCore::CounterNode*);
    9898#endif
    9999
  • trunk/Source/WebCore/rendering/RenderCounter.cpp

    r76859 r77702  
    2525#include "CounterNode.h"
    2626#include "Document.h"
     27#include "Element.h"
    2728#include "HTMLNames.h"
    2829#include "HTMLOListElement.h"
     
    4748}
    4849
    49 static inline RenderObject* previousSiblingOrParent(RenderObject* object)
    50 {
    51     if (RenderObject* sibling = object->previousSibling())
    52         return sibling;
    53     return object->parent();
     50// This function processes the renderer tree in the order of the DOM tree
     51// including pseudo elements as defined in CSS 2.1.
     52// Anonymous renderers are skipped except for those representing pseudo elements.
     53static RenderObject* previousInPreOrder(const RenderObject* object)
     54{
     55    Element* parent;
     56    Element* sibling;
     57    switch (object->style()->styleType()) {
     58    case NOPSEUDO:
     59        ASSERT(!object->isAnonymous());
     60        parent = toElement(object->node());
     61        sibling = parent->previousElementSibling();
     62        parent = parent->parentElement();
     63        break;
     64    case BEFORE:
     65        return object->generatingNode()->renderer(); // It is always the generating node's renderer
     66    case AFTER:
     67        parent = toElement(object->generatingNode());
     68        sibling = parent->lastElementChild();
     69        break;
     70    default:
     71        ASSERT_NOT_REACHED();
     72        return 0;
     73    }
     74    while (sibling) {
     75        if (RenderObject* renderer = sibling->renderer()) {
     76            if (RenderObject* after = renderer->afterPseudoElementRenderer())
     77                return after;
     78            parent = sibling;
     79            sibling = sibling->lastElementChild();
     80            if (!sibling) {
     81                if (RenderObject* before = renderer->beforePseudoElementRenderer())
     82                    return before;
     83                return renderer;
     84            }
     85        } else
     86            sibling = sibling->previousElementSibling();
     87    }
     88    if (!parent)
     89        return 0;
     90    RenderObject* renderer = parent->renderer(); // Should never be null
     91    if (RenderObject* before = renderer->beforePseudoElementRenderer())
     92        return before;
     93    return renderer;
     94}
     95
     96// This function processes the renderer tree in the order of the DOM tree
     97// including pseudo elements as defined in CSS 2.1.
     98// Anonymous renderers are skipped except for those representing pseudo elements.
     99static RenderObject* previousSiblingOrParent(const RenderObject* object)
     100{
     101    Element* parent;
     102    Element* sibling;
     103    switch (object->style()->styleType()) {
     104    case NOPSEUDO:
     105        ASSERT(!object->isAnonymous());
     106        parent = toElement(object->node());
     107        sibling = parent->previousElementSibling();
     108        parent = parent->parentElement();
     109        break;
     110    case BEFORE:
     111        return object->generatingNode()->renderer(); // It is always the generating node's renderer
     112    case AFTER:
     113        parent = toElement(object->generatingNode());
     114        sibling = parent->lastElementChild();
     115        break;
     116    default:
     117        ASSERT_NOT_REACHED();
     118        return 0;
     119    }
     120    while (sibling) {
     121        if (RenderObject* renderer = sibling->renderer()) // This skips invisible nodes
     122            return renderer;
     123        sibling = sibling->previousElementSibling();
     124    }
     125    if (parent) {
     126        RenderObject* renderer = parent->renderer();
     127        if (RenderObject* before = renderer->virtualChildren()->beforePseudoElementRenderer(renderer))
     128            return before;
     129        return renderer;
     130    }
     131    return 0;
     132}
     133
     134static Element* parentElement(RenderObject* object)
     135{
     136    switch (object->style()->styleType()) {
     137    case NOPSEUDO:
     138        ASSERT(!object->isAnonymous());
     139        return toElement(object->node())->parentElement();
     140    case BEFORE:
     141    case AFTER:
     142        return toElement(object->generatingNode());
     143    default:
     144        ASSERT_NOT_REACHED();
     145        return 0;
     146    }
     147}
     148
     149static inline bool areRenderersElementsSiblings(RenderObject* first, RenderObject* second)
     150{
     151    return parentElement(first) == parentElement(second);
     152}
     153
     154// This function processes the renderer tree in the order of the DOM tree
     155// including pseudo elements as defined in CSS 2.1.
     156// Anonymous renderers are skipped except for those representing pseudo elements.
     157static RenderObject* nextInPreOrder(const RenderObject* object, const Element* stayWithin, bool skipDescendants = false)
     158{
     159    Element* self;
     160    Element* child;
     161    RenderObject* result;
     162    self = toElement(object->generatingNode());
     163    if (skipDescendants)
     164        goto nextsibling;
     165    switch (object->style()->styleType()) {
     166    case NOPSEUDO:
     167        ASSERT(!object->isAnonymous());
     168        result = object->beforePseudoElementRenderer();
     169        if (result)
     170            return result;
     171        break;
     172    case BEFORE:
     173        break;
     174    case AFTER:
     175        goto nextsibling;
     176    default:
     177        ASSERT_NOT_REACHED();
     178        return 0;
     179    }
     180    child = self->firstElementChild();
     181    while (true) {
     182        while (child) {
     183            result = child->renderer();
     184            if (result)
     185                return result;
     186            child = child->nextElementSibling();
     187        }
     188        result = self->renderer()->afterPseudoElementRenderer();
     189        if (result)
     190            return result;
     191nextsibling:
     192        if (self == stayWithin)
     193            return 0;
     194        child = self->nextElementSibling();
     195        self = self->parentElement();
     196        if (!self) {
     197            ASSERT(!child); // We can only reach this if we are searching beyond the root element
     198            return 0; //  which cannot have siblings
     199        }
     200    }
    54201}
    55202
     
    62209    if (object->isText() && !object->isBR())
    63210        return false;
    64 
     211    Node* generatingNode = object->generatingNode();
     212    // We must have a generating node or else we cannot have a counter.
     213    if (!generatingNode)
     214        return false;
    65215    RenderStyle* style = object->style();
    66216    ASSERT(style);
     217
     218    switch (style->styleType()) {
     219    case NOPSEUDO:
     220        // Sometimes nodes have more then one renderer. Only the first one gets the counter
     221        // LayoutTests/http/tests/css/counter-crash.html
     222        if (generatingNode->renderer() != object)
     223            return false;
     224        break;
     225    case BEFORE:
     226    case AFTER:
     227        break;
     228    default:
     229        return false; // Counters are forbidden from all other pseudo elements.
     230    }
    67231
    68232    if (const CounterDirectiveMap* directivesMap = style->counterDirectives()) {
     
    134298    // towards the begining of the document for counters with the same identifier as the one
    135299    // we are trying to find a place for. This is the next renderer to be checked.
    136     RenderObject* currentRenderer = counterOwner->previousInPreOrder();
     300    RenderObject* currentRenderer = previousInPreOrder(counterOwner);
    137301    previousSibling = 0;
    138302    while (currentRenderer) {
     
    145309                    if (currentCounter->actsAsReset()) {
    146310                        // We found a reset counter that is on a renderer that is a sibling of ours or a parent.
    147                         if (isReset && currentRenderer->parent() == counterOwner->parent()) {
     311                        if (isReset && areRenderersElementsSiblings(currentRenderer, counterOwner)) {
    148312                            // We are also a reset counter and the previous reset was on a sibling renderer
    149313                            // hence we are the next sibling of that counter if that reset is not a root or
     
    160324                    }
    161325                    // CurrentCounter, the counter at the EndSearchRenderer, is not reset.
    162                     if (!isReset || currentRenderer->parent() != counterOwner->parent()) {
     326                    if (!isReset || !areRenderersElementsSiblings(currentRenderer, counterOwner)) {
    163327                        // If the node we are placing is not reset or we have found a counter that is attached
    164328                        // to an ancestor of the placed counter's renderer we know we are a sibling of that node.
     
    173337                    // to currentCounter.
    174338                    if (currentCounter->actsAsReset()) {
    175                         if (isReset && currentRenderer->parent() == counterOwner->parent()) {
     339                        if (isReset && areRenderersElementsSiblings(currentRenderer, counterOwner)) {
    176340                            parent = currentCounter->parent();
    177341                            previousSibling = currentCounter;
     
    181345                        return true;
    182346                    }
    183                     if (!isReset || currentRenderer->parent() != counterOwner->parent()) {
     347                    if (!isReset || !areRenderersElementsSiblings(currentRenderer, counterOwner)) {
    184348                        parent = currentCounter->parent();
    185349                        previousSibling = currentCounter;
     
    206370                        // We are no longer interested in previous siblings of the currentRenderer or their children
    207371                        // as counters they may have attached cannot be the previous sibling of the counter we are placing.
    208                         currentRenderer = currentRenderer->parent();
     372                        currentRenderer = parentElement(currentRenderer)->renderer();
    209373                        continue;
    210374                    }
     
    257421    }
    258422    nodeMap->set(identifier.impl(), newNode);
    259     if (newNode->parent() || !object->nextInPreOrder(object->parent()))
     423    if (newNode->parent())
    260424        return newNode.get();
    261425    // Checking if some nodes that were previously counter tree root nodes
    262426    // should become children of this node now.
    263427    CounterMaps& maps = counterMaps();
    264     RenderObject* stayWithin = object->parent();
    265     for (RenderObject* currentRenderer = object->nextInPreOrder(stayWithin); currentRenderer; currentRenderer = currentRenderer->nextInPreOrder(stayWithin)) {
     428    Element* stayWithin = parentElement(object);
     429    bool skipDescendants;
     430    for (RenderObject* currentRenderer = nextInPreOrder(object, stayWithin); currentRenderer; currentRenderer = nextInPreOrder(currentRenderer, stayWithin, skipDescendants)) {
     431        skipDescendants = false;
    266432        if (!currentRenderer->m_hasCounterNodeMap)
    267433            continue;
     
    269435        if (!currentCounter)
    270436            continue;
     437        skipDescendants = true;
    271438        if (currentCounter->parent()) {
    272439            ASSERT(newNode->firstChild());
    273             if (currentRenderer->lastChild())
    274                 currentRenderer = currentRenderer->lastChild();
    275440            continue;
    276441        }
    277         if (stayWithin != currentRenderer->parent() || !currentCounter->hasResetType())
    278             newNode->insertAfter(currentCounter, newNode->lastChild(), identifier);
    279         if (currentRenderer->lastChild())
    280             currentRenderer = currentRenderer->lastChild();
     442        if (stayWithin == parentElement(currentRenderer) && currentCounter->hasResetType())
     443            break;
     444        newNode->insertAfter(currentCounter, newNode->lastChild(), identifier);
    281445    }
    282446    return newNode.get();
     
    445609void RenderCounter::rendererSubtreeAttached(RenderObject* renderer)
    446610{
     611    Node* node = renderer->node();
     612    if (node)
     613        node = node->parentNode();
     614    else
     615        node = renderer->generatingNode();
     616    if (node && !node->attached())
     617        return; // No need to update if the parent is not attached yet
    447618    for (RenderObject* descendant = renderer; descendant; descendant = descendant->nextInPreOrder(renderer))
    448619        updateCounters(descendant);
     
    451622void RenderCounter::rendererStyleChanged(RenderObject* renderer, const RenderStyle* oldStyle, const RenderStyle* newStyle)
    452623{
     624    Node* node = renderer->generatingNode();
     625    if (!node || !node->attached())
     626        return; // cannot have generated content or if it can have, it will be handled during attaching
    453627    const CounterDirectiveMap* newCounterDirectives;
    454628    const CounterDirectiveMap* oldCounterDirectives;
     
    490664
    491665} // namespace WebCore
     666
     667#ifndef NDEBUG
     668
     669void showCounterRendererTree(const WebCore::RenderObject* renderer, const char* counterName)
     670{
     671    if (!renderer)
     672        return;
     673    const WebCore::RenderObject* root = renderer;
     674    while (root->parent())
     675        root = root->parent();
     676
     677    AtomicString identifier(counterName);
     678    for (const WebCore::RenderObject* current = root; current; current = current->nextInPreOrder()) {
     679        fprintf(stderr, "%c", (current == renderer) ? '*' : ' ');
     680        for (const WebCore::RenderObject* parent = current; parent && parent != root; parent = parent->parent())
     681            fprintf(stderr, "    ");
     682        fprintf(stderr, "%p N:%p P:%p PS:%p NS:%p C:%p\n",
     683            current, current->node(), current->parent(), current->previousSibling(),
     684            current->nextSibling(), current->m_hasCounterNodeMap?
     685            counterName ? WebCore::counterMaps().get(current)->get(identifier.impl()).get() : (WebCore::CounterNode*)1 : (WebCore::CounterNode*)0);
     686    }
     687}
     688
     689#endif // NDEBUG
  • trunk/Source/WebCore/rendering/RenderCounter.h

    r69437 r77702  
    6868} // namespace WebCore
    6969
     70#ifndef NDEBUG
     71// Outside the WebCore namespace for ease of invocation from gdb.
     72void showCounterRendererTree(const WebCore::RenderObject*, const char* counterName = 0);
     73#endif
     74
    7075#endif // RenderCounter_h
Note: See TracChangeset for help on using the changeset viewer.