mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 08:47:34 +00:00
LibWeb: Add PositionValue class to represent CSS <position>
s
This class represents a <position> and handles resolving it to a Gfx::FloatPoint relative to some rectangle. It can handle all forms of <position>: - Two presets: left center - A preset + a length percentage: 10% bottom - Or relative to some edges: right 20% bottom 30px
This commit is contained in:
parent
067759c0e9
commit
e568c93404
2 changed files with 141 additions and 0 deletions
|
@ -1853,6 +1853,108 @@ void LinearGradientStyleValue::paint(PaintContext& context, Gfx::IntRect const&
|
||||||
Painting::paint_linear_gradient(context, dest_rect, m_resolved->data);
|
Painting::paint_linear_gradient(context, dest_rect, m_resolved->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Gfx::FloatPoint PositionValue::resolved(Layout::Node const& node, Gfx::FloatRect const& rect) const
|
||||||
|
{
|
||||||
|
// Note: A preset + a none default x/y_relative_to is impossible in the syntax (and makes little sense)
|
||||||
|
float x = horizontal_position.visit(
|
||||||
|
[&](HorizontalPreset preset) {
|
||||||
|
return rect.width() * [&] {
|
||||||
|
switch (preset) {
|
||||||
|
case HorizontalPreset::Left:
|
||||||
|
return 0.0f;
|
||||||
|
case HorizontalPreset::Center:
|
||||||
|
return 0.5f;
|
||||||
|
case HorizontalPreset::Right:
|
||||||
|
return 1.0f;
|
||||||
|
default:
|
||||||
|
VERIFY_NOT_REACHED();
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
},
|
||||||
|
[&](LengthPercentage length_percentage) {
|
||||||
|
return length_percentage.resolved(node, Length::make_px(rect.width())).to_px(node);
|
||||||
|
});
|
||||||
|
float y = vertical_position.visit(
|
||||||
|
[&](VerticalPreset preset) {
|
||||||
|
return rect.height() * [&] {
|
||||||
|
switch (preset) {
|
||||||
|
case VerticalPreset::Top:
|
||||||
|
return 0.0f;
|
||||||
|
case VerticalPreset::Center:
|
||||||
|
return 0.5f;
|
||||||
|
case VerticalPreset::Bottom:
|
||||||
|
return 1.0f;
|
||||||
|
default:
|
||||||
|
VERIFY_NOT_REACHED();
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
},
|
||||||
|
[&](LengthPercentage length_percentage) {
|
||||||
|
return length_percentage.resolved(node, Length::make_px(rect.height())).to_px(node);
|
||||||
|
});
|
||||||
|
if (x_relative_to == HorizontalEdge::Right)
|
||||||
|
x = rect.width() - x;
|
||||||
|
if (y_relative_to == VerticalEdge::Bottom)
|
||||||
|
y = rect.height() - y;
|
||||||
|
return Gfx::FloatPoint { rect.x() + x, rect.y() + y };
|
||||||
|
}
|
||||||
|
|
||||||
|
void PositionValue::serialize(StringBuilder& builder) const
|
||||||
|
{
|
||||||
|
// Note: This means our serialization with simplify any with explicit edges that are just `top left`.
|
||||||
|
bool has_relative_edges = x_relative_to == HorizontalEdge::Right || y_relative_to == VerticalEdge::Bottom;
|
||||||
|
if (has_relative_edges)
|
||||||
|
builder.append(x_relative_to == HorizontalEdge::Left ? "left "sv : "right "sv);
|
||||||
|
horizontal_position.visit(
|
||||||
|
[&](HorizontalPreset preset) {
|
||||||
|
builder.append([&] {
|
||||||
|
switch (preset) {
|
||||||
|
case HorizontalPreset::Left:
|
||||||
|
return "left"sv;
|
||||||
|
case HorizontalPreset::Center:
|
||||||
|
return "center"sv;
|
||||||
|
case HorizontalPreset::Right:
|
||||||
|
return "right"sv;
|
||||||
|
default:
|
||||||
|
VERIFY_NOT_REACHED();
|
||||||
|
}
|
||||||
|
}());
|
||||||
|
},
|
||||||
|
[&](LengthPercentage length_percentage) {
|
||||||
|
builder.append(length_percentage.to_string());
|
||||||
|
});
|
||||||
|
builder.append(' ');
|
||||||
|
if (has_relative_edges)
|
||||||
|
builder.append(y_relative_to == VerticalEdge::Top ? "top "sv : "bottom "sv);
|
||||||
|
vertical_position.visit(
|
||||||
|
[&](VerticalPreset preset) {
|
||||||
|
builder.append([&] {
|
||||||
|
switch (preset) {
|
||||||
|
case VerticalPreset::Top:
|
||||||
|
return "top"sv;
|
||||||
|
case VerticalPreset::Center:
|
||||||
|
return "center"sv;
|
||||||
|
case VerticalPreset::Bottom:
|
||||||
|
return "bottom"sv;
|
||||||
|
default:
|
||||||
|
VERIFY_NOT_REACHED();
|
||||||
|
}
|
||||||
|
}());
|
||||||
|
},
|
||||||
|
[&](LengthPercentage length_percentage) {
|
||||||
|
builder.append(length_percentage.to_string());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PositionValue::operator==(PositionValue const& other) const
|
||||||
|
{
|
||||||
|
return (
|
||||||
|
x_relative_to == other.x_relative_to
|
||||||
|
&& y_relative_to == other.y_relative_to
|
||||||
|
&& variant_equals(horizontal_position, other.horizontal_position)
|
||||||
|
&& variant_equals(vertical_position, other.vertical_position));
|
||||||
|
}
|
||||||
|
|
||||||
String ConicGradientStyleValue::to_string() const
|
String ConicGradientStyleValue::to_string() const
|
||||||
{
|
{
|
||||||
StringBuilder builder;
|
StringBuilder builder;
|
||||||
|
|
|
@ -96,6 +96,45 @@ struct ColorStopListElement {
|
||||||
using LinearColorStopListElement = ColorStopListElement<LengthPercentage>;
|
using LinearColorStopListElement = ColorStopListElement<LengthPercentage>;
|
||||||
using AngularColorStopListElement = ColorStopListElement<AnglePercentage>;
|
using AngularColorStopListElement = ColorStopListElement<AnglePercentage>;
|
||||||
|
|
||||||
|
// FIXME: Named PositionValue to avoid conflicts with enums, but this represents a <position>
|
||||||
|
struct PositionValue {
|
||||||
|
enum class HorizontalPreset {
|
||||||
|
Left,
|
||||||
|
Center,
|
||||||
|
Right
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class VerticalPreset {
|
||||||
|
Top,
|
||||||
|
Center,
|
||||||
|
Bottom
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class HorizontalEdge {
|
||||||
|
Left,
|
||||||
|
Right
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class VerticalEdge {
|
||||||
|
Top,
|
||||||
|
Bottom
|
||||||
|
};
|
||||||
|
|
||||||
|
inline static PositionValue center()
|
||||||
|
{
|
||||||
|
return PositionValue { HorizontalPreset::Center, VerticalPreset::Center };
|
||||||
|
}
|
||||||
|
|
||||||
|
Variant<HorizontalPreset, LengthPercentage> horizontal_position { HorizontalPreset::Left };
|
||||||
|
Variant<VerticalPreset, LengthPercentage> vertical_position { VerticalPreset::Top };
|
||||||
|
HorizontalEdge x_relative_to { HorizontalEdge::Left };
|
||||||
|
VerticalEdge y_relative_to { VerticalEdge::Top };
|
||||||
|
|
||||||
|
Gfx::FloatPoint resolved(Layout::Node const&, Gfx::FloatRect const&) const;
|
||||||
|
void serialize(StringBuilder&) const;
|
||||||
|
bool operator==(PositionValue const&) const;
|
||||||
|
};
|
||||||
|
|
||||||
struct EdgeRect {
|
struct EdgeRect {
|
||||||
Length top_edge;
|
Length top_edge;
|
||||||
Length right_edge;
|
Length right_edge;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue