ladybird/Libraries/LibWeb/CSS/Display.h
Andreas Kling a4d949ff55 LibWeb: Inline trivial CSS::Display query methods
Move all the simple bool query methods (is_table_inside,
is_table_cell, is_none, is_block_outside, etc.) from Display.cpp into
Display.h as inline definitions. These are trivial one-liners called
in very hot painting and layout paths.

Keep only to_string() and from_short() out-of-line.
2026-02-21 15:53:22 +01:00

188 lines
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>
#include <LibWeb/Forward.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 : u8 {
No,
Yes,
};
enum class Type : u8 {
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; }
// https://drafts.csswg.org/css-display-3/#internal-table-element
bool is_internal_table() const
{
return is_internal()
&& (internal() == DisplayInternal::TableRowGroup
|| internal() == DisplayInternal::TableHeaderGroup
|| internal() == DisplayInternal::TableFooterGroup
|| internal() == DisplayInternal::TableRow
|| internal() == DisplayInternal::TableCell
|| internal() == DisplayInternal::TableColumnGroup
|| internal() == DisplayInternal::TableColumn);
}
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_);
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 {};
};
}