Add support for <ol reversed>.
authoralexis.menard@openbossa.org <alexis.menard@openbossa.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 16 Dec 2011 13:43:37 +0000 (13:43 +0000)
committeralexis.menard@openbossa.org <alexis.menard@openbossa.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 16 Dec 2011 13:43:37 +0000 (13:43 +0000)
https://bugs.webkit.org/show_bug.cgi?id=36724

The reversed attribute makes an ordered list appear with marker values
decreasing from n, where n is the number of items.
See: http://www.whatwg.org/specs/web-apps/current-work/#attr-ol-reversed

Patch by Alexis Menard  <alexis.menard@openbossa.org>, Jakub Wieczorek <jwieczorek@webkit.org> on 2011-12-16
Reviewed by Darin Adler.

Source/WebCore:

Tests: fast/lists/ol-reversed-dynamic-simple.html
       fast/lists/ol-reversed-dynamic.html
       fast/lists/ol-reversed-nested-items.html
       fast/lists/ol-reversed-nested-list.html
       fast/lists/ol-reversed-simple.html

* html/HTMLAttributeNames.in:
* html/HTMLOListElement.cpp:
(WebCore::HTMLOListElement::HTMLOListElement):
(WebCore::HTMLOListElement::parseMappedAttribute):
(WebCore::HTMLOListElement::updateItemValues):
(WebCore::HTMLOListElement::recalculateItemCount):
* html/HTMLOListElement.h:
(WebCore::HTMLOListElement::start):
(WebCore::HTMLOListElement::isReversed):
(WebCore::HTMLOListElement::itemCountChanged):
(WebCore::HTMLOListElement::itemCount):
* html/HTMLOListElement.idl:
* rendering/RenderListItem.cpp:
(WebCore::RenderListItem::nextListItem):
(WebCore::previousListItem):
(WebCore::RenderListItem::calcValue):
(WebCore::RenderListItem::explicitValueChanged):
(WebCore::previousOrNextItem):
(WebCore::RenderListItem::updateListMarkerNumbers):
* rendering/RenderListItem.h:

LayoutTests:

* fast/lists/ol-reversed-dynamic-expected.txt: Added.
* fast/lists/ol-reversed-dynamic-simple-expected.txt: Added.
* fast/lists/ol-reversed-dynamic-simple.html: Added.
* fast/lists/ol-reversed-dynamic.html: Added.
* fast/lists/ol-reversed-nested-items-expected.txt: Added.
* fast/lists/ol-reversed-nested-items.html: Added.
* fast/lists/ol-reversed-nested-list-expected.txt: Added.
* fast/lists/ol-reversed-nested-list.html: Added.
* fast/lists/ol-reversed-simple-expected.txt: Added.
* fast/lists/ol-reversed-simple.html: Added.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@103062 268f45cc-cd09-0410-ab3c-d52691b4dbfc

