Serenity Operating System
at master 236 lines 7.2 kB view raw
1/* 2 * Copyright (c) 2021, Andreas Kling <kling@serenityos.org> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#pragma once 8 9#include <AK/Assertions.h> 10#include <AK/String.h> 11 12namespace Web::CSS { 13 14class Display { 15public: 16 Display() = default; 17 ~Display() = default; 18 19 ErrorOr<String> to_string() const; 20 21 bool operator==(Display const& other) const 22 { 23 if (m_type != other.m_type) 24 return false; 25 switch (m_type) { 26 case Type::Box: 27 return m_value.box == other.m_value.box; 28 case Type::Internal: 29 return m_value.internal == other.m_value.internal; 30 case Type::OutsideAndInside: 31 return m_value.outside_inside.outside == other.m_value.outside_inside.outside 32 && m_value.outside_inside.inside == other.m_value.outside_inside.inside 33 && m_value.outside_inside.list_item == other.m_value.outside_inside.list_item; 34 } 35 VERIFY_NOT_REACHED(); 36 } 37 38 enum class Outside { 39 Block, 40 Inline, 41 RunIn, 42 }; 43 44 enum class Inside { 45 Flow, 46 FlowRoot, 47 Table, 48 Flex, 49 Grid, 50 Ruby, 51 }; 52 53 enum class Internal { 54 TableRowGroup, 55 TableHeaderGroup, 56 TableFooterGroup, 57 TableRow, 58 TableCell, 59 TableColumnGroup, 60 TableColumn, 61 TableCaption, 62 RubyBase, 63 RubyText, 64 RubyBaseContainer, 65 RubyTextContainer, 66 }; 67 68 enum class Box { 69 Contents, 70 None, 71 }; 72 73 enum class Type { 74 OutsideAndInside, 75 Internal, 76 Box, 77 }; 78 79 bool is_internal() const { return m_type == Type::Internal; } 80 Internal internal() const 81 { 82 VERIFY(is_internal()); 83 return m_value.internal; 84 } 85 bool is_table_column() const { return is_internal() && internal() == Internal::TableColumn; } 86 bool is_table_row_group() const { return is_internal() && internal() == Internal::TableRowGroup; } 87 bool is_table_header_group() const { return is_internal() && internal() == Internal::TableHeaderGroup; } 88 bool is_table_footer_group() const { return is_internal() && internal() == Internal::TableFooterGroup; } 89 bool is_table_row() const { return is_internal() && internal() == Internal::TableRow; } 90 bool is_table_cell() const { return is_internal() && internal() == Internal::TableCell; } 91 bool is_table_column_group() const { return is_internal() && internal() == Internal::TableColumnGroup; } 92 bool is_table_caption() const { return is_internal() && internal() == Internal::TableCaption; } 93 94 bool is_none() const { return m_type == Type::Box && m_value.box == Box::None; } 95 bool is_contents() const { return m_type == Type::Box && m_value.box == Box::Contents; } 96 97 Type type() const { return m_type; } 98 99 bool is_outside_and_inside() const { return m_type == Type::OutsideAndInside; } 100 101 Outside outside() const 102 { 103 VERIFY(is_outside_and_inside()); 104 return m_value.outside_inside.outside; 105 } 106 107 bool is_block_outside() const { return is_outside_and_inside() && outside() == Outside::Block; } 108 bool is_inline_outside() const { return is_outside_and_inside() && outside() == Outside::Inline; } 109 bool is_inline_block() const { return is_inline_outside() && is_flow_root_inside(); } 110 bool is_list_item() const { return is_outside_and_inside() && m_value.outside_inside.list_item == ListItem::Yes; } 111 112 Inside inside() const 113 { 114 VERIFY(is_outside_and_inside()); 115 return m_value.outside_inside.inside; 116 } 117 118 bool is_flow_inside() const { return is_outside_and_inside() && inside() == Inside::Flow; } 119 bool is_flow_root_inside() const { return is_outside_and_inside() && inside() == Inside::FlowRoot; } 120 bool is_table_inside() const { return is_outside_and_inside() && inside() == Inside::Table; } 121 bool is_flex_inside() const { return is_outside_and_inside() && inside() == Inside::Flex; } 122 bool is_grid_inside() const { return is_outside_and_inside() && inside() == Inside::Grid; } 123 bool is_ruby_inside() const { return is_outside_and_inside() && inside() == Inside::Ruby; } 124 125 enum class Short { 126 None, 127 Contents, 128 Block, 129 FlowRoot, 130 Inline, 131 InlineBlock, 132 RunIn, 133 ListItem, 134 InlineListItem, 135 Flex, 136 InlineFlex, 137 Grid, 138 InlineGrid, 139 Ruby, 140 BlockRuby, 141 Table, 142 InlineTable, 143 }; 144 145 enum class ListItem { 146 No, 147 Yes, 148 }; 149 150 static Display from_short(Short short_) 151 { 152 switch (short_) { 153 case Short::None: 154 return Display { Box::None }; 155 case Short::Contents: 156 return Display { Box::Contents }; 157 case Short::Block: 158 return Display { Outside::Block, Inside::Flow }; 159 case Short::FlowRoot: 160 return Display { Outside::Block, Inside::FlowRoot }; 161 case Short::Inline: 162 return Display { Outside::Inline, Inside::Flow }; 163 case Short::InlineBlock: 164 return Display { Outside::Inline, Inside::FlowRoot }; 165 case Short::RunIn: 166 return Display { Outside::RunIn, Inside::Flow }; 167 case Short::ListItem: 168 return Display { Outside::Block, Inside::Flow, ListItem::Yes }; 169 case Short::InlineListItem: 170 return Display { Outside::Inline, Inside::Flow, ListItem::Yes }; 171 case Short::Flex: 172 return Display { Outside::Block, Inside::Flex }; 173 case Short::InlineFlex: 174 return Display { Outside::Inline, Inside::Flex }; 175 case Short::Grid: 176 return Display { Outside::Block, Inside::Grid }; 177 case Short::InlineGrid: 178 return Display { Outside::Inline, Inside::Grid }; 179 case Short::Ruby: 180 return Display { Outside::Inline, Inside::Ruby }; 181 case Short::BlockRuby: 182 return Display { Outside::Block, Inside::Ruby }; 183 case Short::Table: 184 return Display { Outside::Block, Inside::Table }; 185 case Short::InlineTable: 186 return Display { Outside::Inline, Inside::Table }; 187 } 188 VERIFY_NOT_REACHED(); 189 } 190 191 Display(Outside outside, Inside inside) 192 : m_type(Type::OutsideAndInside) 193 { 194 m_value.outside_inside = { 195 .outside = outside, 196 .inside = inside, 197 .list_item = ListItem::No, 198 }; 199 } 200 201 Display(Outside outside, Inside inside, ListItem list_item) 202 : m_type(Type::OutsideAndInside) 203 { 204 m_value.outside_inside = { 205 .outside = outside, 206 .inside = inside, 207 .list_item = list_item, 208 }; 209 } 210 211 explicit Display(Internal internal) 212 : m_type(Type::Internal) 213 { 214 m_value.internal = internal; 215 } 216 217 explicit Display(Box box) 218 : m_type(Type::Box) 219 { 220 m_value.box = box; 221 } 222 223private: 224 Type m_type {}; 225 union { 226 struct { 227 Outside outside; 228 Inside inside; 229 ListItem list_item; 230 } outside_inside; 231 Internal internal; 232 Box box; 233 } m_value {}; 234}; 235 236}