Skip to content

Commit

Permalink
LibWeb: Implement mask-image CSS property support
Browse files Browse the repository at this point in the history
Implemented by reusing AddMask display list item that was initially
added for `background-clip` property.

Progress on flashlight effect on https://null.com/games/athena-crisis
  • Loading branch information
kalenikaliaksandr authored and awesomekling committed Nov 18, 2024
1 parent 7b7bb60 commit 96a3576
Show file tree
Hide file tree
Showing 11 changed files with 149 additions and 58 deletions.
3 changes: 3 additions & 0 deletions Libraries/LibWeb/CSS/ComputedValues.h
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,7 @@ class ComputedValues {
Color stop_color() const { return m_noninherited.stop_color; }
float stop_opacity() const { return m_noninherited.stop_opacity; }
CSS::TextAnchor text_anchor() const { return m_inherited.text_anchor; }
RefPtr<AbstractImageStyleValue const> mask_image() const { return m_noninherited.mask_image; }
Optional<MaskReference> const& mask() const { return m_noninherited.mask; }
CSS::MaskType mask_type() const { return m_noninherited.mask_type; }
Optional<ClipPathReference> const& clip_path() const { return m_noninherited.clip_path; }
Expand Down Expand Up @@ -681,6 +682,7 @@ class ComputedValues {
Optional<MaskReference> mask;
CSS::MaskType mask_type { InitialValues::mask_type() };
Optional<ClipPathReference> clip_path;
RefPtr<CSS::AbstractImageStyleValue> mask_image;

LengthPercentage cx { InitialValues::cx() };
LengthPercentage cy { InitialValues::cy() };
Expand Down Expand Up @@ -838,6 +840,7 @@ class MutableComputedValues final : public ComputedValues {
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_mask_image(CSS::AbstractImageStyleValue const& value) { m_noninherited.mask_image = value; }
void set_clip_path(ClipPathReference value) { m_noninherited.clip_path = value; }
void set_clip_rule(CSS::ClipRule value) { m_inherited.clip_rule = value; }

Expand Down
15 changes: 15 additions & 0 deletions Libraries/LibWeb/CSS/Properties.json
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,9 @@
"-webkit-mask": {
"legacy-alias-for": "mask"
},
"-webkit-mask-image": {
"legacy-alias-for": "mask-image"
},
"-webkit-order": {
"legacy-alias-for": "order"
},
Expand Down Expand Up @@ -1859,6 +1862,18 @@
],
"initial": "none"
},
"mask-image": {
"animation-type": "discrete",
"inherited": false,
"affects-layout": false,
"valid-types": [
"image"
],
"valid-identifiers": [
"none"
],
"initial": "none"
},
"mask-type": {
"animation-type": "discrete",
"inherited": false,
Expand Down
8 changes: 7 additions & 1 deletion Libraries/LibWeb/Layout/Node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ bool Node::establishes_stacking_context() const
// - perspective
// - clip-path
// - mask / mask-image / mask-border
if (computed_values().mask().has_value() || computed_values().clip_path().has_value())
if (computed_values().mask().has_value() || computed_values().clip_path().has_value() || computed_values().mask_image())
return true;

return computed_values().opacity() < 1.0f;
Expand Down Expand Up @@ -829,6 +829,12 @@ 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 const& mask_image = computed_style.property(CSS::PropertyID::MaskImage); mask_image.is_abstract_image()) {
auto const& abstract_image = mask_image.as_abstract_image();
computed_values.set_mask_image(abstract_image);
const_cast<CSS::AbstractImageStyleValue&>(abstract_image).load_any_resources(document());
}

if (auto mask_type = computed_style.mask_type(); mask_type.has_value())
computed_values.set_mask_type(*mask_type);

Expand Down
4 changes: 4 additions & 0 deletions Libraries/LibWeb/Painting/PaintableBox.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1177,6 +1177,10 @@ void PaintableBox::resolve_paint_properties()
if (background_layers) {
m_resolved_background = resolve_background_layers(*background_layers, *this, background_color, background_rect, normalized_border_radii_data());
};

if (auto mask_image = computed_values.mask_image()) {
mask_image->resolve_for_size(layout_node_with_style_and_box_metrics(), absolute_padding_box_rect().size());
}
}

void PaintableWithLines::resolve_paint_properties()
Expand Down
9 changes: 9 additions & 0 deletions Libraries/LibWeb/Painting/StackingContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,15 @@ void StackingContext::paint(PaintContext& context) const
}
context.display_list_recorder().push_stacking_context(push_stacking_context_params);

if (auto mask_image = computed_values.mask_image()) {
auto mask_display_list = DisplayList::create();
DisplayListRecorder display_list_recorder(*mask_display_list);
auto mask_painting_context = context.clone(display_list_recorder);
auto mask_rect_in_device_pixels = context.enclosing_device_rect(paintable_box().absolute_padding_box_rect());
mask_image->paint(mask_painting_context, { {}, mask_rect_in_device_pixels.size() }, CSS::ImageRendering::Auto);
context.display_list_recorder().add_mask(mask_display_list, mask_rect_in_device_pixels.to_type<int>());
}