19 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/lists/ol-reversed-dynamic-expected.txt [new file with mode: 0644]
LayoutTests/fast/lists/ol-reversed-dynamic-simple-expected.txt [new file with mode: 0644]
LayoutTests/fast/lists/ol-reversed-dynamic-simple.html [new file with mode: 0644]
LayoutTests/fast/lists/ol-reversed-dynamic.html [new file with mode: 0644]
LayoutTests/fast/lists/ol-reversed-nested-items-expected.txt [new file with mode: 0644]
LayoutTests/fast/lists/ol-reversed-nested-items.html [new file with mode: 0644]
LayoutTests/fast/lists/ol-reversed-nested-list-expected.txt [new file with mode: 0644]
LayoutTests/fast/lists/ol-reversed-nested-list.html [new file with mode: 0644]
LayoutTests/fast/lists/ol-reversed-simple-expected.txt [new file with mode: 0644]
LayoutTests/fast/lists/ol-reversed-simple.html [new file with mode: 0644]
LayoutTests/fast/lists/ol-reversed-simple.xhtml [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/html/HTMLAttributeNames.in
Source/WebCore/html/HTMLOListElement.cpp
Source/WebCore/html/HTMLOListElement.h
Source/WebCore/html/HTMLOListElement.idl
Source/WebCore/rendering/RenderListItem.cpp
Source/WebCore/rendering/RenderListItem.h

index 3ec6228..8b5ff7c 100644 (file)
@@ -1,3 +1,25 @@
+2011-12-16  Alexis Menard  <alexis.menard@openbossa.org>, Jakub Wieczorek  <jwieczorek@webkit.org>
+
+        Add support for <ol reversed>.
+        https://bugs.webkit.org/show_bug.cgi?id=36724
+
+        The reversed attribute makes an ordered list appear with marker values
+        decreasing from n, where n is the number of items.
+        See: http://www.whatwg.org/specs/web-apps/current-work/#attr-ol-reversed
+
+        Reviewed by Darin Adler.
+
+        * fast/lists/ol-reversed-dynamic-expected.txt: Added.
+        * fast/lists/ol-reversed-dynamic-simple-expected.txt: Added.
+        * fast/lists/ol-reversed-dynamic-simple.html: Added.
+        * fast/lists/ol-reversed-dynamic.html: Added.
+        * fast/lists/ol-reversed-nested-items-expected.txt: Added.
+        * fast/lists/ol-reversed-nested-items.html: Added.
+        * fast/lists/ol-reversed-nested-list-expected.txt: Added.
+        * fast/lists/ol-reversed-nested-list.html: Added.
+        * fast/lists/ol-reversed-simple-expected.txt: Added.
+        * fast/lists/ol-reversed-simple.html: Added.
+
 2011-12-16  Hajime Morrita  <morrita@chromium.org>
 
         Unreviewed, test_expectations.txt update.
diff --git a/LayoutTests/fast/lists/ol-reversed-dynamic-expected.txt b/LayoutTests/fast/lists/ol-reversed-dynamic-expected.txt
new file mode 100644 (file)
index 0000000..27e7440
--- /dev/null
@@ -0,0 +1,40 @@
+This tests that changing the value of an item updates markers accordingly.
+
+10 Ten
+9 Nine
+8 Eight
+7 Seven
+6 Six
+
+This tests that resetting the value of an item updates markers accordingly.
+
+5 Five
+4 Four
+3 Three
+2 Two
+1 One
+
+This tests that changing the start value of the list updates markers accordingly.
+
+20 Twenty
+19 Nineteen
+18 Eighteen
+17 Seventeen
+16 Sixteen
+
+This tests that removing the custom start value of the list updates markers accordingly.
+
+5 Five
+4 Four
+3 Three
+2 Two
+1 One
+
+This tests that changing the custom start value from 1 to "" works.
+
+5 Five
+4 Four
+3 Three
+2 Two
+1 One
+
diff --git a/LayoutTests/fast/lists/ol-reversed-dynamic-simple-expected.txt b/LayoutTests/fast/lists/ol-reversed-dynamic-simple-expected.txt
new file mode 100644 (file)
index 0000000..9c39e6c
--- /dev/null
@@ -0,0 +1,34 @@
+This tests that changing the "reversed" property updates markers.
+
+5 Five
+4 Four
+3 Three
+2 Two
+1 One
+
+This tests that changing the "reversed" attribute updates markers.
+
+5 Five
+4 Four
+3 Three
+2 Two
+1 One
+
+This tests that adding new items to a reversed list updates markers.
+
+7 Seven
+6 Six
+5 Five
+-> 4 Four
+3 Three
+2 Two
+1 One
+
+This tests that removing existing tems from a reversed list updates markers.
+
+5 Five
+4 Four
+3 Three
+2 Two
+1 One
+
diff --git a/LayoutTests/fast/lists/ol-reversed-dynamic-simple.html b/LayoutTests/fast/lists/ol-reversed-dynamic-simple.html
new file mode 100644 (file)
index 0000000..4050f88
--- /dev/null
@@ -0,0 +1,86 @@
+<html>
+    <head>
+        <script src="resources/dump-list.js"></script>
+        <script>
+            function test()
+            {
+                if (window.layoutTestController)
+                    layoutTestController.dumpAsText();
+
+                var list1 = document.getElementById("list1");
+                list1.offsetTop; // Force a relayout.
+                list1.reversed = true;
+                document.getElementById("console1").innerHTML = dumpList(list1);
+
+                var list2 = document.getElementById("list2");
+                list2.setAttribute("reversed", "");
+                document.getElementById("console2").innerHTML = dumpList(list2);
+
+                var list3 = document.getElementById("list3");
+                var li1 = document.createElement("li");
+                li1.innerHTML = "Four";
+                list3.querySelector("p").appendChild(li1);
+                var li2 = document.createElement("li");
+                li2.innerHTML = "One";
+                list3.appendChild(li2);
+                document.getElementById("console3").innerHTML = dumpList(list3);
+
+                var list4 = document.getElementById("list4");
+                var div = list4.querySelector("div");
+                div.removeChild(div.firstElementChild);
+                list4.removeChild(list4.lastElementChild);
+                document.getElementById("console4").innerHTML = dumpList(list4);
+
+                // Don't show the actual lists as they are useless in the text-only mode.
+                list1.parentNode.removeChild(list1);
+                list2.parentNode.removeChild(list2);
+                list3.parentNode.removeChild(list3);
+                list4.parentNode.removeChild(list4);
+            }
+        </script>
+    </head>
+    <body onload="test()">
+        <p>This tests that changing the "reversed" property updates markers.</p>
+        <ol id="list1">
+            <li>Five</li>
+            <li>Four</li>
+            <li>Three</li>
+            <li>Two</li>
+            <li>One</li>
+        </ol>
+        <p id="console1"></p>
+
+        <p>This tests that changing the "reversed" attribute updates markers.</p>
+        <ol id="list2">
+            <li>Five</li>
+            <li>Four</li>
+            <li>Three</li>
+            <li>Two</li>
+            <li>One</li>
+        </ol>
+        <p id="console2"></p>
+
+        <p>This tests that adding new items to a reversed list updates markers.</p>
+        <ol id="list3" reversed>
+            <li>Seven</li>
+            <li>Six</li>
+            <li>Five</li>
+            <p></p>
+            <li>Three</li>
+            <li>Two</li>
+        </ol>
+        <p id="console3"></p>
+
+        <p>This tests that removing existing tems from a reversed list updates markers.</p>
+        <ol id="list4" reversed>
+            <li>Five</li>
+            <li>Four</li>
+            <li>Three</li>
+            <div><li>Foo</li></div>
+            <li>Two</li>
+            <li>One</li>
+            <li>Bar</li>
+        </ol>
+        <p id="console4"></p>
+    </body>
+</html>
diff --git a/LayoutTests/fast/lists/ol-reversed-dynamic.html b/LayoutTests/fast/lists/ol-reversed-dynamic.html
new file mode 100644 (file)
index 0000000..1fe732e
--- /dev/null
@@ -0,0 +1,91 @@
+<html>
+    <head>
+        <script src="resources/dump-list.js"></script>
+        <script>
+            function test()
+            {
+                if (window.layoutTestController)
+                    layoutTestController.dumpAsText();
+
+                var list1 = document.getElementById("list1");
+                list1.offsetTop; // Force a relayout.
+                list1.firstElementChild.value = 10;
+                document.getElementById("console1").innerHTML = dumpList(list1);
+
+                var list2 = document.getElementById("list2");
+                list2.querySelector("li[value=\"20\"]").removeAttribute("value");
+                document.getElementById("console2").innerHTML = dumpList(list2);
+
+                var list3 = document.getElementById("list3");
+                list3.start = 20;
+                document.getElementById("console3").innerHTML = dumpList(list3);
+
+                var list4 = document.getElementById("list4");
+                list4.removeAttribute("start");
+                document.getElementById("console4").innerHTML = dumpList(list4);
+
+                var list5 = document.getElementById("list5");
+                list5.setAttribute("start","");
+                document.getElementById("console5").innerHTML = dumpList(list5);
+
+                // Don't show the actual lists as they are useless in the text-only mode.
+                list1.parentNode.removeChild(list1);
+                list2.parentNode.removeChild(list2);
+                list3.parentNode.removeChild(list3);
+                list4.parentNode.removeChild(list4);
+                list5.parentNode.removeChild(list5);
+            }
+        </script>
+    </head>
+    <body onload="test()">
+        <p>This tests that changing the value of an item updates markers accordingly.</p>
+        <ol id="list1" reversed>
+            <li>Ten</li>
+            <li>Nine</li>
+            <li>Eight</li>
+            <li>Seven</li>
+            <li>Six</li>
+        </ol>
+        <p id="console1"></p>
+
+        <p>This tests that resetting the value of an item updates markers accordingly.</p>
+        <ol id="list2" reversed>
+            <li>Five</li>
+            <li>Four</li>
+            <li value="20">Three</li>
+            <li>Two</li>
+            <li>One</li>
+        </ol>
+        <p id="console2"></p>
+
+        <p>This tests that changing the start value of the list updates markers accordingly.</p>
+        <ol id="list3" reversed start="5">
+            <li>Twenty</li>
+            <li>Nineteen</li>
+            <li>Eighteen</li>
+            <li>Seventeen</li>
+            <li>Sixteen</li>
+        </ol>
+        <p id="console3"></p>
+
+        <p>This tests that removing the custom start value of the list updates markers accordingly.</p>
+        <ol id="list4" reversed start="20">
+            <li>Five</li>
+            <li>Four</li>
+            <li>Three</li>
+            <li>Two</li>
+            <li>One</li>
+        </ol>
+        <p id="console4"></p>
+
+        <p>This tests that changing the custom start value from 1 to "" works.</p>
+        <ol id="list5" reversed start="1">
+            <li>Five</li>
+            <li>Four</li>
+            <li>Three</li>
+            <li>Two</li>
+            <li>One</li>
+        </ol>
+        <p id="console5"></p>
+    </body>
+</html>
diff --git a/LayoutTests/fast/lists/ol-reversed-nested-items-expected.txt b/LayoutTests/fast/lists/ol-reversed-nested-items-expected.txt
new file mode 100644 (file)
index 0000000..19c80eb
--- /dev/null
@@ -0,0 +1,15 @@
+This tests that list items are properly marked when some of the items are indirect children of a reversed list.
+
+12 Twelve
+11 Eleven
+10 Ten
+9 Nine
+8 Eight
+-> 7 Seven
+4 Four
+3 Three
+-> 2 Two
+-> 1 One
+0 Zero
+-1 Minus One
+
diff --git a/LayoutTests/fast/lists/ol-reversed-nested-items.html b/LayoutTests/fast/lists/ol-reversed-nested-items.html
new file mode 100644 (file)
index 0000000..5a9d5a1
--- /dev/null
@@ -0,0 +1,42 @@
+<html>
+    <head>
+        <script src="resources/dump-list.js"></script>
+        <script>
+            function test()
+            {
+                if (window.layoutTestController)
+                    layoutTestController.dumpAsText();
+
+                var list = document.getElementById("list");
+                document.getElementById("console").innerHTML = dumpList(list);
+
+                // Don't show the actual list as it is useless in the text-only mode.
+                list.parentNode.removeChild(list);
+            }
+        </script>
+    </head>
+    <body onload="test()">
+        <p>This tests that list items are properly marked when some of the items are indirect children of a reversed list.</p>
+        <ol id="list" reversed="reversed">
+            <li>Twelve</li>
+            <li>Eleven</li>
+            <li>Ten</li>
+            <li>Nine
+            <li>Eight</li>
+                <b>
+                    <li>Seven</li>
+                </b>
+            </li>
+            <li value="4">Four</li>
+            <li>Three</li>
+            <div>
+                <li>Two</li>
+                <li>One</li>
+            </div>
+            <li>Zero</li>
+            <li>Minus One</li>
+        </ol>
+
+        <div id="console"></div>
+    </body>
+</html>
diff --git a/LayoutTests/fast/lists/ol-reversed-nested-list-expected.txt b/LayoutTests/fast/lists/ol-reversed-nested-list-expected.txt
new file mode 100644 (file)
index 0000000..da61d0e
--- /dev/null
@@ -0,0 +1,16 @@
+This tests that list items are properly marked when a reversed list contains nested lists.
+
+10 Ten
+9 Nine
+8 Eight
+7 Seven One Two
+-> -> ◦ One
+-> -> ◦ Two
+6 Six
+5 Five
+-> 2 Two
+-> 1 One
+4 Four
+3 Three
+2 Two
+
diff --git a/LayoutTests/fast/lists/ol-reversed-nested-list.html b/LayoutTests/fast/lists/ol-reversed-nested-list.html
new file mode 100644 (file)
index 0000000..8c46131
--- /dev/null
@@ -0,0 +1,43 @@
+<html>
+    <head>
+        <script src="resources/dump-list.js"></script>
+        <script>
+            function test()
+            {
+                if (window.layoutTestController)
+                    layoutTestController.dumpAsText();
+
+                var list = document.getElementById("list");
+                document.getElementById("console").innerHTML = dumpList(list);
+
+                // Don't show the actual list as it is useless in the text-only mode.
+                list.parentNode.removeChild(list);
+            }
+        </script>
+    </head>
+    <body onload="test()">
+        <p>This tests that list items are properly marked when a reversed list contains nested lists.</p>
+        <ol id="list" start="10" reversed>
+            <li>Ten</li>
+            <li>Nine</li>
+            <li>Eight</li>
+            <li>Seven
+                <ul>
+                    <li>One</li>
+                    <li>Two</li>
+                </ul>
+            </li>
+            <li>Six</li>
+            <li>Five</li>
+            <ol reversed>
+                <li>Two</li>
+                <li>One</li>
+            </ol>
+            <li>Four</li>
+            <li>Three</li>
+            <li>Two</li>
+        </ol>
+
+        <div id="console"></div>
+    </body>
+</html>
diff --git a/LayoutTests/fast/lists/ol-reversed-simple-expected.txt b/LayoutTests/fast/lists/ol-reversed-simple-expected.txt
new file mode 100644 (file)
index 0000000..b7f9e6e
--- /dev/null
@@ -0,0 +1,46 @@
+This tests that reversed lists render properly.
+
+5 Five
+4 Four
+3 Three
+2 Two
+1 One
+
+This tests that reversed lists with a custom start value render properly.
+
+10 Ten
+9 Nine
+8 Eight
+7 Seven
+6 Six
+
+This tests that reversed lists with explicit item values render properly.
+
+5 Five
+4 Four
+2 Two
+1 One
+0 Zero
+
+This tests that reversed lists with a custom start value and explicit item values render properly.
+
+10 Ten
+9 Nine
+3 Three
+2 Two
+1 One
+3 Three
+2 Two
+1 One
+
+This tests that reversed lists with a negative start value render properly.
+
+-5 Minus Five
+-6 Minus Six
+-7 Minus Seven
+-8 Minus Eight
+-9 Minus Nine
+
+This tests that reversed lists have the start attribute equals the number of list items when no start value is specified.
+
+Value of start attribute of the list is : 5
diff --git a/LayoutTests/fast/lists/ol-reversed-simple.html b/LayoutTests/fast/lists/ol-reversed-simple.html
new file mode 100644 (file)
index 0000000..3cde91f
--- /dev/null
@@ -0,0 +1,103 @@
+<html>
+    <head>
+        <script src="resources/dump-list.js"></script>
+        <script>
+            function test()
+            {
+                if (window.layoutTestController)
+                    layoutTestController.dumpAsText();
+
+                var list1 = document.getElementById("list1");
+                document.getElementById("console1").innerHTML = dumpList(list1);
+
+                var list2 = document.getElementById("list2");
+                document.getElementById("console2").innerHTML = dumpList(list2);
+
+                var list3 = document.getElementById("list3");
+                document.getElementById("console3").innerHTML = dumpList(list3);
+
+                var list4 = document.getElementById("list4");
+                document.getElementById("console4").innerHTML = dumpList(list4);
+
+                var list5 = document.getElementById("list5");
+                document.getElementById("console5").innerHTML = dumpList(list5);
+
+                var list6 = document.getElementById("list6");
+                document.getElementById("console6").innerHTML = "Value of start attribute of the list is : " + list6.start;
+
+                // Don't show the actual lists as they are useless in the text-only mode.
+                list1.parentNode.removeChild(list1);
+                list2.parentNode.removeChild(list2);
+                list3.parentNode.removeChild(list3);
+                list4.parentNode.removeChild(list4);
+                list5.parentNode.removeChild(list5);
+                list6.parentNode.removeChild(list6);
+            }
+        </script>
+    </head>
+    <body onload="test()">
+        <p>This tests that reversed lists render properly.</p>
+        <ol id="list1" reversed>
+            <li>Five</li>
+            <li>Four</li>
+            <div style="display: list-item">Three</div>
+            <li>Two</li>
+            <li>One</li>
+        </ol>
+        <p id="console1"></p>
+
+        <p>This tests that reversed lists with a custom start value render properly.</p>
+        <ol id="list2" reversed="reversed" start="10">
+            <li>Ten</li>
+            <li>Nine</li>
+            <li>Eight</li>
+            <li>Seven</li>
+            <li>Six</li>
+        </ol>
+        <p id="console2"></p>
+
+        <p>This tests that reversed lists with explicit item values render properly.</p>
+        <ol id="list3" reversed>
+            <li>Five</li>
+            <li>Four</li>
+            <li value="2">Two</li>
+            <li>One</li>
+            <li>Zero</li>
+        </ol>
+        <p id="console3"></p>
+
+        <p>This tests that reversed lists with a custom start value and explicit item values render properly.</p>
+        <ol id="list4" reversed start="10">
+            <li>Ten</li>
+            <li>Nine</li>
+            <li value="3">Three</li>
+            <li>Two</li>
+            <li>One</li>
+            <li value="3">Three</li>
+            <li>Two</li>
+            <li>One</li>
+        </ol>
+        <p id="console4"></p>
+
+        <p>This tests that reversed lists with a negative start value render properly.</p>
+        <ol id="list5" reversed="reversed" start="-5">
+            <li>Minus Five</li>
+            <li>Minus Six</li>
+            <li>Minus Seven</li>
+            <li>Minus Eight</li>
+            <li>Minus Nine</li>
+        </ol>
+        <p id="console5"></p>
+
+        <p>This tests that reversed lists have the start attribute equals the number of list items when no start value is specified.</p>
+        <ol id="list6" reversed>
+            <li>Five</li>
+            <li>Four</li>
+            <li>Three</li>
+            <li>Two</li>
+            <li>One</li>
+        </ol>
+        <p id="console6"></p>
+
+    </body>
+</html>
diff --git a/LayoutTests/fast/lists/ol-reversed-simple.xhtml b/LayoutTests/fast/lists/ol-reversed-simple.xhtml
new file mode 100644 (file)
index 0000000..52dcae7
--- /dev/null
@@ -0,0 +1,104 @@
+<?xml version="1.0"?>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+    <script src="resources/dump-list.js"></script>
+    <script>
+        function test()
+        {
+            if (window.layoutTestController)
+                layoutTestController.dumpAsText();
+
+            var list1 = document.getElementById("list1");
+            document.getElementById("console1").innerHTML = dumpList(list1);
+
+            var list2 = document.getElementById("list2");
+            document.getElementById("console2").innerHTML = dumpList(list2);
+
+            var list3 = document.getElementById("list3");
+            document.getElementById("console3").innerHTML = dumpList(list3);
+
+            var list4 = document.getElementById("list4");
+            document.getElementById("console4").innerHTML = dumpList(list4);
+
+            var list5 = document.getElementById("list5");
+            document.getElementById("console5").innerHTML = dumpList(list5);
+
+            var list6 = document.getElementById("list6");
+            document.getElementById("console6").innerHTML = "Value of start attribute of the list is : " + list6.start;
+
+            // Don't show the actual lists as they are useless in the text-only mode.
+            list1.parentNode.removeChild(list1);
+            list2.parentNode.removeChild(list2);
+            list3.parentNode.removeChild(list3);
+            list4.parentNode.removeChild(list4);
+            list5.parentNode.removeChild(list5);
+            list6.parentNode.removeChild(list6);
+        }
+    </script>
+</head>
+<body onload="test()">
+    <p>This tests that reversed lists render properly.</p>
+    <ol id="list1" reversed="reversed">
+        <li>Five</li>
+        <li>Four</li>
+        <div style="display: list-item">Three</div>
+        <li>Two</li>
+        <li>One</li>
+    </ol>
+    <p id="console1"></p>
+
+    <p>This tests that reversed lists with a custom start value render properly.</p>
+    <ol id="list2" reversed="reversed" start="10">
+        <li>Ten</li>
+        <li>Nine</li>
+        <li>Eight</li>
+        <li>Seven</li>
+        <li>Six</li>
+    </ol>
+    <p id="console2"></p>
+
+    <p>This tests that reversed lists with explicit item values render properly.</p>
+    <ol id="list3" reversed="reversed">
+        <li>Five</li>
+        <li>Four</li>
+        <li value="2">Two</li>
+        <li>One</li>
+        <li>Zero</li>
+    </ol>
+    <p id="console3"></p>
+
+    <p>This tests that reversed lists with a custom start value and explicit item values render properly.</p>
+    <ol id="list4" reversed="reversed" start="10">
+        <li>Ten</li>
+        <li>Nine</li>
+        <li value="3">Three</li>
+        <li>Two</li>
+        <li>One</li>
+        <li value="3">Three</li>
+        <li>Two</li>
+        <li>One</li>
+    </ol>
+    <p id="console4"></p>
+
+    <p>This tests that reversed lists with a negative start value render properly.</p>
+    <ol id="list5" reversed="reversed" start="-5">
+        <li>Minus Five</li>
+        <li>Minus Six</li>
+        <li>Minus Seven</li>
+        <li>Minus Eight</li>
+        <li>Minus Nine</li>
+    </ol>
+    <p id="console5"></p>
+
+    <p>This tests that reversed lists have the start attribute equals the number of list items when no start value is specified.</p>
+    <ol id="list6" reversed="reversed">
+        <li>Five</li>
+        <li>Four</li>
+        <li>Three</li>
+        <li>Two</li>
+        <li>One</li>
+    </ol>
+    <p id="console6"></p>
+
+</body>
+</html>
index a9ff74e..c08b334 100644 (file)
@@ -1,3 +1,41 @@
+2011-12-16  Alexis Menard  <alexis.menard@openbossa.org>, Jakub Wieczorek  <jwieczorek@webkit.org>
+
+        Add support for <ol reversed>.
+        https://bugs.webkit.org/show_bug.cgi?id=36724
+
+        The reversed attribute makes an ordered list appear with marker values
+        decreasing from n, where n is the number of items.
+        See: http://www.whatwg.org/specs/web-apps/current-work/#attr-ol-reversed
+
+        Reviewed by Darin Adler.
+
+        Tests: fast/lists/ol-reversed-dynamic-simple.html
+               fast/lists/ol-reversed-dynamic.html
+               fast/lists/ol-reversed-nested-items.html
+               fast/lists/ol-reversed-nested-list.html
+               fast/lists/ol-reversed-simple.html
+
+        * html/HTMLAttributeNames.in:
+        * html/HTMLOListElement.cpp:
+        (WebCore::HTMLOListElement::HTMLOListElement):
+        (WebCore::HTMLOListElement::parseMappedAttribute):
+        (WebCore::HTMLOListElement::updateItemValues):
+        (WebCore::HTMLOListElement::recalculateItemCount):
+        * html/HTMLOListElement.h:
+        (WebCore::HTMLOListElement::start):
+        (WebCore::HTMLOListElement::isReversed):
+        (WebCore::HTMLOListElement::itemCountChanged):
+        (WebCore::HTMLOListElement::itemCount):
+        * html/HTMLOListElement.idl:
+        * rendering/RenderListItem.cpp:
+        (WebCore::RenderListItem::nextListItem):
+        (WebCore::previousListItem):
+        (WebCore::RenderListItem::calcValue):
+        (WebCore::RenderListItem::explicitValueChanged):
+        (WebCore::previousOrNextItem):
+        (WebCore::RenderListItem::updateListMarkerNumbers):
+        * rendering/RenderListItem.h:
+
 2011-12-15  Stephen White  <senorblanco@chromium.org>
 
         Enable CSS_FILTERS in Chromium.
index 4c1d5a7..d90a2f7 100644 (file)
@@ -35,7 +35,11 @@ using namespace HTMLNames;
 
 HTMLOListElement::HTMLOListElement(const QualifiedName& tagName, Document* document)
     : HTMLElement(tagName, document)
-    , m_start(1)
+    , m_start(0xBADBEEF)
+    , m_itemCount(0)
+    , m_hasExplicitStart(false)
+    , m_isReversed(false)
+    , m_shouldRecalculateItemCount(false)
 {
     ASSERT(hasTagName(olTag));
 }
@@ -74,17 +78,20 @@ void HTMLOListElement::parseMappedAttribute(Attribute* attr)
         else if (attr->value() == "1")
             addCSSProperty(attr, CSSPropertyListStyleType, CSSValueDecimal);
     } else if (attr->name() == startAttr) {
+        int oldStart = start();
         bool canParse;
-        int start = attr->value().toInt(&canParse);
-        if (!canParse)
-            start = 1;
-        if (start == m_start)
+        int parsedStart = attr->value().toInt(&canParse);
+        m_hasExplicitStart = canParse;
+        m_start = canParse ? parsedStart : 0xBADBEEF;
+        if (oldStart == start())
             return;
-        m_start = start;
-        for (RenderObject* child = renderer(); child; child = child->nextInPreOrder(renderer())) {
-            if (child->isListItem())
-                toRenderListItem(child)->updateValue();
-        }
+        updateItemValues();
+    } else if (attr->name() == reversedAttr) {
+        bool reversed = !attr->isNull();
+        if (reversed == m_isReversed)
+            return;
+        m_isReversed = reversed;
+        updateItemValues();
     } else
         HTMLElement::parseMappedAttribute(attr);
 }
