Display.h 7.1 KB

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