From 1cdbfc2ff19a9f335bbb72c160e97fa9ab0b75a6 Mon Sep 17 00:00:00 2001 From: Bastiaan van der Plaat Date: Wed, 11 Oct 2023 18:42:09 +0200 Subject: [PATCH] LibWeb: Add ol start and li value attributes support --- Base/res/html/misc/lists.html | 39 +++++-- Tests/LibWeb/Layout/expected/ordered-list.txt | 107 ++++++++++++++++++ Tests/LibWeb/Layout/input/ordered-list.html | 11 ++ .../Libraries/LibWeb/HTML/AttributeNames.h | 1 + .../Libraries/LibWeb/HTML/HTMLLIElement.h | 6 + .../Libraries/LibWeb/HTML/HTMLLIElement.idl | 2 +- .../Libraries/LibWeb/HTML/HTMLOListElement.h | 6 + .../LibWeb/HTML/HTMLOListElement.idl | 2 +- .../Libraries/LibWeb/Layout/TreeBuilder.cpp | 29 ++++- .../Libraries/LibWeb/Layout/TreeBuilder.h | 2 + 10 files changed, 189 insertions(+), 16 deletions(-) create mode 100644 Tests/LibWeb/Layout/expected/ordered-list.txt create mode 100644 Tests/LibWeb/Layout/input/ordered-list.html diff --git a/Base/res/html/misc/lists.html b/Base/res/html/misc/lists.html index 19e7fb67c2..4af53801bf 100644 --- a/Base/res/html/misc/lists.html +++ b/Base/res/html/misc/lists.html @@ -106,6 +106,21 @@
  • Third
  • +

    with start offset

    +
      +
    1. Item 20
    2. +
    3. Item 21
    4. +
    5. Item 22
    6. +
    + +

    with different order

    +
      +
    1. Item 1
    2. +
    3. Item 5
    4. +
    5. Item 2
    6. +
    7. Item 3
    8. +
    +

    list-style: decimal

    1. First
    2. @@ -118,8 +133,8 @@
    3. First
    4. Second
    5. Third
    6. -
    7. Another Entry
    8. -
    9. Another Entry
    10. +
    11. Another Entry
    12. +
    13. Another Entry
    14. Another Entry
    15. Another Entry
    16. Another Entry
    17. @@ -132,8 +147,8 @@
    18. First
    19. Second
    20. Third
    21. -
    22. Another Entry
    23. -
    24. Another Entry
    25. +
    26. Another Entry
    27. +
    28. Another Entry
    29. Another Entry
    30. Another Entry
    31. Another Entry
    32. @@ -166,8 +181,8 @@
    33. First
    34. Second
    35. Third
    36. -
    37. Another Entry
    38. -
    39. Another Entry
    40. +
    41. Another Entry
    42. +
    43. Another Entry
    44. Another Entry
    45. Another Entry
    46. Another Entry
    47. @@ -200,8 +215,8 @@
    48. First
    49. Second
    50. Third
    51. -
    52. Another Entry
    53. -
    54. Another Entry
    55. +
    56. Another Entry
    57. +
    58. Another Entry
    59. Another Entry
    60. Another Entry
    61. Another Entry
    62. @@ -223,8 +238,8 @@
    63. First
    64. Second
    65. Third
    66. -
    67. Another Entry
    68. -
    69. Another Entry
    70. +
    71. Another Entry
    72. +
    73. Another Entry
    74. Another Entry
    75. Another Entry
    76. Another Entry
    77. @@ -246,8 +261,8 @@
    78. First
    79. Second
    80. Third
    81. -
    82. Another Entry
    83. -
    84. Another Entry
    85. +
    86. Another Entry
    87. +
    88. Another Entry
    89. Another Entry
    90. Another Entry
    91. Another Entry
    92. diff --git a/Tests/LibWeb/Layout/expected/ordered-list.txt b/Tests/LibWeb/Layout/expected/ordered-list.txt new file mode 100644 index 0000000000..3dfec01758 --- /dev/null +++ b/Tests/LibWeb/Layout/expected/ordered-list.txt @@ -0,0 +1,107 @@ +Viewport <#document> at (0,0) content-size 800x600 children: not-inline + BlockContainer at (0,0) content-size 800x600 [BFC] children: not-inline + BlockContainer at (8,16) content-size 784x138.28125 children: not-inline + BlockContainer
        at (48,16) content-size 744x52.40625 children: not-inline + BlockContainer <(anonymous)> at (48,16) content-size 744x0 children: inline + TextNode <#text> + ListItemBox
      1. at (48,16) content-size 744x17.46875 children: inline + line 0 width: 58.78125, height: 17.46875, bottom: 17.46875, baseline: 13.53125 + frag 0 from TextNode start: 0, length: 7, rect: [48,16 58.78125x17.46875] + "Item 20" + TextNode <#text> + ListItemMarkerBox <(anonymous)> at (13.25,16.234375) content-size 22.75x17 children: not-inline + BlockContainer <(anonymous)> at (48,33.46875) content-size 744x0 children: inline + TextNode <#text> + ListItemBox
      2. at (48,33.46875) content-size 744x17.46875 children: inline + line 0 width: 55.53125, height: 17.46875, bottom: 17.46875, baseline: 13.53125 + frag 0 from TextNode start: 0, length: 7, rect: [48,33.46875 55.53125x17.46875] + "Item 21" + TextNode <#text> + ListItemMarkerBox <(anonymous)> at (16.5,33.703125) content-size 19.5x17 children: not-inline + BlockContainer <(anonymous)> at (48,50.9375) content-size 744x0 children: inline + TextNode <#text> + ListItemBox
      3. at (48,50.9375) content-size 744x17.46875 children: inline + line 0 width: 58, height: 17.46875, bottom: 17.46875, baseline: 13.53125 + frag 0 from TextNode start: 0, length: 7, rect: [48,50.9375 58x17.46875] + "Item 22" + TextNode <#text> + ListItemMarkerBox <(anonymous)> at (14.03125,51.171875) content-size 21.96875x17 children: not-inline + BlockContainer <(anonymous)> at (48,68.40625) content-size 744x0 children: inline + TextNode <#text> + BlockContainer <(anonymous)> at (8,84.40625) content-size 784x0 children: inline + TextNode <#text> + BlockContainer
          at (48,84.40625) content-size 744x69.875 children: not-inline + BlockContainer <(anonymous)> at (48,84.40625) content-size 744x0 children: inline + TextNode <#text> + ListItemBox
        1. at (48,84.40625) content-size 744x17.46875 children: inline + line 0 width: 46.71875, height: 17.46875, bottom: 17.46875, baseline: 13.53125 + frag 0 from TextNode start: 0, length: 6, rect: [48,84.40625 46.71875x17.46875] + "Item 1" + TextNode <#text> + ListItemMarkerBox <(anonymous)> at (25.3125,84.640625) content-size 10.6875x17 children: not-inline + BlockContainer <(anonymous)> at (48,101.875) content-size 744x0 children: inline + TextNode <#text> + ListItemBox
        2. at (48,101.875) content-size 744x17.46875 children: inline + line 0 width: 48.828125, height: 17.46875, bottom: 17.46875, baseline: 13.53125 + frag 0 from TextNode start: 0, length: 6, rect: [48,101.875 48.828125x17.46875] + "Item 5" + TextNode <#text> + ListItemMarkerBox <(anonymous)> at (23.203125,102.109375) content-size 12.796875x17 children: not-inline + BlockContainer <(anonymous)> at (48,119.34375) content-size 744x0 children: inline + TextNode <#text> + ListItemBox
        3. at (48,119.34375) content-size 744x17.46875 children: inline + line 0 width: 49.109375, height: 17.46875, bottom: 17.46875, baseline: 13.53125 + frag 0 from TextNode start: 0, length: 6, rect: [48,119.34375 49.109375x17.46875] + "Item 6" + TextNode <#text> + ListItemMarkerBox <(anonymous)> at (22.921875,119.578125) content-size 13.078125x17 children: not-inline + BlockContainer <(anonymous)> at (48,136.8125) content-size 744x0 children: inline + TextNode <#text> + ListItemBox
        4. at (48,136.8125) content-size 744x17.46875 children: inline + line 0 width: 49.09375, height: 17.46875, bottom: 17.46875, baseline: 13.53125 + frag 0 from TextNode start: 0, length: 6, rect: [48,136.8125 49.09375x17.46875] + "Item 7" + TextNode <#text> + ListItemMarkerBox <(anonymous)> at (22.9375,137.046875) content-size 13.0625x17 children: not-inline + BlockContainer <(anonymous)> at (48,154.28125) content-size 744x0 children: inline + TextNode <#text> + BlockContainer <(anonymous)> at (8,170.28125) content-size 784x0 children: inline + TextNode <#text> + +ViewportPaintable (Viewport<#document>) [0,0 800x600] + PaintableWithLines (BlockContainer) [0,0 800x600] + PaintableWithLines (BlockContainer) [8,16 784x138.28125] overflow: [8,16 784x154.28125] + PaintableWithLines (BlockContainer
            ) [8,16 784x52.40625] + PaintableWithLines (BlockContainer(anonymous)) [48,16 744x0] + PaintableWithLines (ListItemBox
          1. ) [48,16 744x17.46875] + TextPaintable (TextNode<#text>) + MarkerPaintable (ListItemMarkerBox(anonymous)) [13.25,16.234375 22.75x17] + PaintableWithLines (BlockContainer(anonymous)) [48,33.46875 744x0] + PaintableWithLines (ListItemBox
          2. ) [48,33.46875 744x17.46875] + TextPaintable (TextNode<#text>) + MarkerPaintable (ListItemMarkerBox(anonymous)) [16.5,33.703125 19.5x17] + PaintableWithLines (BlockContainer(anonymous)) [48,50.9375 744x0] + PaintableWithLines (ListItemBox
          3. ) [48,50.9375 744x17.46875] + TextPaintable (TextNode<#text>) + MarkerPaintable (ListItemMarkerBox(anonymous)) [14.03125,51.171875 21.96875x17] + PaintableWithLines (BlockContainer(anonymous)) [48,68.40625 744x0] + PaintableWithLines (BlockContainer(anonymous)) [8,84.40625 784x0] + PaintableWithLines (BlockContainer
              ) [8,84.40625 784x69.875] + PaintableWithLines (BlockContainer(anonymous)) [48,84.40625 744x0] + PaintableWithLines (ListItemBox
            1. ) [48,84.40625 744x17.46875] + TextPaintable (TextNode<#text>) + MarkerPaintable (ListItemMarkerBox(anonymous)) [25.3125,84.640625 10.6875x17] + PaintableWithLines (BlockContainer(anonymous)) [48,101.875 744x0] + PaintableWithLines (ListItemBox
            2. ) [48,101.875 744x17.46875] + TextPaintable (TextNode<#text>) + MarkerPaintable (ListItemMarkerBox(anonymous)) [23.203125,102.109375 12.796875x17] + PaintableWithLines (BlockContainer(anonymous)) [48,119.34375 744x0] + PaintableWithLines (ListItemBox
            3. ) [48,119.34375 744x17.46875] + TextPaintable (TextNode<#text>) + MarkerPaintable (ListItemMarkerBox(anonymous)) [22.921875,119.578125 13.078125x17] + PaintableWithLines (BlockContainer(anonymous)) [48,136.8125 744x0] + PaintableWithLines (ListItemBox
            4. ) [48,136.8125 744x17.46875] + TextPaintable (TextNode<#text>) + MarkerPaintable (ListItemMarkerBox(anonymous)) [22.9375,137.046875 13.0625x17] + PaintableWithLines (BlockContainer(anonymous)) [48,154.28125 744x0] + PaintableWithLines (BlockContainer(anonymous)) [8,170.28125 784x0] diff --git a/Tests/LibWeb/Layout/input/ordered-list.html b/Tests/LibWeb/Layout/input/ordered-list.html new file mode 100644 index 0000000000..003d250d38 --- /dev/null +++ b/Tests/LibWeb/Layout/input/ordered-list.html @@ -0,0 +1,11 @@ +
                +
              1. Item 20
              2. +
              3. Item 21
              4. +
              5. Item 22
              6. +
              +
                +
              1. Item 1
              2. +
              3. Item 5
              4. +
              5. Item 6
              6. +
              7. Item 7
              8. +
              diff --git a/Userland/Libraries/LibWeb/HTML/AttributeNames.h b/Userland/Libraries/LibWeb/HTML/AttributeNames.h index fdb9f0eb37..ed081927df 100644 --- a/Userland/Libraries/LibWeb/HTML/AttributeNames.h +++ b/Userland/Libraries/LibWeb/HTML/AttributeNames.h @@ -223,6 +223,7 @@ namespace AttributeNames { __ENUMERATE_HTML_ATTRIBUTE(srclang) \ __ENUMERATE_HTML_ATTRIBUTE(srcset) \ __ENUMERATE_HTML_ATTRIBUTE(standby) \ + __ENUMERATE_HTML_ATTRIBUTE(start) \ __ENUMERATE_HTML_ATTRIBUTE(step) \ __ENUMERATE_HTML_ATTRIBUTE(style) \ __ENUMERATE_HTML_ATTRIBUTE(summary) \ diff --git a/Userland/Libraries/LibWeb/HTML/HTMLLIElement.h b/Userland/Libraries/LibWeb/HTML/HTMLLIElement.h index 50aaf76e24..d7a5a00c26 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLLIElement.h +++ b/Userland/Libraries/LibWeb/HTML/HTMLLIElement.h @@ -20,6 +20,12 @@ public: // https://www.w3.org/TR/html-aria/#el-li virtual Optional default_role() const override { return ARIA::Role::listitem; } + i32 value() { return get_attribute(AttributeNames::value).value_or("0"_string).to_number().value_or(0); } + void set_value(i32 value) + { + set_attribute(AttributeNames::value, MUST(String::number(value))).release_value_but_fixme_should_propagate_errors(); + } + private: HTMLLIElement(DOM::Document&, DOM::QualifiedName); diff --git a/Userland/Libraries/LibWeb/HTML/HTMLLIElement.idl b/Userland/Libraries/LibWeb/HTML/HTMLLIElement.idl index 8f2799825b..31412f0eab 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLLIElement.idl +++ b/Userland/Libraries/LibWeb/HTML/HTMLLIElement.idl @@ -6,7 +6,7 @@ interface HTMLLIElement : HTMLElement { [HTMLConstructor] constructor(); - // FIXME: [CEReactions] attribute long value; + [CEReactions] attribute long value; // Obsolete [CEReactions, Reflect] attribute DOMString type; diff --git a/Userland/Libraries/LibWeb/HTML/HTMLOListElement.h b/Userland/Libraries/LibWeb/HTML/HTMLOListElement.h index a4af74b0b7..b09347beb7 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLOListElement.h +++ b/Userland/Libraries/LibWeb/HTML/HTMLOListElement.h @@ -20,6 +20,12 @@ public: // https://www.w3.org/TR/html-aria/#el-ol virtual Optional default_role() const override { return ARIA::Role::list; } + i32 start() { return get_attribute(AttributeNames::start).value_or("1"_string).to_number().value_or(1); } + void set_start(i32 start) + { + set_attribute(AttributeNames::start, MUST(String::number(start))).release_value_but_fixme_should_propagate_errors(); + } + private: HTMLOListElement(DOM::Document&, DOM::QualifiedName); diff --git a/Userland/Libraries/LibWeb/HTML/HTMLOListElement.idl b/Userland/Libraries/LibWeb/HTML/HTMLOListElement.idl index a59842bbec..bde11929ac 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLOListElement.idl +++ b/Userland/Libraries/LibWeb/HTML/HTMLOListElement.idl @@ -7,7 +7,7 @@ interface HTMLOListElement : HTMLElement { [HTMLConstructor] constructor(); [CEReactions, Reflect] attribute boolean reversed; - // FIXME: [CEReactions] attribute long start; + [CEReactions] attribute long start; [CEReactions, Reflect] attribute DOMString type; // Obsolete diff --git a/Userland/Libraries/LibWeb/Layout/TreeBuilder.cpp b/Userland/Libraries/LibWeb/Layout/TreeBuilder.cpp index e836aad686..c13a8f1d1f 100644 --- a/Userland/Libraries/LibWeb/Layout/TreeBuilder.cpp +++ b/Userland/Libraries/LibWeb/Layout/TreeBuilder.cpp @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include #include #include @@ -251,6 +253,30 @@ static bool is_ignorable_whitespace(Layout::Node const& node) return false; } +i32 TreeBuilder::calculate_list_item_index(DOM::Node& dom_node) +{ + if (is(dom_node)) { + auto& li = static_cast(dom_node); + if (li.value() != 0) + return li.value(); + } + + if (dom_node.previous_sibling() != nullptr) { + DOM::Node* current = dom_node.previous_sibling(); + while (current != nullptr) { + if (is(*current)) + return calculate_list_item_index(*current) + 1; + current = current->previous_sibling(); + } + } + + if (is(*dom_node.parent())) { + auto& ol = static_cast(*dom_node.parent()); + return ol.start(); + } + return 1; +} + ErrorOr TreeBuilder::create_layout_tree(DOM::Node& dom_node, TreeBuilder::Context& context) { JS::GCPtr layout_node; @@ -349,9 +375,8 @@ ErrorOr TreeBuilder::create_layout_tree(DOM::Node& dom_node, TreeBuilder:: if (is(*layout_node)) { auto& element = static_cast(dom_node); - int child_index = layout_node->parent()->index_of_child(*layout_node).value(); auto marker_style = TRY(style_computer.compute_style(element, CSS::Selector::PseudoElement::Marker)); - auto list_item_marker = document.heap().allocate_without_realm(document, layout_node->computed_values().list_style_type(), layout_node->computed_values().list_style_position(), child_index + 1, *marker_style); + auto list_item_marker = document.heap().allocate_without_realm(document, layout_node->computed_values().list_style_type(), layout_node->computed_values().list_style_position(), calculate_list_item_index(dom_node), *marker_style); static_cast(*layout_node).set_marker(list_item_marker); element.set_pseudo_element_node({}, CSS::Selector::PseudoElement::Marker, list_item_marker); layout_node->append_child(*list_item_marker); diff --git a/Userland/Libraries/LibWeb/Layout/TreeBuilder.h b/Userland/Libraries/LibWeb/Layout/TreeBuilder.h index 8c82746e39..291aec79e5 100644 --- a/Userland/Libraries/LibWeb/Layout/TreeBuilder.h +++ b/Userland/Libraries/LibWeb/Layout/TreeBuilder.h @@ -25,6 +25,8 @@ private: bool has_svg_root = false; }; + i32 calculate_list_item_index(DOM::Node&); + ErrorOr create_layout_tree(DOM::Node&, Context&); void push_parent(Layout::NodeWithStyle& node) { m_ancestor_stack.append(node); }