@@ -94,4 +101,20 @@ void HTMLOListElement::setStart(int start)
     setAttribute(startAttr, String::number(start));
 }
 
+void HTMLOListElement::updateItemValues()
+{
+    for (RenderListItem* listItem = RenderListItem::nextListItem(renderer()); listItem; listItem = RenderListItem::nextListItem(renderer(), listItem))
+        listItem->updateValue();
+}
+
+void HTMLOListElement::recalculateItemCount()
+{
+    m_itemCount = 0;
+
+    for (RenderListItem* listItem = RenderListItem::nextListItem(renderer()); listItem; listItem = RenderListItem::nextListItem(renderer(), listItem))
+        m_itemCount++;
+
+    m_shouldRecalculateItemCount = false;
+}
+
 }
index 179fec0..8000b28 100644 (file)
@@ -32,16 +32,36 @@ public:
     static PassRefPtr<HTMLOListElement> create(Document*);
     static PassRefPtr<HTMLOListElement> create(const QualifiedName&, Document*);
 
-    int start() const { return m_start; }
+    int start() const { return m_hasExplicitStart ? m_start : (m_isReversed ? itemCount() : 1); }
     void setStart(int);
 
+    bool isReversed() const { return m_isReversed; }
+
+    void itemCountChanged() { m_shouldRecalculateItemCount = true; }
+
 private:
     HTMLOListElement(const QualifiedName&, Document*);
         
