diff --git a/Tests/LibWeb/Text/expected/css/getComputedStyle-print-all.txt b/Tests/LibWeb/Text/expected/css/getComputedStyle-print-all.txt index d53d42516c..c26d49b7a5 100644 --- a/Tests/LibWeb/Text/expected/css/getComputedStyle-print-all.txt +++ b/Tests/LibWeb/Text/expected/css/getComputedStyle-print-all.txt @@ -104,6 +104,7 @@ margin-left: 8px margin-right: 8px margin-top: 8px mask: none +mask-type: luminance math-depth: 0 math-shift: normal math-style: normal diff --git a/Userland/Libraries/LibWeb/CSS/ComputedValues.h b/Userland/Libraries/LibWeb/CSS/ComputedValues.h index ae62480888..21ec32f74a 100644 --- a/Userland/Libraries/LibWeb/CSS/ComputedValues.h +++ b/Userland/Libraries/LibWeb/CSS/ComputedValues.h @@ -131,6 +131,7 @@ public: static CSS::TableLayout table_layout() { return CSS::TableLayout::Auto; } static QuotesData quotes() { return QuotesData { .type = QuotesData::Type::Auto }; } + static CSS::MaskType mask_type() { return CSS::MaskType::Luminance; } static CSS::MathShift math_shift() { return CSS::MathShift::Normal; } static CSS::MathStyle math_style() { return CSS::MathStyle::Normal; } static int math_depth() { return 0; } @@ -360,6 +361,7 @@ public: float stop_opacity() const { return m_noninherited.stop_opacity; } CSS::TextAnchor text_anchor() const { return m_inherited.text_anchor; } Optional const& mask() const { return m_noninherited.mask; } + CSS::MaskType mask_type() const { return m_noninherited.mask_type; } Vector const& transformations() const { return m_noninherited.transformations; } CSS::TransformOrigin const& transform_origin() const { return m_noninherited.transform_origin; } @@ -506,6 +508,7 @@ protected: CSS::TableLayout table_layout { InitialValues::table_layout() }; Optional mask; + CSS::MaskType mask_type { InitialValues::mask_type() }; } m_noninherited; }; @@ -624,6 +627,7 @@ public: void set_outline_style(CSS::OutlineStyle value) { m_noninherited.outline_style = value; } void set_outline_width(CSS::Length value) { m_noninherited.outline_width = value; } void set_mask(MaskReference value) { m_noninherited.mask = value; } + void set_mask_type(CSS::MaskType value) { m_noninherited.mask_type = value; } void set_math_shift(CSS::MathShift value) { m_inherited.math_shift = value; } void set_math_style(CSS::MathStyle value) { m_inherited.math_style = value; } diff --git a/Userland/Libraries/LibWeb/CSS/Enums.json b/Userland/Libraries/LibWeb/CSS/Enums.json index 5e890d3701..670ffdcd70 100644 --- a/Userland/Libraries/LibWeb/CSS/Enums.json +++ b/Userland/Libraries/LibWeb/CSS/Enums.json @@ -276,6 +276,10 @@ "inside", "outside" ], + "mask-type": [ + "luminance", + "alpha" + ], "math-shift": [ "normal", "compact" diff --git a/Userland/Libraries/LibWeb/CSS/Identifiers.json b/Userland/Libraries/LibWeb/CSS/Identifiers.json index 8a695ed7a6..e5714c5327 100644 --- a/Userland/Libraries/LibWeb/CSS/Identifiers.json +++ b/Userland/Libraries/LibWeb/CSS/Identifiers.json @@ -68,6 +68,7 @@ "alias", "all", "all-scroll", + "alpha", "alternate", "alternate-reverse", "anywhere", @@ -220,6 +221,7 @@ "lowercase", "ltr", "listbox", + "luminance", "mark", "marktext", "math", diff --git a/Userland/Libraries/LibWeb/CSS/Properties.json b/Userland/Libraries/LibWeb/CSS/Properties.json index 8240dcab6b..1c953f9d0f 100644 --- a/Userland/Libraries/LibWeb/CSS/Properties.json +++ b/Userland/Libraries/LibWeb/CSS/Properties.json @@ -1502,6 +1502,14 @@ ], "initial": "none" }, + "mask-type": { + "inherited": false, + "affects-layout": false, + "valid-types": [ + "mask-type" + ], + "initial": "luminance" + }, "math-depth": { "inherited": true, "initial": "0", diff --git a/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp b/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp index a83043ed36..a39da7fea2 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleProperties.cpp @@ -1015,6 +1015,12 @@ Optional StyleProperties::table_layout() const return value_id_to_table_layout(value->to_identifier()); } +Optional StyleProperties::mask_type() const +{ + auto value = property(CSS::PropertyID::MaskType); + return value_id_to_mask_type(value->to_identifier()); +} + Color StyleProperties::stop_color() const { auto value = property(CSS::PropertyID::StopColor); diff --git a/Userland/Libraries/LibWeb/CSS/StyleProperties.h b/Userland/Libraries/LibWeb/CSS/StyleProperties.h index 50cc6a78a1..9aaeefd6f9 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleProperties.h +++ b/Userland/Libraries/LibWeb/CSS/StyleProperties.h @@ -122,6 +122,7 @@ public: Vector transformations() const; CSS::TransformOrigin transform_origin() const; + Optional mask_type() const; Color stop_color() const; float stop_opacity() const; float fill_opacity() const; diff --git a/Userland/Libraries/LibWeb/Layout/Node.cpp b/Userland/Libraries/LibWeb/Layout/Node.cpp index c30b52f539..aff4b62ea6 100644 --- a/Userland/Libraries/LibWeb/Layout/Node.cpp +++ b/Userland/Libraries/LibWeb/Layout/Node.cpp @@ -778,6 +778,9 @@ void NodeWithStyle::apply_style(const CSS::StyleProperties& computed_style) else if (stroke_width->is_percentage()) computed_values.set_stroke_width(CSS::LengthPercentage { stroke_width->as_percentage().percentage() }); + if (auto mask_type = computed_style.mask_type(); mask_type.has_value()) + computed_values.set_mask_type(*mask_type); + if (auto mask = computed_style.property(CSS::PropertyID::Mask); mask->is_url()) computed_values.set_mask(mask->as_url().url()); diff --git a/Userland/Libraries/LibWeb/Painting/SVGGraphicsPaintable.cpp b/Userland/Libraries/LibWeb/Painting/SVGGraphicsPaintable.cpp index ddad7ec223..4e5c3b1a61 100644 --- a/Userland/Libraries/LibWeb/Painting/SVGGraphicsPaintable.cpp +++ b/Userland/Libraries/LibWeb/Painting/SVGGraphicsPaintable.cpp @@ -40,6 +40,18 @@ Optional SVGGraphicsPaintable::get_masking_area() const return {}; } +static Gfx::Bitmap::MaskKind mask_type_to_gfx_mask_kind(CSS::MaskType mask_type) +{ + switch (mask_type) { + case CSS::MaskType::Alpha: + return Gfx::Bitmap::MaskKind::Alpha; + case CSS::MaskType::Luminance: + return Gfx::Bitmap::MaskKind::Luminance; + default: + VERIFY_NOT_REACHED(); + } +} + void SVGGraphicsPaintable::apply_mask(PaintContext& context, Gfx::Bitmap& target, CSSPixelRect const& masking_area) const { auto const& graphics_element = verify_cast(*dom_node()); @@ -65,9 +77,9 @@ void SVGGraphicsPaintable::apply_mask(PaintContext& context, Gfx::Bitmap& target StackingContext::paint_node_as_stacking_context(mask_paintable, paint_context); } } - // TODO: Follow mask-type attribute to select between alpha/luminance masks. if (mask_bitmap) - target.apply_mask(*mask_bitmap, Gfx::Bitmap::MaskKind::Luminance); + target.apply_mask(*mask_bitmap, + mask_type_to_gfx_mask_kind(mask->layout_node()->computed_values().mask_type())); return; }