if (auto masking_area = paintable_box().get_masking_area(); masking_area.has_value()) {
if (masking_area->is_empty())
return;
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CSS Masking: mask-image: mask layer image</title>
<link rel="author" title="Astley Chen" href="mailto:[email protected]">
<link rel="author" title="Mozilla" href="https://www.mozilla.org">
<style type="text/css">
div {
background-color: purple;
width: 100px;
height: 50px;
}
</style>
</head>
<body>
<div></div>
</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CSS Masking: mask-image: mask layer image</title>
<link rel="author" title="Astley Chen" href="mailto:[email protected]">
<link rel="author" title="Mozilla" href="https://www.mozilla.org">
<link rel="help" href="https://www.w3.org/TR/css-masking-1/#the-mask-image">
<link rel="match" href="../../../../../expected/wpt-import/css/css-masking/mask-image/mask-image-1-ref.html">
<meta name="assert" content="Test checks whether image as mask layer works correctly or not.">
<style type="text/css">
div {
background-color: purple;
width: 100px;
height: 100px;
}

div.mask-by-png {
mask-image: url(../../../../../data/transparent-100x50-blue-100x50.png);
}
</style>
</head>
<body>
<div class="mask-by-png"></div>
<!-- Hack to make the test runner wait for the image to load -->
<img src="../../../../../data/transparent-100x50-blue-100x50.png" style="opacity: 0"/>
</body>
</html>
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
All supported properties and their default values exposed from CSSStyleDeclaration from getComputedStyle:
'cssText': ''
'length': '201'
'length': '202'
'parentRule': 'null'
'cssFloat': 'none'
'WebkitAlignContent': 'normal'
Expand Down Expand Up @@ -99,6 +99,9 @@ All supported properties and their default values exposed from CSSStyleDeclarati
'WebkitMask': 'none'
'webkitMask': 'none'
'-webkit-mask': 'none'
'WebkitMaskImage': 'none'
'webkitMaskImage': 'none'
'-webkit-mask-image': 'none'
'WebkitOrder': '0'
'webkitOrder': '0'
'-webkit-order': '0'
Expand Down Expand Up @@ -403,6 +406,8 @@ All supported properties and their default values exposed from CSSStyleDeclarati
'marginTop': '8px'
'margin-top': '8px'
'mask': 'none'
'maskImage': 'none'
'mask-image': 'none'
'maskType': 'luminance'
'mask-type': 'luminance'
'mathDepth': '0'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,62 +145,63 @@ All properties associated with getComputedStyle(document.body):
"142": "margin-right",
"143": "margin-top",
"144": "mask",
"145": "mask-type",
"146": "max-height",
"147": "max-inline-size",
"148": "max-width",
"149": "min-height",
"150": "min-inline-size",
"151": "min-width",
"152": "object-fit",
"153": "object-position",
"154": "opacity",
"155": "order",
"156": "outline-color",
"157": "outline-offset",
"158": "outline-style",
"159": "outline-width",
"160": "overflow-x",
"161": "overflow-y",
"162": "padding-block-end",
"163": "padding-block-start",
"164": "padding-bottom",
"165": "padding-inline-end",
"166": "padding-inline-start",
"167": "padding-left",
"168": "padding-right",
"169": "padding-top",
"170": "position",
"171": "r",
"172": "right",
"173": "rotate",
"174": "row-gap",
"175": "rx",
"176": "ry",
"177": "scrollbar-gutter",
"178": "scrollbar-width",
"179": "stop-color",
"180": "stop-opacity",
"181": "table-layout",
"182": "text-decoration-color",
"183": "text-decoration-style",
"184": "text-decoration-thickness",
"185": "text-overflow",
"186": "top",
"187": "transform",
"188": "transform-box",
"189": "transform-origin",
"190": "transition-delay",
"191": "transition-duration",
"192": "transition-property",
"193": "transition-timing-function",
"194": "unicode-bidi",
"195": "user-select",
"196": "vertical-align",
"197": "width",
"198": "x",
"199": "y",
"200": "z-index"
"145": "mask-image",
"146": "mask-type",
"147": "max-height",
"148": "max-inline-size",
"149": "max-width",
"150": "min-height",
"151": "min-inline-size",
"152": "min-width",
"153": "object-fit",
"154": "object-position",
"155": "opacity",
"156": "order",
"157": "outline-color",
"158": "outline-offset",
"159": "outline-style",
"160": "outline-width",
"161": "overflow-x",
"162": "overflow-y",
"163": "padding-block-end",
"164": "padding-block-start",
"165": "padding-bottom",
"166": "padding-inline-end",
"167": "padding-inline-start",
"168": "padding-left",
"169": "padding-right",
"170": "padding-top",
"171": "position",
"172": "r",
"173": "right",
"174": "rotate",
"175": "row-gap",
"176": "rx",
"177": "ry",
"178": "scrollbar-gutter",
"179": "scrollbar-width",
"180": "stop-color",
"181": "stop-opacity",
"182": "table-layout",
"183": "text-decoration-color",
"184": "text-decoration-style",
"185": "text-decoration-thickness",
"186": "text-overflow",
"187": "top",
"188": "transform",
"189": "transform-box",
"190": "transform-origin",
"191": "transition-delay",
"192": "transition-duration",
"193": "transition-property",
"194": "transition-timing-function",
"195": "unicode-bidi",
"196": "user-select",
"197": "vertical-align",
"198": "width",
"199": "x",
"200": "y",
"201": "z-index"
}
All properties associated with document.body.style by default:
{}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ margin-left: 8px
margin-right: 8px
margin-top: 8px
mask: none
mask-image: none
mask-type: luminance
max-height: none
max-inline-size: none
Expand Down

0 comments on commit 96a3576

Please sign in to comment.