Browse Source

LibWeb: Compute `display: contents` as `none` for unusual elements

https://drafts.csswg.org/css-display-3/#unbox-html specifies certain
elements that have their `display` style computed as `none` when
specified as `contents`.

This fixes at least one WPT test:
http://wpt.live/css/css-display/display-contents-suppression-dynamic-001.html
Michael Watt 8 months ago
parent
commit
3b1d1d4582
31 changed files with 156 additions and 0 deletions
  1. 8 0
      Libraries/LibWeb/HTML/HTMLAudioElement.cpp
  2. 1 0
      Libraries/LibWeb/HTML/HTMLAudioElement.h
  3. 8 0
      Libraries/LibWeb/HTML/HTMLBRElement.cpp
  4. 1 0
      Libraries/LibWeb/HTML/HTMLBRElement.h
  5. 8 0
      Libraries/LibWeb/HTML/HTMLCanvasElement.cpp
  6. 1 0
      Libraries/LibWeb/HTML/HTMLCanvasElement.h
  7. 10 0
      Libraries/LibWeb/HTML/HTMLElement.cpp
  8. 2 0
      Libraries/LibWeb/HTML/HTMLElement.h
  9. 8 0
      Libraries/LibWeb/HTML/HTMLEmbedElement.cpp
  10. 1 0
      Libraries/LibWeb/HTML/HTMLEmbedElement.h
  11. 8 0
      Libraries/LibWeb/HTML/HTMLFrameElement.cpp
  12. 1 0
      Libraries/LibWeb/HTML/HTMLFrameElement.h
  13. 8 0
      Libraries/LibWeb/HTML/HTMLFrameSetElement.cpp
  14. 2 0
      Libraries/LibWeb/HTML/HTMLFrameSetElement.h
  15. 8 0
      Libraries/LibWeb/HTML/HTMLIFrameElement.cpp
  16. 1 0
      Libraries/LibWeb/HTML/HTMLIFrameElement.h
  17. 8 0
      Libraries/LibWeb/HTML/HTMLImageElement.cpp
  18. 1 0
      Libraries/LibWeb/HTML/HTMLImageElement.h
  19. 4 0
      Libraries/LibWeb/HTML/HTMLInputElement.cpp
  20. 8 0
      Libraries/LibWeb/HTML/HTMLMeterElement.cpp
  21. 2 0
      Libraries/LibWeb/HTML/HTMLMeterElement.h
  22. 8 0
      Libraries/LibWeb/HTML/HTMLObjectElement.cpp
  23. 1 0
      Libraries/LibWeb/HTML/HTMLObjectElement.h
  24. 8 0
      Libraries/LibWeb/HTML/HTMLProgressElement.cpp
  25. 2 0
      Libraries/LibWeb/HTML/HTMLProgressElement.h
  26. 4 0
      Libraries/LibWeb/HTML/HTMLSelectElement.cpp
  27. 4 0
      Libraries/LibWeb/HTML/HTMLTextAreaElement.cpp
  28. 8 0
      Libraries/LibWeb/HTML/HTMLVideoElement.cpp
  29. 1 0
      Libraries/LibWeb/HTML/HTMLVideoElement.h
  30. 5 0
      Tests/LibWeb/Ref/expected/wpt-import/css/css-display/display-contents-suppression-dynamic-001-ref.html
  31. 16 0
      Tests/LibWeb/Ref/input/wpt-import/css/css-display/display-contents-suppression-dynamic-001.html

+ 8 - 0
Libraries/LibWeb/HTML/HTMLAudioElement.cpp

@@ -5,6 +5,7 @@
  */
  */
 
 
 #include <LibWeb/Bindings/HTMLAudioElementPrototype.h>
 #include <LibWeb/Bindings/HTMLAudioElementPrototype.h>
+#include <LibWeb/CSS/StyleValues/DisplayStyleValue.h>
 #include <LibWeb/HTML/AudioTrack.h>
 #include <LibWeb/HTML/AudioTrack.h>
 #include <LibWeb/HTML/AudioTrackList.h>
 #include <LibWeb/HTML/AudioTrackList.h>
 #include <LibWeb/HTML/HTMLAudioElement.h>
 #include <LibWeb/HTML/HTMLAudioElement.h>
@@ -33,6 +34,13 @@ JS::GCPtr<Layout::Node> HTMLAudioElement::create_layout_node(CSS::StylePropertie
     return heap().allocate_without_realm<Layout::AudioBox>(document(), *this, move(style));
     return heap().allocate_without_realm<Layout::AudioBox>(document(), *this, move(style));
 }
 }
 
 