+    void updateItemValues();
+
+    unsigned itemCount() const
+    {
+        if (m_shouldRecalculateItemCount)
+            const_cast<HTMLOListElement*>(this)->recalculateItemCount();
+        return m_itemCount;
+    }
+
+    void recalculateItemCount();
+
     virtual bool mapToEntry(const QualifiedName&, MappedAttributeEntry&) const;
     virtual void parseMappedAttribute(Attribute*);
 
     int m_start;
+    unsigned m_itemCount;
+
+    bool m_hasExplicitStart : 1;
+    bool m_isReversed : 1;
+    bool m_shouldRecalculateItemCount : 1;
 };
 
 
index 63e06b2..8d1d3a4 100644 (file)
@@ -22,6 +22,7 @@ module html {
     interface HTMLOListElement : HTMLElement {
         attribute [Reflect] boolean compact;
         attribute long start;
+        attribute [Reflect] boolean reversed;
         attribute [Reflect] DOMString type;
     };
 
index 49c9bf8..ce035d3 100644 (file)
@@ -101,14 +101,33 @@ static Node* enclosingList(const RenderListItem* listItem)
     return firstNode;
 }
 
-static RenderListItem* previousListItem(Node* list, const RenderListItem* item)
+RenderListItem* RenderListItem::nextListItem(RenderObject* list, RenderListItem* item)
 {
-    for (RenderObject* renderer = item->previousInPreOrder(); renderer && renderer != list->renderer(); renderer = renderer->previousInPreOrder()) {
+    if (!list)
+        return 0;
+
+    RenderObject* renderer = item ? item : list;
+    while ((renderer = renderer->nextInPreOrder(list))) {
+        if (renderer->node() && isList(renderer->node())) {
+            // We've found a nested, independent list: nothing to do here.
+            renderer = renderer->nextInPreOrderAfterChildren(list);
+            continue;
+        }
+
+        if (renderer->isListItem())
+            return toRenderListItem(renderer);
+    }
+    return 0;
+}
+
+static RenderListItem* previousListItem(RenderObject* list, const RenderListItem* item)
+{
+    for (RenderObject* renderer = item->previousInPreOrder(); renderer && renderer != list; renderer = renderer->previousInPreOrder()) {
         if (!renderer->isListItem())
             continue;
         Node* otherList = enclosingList(toRenderListItem(renderer));
         // This item is part of our current list, so it's what we're looking for.
-        if (list == otherList)
+        if (list->node() == otherList)
             return toRenderListItem(renderer);
         // We found ourself inside another list; lets skip the rest of it.
         // Use nextInPreOrder() here because the other list itself may actually
@@ -124,13 +143,22 @@ inline int RenderListItem::calcValue() const
 {
     if (m_hasExplicitValue)
         return m_explicitValue;
+
     Node* list = enclosingList(this);
+    RenderObject* listRenderer = list ? list->renderer() : 0;
+    HTMLOListElement* oListElement = (list && list->hasTagName(olTag)) ? static_cast<HTMLOListElement*>(list) : 0;
+    int valueStep = 1;
+    if (oListElement && oListElement->isReversed())
+        valueStep = -1;
+
     // FIXME: This recurses to a possible depth of the length of the list.
     // That's not good -- we need to change this to an iterative algorithm.
-    if (RenderListItem* previousItem = previousListItem(list, this))
-        return previousItem->value() + 1;
-    if (list && list->hasTagName(olTag))
-        return static_cast<HTMLOListElement*>(list)->start();
+    if (RenderListItem* previousItem = previousListItem(listRenderer, this))
+        return previousItem->value() + valueStep;
+
+    if (oListElement)
+        return oListElement->start();
+
     return 1;
 }
 
@@ -392,15 +420,8 @@ void RenderListItem::explicitValueChanged()
     RenderObject* listRenderer = 0;
     if (listNode)
         listRenderer = listNode->renderer();
-    for (RenderObject* renderer = this; renderer; renderer = renderer->nextInPreOrder(listRenderer))
-        if (renderer->isListItem()) {
-            RenderListItem* item = toRenderListItem(renderer);
-            if (!item->m_hasExplicitValue) {
-                item->m_isValueUpToDate = false;
-                if (RenderListMarker* marker = item->m_marker)
-                    marker->setNeedsLayoutAndPrefWidthsRecalc();
-            }
-        }
+    for (RenderListItem* item = this; item; item = nextListItem(listRenderer, item))
+        item->updateValue();
 }
 
 void RenderListItem::setExplicitValue(int value)
@@ -426,6 +447,11 @@ void RenderListItem::clearExplicitValue()
     explicitValueChanged();
 }
 
+static RenderListItem* previousOrNextItem(bool isListReversed, RenderObject* list, RenderListItem* item)
+{
+    return isListReversed ? previousListItem(list, item) : RenderListItem::nextListItem(list, item);
+}
+
 void RenderListItem::updateListMarkerNumbers()
 {
     Node* listNode = enclosingList(this);
@@ -433,30 +459,22 @@ void RenderListItem::updateListMarkerNumbers()
     if (!listNode || !listNode->renderer())
         return;
 
+    bool isListReversed = false;
     RenderObject* list = listNode->renderer();
-    RenderObject* child = nextInPreOrder(list);
-    while (child) {
-        if (child->node() && isList(child->node())) {
-            // We've found a nested, independent list: nothing to do here.
-            child = child->nextInPreOrderAfterChildren(list);
-            continue;
-        }
-
-        if (child->isListItem()) {
-            RenderListItem* item = toRenderListItem(child);
-
-            if (!item->m_isValueUpToDate) {
-                // If an item has been marked for update before, we can safely
-                // assume that all the following ones have too.
-                // This gives us the opportunity to stop here and avoid
-                // marking the same nodes again.
-                break;
-            }
-
-            item->updateValue();
+    HTMLOListElement* oListElement = (listNode && listNode->hasTagName(olTag)) ? static_cast<HTMLOListElement*>(listNode) : 0;
+    if (oListElement) {
+        oListElement->itemCountChanged();
+        isListReversed = oListElement->isReversed();
+    }
+    for (RenderListItem* item = previousOrNextItem(isListReversed, list, this); item; item = previousOrNextItem(isListReversed, list, item)) {
+        if (!item->m_isValueUpToDate) {
+            // If an item has been marked for update before, we can safely
+            // assume that all the following ones have too.
+            // This gives us the opportunity to stop here and avoid
+            // marking the same nodes again.
+            break;
         }
-
-        child = child->nextInPreOrder(list);
+        item->updateValue();
     }
 }
 
index 76d98b3..e6767dd 100644 (file)
@@ -49,6 +49,8 @@ public:
 
     void updateListMarkerNumbers();
 
+    static RenderListItem* nextListItem(RenderObject* listRenderer, RenderListItem* = 0);
+
 private:
     virtual const char* renderName() const { return "RenderListItem"; }