diff --git a/Tests/LibWeb/Text/expected/HTML/dimension-attributes.txt b/Tests/LibWeb/Text/expected/HTML/dimension-attributes.txt index 1d8eb369d9c..c98be015578 100644 --- a/Tests/LibWeb/Text/expected/HTML/dimension-attributes.txt +++ b/Tests/LibWeb/Text/expected/HTML/dimension-attributes.txt @@ -19,3 +19,39 @@ Test marquee.width = "120." maps to width: 120px Test marquee.height = "100" maps to height: 100px Test marquee.height = " 00110 " maps to height: 110px Test marquee.height = "120." maps to height: 120px +Test object.hspace = "100" maps to marginLeft: 100px +Test object.hspace = " 00110 " maps to marginLeft: 110px +Test object.hspace = "120." maps to marginLeft: 120px +Test object.hspace = "100" maps to marginRight: 100px +Test object.hspace = " 00110 " maps to marginRight: 110px +Test object.hspace = "120." maps to marginRight: 120px +Test object.vspace = "100" maps to marginTop: 100px +Test object.vspace = " 00110 " maps to marginTop: 110px +Test object.vspace = "120." maps to marginTop: 120px +Test object.vspace = "100" maps to marginBottom: 100px +Test object.vspace = " 00110 " maps to marginBottom: 110px +Test object.vspace = "120." maps to marginBottom: 120px +Test object.width = "100" maps to width: 100px +Test object.width = " 00110 " maps to width: 110px +Test object.width = "120." maps to width: 120px +Test object.height = "100" maps to height: 100px +Test object.height = " 00110 " maps to height: 110px +Test object.height = "120." maps to height: 120px +Test embed.hspace = "100" maps to marginLeft: 100px +Test embed.hspace = " 00110 " maps to marginLeft: 110px +Test embed.hspace = "120." maps to marginLeft: 120px +Test embed.hspace = "100" maps to marginRight: 100px +Test embed.hspace = " 00110 " maps to marginRight: 110px +Test embed.hspace = "120." maps to marginRight: 120px +Test embed.vspace = "100" maps to marginTop: 100px +Test embed.vspace = " 00110 " maps to marginTop: 110px +Test embed.vspace = "120." maps to marginTop: 120px +Test embed.vspace = "100" maps to marginBottom: 100px +Test embed.vspace = " 00110 " maps to marginBottom: 110px +Test embed.vspace = "120." maps to marginBottom: 120px +Test embed.width = "100" maps to width: 100px +Test embed.width = " 00110 " maps to width: 110px +Test embed.width = "120." maps to width: 120px +Test embed.height = "100" maps to height: 100px +Test embed.height = " 00110 " maps to height: 110px +Test embed.height = "120." maps to height: 120px diff --git a/Tests/LibWeb/Text/input/HTML/dimension-attributes.html b/Tests/LibWeb/Text/input/HTML/dimension-attributes.html index 656d5c24582..bcd257fa2b7 100644 --- a/Tests/LibWeb/Text/input/HTML/dimension-attributes.html +++ b/Tests/LibWeb/Text/input/HTML/dimension-attributes.html @@ -10,6 +10,18 @@ { elementName: "marquee", attribute: "vspace", mappedProperty: "marginBottom" }, { elementName: "marquee", attribute: "width", mappedProperty: "width" }, { elementName: "marquee", attribute: "height", mappedProperty: "height" }, + { elementName: "object", attribute: "hspace", mappedProperty: "marginLeft" }, + { elementName: "object", attribute: "hspace", mappedProperty: "marginRight" }, + { elementName: "object", attribute: "vspace", mappedProperty: "marginTop" }, + { elementName: "object", attribute: "vspace", mappedProperty: "marginBottom" }, + { elementName: "object", attribute: "width", mappedProperty: "width" }, + { elementName: "object", attribute: "height", mappedProperty: "height" }, + { elementName: "embed", attribute: "hspace", mappedProperty: "marginLeft" }, + { elementName: "embed", attribute: "hspace", mappedProperty: "marginRight" }, + { elementName: "embed", attribute: "vspace", mappedProperty: "marginTop" }, + { elementName: "embed", attribute: "vspace", mappedProperty: "marginBottom" }, + { elementName: "embed", attribute: "width", mappedProperty: "width" }, + { elementName: "embed", attribute: "height", mappedProperty: "height" }, ]; const values = ["100", " 00110 ", "120."]; @@ -18,7 +30,7 @@ document.body.appendChild(element); const style = document.defaultView.getComputedStyle(element); for (const value of values) { - element[attribute] = value; + element.setAttribute(attribute, value); println(`Test ${elementName}.${attribute} = "${value}" maps to ${mappedProperty}: ${style[mappedProperty]}`); } element.remove(); diff --git a/Userland/Libraries/LibWeb/HTML/HTMLEmbedElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLEmbedElement.cpp index 68316e57d33..4182abad500 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLEmbedElement.cpp +++ b/Userland/Libraries/LibWeb/HTML/HTMLEmbedElement.cpp @@ -6,7 +6,10 @@ #include #include +#include +#include #include +#include namespace Web::HTML { @@ -25,4 +28,35 @@ void HTMLEmbedElement::initialize(JS::Realm& realm) WEB_SET_PROTOTYPE_FOR_INTERFACE(HTMLEmbedElement); } +void HTMLEmbedElement::apply_presentational_hints(CSS::StyleProperties& style) const +{ + for_each_attribute([&](auto& name, auto& value) { + if (name == HTML::AttributeNames::align) { + if (value.equals_ignoring_ascii_case("center"sv)) + style.set_property(CSS::PropertyID::TextAlign, CSS::CSSKeywordValue::create(CSS::Keyword::Center)); + else if (value.equals_ignoring_ascii_case("middle"sv)) + style.set_property(CSS::PropertyID::TextAlign, CSS::CSSKeywordValue::create(CSS::Keyword::Middle)); + } else if (name == HTML::AttributeNames::height) { + if (auto parsed_value = parse_dimension_value(value)) + style.set_property(CSS::PropertyID::Height, *parsed_value); + } + // https://html.spec.whatwg.org/multipage/rendering.html#attributes-for-embedded-content-and-images:maps-to-the-dimension-property + else if (name == HTML::AttributeNames::hspace) { + if (auto parsed_value = parse_dimension_value(value)) { + style.set_property(CSS::PropertyID::MarginLeft, *parsed_value); + style.set_property(CSS::PropertyID::MarginRight, *parsed_value); + } + } else if (name == HTML::AttributeNames::vspace) { + if (auto parsed_value = parse_dimension_value(value)) { + style.set_property(CSS::PropertyID::MarginTop, *parsed_value); + style.set_property(CSS::PropertyID::MarginBottom, *parsed_value); + } + } else if (name == HTML::AttributeNames::width) { + if (auto parsed_value = parse_dimension_value(value)) { + style.set_property(CSS::PropertyID::Width, *parsed_value); + } + } + }); +} + } diff --git a/Userland/Libraries/LibWeb/HTML/HTMLEmbedElement.h b/Userland/Libraries/LibWeb/HTML/HTMLEmbedElement.h index 83c569f4a7d..544d2defc07 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLEmbedElement.h +++ b/Userland/Libraries/LibWeb/HTML/HTMLEmbedElement.h @@ -22,6 +22,7 @@ private: virtual bool is_html_embed_element() const override { return true; } virtual void initialize(JS::Realm&) override; + virtual void apply_presentational_hints(CSS::StyleProperties&) const override; }; } diff --git a/Userland/Libraries/LibWeb/HTML/HTMLInputElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLInputElement.cpp index 38a5c614eba..1d6fa5d2c3f 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLInputElement.cpp +++ b/Userland/Libraries/LibWeb/HTML/HTMLInputElement.cpp @@ -1530,6 +1530,55 @@ void HTMLInputElement::form_associated_element_was_removed(DOM::Node*) set_shadow_root(nullptr); } +void HTMLInputElement::apply_presentational_hints(CSS::StyleProperties& style) const +{ + if (type_state() != TypeAttributeState::ImageButton) + return; + + for_each_attribute([&](auto& name, auto& value) { + if (name == HTML::AttributeNames::align) { + if (value.equals_ignoring_ascii_case("center"sv)) + style.set_property(CSS::PropertyID::TextAlign, CSS::CSSKeywordValue::create(CSS::Keyword::Center)); + else if (value.equals_ignoring_ascii_case("middle"sv)) + style.set_property(CSS::PropertyID::TextAlign, CSS::CSSKeywordValue::create(CSS::Keyword::Middle)); + } else if (name == HTML::AttributeNames::border) { + if (auto parsed_value = parse_non_negative_integer(value); parsed_value.has_value() && *parsed_value > 0) { + auto width_style_value = CSS::LengthStyleValue::create(CSS::Length::make_px(*parsed_value)); + style.set_property(CSS::PropertyID::BorderTopWidth, width_style_value); + style.set_property(CSS::PropertyID::BorderRightWidth, width_style_value); + style.set_property(CSS::PropertyID::BorderBottomWidth, width_style_value); + style.set_property(CSS::PropertyID::BorderLeftWidth, width_style_value); + + auto border_style_value = CSS::CSSKeywordValue::create(CSS::Keyword::Solid); + style.set_property(CSS::PropertyID::BorderTopStyle, border_style_value); + style.set_property(CSS::PropertyID::BorderRightStyle, border_style_value); + style.set_property(CSS::PropertyID::BorderBottomStyle, border_style_value); + style.set_property(CSS::PropertyID::BorderLeftStyle, border_style_value); + } + } else if (name == HTML::AttributeNames::height) { + if (auto parsed_value = parse_dimension_value(value)) { + style.set_property(CSS::PropertyID::Height, *parsed_value); + } + } + // https://html.spec.whatwg.org/multipage/rendering.html#attributes-for-embedded-content-and-images:maps-to-the-dimension-property + else if (name == HTML::AttributeNames::hspace) { + if (auto parsed_value = parse_dimension_value(value)) { + style.set_property(CSS::PropertyID::MarginLeft, *parsed_value); + style.set_property(CSS::PropertyID::MarginRight, *parsed_value); + } + } else if (name == HTML::AttributeNames::vspace) { + if (auto parsed_value = parse_dimension_value(value)) { + style.set_property(CSS::PropertyID::MarginTop, *parsed_value); + style.set_property(CSS::PropertyID::MarginBottom, *parsed_value); + } + } else if (name == HTML::AttributeNames::width) { + if (auto parsed_value = parse_dimension_value(value)) { + style.set_property(CSS::PropertyID::Width, *parsed_value); + } + } + }); +} + // https://html.spec.whatwg.org/multipage/input.html#the-input-element%3Aconcept-node-clone-ext WebIDL::ExceptionOr HTMLInputElement::cloned(DOM::Node& copy, bool) { diff --git a/Userland/Libraries/LibWeb/HTML/HTMLInputElement.h b/Userland/Libraries/LibWeb/HTML/HTMLInputElement.h index bc2ea4d7ad8..4c701de4e18 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLInputElement.h +++ b/Userland/Libraries/LibWeb/HTML/HTMLInputElement.h @@ -216,6 +216,8 @@ private: void type_attribute_changed(TypeAttributeState old_state, TypeAttributeState new_state); + virtual void apply_presentational_hints(CSS::StyleProperties&) const override; + // ^DOM::Node virtual bool is_html_input_element() const final { return true; } diff --git a/Userland/Libraries/LibWeb/HTML/HTMLObjectElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLObjectElement.cpp index 352d9fbe998..8c38b6bfa60 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLObjectElement.cpp +++ b/Userland/Libraries/LibWeb/HTML/HTMLObjectElement.cpp @@ -7,6 +7,8 @@ #include #include #include +#include +#include #include #include #include @@ -14,6 +16,8 @@ #include #include #include +#include +#include #include #include #include @@ -74,6 +78,54 @@ void HTMLObjectElement::form_associated_element_was_removed(DOM::Node*) destroy_the_child_navigable(); } +void HTMLObjectElement::apply_presentational_hints(CSS::StyleProperties& style) const +{ + for_each_attribute([&](auto& name, auto& value) { + if (name == HTML::AttributeNames::align) { + if (value.equals_ignoring_ascii_case("center"sv)) + style.set_property(CSS::PropertyID::TextAlign, CSS::CSSKeywordValue::create(CSS::Keyword::Center)); + else if (value.equals_ignoring_ascii_case("middle"sv)) + style.set_property(CSS::PropertyID::TextAlign, CSS::CSSKeywordValue::create(CSS::Keyword::Middle)); + } else if (name == HTML::AttributeNames::border) { + if (auto parsed_value = parse_non_negative_integer(value); parsed_value.has_value() && *parsed_value > 0) { + auto width_style_value = CSS::LengthStyleValue::create(CSS::Length::make_px(*parsed_value)); + style.set_property(CSS::PropertyID::BorderTopWidth, width_style_value); + style.set_property(CSS::PropertyID::BorderRightWidth, width_style_value); + style.set_property(CSS::PropertyID::BorderBottomWidth, width_style_value); + style.set_property(CSS::PropertyID::BorderLeftWidth, width_style_value); + + auto border_style_value = CSS::CSSKeywordValue::create(CSS::Keyword::Solid); + style.set_property(CSS::PropertyID::BorderTopStyle, border_style_value); + style.set_property(CSS::PropertyID::BorderRightStyle, border_style_value); + style.set_property(CSS::PropertyID::BorderBottomStyle, border_style_value); + style.set_property(CSS::PropertyID::BorderLeftStyle, border_style_value); + } + } + // https://html.spec.whatwg.org/multipage/rendering.html#attributes-for-embedded-content-and-images:maps-to-the-dimension-property-3 + else if (name == HTML::AttributeNames::height) { + if (auto parsed_value = parse_dimension_value(value)) { + style.set_property(CSS::PropertyID::Height, *parsed_value); + } + } + // https://html.spec.whatwg.org/multipage/rendering.html#attributes-for-embedded-content-and-images:maps-to-the-dimension-property + else if (name == HTML::AttributeNames::hspace) { + if (auto parsed_value = parse_dimension_value(value)) { + style.set_property(CSS::PropertyID::MarginLeft, *parsed_value); + style.set_property(CSS::PropertyID::MarginRight, *parsed_value); + } + } else if (name == HTML::AttributeNames::vspace) { + if (auto parsed_value = parse_dimension_value(value)) { + style.set_property(CSS::PropertyID::MarginTop, *parsed_value); + style.set_property(CSS::PropertyID::MarginBottom, *parsed_value); + } + } else if (name == HTML::AttributeNames::width) { + if (auto parsed_value = parse_dimension_value(value)) { + style.set_property(CSS::PropertyID::Width, *parsed_value); + } + } + }); +} + // https://html.spec.whatwg.org/multipage/iframe-embed-object.html#attr-object-data String HTMLObjectElement::data() const { diff --git a/Userland/Libraries/LibWeb/HTML/HTMLObjectElement.h b/Userland/Libraries/LibWeb/HTML/HTMLObjectElement.h index 7acbd47fb35..b0477e2084d 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLObjectElement.h +++ b/Userland/Libraries/LibWeb/HTML/HTMLObjectElement.h @@ -56,6 +56,8 @@ private: virtual void initialize(JS::Realm&) override; + virtual void apply_presentational_hints(CSS::StyleProperties&) const override; + virtual JS::GCPtr create_layout_node(NonnullRefPtr) override; bool has_ancestor_media_element_or_object_element_not_showing_fallback_content() const;