+void HTMLAudioElement::adjust_computed_style(CSS::StyleProperties& style)
+{
+    // https://drafts.csswg.org/css-display-3/#unbox
+    if (style.display().is_contents())
+        style.set_property(CSS::PropertyID::Display, CSS::DisplayStyleValue::create(CSS::Display::from_short(CSS::Display::Short::None)));
+}
+
 Layout::AudioBox* HTMLAudioElement::layout_node()
 Layout::AudioBox* HTMLAudioElement::layout_node()
 {
 {
     return static_cast<Layout::AudioBox*>(Node::layout_node());
     return static_cast<Layout::AudioBox*>(Node::layout_node());

+ 1 - 0
Libraries/LibWeb/HTML/HTMLAudioElement.h

@@ -26,6 +26,7 @@ private:
     virtual void initialize(JS::Realm&) override;
     virtual void initialize(JS::Realm&) override;
 
 
     virtual JS::GCPtr<Layout::Node> create_layout_node(CSS::StyleProperties) override;
     virtual JS::GCPtr<Layout::Node> create_layout_node(CSS::StyleProperties) override;
+    virtual void adjust_computed_style(CSS::StyleProperties&) override;
 
 
     virtual void on_playing() override;
     virtual void on_playing() override;
     virtual void on_paused() override;
     virtual void on_paused() override;

+ 8 - 0
Libraries/LibWeb/HTML/HTMLBRElement.cpp

@@ -5,6 +5,7 @@
  */
  */
 
 
 #include <LibWeb/Bindings/HTMLBRElementPrototype.h>
 #include <LibWeb/Bindings/HTMLBRElementPrototype.h>
+#include <LibWeb/CSS/StyleValues/DisplayStyleValue.h>
 #include <LibWeb/DOM/Document.h>
 #include <LibWeb/DOM/Document.h>
 #include <LibWeb/HTML/HTMLBRElement.h>
 #include <LibWeb/HTML/HTMLBRElement.h>
 #include <LibWeb/Layout/BreakNode.h>
 #include <LibWeb/Layout/BreakNode.h>
@@ -31,4 +32,11 @@ JS::GCPtr<Layout::Node> HTMLBRElement::create_layout_node(CSS::StyleProperties s
     return heap().allocate_without_realm<Layout::BreakNode>(document(), *this, move(style));
     return heap().allocate_without_realm<Layout::BreakNode>(document(), *this, move(style));
 }
 }
 
 
+void HTMLBRElement::adjust_computed_style(CSS::StyleProperties& style)
+{
+    // https://drafts.csswg.org/css-display-3/#unbox
+    if (style.display().is_contents())
+        style.set_property(CSS::PropertyID::Display, CSS::DisplayStyleValue::create(CSS::Display::from_short(CSS::Display::Short::None)));
+}
+
 }
 }

+ 1 - 0
Libraries/LibWeb/HTML/HTMLBRElement.h

@@ -18,6 +18,7 @@ public:
     virtual ~HTMLBRElement() override;
     virtual ~HTMLBRElement() override;
 
 
     virtual JS::GCPtr<Layout::Node> create_layout_node(CSS::StyleProperties) override;
     virtual JS::GCPtr<Layout::Node> create_layout_node(CSS::StyleProperties) override;
+    virtual void adjust_computed_style(CSS::StyleProperties&) override;
 
 
 private:
 private:
     virtual bool is_html_br_element() const override { return true; }
     virtual bool is_html_br_element() const override { return true; }

+ 8 - 0
Libraries/LibWeb/HTML/HTMLCanvasElement.cpp

@@ -14,6 +14,7 @@
 #include <LibWeb/Bindings/HTMLCanvasElementPrototype.h>
 #include <LibWeb/Bindings/HTMLCanvasElementPrototype.h>
 #include <LibWeb/CSS/StyleComputer.h>
 #include <LibWeb/CSS/StyleComputer.h>
 #include <LibWeb/CSS/StyleValues/CSSKeywordValue.h>
 #include <LibWeb/CSS/StyleValues/CSSKeywordValue.h>
+#include <LibWeb/CSS/StyleValues/DisplayStyleValue.h>
 #include <LibWeb/CSS/StyleValues/RatioStyleValue.h>
 #include <LibWeb/CSS/StyleValues/RatioStyleValue.h>
 #include <LibWeb/CSS/StyleValues/StyleValueList.h>
 #include <LibWeb/CSS/StyleValues/StyleValueList.h>
 #include <LibWeb/DOM/Document.h>
 #include <LibWeb/DOM/Document.h>
@@ -134,6 +135,13 @@ JS::GCPtr<Layout::Node> HTMLCanvasElement::create_layout_node(CSS::StyleProperti
     return heap().allocate_without_realm<Layout::CanvasBox>(document(), *this, move(style));
     return heap().allocate_without_realm<Layout::CanvasBox>(document(), *this, move(style));
 }
 }
 
 
