mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-26 09:30:24 +00:00
LibWeb: Parse rect style value
Add ability to parse a rect when it is used as the value of a style property.
This commit is contained in:
parent
4d1ceaaa43
commit
b4dd477644
Notes:
sideshowbarker
2024-07-17 08:23:06 +09:00
Author: https://github.com/martinfalisse Commit: https://github.com/SerenityOS/serenity/commit/b4dd477644 Pull-request: https://github.com/SerenityOS/serenity/pull/14730 Reviewed-by: https://github.com/AtkinsSJ Reviewed-by: https://github.com/MacDue ✅ Reviewed-by: https://github.com/awesomekling
7 changed files with 117 additions and 0 deletions
|
@ -501,6 +501,11 @@ bool property_accepts_value(PropertyID property_id, StyleValue& style_value)
|
|||
output_numeric_value_check(property_generator, "has_number"sv, "to_number()"sv, Array { "Integer"sv, "Number"sv }, min_value, max_value);
|
||||
} else if (type_name == "percentage") {
|
||||
output_numeric_value_check(property_generator, "is_percentage"sv, "as_percentage().percentage().value()"sv, Array { "Percentage"sv }, min_value, max_value);
|
||||
} else if (type_name == "rect") {
|
||||
property_generator.append(R"~~~(
|
||||
if (style_value.has_rect())
|
||||
return true;
|
||||
)~~~");
|
||||
} else if (type_name == "resolution") {
|
||||
output_numeric_value_check(property_generator, "is_resolution"sv, "as_resolution().resolution().to_dots_per_pixel()"sv, Array<StringView, 0> {}, min_value, max_value);
|
||||
} else if (type_name == "string") {
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include <LibWeb/CSS/Parser/Parser.h>
|
||||
#include <LibWeb/CSS/Parser/Rule.h>
|
||||
#include <LibWeb/CSS/Selector.h>
|
||||
#include <LibWeb/CSS/StyleValue.h>
|
||||
#include <LibWeb/DOM/Document.h>
|
||||
#include <LibWeb/Dump.h>
|
||||
|
||||
|
@ -3350,6 +3351,46 @@ Optional<Color> Parser::parse_rgb_or_hsl_color(StringView function_name, Vector<
|
|||
return {};
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/CSS2/visufx.html#value-def-shape
|
||||
RefPtr<StyleValue> Parser::parse_rect_value(ComponentValue const& component_value)
|
||||
{
|
||||
if (!component_value.is_function())
|
||||
return {};
|
||||
auto& function = component_value.function();
|
||||
if (!function.name().equals_ignoring_case("rect"sv))
|
||||
return {};
|
||||
|
||||
Vector<Length, 4> params;
|
||||
auto tokens = TokenStream { function.values() };
|
||||
|
||||
// In CSS 2.1, the only valid <shape> value is: rect(<top>, <right>, <bottom>, <left>) where
|
||||
// <top> and <bottom> specify offsets from the top border edge of the box, and <right>, and
|
||||
// <left> specify offsets from the left border edge of the box.
|
||||
for (size_t idx = 0; idx < 4; idx++) {
|
||||
tokens.skip_whitespace();
|
||||
|
||||
// <top>, <right>, <bottom>, and <left> may either have a <length> value or 'auto'.
|
||||
// Negative lengths are permitted.
|
||||
auto current_token = tokens.next_token().token();
|
||||
if (current_token.to_string() == "auto") {
|
||||
params.append(Length::make_auto());
|
||||
} else {
|
||||
auto maybe_length = parse_length(current_token);
|
||||
if (!maybe_length.has_value())
|
||||
return {};
|
||||
params.append(maybe_length.value());
|
||||
}
|
||||
tokens.skip_whitespace();
|
||||
|
||||
// Authors should separate offset values with commas. User agents must support separation
|
||||
// with commas, but may also support separation without commas (but not a combination),
|
||||
// because a previous revision of this specification was ambiguous in this respect.
|
||||
if (tokens.peek_token().is(Token::Type::Comma))
|
||||
tokens.next_token();
|
||||
}
|
||||
return RectStyleValue::create(EdgeRect { params[0], params[1], params[2], params[3] });
|
||||
}
|
||||
|
||||
Optional<Color> Parser::parse_color(ComponentValue const& component_value)
|
||||
{
|
||||
// https://www.w3.org/TR/css-color-4/
|
||||
|
@ -5416,6 +5457,9 @@ RefPtr<StyleValue> Parser::parse_css_value(ComponentValue const& component_value
|
|||
if (auto image = parse_image_value(component_value))
|
||||
return image;
|
||||
|
||||
if (auto rect = parse_rect_value(component_value))
|
||||
return rect;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
|
|
|
@ -328,6 +328,7 @@ private:
|
|||
RefPtr<StyleValue> parse_numeric_value(ComponentValue const&);
|
||||
RefPtr<StyleValue> parse_identifier_value(ComponentValue const&);
|
||||
RefPtr<StyleValue> parse_color_value(ComponentValue const&);
|
||||
RefPtr<StyleValue> parse_rect_value(ComponentValue const&);
|
||||
RefPtr<StyleValue> parse_string_value(ComponentValue const&);
|
||||
RefPtr<StyleValue> parse_image_value(ComponentValue const&);
|
||||
template<typename ParseFunction>
|
||||
|
|
|
@ -475,6 +475,9 @@
|
|||
"valid-identifiers": [
|
||||
"auto"
|
||||
],
|
||||
"valid-types": [
|
||||
"rect"
|
||||
],
|
||||
"quirks": [
|
||||
"unitless-length"
|
||||
]
|
||||
|
|
|
@ -179,6 +179,12 @@ PositionStyleValue const& StyleValue::as_position() const
|
|||
return static_cast<PositionStyleValue const&>(*this);
|
||||
}
|
||||
|
||||
RectStyleValue const& StyleValue::as_rect() const
|
||||
{
|
||||
VERIFY(is_rect());
|
||||
return static_cast<RectStyleValue const&>(*this);
|
||||
}
|
||||
|
||||
ResolutionStyleValue const& StyleValue::as_resolution() const
|
||||
{
|
||||
VERIFY(is_resolution());
|
||||
|
@ -1485,6 +1491,11 @@ static bool operator==(ColorStopListElement a, ColorStopListElement b)
|
|||
return a.transition_hint == b.transition_hint && a.color_stop == b.color_stop;
|
||||
}
|
||||
|
||||
static bool operator==(EdgeRect a, EdgeRect b)
|
||||
{
|
||||
return a.top_edge == b.top_edge && a.right_edge == b.right_edge && a.bottom_edge == b.bottom_edge && a.left_edge == b.left_edge;
|
||||
}
|
||||
|
||||
bool LinearGradientStyleValue::equals(StyleValue const& other_) const
|
||||
{
|
||||
if (type() != other_.type())
|
||||
|
@ -1650,6 +1661,19 @@ bool PositionStyleValue::equals(StyleValue const& other) const
|
|||
&& m_offset_y == typed_other.m_offset_y;
|
||||
}
|
||||
|
||||
String RectStyleValue::to_string() const
|
||||
{
|
||||
return String::formatted("top_edge: {}, right_edge: {}, bottom_edge: {}, left_edge: {}", m_rect.top_edge, m_rect.right_edge, m_rect.bottom_edge, m_rect.left_edge);
|
||||
}
|
||||
|
||||
bool RectStyleValue::equals(StyleValue const& other) const
|
||||
{
|
||||
if (type() != other.type())
|
||||
return false;
|
||||
auto const& typed_other = other.as_rect();
|
||||
return m_rect == typed_other.rect();
|
||||
}
|
||||
|
||||
bool ResolutionStyleValue::equals(StyleValue const& other) const
|
||||
{
|
||||
if (type() != other.type())
|
||||
|
@ -1810,6 +1834,11 @@ NonnullRefPtr<ColorStyleValue> ColorStyleValue::create(Color color)
|
|||
return adopt_ref(*new ColorStyleValue(color));
|
||||
}
|
||||
|
||||
NonnullRefPtr<RectStyleValue> RectStyleValue::create(EdgeRect rect)
|
||||
{
|
||||
return adopt_ref(*new RectStyleValue(rect));
|
||||
}
|
||||
|
||||
NonnullRefPtr<LengthStyleValue> LengthStyleValue::create(Length const& length)
|
||||
{
|
||||
if (length.is_auto()) {
|
||||
|
|
|
@ -84,6 +84,13 @@ struct ColorStopListElement {
|
|||
GradientColorStop color_stop;
|
||||
};
|
||||
|
||||
struct EdgeRect {
|
||||
Length top_edge;
|
||||
Length right_edge;
|
||||
Length bottom_edge;
|
||||
Length left_edge;
|
||||
};
|
||||
|
||||
// FIXME: Find a better place for this helper.
|
||||
inline Gfx::Painter::ScalingMode to_gfx_scaling_mode(CSS::ImageRendering css_value)
|
||||
{
|
||||
|
@ -131,6 +138,7 @@ public:
|
|||
Overflow,
|
||||
Percentage,
|
||||
Position,
|
||||
Rect,
|
||||
Resolution,
|
||||
Shadow,
|
||||
String,
|
||||
|
@ -169,6 +177,7 @@ public:
|
|||
bool is_overflow() const { return type() == Type::Overflow; }
|
||||
bool is_percentage() const { return type() == Type::Percentage; }
|
||||
bool is_position() const { return type() == Type::Position; }
|
||||
bool is_rect() const { return type() == Type::Rect; }
|
||||
bool is_resolution() const { return type() == Type::Resolution; }
|
||||
bool is_shadow() const { return type() == Type::Shadow; }
|
||||
bool is_string() const { return type() == Type::String; }
|
||||
|
@ -206,6 +215,7 @@ public:
|
|||
OverflowStyleValue const& as_overflow() const;
|
||||
PercentageStyleValue const& as_percentage() const;
|
||||
PositionStyleValue const& as_position() const;
|
||||
RectStyleValue const& as_rect() const;
|
||||
ResolutionStyleValue const& as_resolution() const;
|
||||
ShadowStyleValue const& as_shadow() const;
|
||||
StringStyleValue const& as_string() const;
|
||||
|
@ -241,6 +251,7 @@ public:
|
|||
OverflowStyleValue& as_overflow() { return const_cast<OverflowStyleValue&>(const_cast<StyleValue const&>(*this).as_overflow()); }
|
||||
PercentageStyleValue& as_percentage() { return const_cast<PercentageStyleValue&>(const_cast<StyleValue const&>(*this).as_percentage()); }
|
||||
PositionStyleValue& as_position() { return const_cast<PositionStyleValue&>(const_cast<StyleValue const&>(*this).as_position()); }
|
||||
RectStyleValue& as_rect() { return const_cast<RectStyleValue&>(const_cast<StyleValue const&>(*this).as_rect()); }
|
||||
ResolutionStyleValue& as_resolution() { return const_cast<ResolutionStyleValue&>(const_cast<StyleValue const&>(*this).as_resolution()); }
|
||||
ShadowStyleValue& as_shadow() { return const_cast<ShadowStyleValue&>(const_cast<StyleValue const&>(*this).as_shadow()); }
|
||||
StringStyleValue& as_string() { return const_cast<StringStyleValue&>(const_cast<StyleValue const&>(*this).as_string()); }
|
||||
|
@ -255,12 +266,14 @@ public:
|
|||
virtual bool has_color() const { return false; }
|
||||
virtual bool has_identifier() const { return false; }
|
||||
virtual bool has_length() const { return false; }
|
||||
virtual bool has_rect() const { return false; }
|
||||
virtual bool has_number() const { return false; }
|
||||
virtual bool has_integer() const { return false; }
|
||||
|
||||
virtual NonnullRefPtr<StyleValue> absolutized(Gfx::IntRect const& viewport_rect, Gfx::FontPixelMetrics const& font_metrics, float font_size, float root_font_size) const;
|
||||
|
||||
virtual Color to_color(Layout::NodeWithStyle const&) const { return {}; }
|
||||
virtual EdgeRect to_rect() const { VERIFY_NOT_REACHED(); }
|
||||
virtual CSS::ValueID to_identifier() const { return ValueID::Invalid; }
|
||||
virtual Length to_length() const { VERIFY_NOT_REACHED(); }
|
||||
virtual float to_number() const { return 0; }
|
||||
|
@ -1440,6 +1453,27 @@ private:
|
|||
NonnullRefPtrVector<StyleValue> m_values;
|
||||
};
|
||||
|
||||
class RectStyleValue : public StyleValue {
|
||||
public:
|
||||
static NonnullRefPtr<RectStyleValue> create(EdgeRect rect);
|
||||
virtual ~RectStyleValue() override = default;
|
||||
|
||||
EdgeRect rect() const { return m_rect; }
|
||||
virtual String to_string() const override;
|
||||
virtual bool has_rect() const override { return true; }
|
||||
virtual EdgeRect to_rect() const override { return m_rect; }
|
||||
virtual bool equals(StyleValue const& other) const override;
|
||||
|
||||
private:
|
||||
explicit RectStyleValue(EdgeRect rect)
|
||||
: StyleValue(Type::Rect)
|
||||
, m_rect(rect)
|
||||
{
|
||||
}
|
||||
|
||||
EdgeRect m_rect;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template<>
|
||||
|
|
|
@ -75,6 +75,7 @@ class Percentage;
|
|||
class PercentageStyleValue;
|
||||
class PositionStyleValue;
|
||||
class PropertyOwningCSSStyleDeclaration;
|
||||
class RectStyleValue;
|
||||
class Resolution;
|
||||
class ResolutionStyleValue;
|
||||
class Screen;
|
||||
|
|
Loading…
Reference in a new issue