Changeset 148026 in webkit


Ignore:
Timestamp:
Apr 9, 2013 8:27:05 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

    r148022 r148026  
     12013-04-09  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-04-09  Rafael Brandao  <rafael.lobo@openbossa.org>
    217
  • trunk/LayoutTests/fast/dom/shadow/shadow-and-list-elements-expected.html

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

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

    r148020 r148026  
     12013-04-09  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-04-09  Bruno de Oliveira Abinader  <bruno.abinader@basyskom.com>
    276
  • trunk/Source/WebCore/dom/Node.cpp

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

    r147795 r148026  
    194194    bool hasAttributes() const;
    195195    NamedNodeMap* attributes() const;
     196    Node* pseudoAwareNextSibling() const;
     197    Node* pseudoAwarePreviousSibling() const;
     198    Node* pseudoAwareFirstChild() const;
     199    Node* pseudoAwareLastChild() const;
    196200
    197201    virtual KURL baseURI() const;
  • trunk/Source/WebCore/dom/NodeTraversal.cpp

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

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

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

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

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

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

    r146883 r148026  
    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.