1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 11:48:10 +00:00

LibWeb: Implement and use BorderRadiusStyleValue

This parses the elliptical border-radius values, though currently we
only support circular ones. So, to_length() is overloaded to return the
horizontal-radius. This means the code in Layout/Node.cpp does not need
to change for now.
This commit is contained in:
Sam Atkins 2021-08-06 16:55:08 +01:00 committed by Andreas Kling
parent e3cbd366c7
commit 168865dbdc
5 changed files with 159 additions and 45 deletions

View file

@ -1926,6 +1926,109 @@ RefPtr<StyleValue> Parser::parse_border_value(ParsingContext const& context, Pro
return BorderStyleValue::create(border_width.release_nonnull(), border_style.release_nonnull(), border_color.release_nonnull());
}
RefPtr<StyleValue> Parser::parse_border_radius_value(ParsingContext const& context, Vector<StyleComponentValueRule> const& component_values)
{
if (component_values.size() == 2) {
auto horizontal = parse_length(context, component_values[0]);
auto vertical = parse_length(context, component_values[1]);
if (horizontal.has_value() && vertical.has_value())
return BorderRadiusStyleValue::create(horizontal.value(), vertical.value());
return nullptr;
}
if (component_values.size() == 1) {
auto radius = parse_length(context, component_values[0]);
if (radius.has_value())
return BorderRadiusStyleValue::create(radius.value(), radius.value());
return nullptr;
}
return nullptr;
}
RefPtr<StyleValue> Parser::parse_border_radius_shorthand_value(ParsingContext const& context, Vector<StyleComponentValueRule> const& component_values)
{
auto top_left = [&](Vector<Length>& radii) { return radii[0]; };
auto top_right = [&](Vector<Length>& radii) {
switch (radii.size()) {
case 4:
case 3:
case 2:
return radii[1];
case 1:
return radii[0];
default:
VERIFY_NOT_REACHED();
}
};
auto bottom_right = [&](Vector<Length>& radii) {
switch (radii.size()) {
case 4:
case 3:
return radii[2];
case 2:
case 1:
return radii[0];
default:
VERIFY_NOT_REACHED();
}
};
auto bottom_left = [&](Vector<Length>& radii) {
switch (radii.size()) {
case 4:
return radii[3];
case 3:
case 2:
return radii[1];
case 1:
return radii[0];
default:
VERIFY_NOT_REACHED();
}
};
Vector<Length> horizontal_radii;
Vector<Length> vertical_radii;
bool reading_vertical = false;
for (auto& value : component_values) {
if (value.is(Token::Type::Delim) && value.token().delim() == "/"sv) {
if (reading_vertical || horizontal_radii.is_empty())
return nullptr;
reading_vertical = true;
continue;
}
auto maybe_length = parse_length(context, value);
if (!maybe_length.has_value())
return nullptr;
if (reading_vertical) {
vertical_radii.append(maybe_length.value());
} else {
horizontal_radii.append(maybe_length.value());
}
}
if (horizontal_radii.size() > 4 || vertical_radii.size() > 4
|| horizontal_radii.is_empty()
|| (reading_vertical && vertical_radii.is_empty()))
return nullptr;
NonnullRefPtrVector<StyleValue> border_radii;
border_radii.append(BorderRadiusStyleValue::create(top_left(horizontal_radii),
vertical_radii.is_empty() ? top_left(horizontal_radii) : top_left(vertical_radii)));
border_radii.append(BorderRadiusStyleValue::create(top_right(horizontal_radii),
vertical_radii.is_empty() ? top_right(horizontal_radii) : top_right(vertical_radii)));
border_radii.append(BorderRadiusStyleValue::create(bottom_right(horizontal_radii),
vertical_radii.is_empty() ? bottom_right(horizontal_radii) : bottom_right(vertical_radii)));
border_radii.append(BorderRadiusStyleValue::create(bottom_left(horizontal_radii),
vertical_radii.is_empty() ? bottom_left(horizontal_radii) : bottom_left(vertical_radii)));
return StyleValueList::create(move(border_radii));
}
RefPtr<StyleValue> Parser::parse_box_shadow_value(ParsingContext const& context, Vector<StyleComponentValueRule> const& component_values)
{
// FIXME: Also support inset, spread-radius and multiple comma-seperated box-shadows
@ -2516,6 +2619,17 @@ RefPtr<StyleValue> Parser::parse_css_value(PropertyID property_id, TokenStream<S
if (auto parsed_value = parse_border_value(m_context, property_id, component_values))
return parsed_value;
break;
case PropertyID::BorderTopLeftRadius:
case PropertyID::BorderTopRightRadius:
case PropertyID::BorderBottomRightRadius:
case PropertyID::BorderBottomLeftRadius:
if (auto parsed_value = parse_border_radius_value(m_context, component_values))
return parsed_value;
break;
case PropertyID::BorderRadius:
if (auto parsed_value = parse_border_radius_shorthand_value(m_context, component_values))
return parsed_value;
break;
case PropertyID::BoxShadow:
if (auto parsed_box_shadow = parse_box_shadow_value(m_context, component_values))
return parsed_box_shadow;