ladybird/Libraries/LibWeb/CSS/Display.h

217 lines
7.6 KiB
C++

/*
* Copyright (c) 2021, Andreas Kling <andreas@ladybird.org>
* Copyright (c) 2023, Sam Atkins <atkinssj@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/Assertions.h>
#include <AK/String.h>
#include <LibWeb/CSS/Enums.h>
namespace Web::CSS {
class Display {
public:
Display() = default;
~Display() = default;
String to_string() const;
bool operator==(Display const& other) const
{
if (m_type != other.m_type)
return false;
switch (m_type) {
case Type::Box:
return m_value.box == other.m_value.box;
case Type::Internal:
return m_value.internal == other.m_value.internal;
case Type::OutsideAndInside:
return m_value.outside_inside.outside == other.m_value.outside_inside.outside
&& m_value.outside_inside.inside == other.m_value.outside_inside.inside
&& m_value.outside_inside.list_item == other.m_value.outside_inside.list_item;
}
VERIFY_NOT_REACHED();
}
enum class ListItem {
No,
Yes,
};
enum class Type {
OutsideAndInside,
Internal,
Box,
};
bool is_internal() const { return m_type == Type::Internal; }
DisplayInternal internal() const
{
VERIFY(is_internal());
return m_value.internal;
}
bool is_table_column() const { return is_internal() && internal() == DisplayInternal::TableColumn; }
bool is_table_row_group() const { return is_internal() && internal() == DisplayInternal::TableRowGroup; }
bool is_table_header_group() const { return is_internal() && internal() == DisplayInternal::TableHeaderGroup; }
bool is_table_footer_group() const { return is_internal() && internal() == DisplayInternal::TableFooterGroup; }
bool is_table_row() const { return is_internal() && internal() == DisplayInternal::TableRow; }
bool is_table_cell() const { return is_internal() && internal() == DisplayInternal::TableCell; }
bool is_table_column_group() const { return is_internal() && internal() == DisplayInternal::TableColumnGroup; }
bool is_table_caption() const { return is_internal() && internal() == DisplayInternal::TableCaption; }
bool is_none() const { return m_type == Type::Box && m_value.box == DisplayBox::None; }
bool is_contents() const { return m_type == Type::Box && m_value.box == DisplayBox::Contents; }
Type type() const { return m_type; }
bool is_outside_and_inside() const { return m_type == Type::OutsideAndInside; }
DisplayOutside outside() const
{
VERIFY(is_outside_and_inside());
return m_value.outside_inside.outside;
}
bool is_block_outside() const { return is_outside_and_inside() && outside() == DisplayOutside::Block; }
bool is_inline_outside() const { return is_outside_and_inside() && outside() == DisplayOutside::Inline; }
bool is_inline_block() const { return is_inline_outside() && is_flow_root_inside(); }
ListItem list_item() const
{
VERIFY(is_outside_and_inside());
return m_value.outside_inside.list_item;
}
bool is_list_item() const { return is_outside_and_inside() && list_item() == ListItem::Yes; }
DisplayInside inside() const
{
VERIFY(is_outside_and_inside());
return m_value.outside_inside.inside;
}
bool is_flow_inside() const { return is_outside_and_inside() && inside() == DisplayInside::Flow; }
bool is_flow_root_inside() const { return is_outside_and_inside() && inside() == DisplayInside::FlowRoot; }
bool is_table_inside() const { return is_outside_and_inside() && inside() == DisplayInside::Table; }
bool is_flex_inside() const { return is_outside_and_inside() && inside() == DisplayInside::Flex; }
bool is_grid_inside() const { return is_outside_and_inside() && inside() == DisplayInside::Grid; }
bool is_ruby_inside() const { return is_outside_and_inside() && inside() == DisplayInside::Ruby; }
bool is_math_inside() const { return is_outside_and_inside() && inside() == DisplayInside::Math; }
enum class Short {
None,
Contents,
Block,
Flow,
FlowRoot,
Inline,
InlineBlock,
RunIn,
ListItem,
InlineListItem,
Flex,
InlineFlex,
Grid,
InlineGrid,
Ruby,
Table,
InlineTable,
Math,
};
static Display from_short(Short short_)
{
switch (short_) {
case Short::None:
return Display { DisplayBox::None };
case Short::Contents:
return Display { DisplayBox::Contents };
case Short::Block:
return Display { DisplayOutside::Block, DisplayInside::Flow };
case Short::Inline:
return Display { DisplayOutside::Inline, DisplayInside::Flow };
case Short::Flow:
return Display { DisplayOutside::Block, DisplayInside::Flow };
case Short::FlowRoot:
return Display { DisplayOutside::Block, DisplayInside::FlowRoot };
case Short::InlineBlock:
return Display { DisplayOutside::Inline, DisplayInside::FlowRoot };
case Short::RunIn:
return Display { DisplayOutside::RunIn, DisplayInside::Flow };
case Short::ListItem:
return Display { DisplayOutside::Block, DisplayInside::Flow, ListItem::Yes };
case Short::InlineListItem:
return Display { DisplayOutside::Inline, DisplayInside::Flow, ListItem::Yes };
case Short::Flex:
return Display { DisplayOutside::Block, DisplayInside::Flex };
case Short::InlineFlex:
return Display { DisplayOutside::Inline, DisplayInside::Flex };
case Short::Grid:
return Display { DisplayOutside::Block, DisplayInside::Grid };
case Short::InlineGrid:
return Display { DisplayOutside::Inline, DisplayInside::Grid };
case Short::Ruby:
return Display { DisplayOutside::Inline, DisplayInside::Ruby };
case Short::Table:
return Display { DisplayOutside::Block, DisplayInside::Table };
case Short::InlineTable:
return Display { DisplayOutside::Inline, DisplayInside::Table };
case Short::Math:
// NOTE: The spec ( https://w3c.github.io/mathml-core/#new-display-math-value ) does not
// mention what the outside value for `display: math` should be.
// The UA stylesheet does `* { display: block math; }` so let's go with that.
return Display { DisplayOutside::Block, DisplayInside::Math };
}
VERIFY_NOT_REACHED();
}
Display(DisplayOutside outside, DisplayInside inside)
: m_type(Type::OutsideAndInside)
{
m_value.outside_inside = {
.outside = outside,
.inside = inside,
.list_item = ListItem::No,
};
}
Display(DisplayOutside outside, DisplayInside inside, ListItem list_item)
: m_type(Type::OutsideAndInside)
{
m_value.outside_inside = {
.outside = outside,
.inside = inside,
.list_item = list_item,
};
}
explicit Display(DisplayInternal internal)
: m_type(Type::Internal)
{
m_value.internal = internal;
}
explicit Display(DisplayBox box)
: m_type(Type::Box)
{
m_value.box = box;
}
private:
Type m_type {};
union {
struct {
DisplayOutside outside;
DisplayInside inside;
ListItem list_item;
} outside_inside;
DisplayInternal internal;
DisplayBox box;
} m_value {};
};
}