+void HTMLCanvasElement::adjust_computed_style(CSS::StyleProperties& style)
+{
+    // https://drafts.csswg.org/css-display-3/#unbox
+    if (style.display().is_contents())
+        style.set_property(CSS::PropertyID::Display, CSS::DisplayStyleValue::create(CSS::Display::from_short(CSS::Display::Short::None)));
+}
+
 HTMLCanvasElement::HasOrCreatedContext HTMLCanvasElement::create_2d_context()
 HTMLCanvasElement::HasOrCreatedContext HTMLCanvasElement::create_2d_context()
 {
 {
     if (!m_context.has<Empty>())
     if (!m_context.has<Empty>())

+ 1 - 0
Libraries/LibWeb/HTML/HTMLCanvasElement.h

@@ -49,6 +49,7 @@ private:
     virtual void apply_presentational_hints(CSS::StyleProperties&) const override;
     virtual void apply_presentational_hints(CSS::StyleProperties&) const override;
 
 
     virtual JS::GCPtr<Layout::Node> create_layout_node(CSS::StyleProperties) override;
     virtual JS::GCPtr<Layout::Node> create_layout_node(CSS::StyleProperties) override;
+    virtual void adjust_computed_style(CSS::StyleProperties&) override;
 
 
     enum class HasOrCreatedContext {
     enum class HasOrCreatedContext {
         No,
         No,

+ 10 - 0
Libraries/LibWeb/HTML/HTMLElement.cpp

@@ -8,6 +8,7 @@
 #include <LibWeb/ARIA/Roles.h>
 #include <LibWeb/ARIA/Roles.h>
 #include <LibWeb/Bindings/ExceptionOrUtils.h>
 #include <LibWeb/Bindings/ExceptionOrUtils.h>
 #include <LibWeb/Bindings/HTMLElementPrototype.h>
 #include <LibWeb/Bindings/HTMLElementPrototype.h>
+#include <LibWeb/CSS/StyleValues/DisplayStyleValue.h>
 #include <LibWeb/DOM/Document.h>
 #include <LibWeb/DOM/Document.h>
 #include <LibWeb/DOM/EditingHostManager.h>
 #include <LibWeb/DOM/EditingHostManager.h>
 #include <LibWeb/DOM/ElementFactory.h>
 #include <LibWeb/DOM/ElementFactory.h>
@@ -907,6 +908,15 @@ WebIDL::ExceptionOr<void> HTMLElement::set_popover(Optional<String> value)
     return {};
     return {};
 }
 }
 
 
+void HTMLElement::adjust_computed_style(CSS::StyleProperties& style)
+{
+    // https://drafts.csswg.org/css-display-3/#unbox
+    if (local_name() == HTML::TagNames::wbr) {
+        if (style.display().is_contents())
+            style.set_property(CSS::PropertyID::Display, CSS::DisplayStyleValue::create(CSS::Display::from_short(CSS::Display::Short::None)));
+    }
+}
+
 void HTMLElement::did_receive_focus()
 void HTMLElement::did_receive_focus()
 {
 {
     if (m_content_editable_state != ContentEditableState::True)
     if (m_content_editable_state != ContentEditableState::True)

+ 2 - 0
Libraries/LibWeb/HTML/HTMLElement.h

@@ -91,6 +91,8 @@ protected:
 private:
 private:
     virtual bool is_html_element() const final { return true; }
     virtual bool is_html_element() const final { return true; }
 
 
+    virtual void adjust_computed_style(CSS::StyleProperties&) override;
+
     // ^HTML::GlobalEventHandlers
     // ^HTML::GlobalEventHandlers
     virtual JS::GCPtr<DOM::EventTarget> global_event_handlers_to_event_target(FlyString const&) override { return *this; }
     virtual JS::GCPtr<DOM::EventTarget> global_event_handlers_to_event_target(FlyString const&) override { return *this; }
     virtual void did_receive_focus() override;
     virtual void did_receive_focus() override;

+ 8 - 0
Libraries/LibWeb/HTML/HTMLEmbedElement.cpp

@@ -8,6 +8,7 @@
 #include <LibWeb/Bindings/Intrinsics.h>
 #include <LibWeb/Bindings/Intrinsics.h>
 #include <LibWeb/CSS/StyleProperties.h>
 #include <LibWeb/CSS/StyleProperties.h>
 #include <LibWeb/CSS/StyleValues/CSSKeywordValue.h>
 #include <LibWeb/CSS/StyleValues/CSSKeywordValue.h>
+#include <LibWeb/CSS/StyleValues/DisplayStyleValue.h>
 #include <LibWeb/HTML/HTMLEmbedElement.h>
 #include <LibWeb/HTML/HTMLEmbedElement.h>
 #include <LibWeb/HTML/Parser/HTMLParser.h>
 #include <LibWeb/HTML/Parser/HTMLParser.h>
 
 
@@ -59,4 +60,11 @@ void HTMLEmbedElement::apply_presentational_hints(CSS::StyleProperties& style) c
     });
     });
 }
 }
 
 
+void HTMLEmbedElement::adjust_computed_style(CSS::StyleProperties& style)
+{
+    // https://drafts.csswg.org/css-display-3/#unbox
+    if (style.display().is_contents())
+        style.set_property(CSS::PropertyID::Display, CSS::DisplayStyleValue::create(CSS::Display::from_short(CSS::Display::Short::None)));
+}
+
 }
 }

+ 1 - 0
Libraries/LibWeb/HTML/HTMLEmbedElement.h

@@ -23,6 +23,7 @@ private:
     virtual bool is_html_embed_element() const override { return true; }
     virtual bool is_html_embed_element() const override { return true; }
     virtual void initialize(JS::Realm&) override;
     virtual void initialize(JS::Realm&) override;
     virtual void apply_presentational_hints(CSS::StyleProperties&) const override;
     virtual void apply_presentational_hints(CSS::StyleProperties&) const override;
