From 58c523ae46af90ab17d6b98966d97fa776ae2bf4 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sun, 20 Oct 2024 18:20:42 +0200 Subject: [PATCH] LibWeb: Honor `appearance: none` when creating input element layout node Per css-ui-4, setting `appearance: none` is supposed to suppress the creation of a native-looking widget for stuff like checkboxes, radio buttons, etc. This patch implements this behavior by simply falling back to creating a layout node based on the CSS `display` property in such cases. This fixes an issue on the hey.com imbox page where we were rendering checkboxes on top of sender profile photos. --- .../Layout/expected/css-appearance-none.txt | 77 +++++++++++++++++++ .../Layout/input/css-appearance-none.html | 7 ++ .../LibWeb/HTML/HTMLInputElement.cpp | 17 +++- 3 files changed, 98 insertions(+), 3 deletions(-) create mode 100644 Tests/LibWeb/Layout/expected/css-appearance-none.txt create mode 100644 Tests/LibWeb/Layout/input/css-appearance-none.html diff --git a/Tests/LibWeb/Layout/expected/css-appearance-none.txt b/Tests/LibWeb/Layout/expected/css-appearance-none.txt new file mode 100644 index 00000000000..3281c072510 --- /dev/null +++ b/Tests/LibWeb/Layout/expected/css-appearance-none.txt @@ -0,0 +1,77 @@ +Viewport <#document> at (0,0) content-size 800x600 children: not-inline + BlockContainer at (0,0) content-size 800x126 [BFC] children: not-inline + BlockContainer at (8,8) content-size 784x110 children: inline + frag 0 from BlockContainer start: 0, length: 0, rect: [13,10 0x17] baseline: 15.296875 + frag 1 from TextNode start: 0, length: 13, rect: [18,10 116.171875x17] baseline: 13.296875 + "Normal button" + frag 2 from BlockContainer start: 0, length: 0, rect: [13,31 0x17] baseline: 15.296875 + frag 3 from TextNode start: 0, length: 20, rect: [18,31 181.203125x17] baseline: 13.296875 + "No appearance button" + frag 4 from CheckBox start: 0, length: 0, rect: [8,50 13x13] baseline: 13 + frag 5 from TextNode start: 0, length: 15, rect: [21,50 136.296875x17] baseline: 13.296875 + "Normal checkbox" + frag 6 from BlockContainer start: 0, length: 0, rect: [8,80 0x0] baseline: 0 + frag 7 from TextNode start: 0, length: 22, rect: [8,67 201.328125x17] baseline: 13.296875 + "No appearance checkbox" + frag 8 from RadioButton start: 0, length: 0, rect: [8,85 12x12] baseline: 12 + frag 9 from TextNode start: 0, length: 12, rect: [20,84 104.203125x17] baseline: 13.296875 + "Normal radio" + frag 10 from BlockContainer start: 0, length: 0, rect: [8,114 0x0] baseline: 0 + frag 11 from TextNode start: 0, length: 19, rect: [8,101 169.234375x17] baseline: 13.296875 + "No appearance radio" + BlockContainer at (13,10) content-size 0x17 inline-block [BFC] children: not-inline + BlockContainer <(anonymous)> at (13,10) content-size 0x17 flex-container(column) [FFC] children: not-inline + BlockContainer <(anonymous)> at (13,10) content-size 0x17 flex-item [BFC] children: inline + frag 0 from BlockContainer start: 0, length: 0, rect: [13,23 0x0] baseline: 0 + BlockContainer at (13,23) content-size 0x0 inline-block [BFC] children: inline + TextNode <#text> + TextNode <#text> + BreakNode
+ TextNode <#text> + BlockContainer at (13,31) content-size 0x17 inline-block [BFC] children: not-inline + BlockContainer <(anonymous)> at (13,31) content-size 0x17 flex-container(column) [FFC] children: not-inline + BlockContainer <(anonymous)> at (13,31) content-size 0x17 flex-item [BFC] children: inline + frag 0 from BlockContainer start: 0, length: 0, rect: [13,44 0x0] baseline: 0 + BlockContainer at (13,44) content-size 0x0 inline-block [BFC] children: inline + TextNode <#text> + TextNode <#text> + BreakNode
+ TextNode <#text> + CheckBox at (8,50) content-size 13x13 inline-block children: not-inline + TextNode <#text> + BreakNode
+ TextNode <#text> + BlockContainer at (8,80) content-size 0x0 inline-block [BFC] children: not-inline + TextNode <#text> + BreakNode
+ TextNode <#text> + RadioButton at (8,85) content-size 12x12 inline-block children: not-inline + TextNode <#text> + BreakNode
+ TextNode <#text> + BlockContainer at (8,114) content-size 0x0 inline-block [BFC] children: not-inline + TextNode <#text> + BreakNode
+ TextNode <#text> + +ViewportPaintable (Viewport<#document>) [0,0 800x600] + PaintableWithLines (BlockContainer) [0,0 800x126] + PaintableWithLines (BlockContainer) [8,8 784x110] + PaintableWithLines (BlockContainer) [8,8 10x21] + PaintableWithLines (BlockContainer(anonymous)) [13,10 0x17] + PaintableWithLines (BlockContainer(anonymous)) [13,10 0x17] + PaintableWithLines (BlockContainer) [13,23 0x0] + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer) [8,29 10x21] + PaintableWithLines (BlockContainer(anonymous)) [13,31 0x17] + PaintableWithLines (BlockContainer(anonymous)) [13,31 0x17] + PaintableWithLines (BlockContainer) [13,44 0x0] + TextPaintable (TextNode<#text>) + CheckBoxPaintable (CheckBox) [8,50 13x13] + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer) [8,80 0x0] + TextPaintable (TextNode<#text>) + RadioButtonPaintable (RadioButton) [8,85 12x12] + TextPaintable (TextNode<#text>) + PaintableWithLines (BlockContainer) [8,114 0x0] + TextPaintable (TextNode<#text>) diff --git a/Tests/LibWeb/Layout/input/css-appearance-none.html b/Tests/LibWeb/Layout/input/css-appearance-none.html new file mode 100644 index 00000000000..5cd87d66f2b --- /dev/null +++ b/Tests/LibWeb/Layout/input/css-appearance-none.html @@ -0,0 +1,7 @@ + +Normal button
+No appearance button
+Normal checkbox
+No appearance checkbox
+Normal radio
+No appearance radio
diff --git a/Userland/Libraries/LibWeb/HTML/HTMLInputElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLInputElement.cpp index d73b0598443..807e584f01d 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLInputElement.cpp +++ b/Userland/Libraries/LibWeb/HTML/HTMLInputElement.cpp @@ -103,12 +103,23 @@ JS::GCPtr HTMLInputElement::create_layout_node(NonnullRefPtr(document(), *this, move(style), *this); + } + + // https://drafts.csswg.org/css-ui/#appearance-switching + // This specification introduces the appearance property to provide some control over this behavior. + // In particular, using appearance: none allows authors to suppress the native appearance of widgets, + // giving them a primitive appearance where CSS can be used to restyle them. + if (style->appearance() == CSS::Appearance::None) { + return Element::create_layout_node_for_display_type(document(), style->display(), style, this); + } + if (type_state() == TypeAttributeState::SubmitButton || type_state() == TypeAttributeState::Button || type_state() == TypeAttributeState::ResetButton) return heap().allocate_without_realm(document(), this, move(style)); - if (type_state() == TypeAttributeState::ImageButton) - return heap().allocate_without_realm(document(), *this, move(style), *this); - if (type_state() == TypeAttributeState::Checkbox) return heap().allocate_without_realm(document(), *this, move(style));