Changeset 146879 in webkit


Ignore:
Timestamp:
Mar 26, 2013 6:53:19 AM (11 years ago)
Author:
abucur@adobe.com
Message:

Use DOM ordering for list counts
https://bugs.webkit.org/show_bug.cgi?id=110352

Reviewed by Elliott Sprehn.

Source/WebCore:

Currently the list items ordering is made by traversing the render tree. This gives bad results for:

  • list items flown inside regions because they are not rendered as descendants of their DOM list ancestors.
  • list items matched to insertion points inside a shadow tree. The insertion point may be a child of a

list so the numbering gets broken.

To implement correct DOM ordering I've taken into account the fact that pseudo-elements can have display: list-item
so they should be included when traversing the DOM tree. I've added helper methods on the NodeTraversal
namespace that should allow easily traversing the tree including the pseudo-elements (e.g. firstChildWithPseudo
for an element with pseudo-before will return the before PseudoElement). Using these helper methods I've implemented
pre-order traversal methods aware of the pseudo-elements.
An effect of this change is how the list items inside shadow tree update their counting. With the patch, if there's
no <ol> or <ul> element on the ancestor chain of a <li> element to the shadow root, the list node will be considered the
first parent of the <li> or the shadow root if there is no ancestor.
The RenderListItem class now makes use of this new method of traversal, replacing the one based on the render tree.
To simplify the CSS counters implementation, I've changed the traversal functions inside RenderCounter to also make use
of this method. The CSS counters and the list items now have the same traversal algorithm.

In later patches I'll add tests that should cover the regions and shadow DOM use cases.
Tests bug for shadow DOM: https://bugs.webkit.org/show_bug.cgi?id=113193
Tests bug for regions: https://bugs.webkit.org/show_bug.cgi?id=103975

Tests: no new tests is this patch; added the correct expectations for fast/lists/positioned-count-crash.html
and fast/dom/shadow/shadow-and-list-elements.html

  • dom/Node.cpp:

(WebCore::Node::pseudoAwarePreviousSibling):
(WebCore):
(WebCore::Node::pseudoAwareNextSibling):
(WebCore::Node::pseudoAwareFirstChild):
(WebCore::Node::pseudoAwareLastChild):

  • dom/Node.h:

(Node):

  • dom/NodeTraversal.cpp:

(WebCore):
(WebCore::NodeTraversal::previousIncludingPseudo):
(NodeTraversal):
(WebCore::NodeTraversal::nextIncludingPseudo):
(WebCore::NodeTraversal::nextIncludingPseudoSkippingChildren):

  • dom/NodeTraversal.h:

(ElementTraversal):
(NodeTraversal):
(WebCore::ElementTraversal::previousIncludingPseudo):
(WebCore::ElementTraversal::nextIncludingPseudo):
(WebCore::ElementTraversal::nextIncludingPseudoSkippingChildren):
(WebCore::ElementTraversal::pseudoAwarePreviousSibling):

  • html/HTMLLIElement.cpp:

(WebCore::HTMLLIElement::attach):

  • html/HTMLOListElement.cpp:

(WebCore::HTMLOListElement::updateItemValues):
(WebCore::HTMLOListElement::recalculateItemCount):

  • rendering/RenderCounter.cpp:

(WebCore::previousInPreOrder):
(WebCore::previousSiblingOrParent):
(WebCore::parentElement):
(WebCore::nextInPreOrder):

  • rendering/RenderListItem.cpp:

(WebCore):
(WebCore::enclosingList):
(WebCore::RenderListItem::nextListItem):
(WebCore::previousListItem):
(WebCore::RenderListItem::calcValue):
(WebCore::RenderListItem::explicitValueChanged):
(WebCore::previousOrNextItem):
(WebCore::RenderListItem::updateListMarkerNumbers):

  • rendering/RenderListItem.h:

(RenderListItem):

LayoutTests:

The fast/dom/shadow/shadow-and-list-elements-expected.html has changed because the list items
inside the shadow tree no longer see the root <ol> element.
The test fast/lists/positioned-count-crash.html has the correct rendering after changing
the list counting to be in DOM order.

  • fast/dom/shadow/shadow-and-list-elements-expected.html:
  • fast/lists/positioned-count-crash-expected.txt:
