mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-21 23:20:20 +00:00
LibWeb: Implement mask-image
CSS property support
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
This commit is contained in:
parent
7b7bb60393
commit
96a35767b6
Notes:
github-actions[bot]
2024-11-18 21:59:52 +00:00
Author: https://github.com/kalenikaliaksandr Commit: https://github.com/LadybirdBrowser/ladybird/commit/96a35767b61 Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/2418
11 changed files with 149 additions and 58 deletions
|
@ -486,6 +486,7 @@ public:
|
|||
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; }
|
||||
|
@ -681,6 +682,7 @@ protected:
|
|||
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() };
|
||||
|
@ -838,6 +840,7 @@ public:
|
|||
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; }
|
||||
|
||||
|
|
|
@ -95,6 +95,9 @@
|
|||
"-webkit-mask": {
|
||||
"legacy-alias-for": "mask"
|
||||
},
|
||||
"-webkit-mask-image": {
|
||||
"legacy-alias-for": "mask-image"
|
||||
},
|
||||
"-webkit-order": {
|
||||
"legacy-alias-for": "order"
|
||||
},
|
||||
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
|
|
BIN
Tests/LibWeb/Ref/data/transparent-100x50-blue-100x50.png
Normal file
BIN
Tests/LibWeb/Ref/data/transparent-100x50-blue-100x50.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 233 B |
|
@ -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:aschen@mozilla.com">
|
||||
<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>
|
|
@ -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:aschen@mozilla.com">
|
||||
<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>
|
|
@ -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'
|
||||
|
@ -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'
|
||||
|
@ -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'
|
||||
|
|
|
@ -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:
|
||||
{}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue