diff --git a/Libraries/LibWeb/HTML/HTMLButtonElement.h b/Libraries/LibWeb/HTML/HTMLButtonElement.h
index 2dafbc81ad8..2a2ee516cae 100644
--- a/Libraries/LibWeb/HTML/HTMLButtonElement.h
+++ b/Libraries/LibWeb/HTML/HTMLButtonElement.h
@@ -87,6 +87,9 @@ public:
GC::Ptr command_for_element() { return m_command_for_element; }
void set_command_for_element(GC::Ptr value) { m_command_for_element = value; }
+ // https://html.spec.whatwg.org/multipage/rendering.html#the-button-element-2:button-layout-2
+ virtual bool uses_button_layout() const override { return true; }
+
private:
virtual void visit_edges(Visitor&) override;
diff --git a/Libraries/LibWeb/HTML/HTMLElement.h b/Libraries/LibWeb/HTML/HTMLElement.h
index be840e4771e..162c3c09ee2 100644
--- a/Libraries/LibWeb/HTML/HTMLElement.h
+++ b/Libraries/LibWeb/HTML/HTMLElement.h
@@ -165,6 +165,9 @@ public:
bool is_form_associated_custom_element();
+ // https://html.spec.whatwg.org/multipage/rendering.html#button-layout
+ virtual bool uses_button_layout() const { return false; }
+
protected:
HTMLElement(DOM::Document&, DOM::QualifiedName);
diff --git a/Libraries/LibWeb/HTML/HTMLInputElement.cpp b/Libraries/LibWeb/HTML/HTMLInputElement.cpp
index 2f28da4dfb7..9c3125de172 100644
--- a/Libraries/LibWeb/HTML/HTMLInputElement.cpp
+++ b/Libraries/LibWeb/HTML/HTMLInputElement.cpp
@@ -3622,4 +3622,27 @@ bool HTMLInputElement::is_mutable() const
&& !(has_attribute(AttributeNames::readonly) && is_allowed_to_be_readonly(m_type));
}
+// https://html.spec.whatwg.org/multipage/rendering.html#button-layout
+bool HTMLInputElement::uses_button_layout() const
+{
+ // https://html.spec.whatwg.org/multipage/rendering.html#the-input-element-as-a-button:button-layout-2
+ // An input element whose type attribute is in the Submit Button, Reset Button, or Button state, when it generates a
+ // CSS box, is expected to depict a button and use button layout [..]
+
+ // https://html.spec.whatwg.org/multipage/rendering.html#the-input-element-as-a-colour-well:button-layout-2
+ // The element, when it generates a CSS box, is expected to use button layout, that has no child boxes of the
+ // anonymous button content box.
+
+ // https://html.spec.whatwg.org/multipage/rendering.html#the-input-element-as-a-file-upload-control:button-layout-2
+ // The button is expected to use button layout and match the '::file-selector-button' pseudo-element.
+
+ // https://html.spec.whatwg.org/multipage/input.html#image-button-state-(type=image):concept-button
+ // The element is a button, specifically a submit button.
+ // NOTE: Although type=image is specified to be a submit button, that does not mean that the type attribute is
+ // Submit Button, so we don't include ::ImageButton below.
+
+ return first_is_one_of(type_state(), TypeAttributeState::SubmitButton, TypeAttributeState::ResetButton,
+ TypeAttributeState::Button, TypeAttributeState::Color, TypeAttributeState::FileUpload);
+}
+
}
diff --git a/Libraries/LibWeb/HTML/HTMLInputElement.h b/Libraries/LibWeb/HTML/HTMLInputElement.h
index 5662eee295f..69dde7a2b01 100644
--- a/Libraries/LibWeb/HTML/HTMLInputElement.h
+++ b/Libraries/LibWeb/HTML/HTMLInputElement.h
@@ -253,6 +253,7 @@ public:
virtual bool suffering_from_bad_input() const override;
virtual bool is_mutable() const override;
+ virtual bool uses_button_layout() const override;
private:
HTMLInputElement(DOM::Document&, DOM::QualifiedName);
diff --git a/Libraries/LibWeb/Layout/TreeBuilder.cpp b/Libraries/LibWeb/Layout/TreeBuilder.cpp
index 776177caefc..3fbd2c6d75e 100644
--- a/Libraries/LibWeb/Layout/TreeBuilder.cpp
+++ b/Libraries/LibWeb/Layout/TreeBuilder.cpp
@@ -724,36 +724,23 @@ void TreeBuilder::update_layout_tree(DOM::Node& dom_node, TreeBuilder::Context&
void TreeBuilder::wrap_in_button_layout_tree_if_needed(DOM::Node& dom_node, GC::Ref layout_node)
{
- auto is_button_layout = [&] {
- if (dom_node.is_html_button_element())
- return true;
- if (!dom_node.is_html_input_element())
- return false;
- // https://html.spec.whatwg.org/multipage/rendering.html#the-input-element-as-a-button
- // An input element whose type attribute is in the Submit Button, Reset Button, or Button state, when it generates a CSS box, is expected to depict a button and use button layout
- auto const& input_element = static_cast(dom_node);
- if (input_element.is_button())
- return true;
- return false;
- }();
-
- if (!is_button_layout)
+ auto const* html_element = as_if(dom_node);
+ if (!html_element || !html_element->uses_button_layout())
return;
- auto display = layout_node->display();
-
// https://html.spec.whatwg.org/multipage/rendering.html#button-layout
// If the computed value of 'inline-size' is 'auto', then the used value is the fit-content inline size.
- if (is_button_layout && dom_node.layout_node()->computed_values().width().is_auto()) {
+ if (dom_node.layout_node()->computed_values().width().is_auto()) {
auto& computed_values = as(*dom_node.layout_node()).mutable_computed_values();
computed_values.set_width(CSS::Size::make_fit_content());
}
// https://html.spec.whatwg.org/multipage/rendering.html#button-layout
- // If the element is an input element, or if it is a button element and its computed value for
- // 'display' is not 'inline-grid', 'grid', 'inline-flex', or 'flex', then the element's box has
- // a child anonymous button content box with the following behaviors:
- if (is_button_layout && !display.is_grid_inside() && !display.is_flex_inside()) {
+ // If the element is an input element, or if it is a button element and its computed value for 'display' is not
+ // 'inline-grid', 'grid', 'inline-flex', or 'flex', then the element's box has a child anonymous button content box
+ // with the following behaviors:
+ auto display = layout_node->display();
+ if (!display.is_grid_inside() && !display.is_flex_inside()) {
auto& parent = *layout_node;
// If the box does not overflow in the vertical axis, then it is centered vertically.
diff --git a/Tests/LibWeb/Layout/expected/input-file.txt b/Tests/LibWeb/Layout/expected/input-file.txt
index 427db14a0bc..fa060c392b0 100644
--- a/Tests/LibWeb/Layout/expected/input-file.txt
+++ b/Tests/LibWeb/Layout/expected/input-file.txt
@@ -1,83 +1,95 @@
Viewport <#document> at (0,0) content-size 800x600 children: not-inline
- BlockContainer at (0,0) content-size 800x38 [BFC] children: not-inline
- BlockContainer at (8,8) content-size 784x22 children: inline
- frag 0 from BlockContainer start: 0, length: 0, rect: [8,8 236.65625x22] baseline: 15.796875
+ BlockContainer at (0,0) content-size 800x42 [BFC] children: not-inline
+ BlockContainer at (8,8) content-size 784x26 children: inline
+ frag 0 from BlockContainer start: 0, length: 0, rect: [8,8 236.65625x26] baseline: 15.796875
frag 1 from TextNode start: 0, length: 1, rect: [244.65625,10 8x18] baseline: 13.796875
" "
- frag 2 from BlockContainer start: 0, length: 0, rect: [252.65625,8 255.34375x22] baseline: 15.796875
+ frag 2 from BlockContainer start: 0, length: 0, rect: [252.65625,8 255.34375x26] baseline: 15.796875
frag 3 from TextNode start: 0, length: 1, rect: [508,10 8x18] baseline: 13.796875
" "
- frag 4 from BlockContainer start: 0, length: 0, rect: [516,8 255.34375x22] baseline: 15.796875
- BlockContainer at (8,8) content-size 236.65625x22 inline-block [BFC] children: inline
- frag 0 from BlockContainer start: 0, length: 0, rect: [13,10 94.375x18] baseline: 15.796875
- frag 1 from Label start: 0, length: 0, rect: [116.375,10 128.28125x18] baseline: 13.796875
- BlockContainer