/* * Copyright (c) 2022-2023, MacDue * * SPDX-License-Identifier: BSD-2-Clause */ #include "Position.h" #include #include 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 { return rect.width() * [&] { switch (preset) { case HorizontalPreset::Left: return 0.; case HorizontalPreset::Center: return 0.5; case HorizontalPreset::Right: return 1.; default: VERIFY_NOT_REACHED(); } }(); }, [&](LengthPercentage length_percentage) -> CSSPixels { return length_percentage.to_px(node, rect.width()); }); CSSPixels y = vertical_position.visit( [&](VerticalPreset preset) -> CSSPixels { return rect.height() * [&] { switch (preset) { case VerticalPreset::Top: return 0.; case VerticalPreset::Center: return 0.5; case VerticalPreset::Bottom: return 1.; 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 }; } ErrorOr 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) TRY(builder.try_append(x_relative_to == HorizontalEdge::Left ? "left "sv : "right "sv)); TRY(horizontal_position.visit( [&](HorizontalPreset preset) -> ErrorOr { return builder.try_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) -> ErrorOr { return builder.try_appendff(TRY(length_percentage.to_string())); })); TRY(builder.try_append(' ')); if (has_relative_edges) TRY(builder.try_append(y_relative_to == VerticalEdge::Top ? "top "sv : "bottom "sv)); TRY(vertical_position.visit( [&](VerticalPreset preset) -> ErrorOr { return builder.try_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) -> ErrorOr { return builder.try_append(TRY(length_percentage.to_string())); })); return {}; } }