Location:
trunk
Files:
13 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r146877 r146879  
     12013-03-26  Andrei Bucur  <abucur@adobe.com>
     2
     3        Use DOM ordering for list counts
     4        https://bugs.webkit.org/show_bug.cgi?id=110352
     5
     6        Reviewed by Elliott Sprehn.
     7
     8        The fast/dom/shadow/shadow-and-list-elements-expected.html has changed because the list items
     9        inside the shadow tree no longer see the root <ol> element.
     10        The test fast/lists/positioned-count-crash.html has the correct rendering after changing
     11        the list counting to be in DOM order.
     12
     13        * fast/dom/shadow/shadow-and-list-elements-expected.html:
     14        * fast/lists/positioned-count-crash-expected.txt:
     15
    1162013-03-26  Zoltan Arvai  <zarvai@inf.u-szeged.hu>
    217
  • trunk/LayoutTests/fast/dom/shadow/shadow-and-list-elements-expected.html

    r123570 r146879  
    2323// </ol>   
    2424var hostEquivalent = document.getElementById("hostEquivalent");
     25var shadowListRoot = document.createElement("ol");
     26shadowListRoot.style.paddingLeft = "0px";
     27hostEquivalent.appendChild(shadowListRoot);
    2528
    2629var childX = document.createElement("li");
    2730childX.innerHTML = "X";
    28 hostEquivalent.appendChild(childX);
     31childX.style.listStylePosition = "inside";
     32shadowListRoot.appendChild(childX);
    2933
    3034var childUl = document.createElement("ul");
    3135childUl.innerHTML = "B";
    32 hostEquivalent.appendChild(childUl);
     36shadowListRoot.appendChild(childUl);
    3337
    3438var childY = document.createElement("li");
    3539childY.innerHTML = "Y";
    36 hostEquivalent.appendChild(childY);
     40childY.style.listStylePosition = "inside";
     41shadowListRoot.appendChild(childY);
    3742</script>
    3843</body>
  • trunk/LayoutTests/fast/lists/positioned-count-crash-expected.txt

    r70132 r146879  
    33
    44For manual test: If you see no crash and "II II", it means this test PASS.
    5 FAIL list marker should be II. Was I.
     5PASS list marker is II.
    66
  • trunk/Source/WebCore/ChangeLog

    r146878 r146879  
     12013-03-26  Andrei Bucur  <abucur@adobe.com>
     2
     3        Use DOM ordering for list counts
     4        https://bugs.webkit.org/show_bug.cgi?id=110352
     5
     6        Reviewed by Elliott Sprehn.
     7
     8        Currently the list items ordering is made by traversing the render tree. This gives bad results for:
     9        - list items flown inside regions because they are not rendered as descendants of their DOM list ancestors.
     10        - list items matched to insertion points inside a shadow tree. The insertion point may be a child of a
     11        list so the numbering gets broken.
     12
     13        To implement correct DOM ordering I've taken into account the fact that pseudo-elements can have display: list-item
     14        so they should be included when traversing the DOM tree. I've added helper methods on the NodeTraversal
     15        namespace that should allow easily traversing the tree including the pseudo-elements (e.g. firstChildWithPseudo
     16        for an element with pseudo-before will return the before PseudoElement). Using these helper methods I've implemented
     17        pre-order traversal methods aware of the pseudo-elements.
     18        An effect of this change is how the list items inside shadow tree update their counting. With the patch, if there's
     19        no <ol> or <ul> element on the ancestor chain of a <li> element to the shadow root, the list node will be considered the
     20        first parent of the <li> or the shadow root if there is no ancestor.
     21        The RenderListItem class now makes use of this new method of traversal, replacing the one based on the render tree.
     22        To simplify the CSS counters implementation, I've changed the traversal functions inside RenderCounter to also make use
     23        of this method. The CSS counters and the list items now have the same traversal algorithm.
     24
     25        In later patches I'll add tests that should cover the regions and shadow DOM use cases.
     26        Tests bug for shadow DOM: https://bugs.webkit.org/show_bug.cgi?id=113193
     27        Tests bug for regions: https://bugs.webkit.org/show_bug.cgi?id=103975
     28
     29        Tests: no new tests is this patch; added the correct expectations for fast/lists/positioned-count-crash.html
     30        and fast/dom/shadow/shadow-and-list-elements.html
     31
     32        * dom/Node.cpp:
     33        (WebCore::Node::pseudoAwarePreviousSibling):
     34        (WebCore):
     35        (WebCore::Node::pseudoAwareNextSibling):
     36        (WebCore::Node::pseudoAwareFirstChild):
     37        (WebCore::Node::pseudoAwareLastChild):
     38        * dom/Node.h:
     39        (Node):
     40        * dom/NodeTraversal.cpp:
     41        (WebCore):
     42        (WebCore::NodeTraversal::previousIncludingPseudo):
     43        (NodeTraversal):
     44        (WebCore::NodeTraversal::nextIncludingPseudo):
     45        (WebCore::NodeTraversal::nextIncludingPseudoSkippingChildren):
     46        * dom/NodeTraversal.h:
     47        (ElementTraversal):
     48        (NodeTraversal):
     49        (WebCore::ElementTraversal::previousIncludingPseudo):
     50        (WebCore::ElementTraversal::nextIncludingPseudo):
     51        (WebCore::ElementTraversal::nextIncludingPseudoSkippingChildren):
     52        (WebCore::ElementTraversal::pseudoAwarePreviousSibling):
     53        * html/HTMLLIElement.cpp:
     54        (WebCore::HTMLLIElement::attach):
     55        * html/HTMLOListElement.cpp:
     56        (WebCore::HTMLOListElement::updateItemValues):
     57        (WebCore::HTMLOListElement::recalculateItemCount):
     58        * rendering/RenderCounter.cpp:
     59        (WebCore::previousInPreOrder):
     60        (WebCore::previousSiblingOrParent):
     61        (WebCore::parentElement):
     62        (WebCore::nextInPreOrder):
     63        * rendering/RenderListItem.cpp:
     64        (WebCore):
     65        (WebCore::enclosingList):
     66        (WebCore::RenderListItem::nextListItem):
     67        (WebCore::previousListItem):
     68        (WebCore::RenderListItem::calcValue):
     69        (WebCore::RenderListItem::explicitValueChanged):
     70        (WebCore::previousOrNextItem):
     71        (WebCore::RenderListItem::updateListMarkerNumbers):
     72        * rendering/RenderListItem.h:
     73        (RenderListItem):
     74
    1752013-03-26  Allan Sandfeld Jensen  <allan.jensen@digia.com>
    276
  • trunk/Source/WebCore/dom/Node.cpp

    r146853 r146879  
    11351135}
    11361136
     1137Node* Node::pseudoAwarePreviousSibling() const
     1138{
     1139    if (parentElement() && !previousSibling()) {
     1140        Element* parent = parentElement();
     1141        if (isAfterPseudoElement() && parent->lastChild())
     1142            return parent->lastChild();
     1143        if (!isBeforePseudoElement())
     1144            return parent->pseudoElement(BEFORE);
     1145    }
     1146    return previousSibling();
     1147}
     1148
     1149Node* Node::pseudoAwareNextSibling() const
     1150{
     1151    if (parentElement() && !nextSibling()) {
     1152        Element* parent = parentElement();
     1153        if (isBeforePseudoElement() && parent->firstChild())
     1154            return parent->firstChild();
     1155        if (!isAfterPseudoElement())
     1156            return parent->pseudoElement(AFTER);
     1157    }
     1158    return nextSibling();
     1159}
     1160
     1161Node* Node::pseudoAwareFirstChild() const
     1162{
     1163    if (isElementNode()) {
     1164        const Element* currentElement = toElement(this);
     1165        Node* first = currentElement->pseudoElement(BEFORE);
     1166        if (first)
     1167            return first;
     1168        first = currentElement->firstChild();
     1169        if (!first)
     1170            first = currentElement->pseudoElement(AFTER);
     1171        return first;
     1172    }
     1173
     1174    return firstChild();
     1175}
     1176
     1177Node* Node::pseudoAwareLastChild() const
     1178{
     1179    if (isElementNode()) {
     1180        const Element* currentElement = toElement(this);
     1181        Node* last = currentElement->pseudoElement(AFTER);
     1182        if (last)
     1183            return last;
     1184        last = currentElement->lastChild();
     1185        if (!last)
     1186            last = currentElement->pseudoElement(BEFORE);
     1187        return last;
     1188    }
     1189
     1190    return lastChild();
     1191}
     1192
    11371193// FIXME: This code is used by editing.  Seems like it could move over there and not pollute Node.
    11381194Node *Node::previousNodeConsideringAtomicNodes() const
  • trunk/Source/WebCore/dom/Node.h

    r146853 r146879  
    196196    bool hasAttributes() const;
    197197    NamedNodeMap* attributes() const;
     198    Node* pseudoAwareNextSibling() const;
     199    Node* pseudoAwarePreviousSibling() const;
     200    Node* pseudoAwareFirstChild() const;
     201    Node* pseudoAwareLastChild() const;
    198202
    199203    virtual KURL baseURI() const;
  • trunk/Source/WebCore/dom/NodeTraversal.cpp

    r137221 r146879  
    2727
    2828#include "ContainerNode.h"
     29#include "PseudoElement.h"
    2930
    3031namespace WebCore {
     32
    3133namespace NodeTraversal {
     34
     35Node* previousIncludingPseudo(const Node* current, const Node* stayWithin)
     36{
     37    Node* previous;
     38    if (current == stayWithin)
     39        return 0;
     40    if ((previous = current->pseudoAwarePreviousSibling())) {
     41        while (previous->pseudoAwareLastChild())
     42            previous = previous->pseudoAwareLastChild();
     43        return previous;
     44    }
     45    return current->parentNode();
     46}
     47
     48Node* nextIncludingPseudo(const Node* current, const Node* stayWithin)
     49{
     50    Node* next;
     51    if ((next = current->pseudoAwareFirstChild()))
     52        return next;
     53    if (current == stayWithin)
     54        return 0;
     55    if ((next = current->pseudoAwareNextSibling()))
     56        return next;
     57    for (current = current->parentNode(); current; current = current->parentNode()) {
     58        if (current == stayWithin)
     59            return 0;
     60        if ((next = current->pseudoAwareNextSibling()))
     61            return next;
     62    }
     63    return 0;
     64}
     65
     66Node* nextIncludingPseudoSkippingChildren(const Node* current, const Node* stayWithin)
     67{
     68    Node* next;
     69    if (current == stayWithin)
     70        return 0;
     71    if ((next = current->pseudoAwareNextSibling()))
     72        return next;
     73    for (current = current->parentNode(); current; current = current->parentNode()) {
     74        if (current == stayWithin)
     75            return 0;
     76        if ((next = current->pseudoAwareNextSibling()))
     77            return next;
     78    }
     79    return 0;
     80}
    3281
    3382Node* nextAncestorSibling(const Node* current)
  • trunk/Source/WebCore/dom/NodeTraversal.h

    r137406 r146879  
    3535Element* firstWithin(const Node*);
    3636Element* firstWithin(const ContainerNode*);
     37
    3738// Pre-order traversal skipping non-element nodes.
    3839Element* next(const Node*);
     
    4041Element* next(const ContainerNode*);
    4142Element* next(const ContainerNode*, const Node* stayWithin);
     43
    4244// Like next, but skips children.
    4345Element* nextSkippingChildren(const Node*);
     
    4547Element* nextSkippingChildren(const ContainerNode*);
    4648Element* nextSkippingChildren(const ContainerNode*, const Node* stayWithin);
     49
     50// Pre-order traversal including the pseudo-elements.
     51Element* previousIncludingPseudo(const Node*, const Node* = 0);
     52Element* nextIncludingPseudo(const Node*, const Node* = 0);
     53Element* nextIncludingPseudoSkippingChildren(const Node*, const Node* = 0);
     54
     55// Utility function to traverse only the element and pseudo-element siblings of a node.
     56Element* pseudoAwarePreviousSibling(const Node*);
    4757
    4858}
     
    7888Node* previousSkippingChildrenPostOrder(const Node*, const Node* stayWithin = 0);
    7989
     90// Pre-order traversal including the pseudo-elements.
     91Node* previousIncludingPseudo(const Node*, const Node* = 0);
     92Node* nextIncludingPseudo(const Node*, const Node* = 0);
     93Node* nextIncludingPseudoSkippingChildren(const Node*, const Node* = 0);
     94
    8095}
    8196
     
    136151inline Element* nextSkippingChildren(const ContainerNode* current, const Node* stayWithin) { return traverseNextElementSkippingChildrenTemplate(current, stayWithin); }
    137152inline Element* nextSkippingChildren(const Node* current, const Node* stayWithin) { return traverseNextElementSkippingChildrenTemplate(current, stayWithin); }
     153
     154inline Element* previousIncludingPseudo(const Node* current, const Node* stayWithin)
     155{
     156    Node* node = NodeTraversal::previousIncludingPseudo(current, stayWithin);
     157    while (node && !node->isElementNode())
     158        node = NodeTraversal::previousIncludingPseudo(node, stayWithin);
     159    return toElement(node);
     160}
     161
     162inline Element* nextIncludingPseudo(const Node* current, const Node* stayWithin)
     163{
     164    Node* node = NodeTraversal::nextIncludingPseudo(current, stayWithin);
     165    while (node && !node->isElementNode())
     166        node = NodeTraversal::nextIncludingPseudo(node, stayWithin);
     167    return toElement(node);
     168}
     169
     170inline Element* nextIncludingPseudoSkippingChildren(const Node* current, const Node* stayWithin)
     171{
     172    Node* node = NodeTraversal::nextIncludingPseudoSkippingChildren(current, stayWithin);
     173    while (node && !node->isElementNode())
     174        node = NodeTraversal::nextIncludingPseudoSkippingChildren(node, stayWithin);
     175    return toElement(node);
     176}
     177
     178inline Element* pseudoAwarePreviousSibling(const Node* current)
     179{
     180    Node* node = current->pseudoAwarePreviousSibling();
     181    while (node && !node->isElementNode())
     182        node = node->pseudoAwarePreviousSibling();
     183    return toElement(node);
     184}
     185
    138186}
    139187
  • trunk/Source/WebCore/html/HTMLLIElement.cpp

    r143843 r146879  
    9393
    9494    if (renderer() && renderer()->isListItem()) {
    95         RenderListItem* render = toRenderListItem(renderer());
     95        RenderListItem* listItemRenderer = toRenderListItem(renderer());
    9696
    9797        // Find the enclosing list node.
    98         Node* listNode = 0;
    99         EventPathWalker walker(this);
     98        Element* listNode = 0;
     99        Element* current = this;
    100100        while (!listNode) {
    101             walker.moveToParent();
    102             if (!walker.node())
     101            current = current->parentElement();
     102            if (!current)
    103103                break;
    104             if (walker.node()->hasTagName(ulTag) || walker.node()->hasTagName(olTag))
    105                 listNode = walker.node();
     104            if (current->hasTagName(ulTag) || current->hasTagName(olTag))
     105                listNode = current;
    106106        }
    107107
     
    109109        // We don't want to change our style to say "inside" since that would affect nested nodes.
    110110        if (!listNode)
    111             render->setNotInList(true);
     111            listItemRenderer->setNotInList(true);
    112112
    113113        parseValue(fastGetAttribute(valueAttr));
  • trunk/Source/WebCore/html/HTMLOListElement.cpp

    r143843 r146879  
    107107void HTMLOListElement::updateItemValues()
    108108{
    109     for (RenderListItem* listItem = RenderListItem::nextListItem(renderer()); listItem; listItem = RenderListItem::nextListItem(renderer(), listItem))
     109    for (RenderListItem* listItem = RenderListItem::nextListItem(this); listItem; listItem = RenderListItem::nextListItem(this, listItem))
    110110        listItem->updateValue();
    111111}
     
    115115    m_itemCount = 0;
    116116
    117     for (RenderListItem* listItem = RenderListItem::nextListItem(renderer()); listItem; listItem = RenderListItem::nextListItem(renderer(), listItem))
     117    for (RenderListItem* listItem = RenderListItem::nextListItem(this); listItem; listItem = RenderListItem::nextListItem(this, listItem))
    118118        m_itemCount++;
    119119
  • trunk/Source/WebCore/rendering/RenderCounter.cpp

    r143380 r146879  
    5858static RenderObject* previousInPreOrder(const RenderObject* object)
    5959{
    60     Element* parent;
    61     Element* sibling;
    62     switch (object->style()->styleType()) {
    63     case NOPSEUDO:
    64         ASSERT(!object->isAnonymous());
    65         parent = toElement(object->node());
    66         sibling = parent->previousElementSibling();
    67         parent = parent->parentElement();
    68         break;
    69     case BEFORE:
    70         return object->generatingNode()->renderer(); // It is always the generating node's renderer
    71     case AFTER:
    72         parent = toElement(object->generatingNode());
    73         sibling = parent->lastElementChild();
    74         break;
    75     default:
    76         ASSERT_NOT_REACHED();
    77         return 0;
    78     }
    79     while (sibling) {
    80         if (RenderObject* renderer = sibling->renderer()) {
    81             if (RenderObject* after = sibling->pseudoElementRenderer(AFTER))
    82                 return after;
    83             parent = sibling;
    84             sibling = sibling->lastElementChild();
    85             if (!sibling) {
    86                 if (RenderObject* before = toElement(renderer->node())->pseudoElementRenderer(BEFORE))
    87                     return before;
    88                 return renderer;
    89             }
    90         } else
    91             sibling = sibling->previousElementSibling();
    92     }
    93     if (!parent)
    94         return 0;
    95     if (RenderObject* before = parent->pseudoElementRenderer(BEFORE))
    96         return before;
    97     return parent->renderer();
     60    Element* self = toElement(object->node());
     61    Element* previous = ElementTraversal::previousIncludingPseudo(self);
     62    while (previous && !previous->renderer())
     63        previous = ElementTraversal::previousIncludingPseudo(previous);
     64    return previous ? previous->renderer() : 0;
    9865}
    9966
     
    10269static RenderObject* previousSiblingOrParent(const RenderObject* object)
    10370{
    104     Element* parent;
    105     Element* sibling;
    106     switch (object->style()->styleType()) {
    107     case NOPSEUDO:
    108         ASSERT(!object->isAnonymous());
    109         parent = toElement(object->node());
    110         sibling = parent->previousElementSibling();
    111         parent = parent->parentElement();
    112         break;
    113     case BEFORE:
    114         return object->generatingNode()->renderer(); // It is always the generating node's renderer
    115     case AFTER:
    116         parent = toElement(object->generatingNode());
    117         sibling = parent->lastElementChild();
    118         break;
    119     default:
    120         ASSERT_NOT_REACHED();
    121         return 0;
    122     }
    123     while (sibling) {
    124         if (RenderObject* renderer = sibling->renderer()) // This skips invisible nodes
    125             return renderer;
    126         sibling = sibling->previousElementSibling();
    127     }
    128     if (!parent)
    129         return 0;
    130     if (RenderObject* before = parent->pseudoElementRenderer(BEFORE))
    131         return before;
    132     return parent->renderer();
    133 }
    134 
    135 static Element* parentElement(RenderObject* object)
    136 {
    137     switch (object->style()->styleType()) {
    138     case NOPSEUDO:
    139         ASSERT(!object->isAnonymous());
    140         return toElement(object->node())->parentElement();
    141     case BEFORE:
    142     case AFTER:
    143         return toElement(object->generatingNode());
    144     default:
    145         ASSERT_NOT_REACHED();
    146         return 0;
    147     }
     71    Element* self = toElement(object->node());
     72    Element* previous = ElementTraversal::pseudoAwarePreviousSibling(self);
     73    while (previous && !previous->renderer())
     74        previous = ElementTraversal::pseudoAwarePreviousSibling(previous);
     75    if (previous)
     76        return previous->renderer();
     77    previous = self->parentElement();
     78    return previous ? previous->renderer() : 0;
     79}
     80
     81static inline Element* parentElement(RenderObject* object)
     82{
     83    return toElement(object->node())->parentElement();
    14884}
    14985
     
    15793static RenderObject* nextInPreOrder(const RenderObject* object, const Element* stayWithin, bool skipDescendants = false)
    15894{
    159     Element* self;
    160     Element* child;
    161     self = toElement(object->generatingNode());
    162     if (skipDescendants)
    163         goto nextsibling;
    164     switch (object->style()->styleType()) {
    165     case NOPSEUDO:
    166         ASSERT(!object->isAnonymous());
    167         if (RenderObject* before = self->pseudoElementRenderer(BEFORE))
    168             return before;
    169         break;
    170     case BEFORE:
    171         break;
    172     case AFTER:
    173         goto nextsibling;
    174     default:
    175         ASSERT_NOT_REACHED();
    176         return 0;
    177     }
    178     child = ElementTraversal::firstWithin(self);
    179     while (true) {
    180         while (child) {
    181             if (RenderObject* renderer = child->renderer())
    182                 return renderer;
    183             child = ElementTraversal::nextSkippingChildren(child, self);
    184         }
    185         if (RenderObject* after = self->pseudoElementRenderer(AFTER))
    186             return after;
    187 nextsibling:
    188         if (self == stayWithin)
    189             return 0;
    190         child = ElementTraversal::nextSkippingChildren(self);
    191         self = self->parentElement();
    192         if (!self) {
    193             ASSERT(!child); // We can only reach this if we are searching beyond the root element
    194             return 0; //  which cannot have siblings
    195         }
    196     }
     95    Element* self = toElement(object->node());
     96    Element* next = skipDescendants ? ElementTraversal::nextIncludingPseudoSkippingChildren(self, stayWithin) : ElementTraversal::nextIncludingPseudo(self, stayWithin);
     97    while (next && !next->renderer())
     98        next = skipDescendants ? ElementTraversal::nextIncludingPseudoSkippingChildren(next, stayWithin) : ElementTraversal::nextIncludingPseudo(next, stayWithin);
     99    return next ? next->renderer() : 0;
    197100}
    198101
  • trunk/Source/WebCore/rendering/RenderListItem.cpp

    r144565 r146879  
    2828#include "HTMLNames.h"
    2929#include "HTMLOListElement.h"
     30#include "NodeTraversal.h"
    3031#include "RenderListMarker.h"
    3132#include "RenderView.h"
     
    9798}
    9899
     100// Returns the enclosing list with respect to the DOM order.
    99101static Node* enclosingList(const RenderListItem* listItem)
    100102{
     103    Node* listItemNode = listItem->node();
    101104    Node* firstNode = 0;
    102 
    103     for (const RenderObject* renderer = listItem->parent(); renderer; renderer = renderer->parent()) {
    104         Node* node = renderer->node();
    105         if (node) {
    106             if (isList(node))
    107                 return node;
    108             if (!firstNode)
    109                 firstNode = node;
    110         }
     105    // We use parentNode because the enclosing list could be a ShadowRoot that's not Element.
     106    for (Node* parent = listItemNode->parentNode(); parent; parent = parent->parentNode()) {
     107        if (isList(parent))
     108            return parent;
     109        if (!firstNode)
     110            firstNode = parent;
    111111    }
    112112
     
    117117}
    118118
    119 RenderListItem* RenderListItem::nextListItem(RenderObject* list, const RenderListItem* item)
    120 {
    121     if (!list)
     119// Returns the next list item with respect to the DOM order.
     120RenderListItem* RenderListItem::nextListItem(Node* listNode, const RenderListItem* item)
     121{
     122    if (!listNode)
    122123        return 0;
    123124
    124     RenderObject* renderer = item ? item->nextInPreOrder(list) : list->nextInPreOrder(list);
    125     while (renderer) {
    126         if (renderer->node() && isList(renderer->node())) {
     125    Node* current = item ? item->node() : listNode;
     126    current = ElementTraversal::nextIncludingPseudo(current, listNode);
     127
     128    while (current) {
     129        if (isList(current)) {
    127130            // We've found a nested, independent list: nothing to do here.
    128             renderer = renderer->nextInPreOrderAfterChildren(list);
     131            current = ElementTraversal::nextIncludingPseudoSkippingChildren(current, listNode);
    129132            continue;
    130133        }
    131134
    132         if (renderer->isListItem())
     135        RenderObject* renderer = current->renderer();
     136        if (renderer && renderer->isListItem())
    133137            return toRenderListItem(renderer);
    134138
    135         renderer = renderer->nextInPreOrder(list);
    136     }
     139        // FIXME: Can this be optimized to skip the children of the elements without a renderer?
     140        current = ElementTraversal::nextIncludingPseudo(current, listNode);
     141    }
     142
    137143    return 0;
    138144}
    139145
    140 static RenderListItem* previousListItem(RenderObject* list, const RenderListItem* item)
    141 {
    142     for (RenderObject* renderer = item->previousInPreOrder(); renderer && renderer != list; renderer = renderer->previousInPreOrder()) {
    143         if (!renderer->isListItem())
     146// Returns the previous list item with respect to the DOM order.
     147static RenderListItem* previousListItem(Node* listNode, const RenderListItem* item)
     148{
     149    Node* current = item->node();
     150    for (current = ElementTraversal::previousIncludingPseudo(current, listNode); current; current = ElementTraversal::previousIncludingPseudo(current, listNode)) {
     151        RenderObject* renderer = current->renderer();
     152        if (!renderer || (renderer && !renderer->isListItem()))
    144153            continue;
    145154        Node* otherList = enclosingList(toRenderListItem(renderer));
    146155        // This item is part of our current list, so it's what we're looking for.
    147         if (list->node() == otherList)
     156        if (listNode == otherList)
    148157            return toRenderListItem(renderer);
    149158        // We found ourself inside another list; lets skip the rest of it.
    150         // Use nextInPreOrder() here because the other list itself may actually
     159        // Use nextIncludingPseudo() here because the other list itself may actually
    151160        // be a list item itself. We need to examine it, so we do this to counteract
    152         // the previousInPreOrder() that will be done by the loop.
     161        // the previousIncludingPseudo() that will be done by the loop.
    153162        if (otherList)
    154             renderer = otherList->renderer()->nextInPreOrder();
     163            current = ElementTraversal::nextIncludingPseudo(otherList);
    155164    }
    156165    return 0;
     
    163172
    164173    Node* list = enclosingList(this);
    165     RenderObject* listRenderer = list ? list->renderer() : 0;
    166174    HTMLOListElement* oListElement = (list && list->hasTagName(olTag)) ? static_cast<HTMLOListElement*>(list) : 0;
    167175    int valueStep = 1;
     
    171179    // FIXME: This recurses to a possible depth of the length of the list.
    172180    // That's not good -- we need to change this to an iterative algorithm.
    173     if (RenderListItem* previousItem = previousListItem(listRenderer, this))
     181    if (RenderListItem* previousItem = previousListItem(list, this))
    174182        return previousItem->value() + valueStep;
    175183
     
    428436        m_marker->setNeedsLayoutAndPrefWidthsRecalc();
    429437    Node* listNode = enclosingList(this);
    430     RenderObject* listRenderer = 0;
    431     if (listNode)
    432         listRenderer = listNode->renderer();
    433     for (RenderListItem* item = this; item; item = nextListItem(listRenderer, item))
     438    for (RenderListItem* item = this; item; item = nextListItem(listNode, item))
    434439        item->updateValue();
    435440}
     
    458463}
    459464
    460 static RenderListItem* previousOrNextItem(bool isListReversed, RenderObject* list, RenderListItem* item)
     465static RenderListItem* previousOrNextItem(bool isListReversed, Node* list, RenderListItem* item)
    461466{
    462467    return isListReversed ? previousListItem(list, item) : RenderListItem::nextListItem(list, item);
     
    466471{
    467472    Node* listNode = enclosingList(this);
    468     ASSERT(listNode && listNode->renderer());
    469     if (!listNode || !listNode->renderer())
     473    // The list node can be the shadow root which has no renderer.
     474    ASSERT(listNode);
     475    if (!listNode)
    470476        return;
    471477
    472478    bool isListReversed = false;
    473     RenderObject* list = listNode->renderer();
    474479    HTMLOListElement* oListElement = (listNode && listNode->hasTagName(olTag)) ? static_cast<HTMLOListElement*>(listNode) : 0;
    475480    if (oListElement) {
     
    477482        isListReversed = oListElement->isReversed();
    478483    }
    479     for (RenderListItem* item = previousOrNextItem(isListReversed, list, this); item; item = previousOrNextItem(isListReversed, list, item)) {
     484    for (RenderListItem* item = previousOrNextItem(isListReversed, listNode, this); item; item = previousOrNextItem(isListReversed, listNode, item)) {
    480485        if (!item->m_isValueUpToDate) {
    481486            // If an item has been marked for update before, we can safely
  • trunk/Source/WebCore/rendering/RenderListItem.h

    r140640 r146879  
    5050    void updateListMarkerNumbers();
    5151
    52     static RenderListItem* nextListItem(RenderObject* listRenderer, const RenderListItem* = 0);
     52    static RenderListItem* nextListItem(Node*, const RenderListItem* = 0);
    5353
    5454private:
Note: See TracChangeset for help on using the changeset viewer.