+    virtual void adjust_computed_style(CSS::StyleProperties&) override;
 };
 };
 
 
 }
 }

+ 8 - 0
Libraries/LibWeb/HTML/HTMLFrameElement.cpp

@@ -6,6 +6,7 @@
 
 
 #include <LibWeb/Bindings/HTMLFrameElementPrototype.h>
 #include <LibWeb/Bindings/HTMLFrameElementPrototype.h>
 #include <LibWeb/Bindings/Intrinsics.h>
 #include <LibWeb/Bindings/Intrinsics.h>
+#include <LibWeb/CSS/StyleValues/DisplayStyleValue.h>
 #include <LibWeb/DOM/Document.h>
 #include <LibWeb/DOM/Document.h>
 #include <LibWeb/DOM/Event.h>
 #include <LibWeb/DOM/Event.h>
 #include <LibWeb/HTML/BrowsingContext.h>
 #include <LibWeb/HTML/BrowsingContext.h>
@@ -81,6 +82,13 @@ i32 HTMLFrameElement::default_tab_index_value() const
     return 0;
     return 0;
 }
 }
 
 
+void HTMLFrameElement::adjust_computed_style(CSS::StyleProperties& style)
+{
+    // https://drafts.csswg.org/css-display-3/#unbox
+    if (style.display().is_contents())
+        style.set_property(CSS::PropertyID::Display, CSS::DisplayStyleValue::create(CSS::Display::from_short(CSS::Display::Short::None)));
+}
+
 // https://html.spec.whatwg.org/multipage/obsolete.html#process-the-frame-attributes
 // https://html.spec.whatwg.org/multipage/obsolete.html#process-the-frame-attributes
 void HTMLFrameElement::process_the_frame_attributes(bool initial_insertion)
 void HTMLFrameElement::process_the_frame_attributes(bool initial_insertion)
 {
 {

+ 1 - 0
Libraries/LibWeb/HTML/HTMLFrameElement.h

@@ -28,6 +28,7 @@ private:
     virtual void removed_from(Node*) override;
     virtual void removed_from(Node*) override;
     virtual void attribute_changed(FlyString const& name, Optional<String> const& old_value, Optional<String> const& value) override;
     virtual void attribute_changed(FlyString const& name, Optional<String> const& old_value, Optional<String> const& value) override;
     virtual i32 default_tab_index_value() const override;
     virtual i32 default_tab_index_value() const override;
+    virtual void adjust_computed_style(CSS::StyleProperties&) override;
 
 
     void process_the_frame_attributes(bool initial_insertion = false);
     void process_the_frame_attributes(bool initial_insertion = false);
 };
 };

+ 8 - 0
Libraries/LibWeb/HTML/HTMLFrameSetElement.cpp

@@ -5,6 +5,7 @@
  */
  */
 
 
 #include <LibWeb/Bindings/HTMLFrameSetElementPrototype.h>
 #include <LibWeb/Bindings/HTMLFrameSetElementPrototype.h>
+#include <LibWeb/CSS/StyleValues/DisplayStyleValue.h>
 #include <LibWeb/DOM/Document.h>
 #include <LibWeb/DOM/Document.h>
 #include <LibWeb/HTML/HTMLFrameSetElement.h>
 #include <LibWeb/HTML/HTMLFrameSetElement.h>
 #include <LibWeb/HTML/Window.h>
 #include <LibWeb/HTML/Window.h>
