mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-09-29 08:11:13 +00:00
LibWeb: Implement the CSS outline-offset
property
This allows you to push the outline a certain distance away from the border (or inside it, if the offset is negative).
This commit is contained in:
parent
fe7e797483
commit
73fa58da34
Notes:
sideshowbarker
2024-07-17 14:36:19 +09:00
Author: https://github.com/AtkinsSJ Commit: https://github.com/SerenityOS/serenity/commit/73fa58da34 Pull-request: https://github.com/SerenityOS/serenity/pull/20331
|
@ -42,9 +42,14 @@
|
|||
}
|
||||
.outline3 {
|
||||
outline: 2px solid green;
|
||||
outline-offset: 5px;
|
||||
border-radius: 10px;
|
||||
border: 2px solid black;
|
||||
}
|
||||
.outline4 {
|
||||
outline: 1px solid red;
|
||||
outline-offset: -20px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
@ -57,7 +62,7 @@
|
|||
</div>
|
||||
<div style="background-color:red;width:3px">This text should only have a strip of red on the left</div>
|
||||
<div class="box">
|
||||
<span class="outline">This text has an outline</span> and <span class="outline2">this text has an outline with a border radius,</span> and <span class="outline3">this also has a border.</span>
|
||||
<span class="outline">This text has an outline</span> and <span class="outline2">this text has an outline with a border radius,</span> and <span class="outline3">this also has a border.</span> <span class="outline4">This outline is a strikethrough.</span>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
p {
|
||||
padding: 5px;
|
||||
border: 2px solid black;
|
||||
margin: 1em;
|
||||
}
|
||||
.outline-default {
|
||||
outline: auto;
|
||||
|
@ -21,6 +22,14 @@
|
|||
color: saddlebrown;
|
||||
outline: 5px dotted currentcolor;
|
||||
}
|
||||
.outline-offset {
|
||||
outline: 5px solid blue;
|
||||
outline-offset: 0.5em;
|
||||
}
|
||||
.outline-inset {
|
||||
outline: 1px solid red;
|
||||
outline-offset: -10em;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
@ -29,5 +38,7 @@
|
|||
<p class="outline-1">I have an outline!</p>
|
||||
<p class="outline-2">I have an outline and a radius!</p>
|
||||
<p class="outline-currentcolor">My outline is dotted and brown!</p>
|
||||
<p class="outline-offset">My outline is blue and away from my border!</p>
|
||||
<p class="outline-inset">My outline is a very thin red line in the middle of this box!</p>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -108,6 +108,7 @@ public:
|
|||
static CSS::Time transition_delay() { return CSS::Time::make_seconds(0); }
|
||||
static CSS::ObjectFit object_fit() { return CSS::ObjectFit::Fill; }
|
||||
static Color outline_color() { return Color::Black; }
|
||||
static CSS::Length outline_offset() { return CSS::Length::make_px(0); }
|
||||
static CSS::OutlineStyle outline_style() { return CSS::OutlineStyle::None; }
|
||||
static CSS::Length outline_width() { return CSS::Length::make_px(3); }
|
||||
};
|
||||
|
@ -328,6 +329,7 @@ public:
|
|||
CSS::Time transition_delay() const { return m_noninherited.transition_delay; }
|
||||
|
||||
Color outline_color() const { return m_noninherited.outline_color; }
|
||||
CSS::Length outline_offset() const { return m_noninherited.outline_offset; }
|
||||
CSS::OutlineStyle outline_style() const { return m_noninherited.outline_style; }
|
||||
CSS::Length outline_width() const { return m_noninherited.outline_width; }
|
||||
|
||||
|
@ -442,6 +444,7 @@ protected:
|
|||
float stop_opacity { InitialValues::stop_opacity() };
|
||||
CSS::Time transition_delay { InitialValues::transition_delay() };
|
||||
Color outline_color { InitialValues::outline_color() };
|
||||
CSS::Length outline_offset { InitialValues::outline_offset() };
|
||||
CSS::OutlineStyle outline_style { InitialValues::outline_style() };
|
||||
CSS::Length outline_width { InitialValues::outline_width() };
|
||||
} m_noninherited;
|
||||
|
@ -554,6 +557,7 @@ public:
|
|||
void set_stop_opacity(float value) { m_noninherited.stop_opacity = value; }
|
||||
void set_text_anchor(CSS::TextAnchor value) { m_inherited.text_anchor = value; }
|
||||
void set_outline_color(Color value) { m_noninherited.outline_color = value; }
|
||||
void set_outline_offset(CSS::Length value) { m_noninherited.outline_offset = value; }
|
||||
void set_outline_style(CSS::OutlineStyle value) { m_noninherited.outline_style = value; }
|
||||
void set_outline_width(CSS::Length value) { m_noninherited.outline_width = value; }
|
||||
};
|
||||
|
|
|
@ -1603,6 +1603,14 @@
|
|||
"color"
|
||||
]
|
||||
},
|
||||
"outline-offset": {
|
||||
"affects-layout": false,
|
||||
"inherited": false,
|
||||
"initial": "0",
|
||||
"valid-types": [
|
||||
"length [-∞,∞]"
|
||||
]
|
||||
},
|
||||
"outline-style": {
|
||||
"affects-layout": false,
|
||||
"inherited": false,
|
||||
|
|
|
@ -738,6 +738,8 @@ ErrorOr<RefPtr<StyleValue const>> ResolvedCSSStyleDeclaration::style_value_for_p
|
|||
}
|
||||
case PropertyID::OutlineColor:
|
||||
return ColorStyleValue::create(layout_node.computed_values().outline_color());
|
||||
case PropertyID::OutlineOffset:
|
||||
return LengthStyleValue::create(layout_node.computed_values().outline_offset());
|
||||
case PropertyID::OutlineStyle:
|
||||
return IdentifierStyleValue::create(to_value_id(layout_node.computed_values().outline_style()));
|
||||
case PropertyID::OutlineWidth:
|
||||
|
|
|
@ -709,6 +709,8 @@ void NodeWithStyle::apply_style(const CSS::StyleProperties& computed_style)
|
|||
|
||||
if (auto outline_color = computed_style.property(CSS::PropertyID::OutlineColor); outline_color->has_color())
|
||||
computed_values.set_outline_color(outline_color->to_color(*this));
|
||||
if (auto outline_offset = computed_style.property(CSS::PropertyID::OutlineOffset); outline_offset->is_length())
|
||||
computed_values.set_outline_offset(outline_offset->as_length().length());
|
||||
if (auto outline_style = computed_style.outline_style(); outline_style.has_value())
|
||||
computed_values.set_outline_style(outline_style.value());
|
||||
if (auto outline_width = computed_style.property(CSS::PropertyID::OutlineWidth); outline_width->is_length())
|
||||
|
|
|
@ -86,7 +86,7 @@ void InlinePaintable::paint(PaintContext& context, PaintPhase phase) const
|
|||
});
|
||||
}
|
||||
|
||||
auto paint_border_or_outline = [&](Optional<BordersData> outline_data = {}) {
|
||||
auto paint_border_or_outline = [&](Optional<BordersData> outline_data = {}, CSSPixels outline_offset = 0) {
|
||||
auto top_left_border_radius = computed_values().border_top_left_radius();
|
||||
auto top_right_border_radius = computed_values().border_top_right_radius();
|
||||
auto bottom_right_border_radius = computed_values().border_bottom_right_radius();
|
||||
|
@ -119,8 +119,21 @@ void InlinePaintable::paint(PaintContext& context, PaintPhase phase) const
|
|||
auto border_radii_data = normalized_border_radii_data(layout_node(), borders_rect, top_left_border_radius, top_right_border_radius, bottom_right_border_radius, bottom_left_border_radius);
|
||||
|
||||
if (outline_data.has_value()) {
|
||||
border_radii_data.inflate(outline_data->top.width, outline_data->right.width, outline_data->bottom.width, outline_data->left.width);
|
||||
borders_rect.inflate(outline_data->top.width, outline_data->right.width, outline_data->bottom.width, outline_data->left.width);
|
||||
auto outline_offset_x = outline_offset;
|
||||
auto outline_offset_y = outline_offset;
|
||||
// "Both the height and the width of the outside of the shape drawn by the outline should not
|
||||
// become smaller than twice the computed value of the outline-width property to make sure
|
||||
// that an outline can be rendered even with large negative values."
|
||||
// https://www.w3.org/TR/css-ui-4/#outline-offset
|
||||
// So, if the horizontal outline offset is > half the borders_rect's width then we set it to that.
|
||||
// (And the same for y)
|
||||
if ((borders_rect.width() / 2) + outline_offset_x < 0)
|
||||
outline_offset_x = -borders_rect.width() / 2;
|
||||
if ((borders_rect.height() / 2) + outline_offset_y < 0)
|
||||
outline_offset_y = -borders_rect.height() / 2;
|
||||
|
||||
border_radii_data.inflate(outline_data->top.width + outline_offset_y, outline_data->right.width + outline_offset_x, outline_data->bottom.width + outline_offset_y, outline_data->left.width + outline_offset_x);
|
||||
borders_rect.inflate(outline_data->top.width + outline_offset_y, outline_data->right.width + outline_offset_x, outline_data->bottom.width + outline_offset_y, outline_data->left.width + outline_offset_x);
|
||||
paint_all_borders(context, borders_rect, border_radii_data, *outline_data);
|
||||
} else {
|
||||
paint_all_borders(context, borders_rect, border_radii_data, borders_data);
|
||||
|
@ -138,7 +151,7 @@ void InlinePaintable::paint(PaintContext& context, PaintPhase phase) const
|
|||
auto outline_width = computed_values().outline_width().to_px(layout_node());
|
||||
auto maybe_outline_data = borders_data_for_outline(layout_node(), computed_values().outline_color(), computed_values().outline_style(), outline_width);
|
||||
if (maybe_outline_data.has_value()) {
|
||||
paint_border_or_outline(maybe_outline_data.value());
|
||||
paint_border_or_outline(maybe_outline_data.value(), computed_values().outline_offset().to_px(layout_node()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -174,9 +174,27 @@ void PaintableBox::paint(PaintContext& context, PaintPhase phase) const
|
|||
auto outline_width = computed_values().outline_width().to_px(layout_node());
|
||||
auto borders_data = borders_data_for_outline(layout_node(), computed_values().outline_color(), computed_values().outline_style(), outline_width);
|
||||
if (borders_data.has_value()) {
|
||||
auto outline_offset = computed_values().outline_offset().to_px(layout_node());
|
||||
auto border_radius_data = normalized_border_radii_data(ShrinkRadiiForBorders::No);
|
||||
border_radius_data.inflate(outline_width, outline_width, outline_width, outline_width);
|
||||
paint_all_borders(context, absolute_border_box_rect().inflated(outline_width, outline_width, outline_width, outline_width), border_radius_data, borders_data.value());
|
||||
auto borders_rect = absolute_border_box_rect();
|
||||
|
||||
auto outline_offset_x = outline_offset;
|
||||
auto outline_offset_y = outline_offset;
|
||||
// "Both the height and the width of the outside of the shape drawn by the outline should not
|
||||
// become smaller than twice the computed value of the outline-width property to make sure
|
||||
// that an outline can be rendered even with large negative values."
|
||||
// https://www.w3.org/TR/css-ui-4/#outline-offset
|
||||
// So, if the horizontal outline offset is > half the borders_rect's width then we set it to that.
|
||||
// (And the same for y)
|
||||
if ((borders_rect.width() / 2) + outline_offset_x < 0)
|
||||
outline_offset_x = -borders_rect.width() / 2;
|
||||
if ((borders_rect.height() / 2) + outline_offset_y < 0)
|
||||
outline_offset_y = -borders_rect.height() / 2;
|
||||
|
||||
border_radius_data.inflate(outline_width + outline_offset_y, outline_width + outline_offset_x, outline_width + outline_offset_y, outline_width + outline_offset_x);
|
||||
borders_rect.inflate(outline_width + outline_offset_y, outline_width + outline_offset_x, outline_width + outline_offset_y, outline_width + outline_offset_x);
|
||||
|
||||
paint_all_borders(context, borders_rect, border_radius_data, borders_data.value());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue