Coverage Report

Created: 2025-12-18 07:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/serenity/Userland/Libraries/LibWeb/CSS/Display.h
Line
Count
Source
1
/*
2
 * Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
3
 * Copyright (c) 2023, Sam Atkins <atkinssj@serenityos.org>
4
 *
5
 * SPDX-License-Identifier: BSD-2-Clause
6
 */
7
8
#pragma once
9
10
#include <AK/Assertions.h>
11
#include <AK/String.h>
12
#include <LibWeb/CSS/Enums.h>
13
14
namespace Web::CSS {
15
16
class Display {
17
public:
18
0
    Display() = default;
19
    ~Display() = default;
20
21
    String to_string() const;
22
23
    bool operator==(Display const& other) const
24
0
    {
25
0
        if (m_type != other.m_type)
26
0
            return false;
27
0
        switch (m_type) {
28
0
        case Type::Box:
29
0
            return m_value.box == other.m_value.box;
30
0
        case Type::Internal:
31
0
            return m_value.internal == other.m_value.internal;
32
0
        case Type::OutsideAndInside:
33
0
            return m_value.outside_inside.outside == other.m_value.outside_inside.outside
34
0
                && m_value.outside_inside.inside == other.m_value.outside_inside.inside
35
0
                && m_value.outside_inside.list_item == other.m_value.outside_inside.list_item;
36
0
        }
37
0
        VERIFY_NOT_REACHED();
38
0
    }
39
40
    enum class ListItem {
41
        No,
42
        Yes,
43
    };
44
45
    enum class Type {
46
        OutsideAndInside,
47
        Internal,
48
        Box,
49
    };
50
51
0
    bool is_internal() const { return m_type == Type::Internal; }
52
    DisplayInternal internal() const
53
0
    {
54
0
        VERIFY(is_internal());
55
0
        return m_value.internal;
56
0
    }
57
0
    bool is_table_column() const { return is_internal() && internal() == DisplayInternal::TableColumn; }
58
0
    bool is_table_row_group() const { return is_internal() && internal() == DisplayInternal::TableRowGroup; }
59
0
    bool is_table_header_group() const { return is_internal() && internal() == DisplayInternal::TableHeaderGroup; }
60
0
    bool is_table_footer_group() const { return is_internal() && internal() == DisplayInternal::TableFooterGroup; }
61
0
    bool is_table_row() const { return is_internal() && internal() == DisplayInternal::TableRow; }
62
0
    bool is_table_cell() const { return is_internal() && internal() == DisplayInternal::TableCell; }
63
0
    bool is_table_column_group() const { return is_internal() && internal() == DisplayInternal::TableColumnGroup; }
64
0
    bool is_table_caption() const { return is_internal() && internal() == DisplayInternal::TableCaption; }
65
66
0
    bool is_none() const { return m_type == Type::Box && m_value.box == DisplayBox::None; }
67
0
    bool is_contents() const { return m_type == Type::Box && m_value.box == DisplayBox::Contents; }
68
69
0
    Type type() const { return m_type; }
70
71
0
    bool is_outside_and_inside() const { return m_type == Type::OutsideAndInside; }
72
73
    DisplayOutside outside() const
74
0
    {
75
0
        VERIFY(is_outside_and_inside());
76
0
        return m_value.outside_inside.outside;
77
0
    }
78
79
0
    bool is_block_outside() const { return is_outside_and_inside() && outside() == DisplayOutside::Block; }
80
0
    bool is_inline_outside() const { return is_outside_and_inside() && outside() == DisplayOutside::Inline; }
81
0
    bool is_inline_block() const { return is_inline_outside() && is_flow_root_inside(); }
82
83
    ListItem list_item() const
84
0
    {
85
0
        VERIFY(is_outside_and_inside());
86
0
        return m_value.outside_inside.list_item;
87
0
    }
88
89
0
    bool is_list_item() const { return is_outside_and_inside() && list_item() == ListItem::Yes; }
90
91
    DisplayInside inside() const
92
0
    {
93
0
        VERIFY(is_outside_and_inside());
94
0
        return m_value.outside_inside.inside;
95
0
    }
96
97
0
    bool is_flow_inside() const { return is_outside_and_inside() && inside() == DisplayInside::Flow; }
98
0
    bool is_flow_root_inside() const { return is_outside_and_inside() && inside() == DisplayInside::FlowRoot; }
99
0
    bool is_table_inside() const { return is_outside_and_inside() && inside() == DisplayInside::Table; }
100
0
    bool is_flex_inside() const { return is_outside_and_inside() && inside() == DisplayInside::Flex; }
101
0
    bool is_grid_inside() const { return is_outside_and_inside() && inside() == DisplayInside::Grid; }
102
0
    bool is_ruby_inside() const { return is_outside_and_inside() && inside() == DisplayInside::Ruby; }
103
0
    bool is_math_inside() const { return is_outside_and_inside() && inside() == DisplayInside::Math; }
104
105
    enum class Short {
106
        None,
107
        Contents,
108
        Block,
109
        Flow,
110
        FlowRoot,
111
        Inline,
112
        InlineBlock,
113
        RunIn,
114
        ListItem,
115
        InlineListItem,
116
        Flex,
117
        InlineFlex,
118
        Grid,
119
        InlineGrid,
120
        Ruby,
121
        Table,
122
        InlineTable,
123
        Math,
124
    };
125
126
    static Display from_short(Short short_)
127
0
    {
128
0
        switch (short_) {
129
0
        case Short::None:
130
0
            return Display { DisplayBox::None };
131
0
        case Short::Contents:
132
0
            return Display { DisplayBox::Contents };
133
0
        case Short::Block:
134
0
            return Display { DisplayOutside::Block, DisplayInside::Flow };
135
0
        case Short::Inline:
136
0
            return Display { DisplayOutside::Inline, DisplayInside::Flow };
137
0
        case Short::Flow:
138
0
            return Display { DisplayOutside::Block, DisplayInside::Flow };
139
0
        case Short::FlowRoot:
140
0
            return Display { DisplayOutside::Block, DisplayInside::FlowRoot };
141
0
        case Short::InlineBlock:
142
0
            return Display { DisplayOutside::Inline, DisplayInside::FlowRoot };
143
0
        case Short::RunIn:
144
0
            return Display { DisplayOutside::RunIn, DisplayInside::Flow };
145
0
        case Short::ListItem:
146
0
            return Display { DisplayOutside::Block, DisplayInside::Flow, ListItem::Yes };
147
0
        case Short::InlineListItem:
148
0
            return Display { DisplayOutside::Inline, DisplayInside::Flow, ListItem::Yes };
149
0
        case Short::Flex:
150
0
            return Display { DisplayOutside::Block, DisplayInside::Flex };
151
0
        case Short::InlineFlex:
152
0
            return Display { DisplayOutside::Inline, DisplayInside::Flex };
153
0
        case Short::Grid:
154
0
            return Display { DisplayOutside::Block, DisplayInside::Grid };
155
0
        case Short::InlineGrid:
156
0
            return Display { DisplayOutside::Inline, DisplayInside::Grid };
157
0
        case Short::Ruby:
158
0
            return Display { DisplayOutside::Inline, DisplayInside::Ruby };
159
0
        case Short::Table:
160
0
            return Display { DisplayOutside::Block, DisplayInside::Table };
161
0
        case Short::InlineTable:
162
0
            return Display { DisplayOutside::Inline, DisplayInside::Table };
163
0
        case Short::Math:
164
            // NOTE: The spec ( https://w3c.github.io/mathml-core/#new-display-math-value ) does not
165
            //       mention what the outside value for `display: math` should be.
166
            //       The UA stylesheet does `* { display: block math; }` so let's go with that.
167
0
            return Display { DisplayOutside::Block, DisplayInside::Math };
168
0
        }
169
0
        VERIFY_NOT_REACHED();
170
0
    }
171
172
    Display(DisplayOutside outside, DisplayInside inside)
173
0
        : m_type(Type::OutsideAndInside)
174
0
    {
175
0
        m_value.outside_inside = {
176
0
            .outside = outside,
177
0
            .inside = inside,
178
0
            .list_item = ListItem::No,
179
0
        };
180
0
    }
181
182
    Display(DisplayOutside outside, DisplayInside inside, ListItem list_item)
183
0
        : m_type(Type::OutsideAndInside)
184
0
    {
185
0
        m_value.outside_inside = {
186
0
            .outside = outside,
187
0
            .inside = inside,
188
0
            .list_item = list_item,
189
0
        };
190
0
    }
191
192
    explicit Display(DisplayInternal internal)
193
0
        : m_type(Type::Internal)
194
0
    {
195
0
        m_value.internal = internal;
196
0
    }
197
198
    explicit Display(DisplayBox box)
199
0
        : m_type(Type::Box)
200
0
    {
201
0
        m_value.box = box;
202
0
    }
203
204
private:
205
    Type m_type {};
206
    union {
207
        struct {
208
            DisplayOutside outside;
209
            DisplayInside inside;
210
            ListItem list_item;
211
        } outside_inside;
212
        DisplayInternal internal;
213
        DisplayBox box;
214
    } m_value {};
215
};
216
217
}