@@ -20,6 +21,13 @@ HTMLFrameSetElement::HTMLFrameSetElement(DOM::Document& document, DOM::Qualified
 
 
 HTMLFrameSetElement::~HTMLFrameSetElement() = default;
 HTMLFrameSetElement::~HTMLFrameSetElement() = default;
 
 
+void HTMLFrameSetElement::adjust_computed_style(CSS::StyleProperties& style)
+{
+    // https://drafts.csswg.org/css-display-3/#unbox
+    if (style.display().is_contents())
+        style.set_property(CSS::PropertyID::Display, CSS::DisplayStyleValue::create(CSS::Display::from_short(CSS::Display::Short::None)));
+}
+
 void HTMLFrameSetElement::initialize(JS::Realm& realm)
 void HTMLFrameSetElement::initialize(JS::Realm& realm)
 {
 {
     Base::initialize(realm);
     Base::initialize(realm);

+ 2 - 0
Libraries/LibWeb/HTML/HTMLFrameSetElement.h

@@ -24,6 +24,8 @@ public:
 private:
 private:
     HTMLFrameSetElement(DOM::Document&, DOM::QualifiedName);
     HTMLFrameSetElement(DOM::Document&, DOM::QualifiedName);
 
 
+    virtual void adjust_computed_style(CSS::StyleProperties&) override;
+
     virtual void initialize(JS::Realm&) override;
     virtual void initialize(JS::Realm&) override;
     virtual void attribute_changed(FlyString const&, Optional<String> const& old_value, Optional<String> const&) override;
     virtual void attribute_changed(FlyString const&, Optional<String> const& old_value, Optional<String> const&) override;
 
 

+ 8 - 0
Libraries/LibWeb/HTML/HTMLIFrameElement.cpp

@@ -7,6 +7,7 @@
 
 
 #include <LibURL/Origin.h>
 #include <LibURL/Origin.h>
 #include <LibWeb/Bindings/HTMLIFrameElementPrototype.h>
 #include <LibWeb/Bindings/HTMLIFrameElementPrototype.h>
+#include <LibWeb/CSS/StyleValues/DisplayStyleValue.h>
 #include <LibWeb/DOM/Document.h>
 #include <LibWeb/DOM/Document.h>
 #include <LibWeb/DOM/Event.h>
 #include <LibWeb/DOM/Event.h>
 #include <LibWeb/HTML/BrowsingContext.h>
 #include <LibWeb/HTML/BrowsingContext.h>
@@ -37,6 +38,13 @@ JS::GCPtr<Layout::Node> HTMLIFrameElement::create_layout_node(CSS::StyleProperti
     return heap().allocate_without_realm<Layout::FrameBox>(document(), *this, move(style));
     return heap().allocate_without_realm<Layout::FrameBox>(document(), *this, move(style));
 }
 }
 
 
+void HTMLIFrameElement::adjust_computed_style(CSS::StyleProperties& style)
+{
+    // https://drafts.csswg.org/css-display-3/#unbox
+    if (style.display().is_contents())
+        style.set_property(CSS::PropertyID::Display, CSS::DisplayStyleValue::create(CSS::Display::from_short(CSS::Display::Short::None)));
+}
+
 void HTMLIFrameElement::attribute_changed(FlyString const& name, Optional<String> const& old_value, Optional<String> const& value)
 void HTMLIFrameElement::attribute_changed(FlyString const& name, Optional<String> const& old_value, Optional<String> const& value)
 {
 {
     HTMLElement::attribute_changed(name, old_value, value);
     HTMLElement::attribute_changed(name, old_value, value);

+ 1 - 0
Libraries/LibWeb/HTML/HTMLIFrameElement.h

@@ -24,6 +24,7 @@ public:
     virtual ~HTMLIFrameElement() override;
     virtual ~HTMLIFrameElement() override;
 
 
     virtual JS::GCPtr<Layout::Node> create_layout_node(CSS::StyleProperties) override;
     virtual JS::GCPtr<Layout::Node> create_layout_node(CSS::StyleProperties) override;
+    virtual void adjust_computed_style(CSS::StyleProperties&) override;
 
 
     void set_current_navigation_was_lazy_loaded(bool value);
     void set_current_navigation_was_lazy_loaded(bool value);
 
 

+ 8 - 0
Libraries/LibWeb/HTML/HTMLImageElement.cpp

@@ -11,6 +11,7 @@
 #include <LibWeb/Bindings/HTMLImageElementPrototype.h>
 #include <LibWeb/Bindings/HTMLImageElementPrototype.h>
 #include <LibWeb/CSS/Parser/Parser.h>
 #include <LibWeb/CSS/Parser/Parser.h>
 #include <LibWeb/CSS/StyleComputer.h>
 #include <LibWeb/CSS/StyleComputer.h>
+#include <LibWeb/CSS/StyleValues/DisplayStyleValue.h>
 #include <LibWeb/DOM/Document.h>
 #include <LibWeb/DOM/Document.h>
 #include <LibWeb/DOM/Event.h>
 #include <LibWeb/DOM/Event.h>
 #include <LibWeb/Fetch/Fetching/Fetching.h>
 #include <LibWeb/Fetch/Fetching/Fetching.h>
@@ -116,6 +117,13 @@ JS::GCPtr<Layout::Node> HTMLImageElement::create_layout_node(CSS::StylePropertie
     return heap().allocate_without_realm<Layout::ImageBox>(document(), *this, move(style), *this);
     return heap().allocate_without_realm<Layout::ImageBox>(document(), *this, move(style), *this);
 }
 }
 
 
+void HTMLImageElement::adjust_computed_style(CSS::StyleProperties& style)
+{
+    // https://drafts.csswg.org/css-display-3/#unbox
+    if (style.display().is_contents())
+        style.set_property(CSS::PropertyID::Display, CSS::DisplayStyleValue::create(CSS::Display::from_short(CSS::Display::Short::None)));
+}
+
 RefPtr<Gfx::ImmutableBitmap> HTMLImageElement::immutable_bitmap() const
 RefPtr<Gfx::ImmutableBitmap> HTMLImageElement::immutable_bitmap() const
 {
 {
     return current_image_bitmap();
     return current_image_bitmap();

+ 1 - 0
Libraries/LibWeb/HTML/HTMLImageElement.h

@@ -131,6 +131,7 @@ private:
     virtual bool supports_dimension_attributes() const override { return true; }
     virtual bool supports_dimension_attributes() const override { return true; }
 
 
     virtual JS::GCPtr<Layout::Node> create_layout_node(CSS::StyleProperties) override;
     virtual JS::GCPtr<Layout::Node> create_layout_node(CSS::StyleProperties) override;
+    virtual void adjust_computed_style(CSS::StyleProperties&) override;
 
 
     virtual void did_set_viewport_rect(CSSPixelRect const&) override;
     virtual void did_set_viewport_rect(CSSPixelRect const&) override;
 
 

+ 4 - 0
Libraries/LibWeb/HTML/HTMLInputElement.cpp

@@ -135,6 +135,10 @@ void HTMLInputElement::adjust_computed_style(CSS::StyleProperties& style)
     if (type_state() == TypeAttributeState::Hidden || type_state() == TypeAttributeState::SubmitButton || type_state() == TypeAttributeState::Button || type_state() == TypeAttributeState::ResetButton || type_state() == TypeAttributeState::ImageButton || type_state() == TypeAttributeState::Checkbox || type_state() == TypeAttributeState::RadioButton)
     if (type_state() == TypeAttributeState::Hidden || type_state() == TypeAttributeState::SubmitButton || type_state() == TypeAttributeState::Button || type_state() == TypeAttributeState::ResetButton || type_state() == TypeAttributeState::ImageButton || type_state() == TypeAttributeState::Checkbox || type_state() == TypeAttributeState::RadioButton)
         return;
         return;
 
 
+    // https://drafts.csswg.org/css-display-3/#unbox
+    if (style.display().is_contents())
+        style.set_property(CSS::PropertyID::Display, CSS::DisplayStyleValue::create(CSS::Display::from_short(CSS::Display::Short::None)));
+
     // AD-HOC: We rewrite `display: inline` to `display: inline-block`.
     // AD-HOC: We rewrite `display: inline` to `display: inline-block`.
     //         This is required for the internal shadow tree to work correctly in layout.
     //         This is required for the internal shadow tree to work correctly in layout.
     if (style.display().is_inline_outside() && style.display().is_flow_inside())
     if (style.display().is_inline_outside() && style.display().is_flow_inside())

+ 8 - 0
Libraries/LibWeb/HTML/HTMLMeterElement.cpp

@@ -6,6 +6,7 @@
  */
  */
 
 
 #include <LibWeb/Bindings/HTMLMeterElementPrototype.h>
 #include <LibWeb/Bindings/HTMLMeterElementPrototype.h>
+#include <LibWeb/CSS/StyleValues/DisplayStyleValue.h>
 #include <LibWeb/DOM/Document.h>
 #include <LibWeb/DOM/Document.h>
 #include <LibWeb/DOM/ElementFactory.h>
 #include <LibWeb/DOM/ElementFactory.h>
 #include <LibWeb/DOM/ShadowRoot.h>
 #include <LibWeb/DOM/ShadowRoot.h>
@@ -177,6 +178,13 @@ void HTMLMeterElement::removed_from(DOM::Node*)
     set_shadow_root(nullptr);
     set_shadow_root(nullptr);
 }
 }
 
 
+void HTMLMeterElement::adjust_computed_style(CSS::StyleProperties& style)
+{
+    // https://drafts.csswg.org/css-display-3/#unbox
+    if (style.display().is_contents())
+        style.set_property(CSS::PropertyID::Display, CSS::DisplayStyleValue::create(CSS::Display::from_short(CSS::Display::Short::None)));
+}
+
 void HTMLMeterElement::create_shadow_tree_if_needed()
 void HTMLMeterElement::create_shadow_tree_if_needed()
 {
 {
     if (shadow_root())
     if (shadow_root())

+ 2 - 0
Libraries/LibWeb/HTML/HTMLMeterElement.h

@@ -37,6 +37,8 @@ public:
     virtual void inserted() override;
     virtual void inserted() override;
     virtual void removed_from(DOM::Node*) override;
     virtual void removed_from(DOM::Node*) override;
 
 
+    virtual void adjust_computed_style(CSS::StyleProperties&) override;
+
     // https://html.spec.whatwg.org/multipage/forms.html#category-label
     // https://html.spec.whatwg.org/multipage/forms.html#category-label
     virtual bool is_labelable() const override { return true; }
     virtual bool is_labelable() const override { return true; }
 
 

+ 8 - 0
Libraries/LibWeb/HTML/HTMLObjectElement.cpp

@@ -8,6 +8,7 @@
 #include <LibWeb/Bindings/HTMLObjectElementPrototype.h>
 #include <LibWeb/Bindings/HTMLObjectElementPrototype.h>
 #include <LibWeb/CSS/StyleComputer.h>
 #include <LibWeb/CSS/StyleComputer.h>
 #include <LibWeb/CSS/StyleValues/CSSKeywordValue.h>
 #include <LibWeb/CSS/StyleValues/CSSKeywordValue.h>
+#include <LibWeb/CSS/StyleValues/DisplayStyleValue.h>
 #include <LibWeb/CSS/StyleValues/LengthStyleValue.h>
 #include <LibWeb/CSS/StyleValues/LengthStyleValue.h>
 #include <LibWeb/DOM/Document.h>
 #include <LibWeb/DOM/Document.h>
 #include <LibWeb/DOM/DocumentLoading.h>
 #include <LibWeb/DOM/DocumentLoading.h>
@@ -155,6 +156,13 @@ JS::GCPtr<Layout::Node> HTMLObjectElement::create_layout_node(CSS::StyleProperti
     return nullptr;
     return nullptr;
 }
 }
 
 
+void HTMLObjectElement::adjust_computed_style(CSS::StyleProperties& style)
+{
+    // https://drafts.csswg.org/css-display-3/#unbox
+    if (style.display().is_contents())
+        style.set_property(CSS::PropertyID::Display, CSS::DisplayStyleValue::create(CSS::Display::from_short(CSS::Display::Short::None)));
+}
+
 bool HTMLObjectElement::has_ancestor_media_element_or_object_element_not_showing_fallback_content() const
 bool HTMLObjectElement::has_ancestor_media_element_or_object_element_not_showing_fallback_content() const
 {
 {
     for (auto const* ancestor = parent(); ancestor; ancestor = ancestor->parent()) {
     for (auto const* ancestor = parent(); ancestor; ancestor = ancestor->parent()) {

+ 1 - 0
Libraries/LibWeb/HTML/HTMLObjectElement.h

@@ -59,6 +59,7 @@ private:
     virtual void apply_presentational_hints(CSS::StyleProperties&) const override;
     virtual void apply_presentational_hints(CSS::StyleProperties&) const override;
 
 
     virtual JS::GCPtr<Layout::Node> create_layout_node(CSS::StyleProperties) override;
     virtual JS::GCPtr<Layout::Node> create_layout_node(CSS::StyleProperties) override;
+    virtual void adjust_computed_style(CSS::StyleProperties&) override;
 
 
     bool has_ancestor_media_element_or_object_element_not_showing_fallback_content() const;
     bool has_ancestor_media_element_or_object_element_not_showing_fallback_content() const;
 
 

+ 8 - 0
Libraries/LibWeb/HTML/HTMLProgressElement.cpp

@@ -8,6 +8,7 @@
 
 
 #include <LibWeb/Bindings/HTMLProgressElementPrototype.h>
 #include <LibWeb/Bindings/HTMLProgressElementPrototype.h>
 #include <LibWeb/CSS/StyleProperties.h>
 #include <LibWeb/CSS/StyleProperties.h>
+#include <LibWeb/CSS/StyleValues/DisplayStyleValue.h>
 #include <LibWeb/DOM/Document.h>
 #include <LibWeb/DOM/Document.h>
 #include <LibWeb/DOM/ElementFactory.h>
 #include <LibWeb/DOM/ElementFactory.h>
 #include <LibWeb/DOM/ShadowRoot.h>
 #include <LibWeb/DOM/ShadowRoot.h>
@@ -98,6 +99,13 @@ void HTMLProgressElement::removed_from(DOM::Node*)
     set_shadow_root(nullptr);
     set_shadow_root(nullptr);
 }
 }
 
 
+void HTMLProgressElement::adjust_computed_style(CSS::StyleProperties& style)
+{
+    // https://drafts.csswg.org/css-display-3/#unbox
+    if (style.display().is_contents())
+        style.set_property(CSS::PropertyID::Display, CSS::DisplayStyleValue::create(CSS::Display::from_short(CSS::Display::Short::None)));
+}
+
 void HTMLProgressElement::create_shadow_tree_if_needed()
 void HTMLProgressElement::create_shadow_tree_if_needed()
 {
 {
     if (shadow_root())
     if (shadow_root())

+ 2 - 0
Libraries/LibWeb/HTML/HTMLProgressElement.h

@@ -31,6 +31,8 @@ public:
     virtual void inserted() override;
     virtual void inserted() override;
     virtual void removed_from(DOM::Node*) override;
     virtual void removed_from(DOM::Node*) override;
 
 
+    virtual void adjust_computed_style(CSS::StyleProperties&) override;
+
     // https://html.spec.whatwg.org/multipage/forms.html#category-label
     // https://html.spec.whatwg.org/multipage/forms.html#category-label
     virtual bool is_labelable() const override { return true; }
     virtual bool is_labelable() const override { return true; }
 
 

+ 4 - 0
Libraries/LibWeb/HTML/HTMLSelectElement.cpp

@@ -66,6 +66,10 @@ void HTMLSelectElement::visit_edges(Cell::Visitor& visitor)
 
 
 void HTMLSelectElement::adjust_computed_style(CSS::StyleProperties& style)
 void HTMLSelectElement::adjust_computed_style(CSS::StyleProperties& style)
 {
 {
+    // https://drafts.csswg.org/css-display-3/#unbox
+    if (style.display().is_contents())
+        style.set_property(CSS::PropertyID::Display, CSS::DisplayStyleValue::create(CSS::Display::from_short(CSS::Display::Short::None)));
+
     // AD-HOC: We rewrite `display: inline` to `display: inline-block`.
     // AD-HOC: We rewrite `display: inline` to `display: inline-block`.
     //         This is required for the internal shadow tree to work correctly in layout.
     //         This is required for the internal shadow tree to work correctly in layout.
     if (style.display().is_inline_outside() && style.display().is_flow_inside())
     if (style.display().is_inline_outside() && style.display().is_flow_inside())

+ 4 - 0
Libraries/LibWeb/HTML/HTMLTextAreaElement.cpp

@@ -43,6 +43,10 @@ HTMLTextAreaElement::~HTMLTextAreaElement() = default;
 
 
 void HTMLTextAreaElement::adjust_computed_style(CSS::StyleProperties& style)
 void HTMLTextAreaElement::adjust_computed_style(CSS::StyleProperties& style)
 {
 {
+    // https://drafts.csswg.org/css-display-3/#unbox
+    if (style.display().is_contents())
+        style.set_property(CSS::PropertyID::Display, CSS::DisplayStyleValue::create(CSS::Display::from_short(CSS::Display::Short::None)));
+
     // AD-HOC: We rewrite `display: inline` to `display: inline-block`.
     // AD-HOC: We rewrite `display: inline` to `display: inline-block`.
     //         This is required for the internal shadow tree to work correctly in layout.
     //         This is required for the internal shadow tree to work correctly in layout.
     if (style.display().is_inline_outside() && style.display().is_flow_inside())
     if (style.display().is_inline_outside() && style.display().is_flow_inside())

+ 8 - 0
Libraries/LibWeb/HTML/HTMLVideoElement.cpp

@@ -8,6 +8,7 @@
 #include <LibGfx/Bitmap.h>
 #include <LibGfx/Bitmap.h>
 #include <LibWeb/Bindings/HTMLVideoElementPrototype.h>
 #include <LibWeb/Bindings/HTMLVideoElementPrototype.h>
 #include <LibWeb/Bindings/Intrinsics.h>
 #include <LibWeb/Bindings/Intrinsics.h>
+#include <LibWeb/CSS/StyleValues/DisplayStyleValue.h>
 #include <LibWeb/DOM/Document.h>
 #include <LibWeb/DOM/Document.h>
 #include <LibWeb/Fetch/Fetching/Fetching.h>
 #include <LibWeb/Fetch/Fetching/Fetching.h>
 #include <LibWeb/Fetch/Infrastructure/FetchAlgorithms.h>
 #include <LibWeb/Fetch/Infrastructure/FetchAlgorithms.h>
@@ -67,6 +68,13 @@ JS::GCPtr<Layout::Node> HTMLVideoElement::create_layout_node(CSS::StylePropertie
     return heap().allocate_without_realm<Layout::VideoBox>(document(), *this, move(style));
     return heap().allocate_without_realm<Layout::VideoBox>(document(), *this, move(style));
 }
 }
 
 
+void HTMLVideoElement::adjust_computed_style(CSS::StyleProperties& style)
+{
+    // https://drafts.csswg.org/css-display-3/#unbox
+    if (style.display().is_contents())
+        style.set_property(CSS::PropertyID::Display, CSS::DisplayStyleValue::create(CSS::Display::from_short(CSS::Display::Short::None)));
+}
+
 Layout::VideoBox* HTMLVideoElement::layout_node()
 Layout::VideoBox* HTMLVideoElement::layout_node()
 {
 {
     return static_cast<Layout::VideoBox*>(Node::layout_node());
     return static_cast<Layout::VideoBox*>(Node::layout_node());

+ 1 - 0
Libraries/LibWeb/HTML/HTMLVideoElement.h

@@ -61,6 +61,7 @@ private:
     virtual bool supports_dimension_attributes() const override { return true; }
     virtual bool supports_dimension_attributes() const override { return true; }
 
 
     virtual JS::GCPtr<Layout::Node> create_layout_node(CSS::StyleProperties) override;
     virtual JS::GCPtr<Layout::Node> create_layout_node(CSS::StyleProperties) override;
+    virtual void adjust_computed_style(CSS::StyleProperties&) override;
 
 
     virtual void on_playing() override;
     virtual void on_playing() override;
     virtual void on_paused() override;
     virtual void on_paused() override;

+ 5 - 0
Tests/LibWeb/Ref/expected/wpt-import/css/css-display/display-contents-suppression-dynamic-001-ref.html

@@ -0,0 +1,5 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Test Reference</title>
+<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
+<p>Test passes if you see nothing below.</p>

+ 16 - 0
Tests/LibWeb/Ref/input/wpt-import/css/css-display/display-contents-suppression-dynamic-001.html

@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Test: display: contents unboxing works in presence of dynamic changes to the tree.</title>
+<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
+<link rel="help" href="https://drafts.csswg.org/css-display-3/#valdef-display-contents">
+<link rel="help" href="https://drafts.csswg.org/css-display-3/#unbox">
+<link rel="match" href="../../../../expected/wpt-import/css/css-display/display-contents-suppression-dynamic-001-ref.html">
+<p>Test passes if you see nothing below.</p>
+<textarea style="display: contents">
+  FAIL
+</textarea>
+<script>
+  let textarea = document.querySelector("textarea");
+  textarea.offsetTop;
+  textarea.appendChild(document.createTextNode("FAIL"));
+</script>