ladybird/Userland/Libraries/LibWeb/CSS/Position.cpp
Zaggy1024 f57c42fad7 LibWeb: Avoid conversion from floating point in CSS position resolution
We can just use division here, since fixed-point division by 2 will
compile down to a shift by 1.
2023-09-09 13:03:11 +02:00

102 lines
3.5 KiB
C++

/*
* Copyright (c) 2022-2023, MacDue <macdue@dueutil.tech>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include "Position.h"
#include <LibGfx/Point.h>
#include <LibGfx/Rect.h>
namespace Web::CSS {
CSSPixelPoint PositionValue::resolved(Layout::Node const& node, CSSPixelRect const& rect) const
{
// Note: A preset + a none default x/y_relative_to is impossible in the syntax (and makes little sense)
CSSPixels x = horizontal_position.visit(
[&](HorizontalPreset preset) -> CSSPixels {
switch (preset) {
case HorizontalPreset::Left:
return 0;
case HorizontalPreset::Center:
return rect.width() / 2;
case HorizontalPreset::Right:
return rect.width();
default:
VERIFY_NOT_REACHED();
}
},
[&](LengthPercentage length_percentage) -> CSSPixels {
return length_percentage.to_px(node, rect.width());
});
CSSPixels y = vertical_position.visit(
[&](VerticalPreset preset) -> CSSPixels {
switch (preset) {
case VerticalPreset::Top:
return 0;
case VerticalPreset::Center:
return rect.height() / 2;
case VerticalPreset::Bottom:
return rect.height();
default:
VERIFY_NOT_REACHED();
}
},
[&](LengthPercentage length_percentage) -> CSSPixels {
return length_percentage.to_px(node, rect.height());
});
if (x_relative_to == HorizontalEdge::Right)
x = rect.width() - x;
if (y_relative_to == VerticalEdge::Bottom)
y = rect.height() - y;
return CSSPixelPoint { 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());
});
}
}