Display.h 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  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. 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. bool operator!=(Display const& other) const { return !(*this == other); }
  32. enum class Outside {
  33. Block,
  34. Inline,
  35. RunIn,
  36. };
  37. enum class Inside {
  38. Flow,
  39. FlowRoot,
  40. Table,
  41. Flex,
  42. Grid,
  43. Ruby,
  44. };
  45. enum class Internal {
  46. TableRowGroup,
  47. TableHeaderGroup,
  48. TableFooterGroup,
  49. TableRow,
  50. TableCell,
  51. TableColumnGroup,
  52. TableColumn,
  53. TableCaption,
  54. RubyBase,
  55. RubyText,
  56. RubyBaseContainer,
  57. RubyTextContainer,
  58. };
  59. enum class Box {
  60. Contents,
  61. None,
  62. };
  63. enum class Type {
  64. OutsideAndInside,
  65. Internal,
  66. Box,
  67. };
  68. bool is_internal() const { return m_type == Type::Internal; }
  69. Internal internal() const
  70. {
  71. VERIFY(is_internal());
  72. return m_value.internal;
  73. }
  74. bool is_table_column() const { return is_internal() && internal() == Internal::TableColumn; }
  75. bool is_table_row_group() const { return is_internal() && internal() == Internal::TableRowGroup; }
  76. bool is_table_header_group() const { return is_internal() && internal() == Internal::TableHeaderGroup; }
  77. bool is_table_footer_group() const { return is_internal() && internal() == Internal::TableFooterGroup; }
  78. bool is_table_row() const { return is_internal() && internal() == Internal::TableRow; }
  79. bool is_table_cell() const { return is_internal() && internal() == Internal::TableCell; }
  80. bool is_table_column_group() const { return is_internal() && internal() == Internal::TableColumnGroup; }
  81. bool is_table_caption() const { return is_internal() && internal() == Internal::TableCaption; }
  82. bool is_none() const { return m_type == Type::Box && m_value.box == Box::None; }
  83. bool is_contents() const { return m_type == Type::Box && m_value.box == Box::Contents; }
  84. Type type() const { return m_type; }
  85. bool is_outside_and_inside() const { return m_type == Type::OutsideAndInside; }
  86. Outside outside() const
  87. {
  88. VERIFY(is_outside_and_inside());
  89. return m_value.outside_inside.outside;
  90. }
  91. bool is_block_outside() const { return is_outside_and_inside() && outside() == Outside::Block; }
  92. bool is_inline_outside() const { return is_outside_and_inside() && outside() == Outside::Inline; }
  93. bool is_inline_block() const { return is_inline_outside() && is_flow_root_inside(); }
  94. bool is_list_item() const { return is_outside_and_inside() && m_value.outside_inside.list_item == ListItem::Yes; }
  95. Inside inside() const
  96. {
  97. VERIFY(is_outside_and_inside());
  98. return m_value.outside_inside.inside;
  99. }
  100. bool is_flow_inside() const { return is_outside_and_inside() && inside() == Inside::Flow; }
  101. bool is_flow_root_inside() const { return is_outside_and_inside() && inside() == Inside::FlowRoot; }
  102. bool is_table_inside() const { return is_outside_and_inside() && inside() == Inside::Table; }
  103. bool is_flex_inside() const { return is_outside_and_inside() && inside() == Inside::Flex; }
  104. bool is_grid_inside() const { return is_outside_and_inside() && inside() == Inside::Grid; }
  105. bool is_ruby_inside() const { return is_outside_and_inside() && inside() == Inside::Ruby; }
  106. enum class Short {
  107. None,
  108. Contents,
  109. Block,
  110. FlowRoot,
  111. Inline,
  112. InlineBlock,
  113. RunIn,
  114. ListItem,
  115. InlineListItem,
  116. Flex,
  117. InlineFlex,
  118. Grid,
  119. InlineGrid,
  120. Ruby,
  121. BlockRuby,
  122. Table,
  123. InlineTable,
  124. };
  125. enum class ListItem {
  126. No,
  127. Yes,
  128. };
  129. static Display from_short(Short short_)
  130. {
  131. switch (short_) {
  132. case Short::None:
  133. return Display { Box::None };
  134. case Short::Contents:
  135. return Display { Box::Contents };
  136. case Short::Block:
  137. return Display { Outside::Block, Inside::Flow };
  138. case Short::FlowRoot:
  139. return Display { Outside::Block, Inside::FlowRoot };
  140. case Short::Inline:
  141. return Display { Outside::Inline, Inside::Flow };
  142. case Short::InlineBlock:
  143. return Display { Outside::Inline, Inside::FlowRoot };
  144. case Short::RunIn:
  145. return Display { Outside::RunIn, Inside::Flow };
  146. case Short::ListItem:
  147. return Display { Outside::Block, Inside::Flow, ListItem::Yes };
  148. case Short::InlineListItem:
  149. return Display { Outside::Inline, Inside::Flow, ListItem::Yes };
  150. case Short::Flex:
  151. return Display { Outside::Block, Inside::Flex };
  152. case Short::InlineFlex:
  153. return Display { Outside::Inline, Inside::Flex };
  154. case Short::Grid:
  155. return Display { Outside::Block, Inside::Grid };
  156. case Short::InlineGrid:
  157. return Display { Outside::Inline, Inside::Grid };
  158. case Short::Ruby:
  159. return Display { Outside::Inline, Inside::Ruby };
  160. case Short::BlockRuby:
  161. return Display { Outside::Block, Inside::Ruby };
  162. case Short::Table:
  163. return Display { Outside::Block, Inside::Table };
  164. case Short::InlineTable:
  165. return Display { Outside::Inline, Inside::Table };
  166. }
  167. VERIFY_NOT_REACHED();
  168. }
  169. Display(Outside outside, Inside inside)
  170. : m_type(Type::OutsideAndInside)
  171. {
  172. m_value.outside_inside = {
  173. .outside = outside,
  174. .inside = inside,
  175. .list_item = ListItem::No,
  176. };
  177. }
  178. Display(Outside outside, Inside inside, ListItem list_item)
  179. : m_type(Type::OutsideAndInside)
  180. {
  181. m_value.outside_inside = {
  182. .outside = outside,
  183. .inside = inside,
  184. .list_item = list_item,
  185. };
  186. }
  187. explicit Display(Internal internal)
  188. : m_type(Type::Internal)
  189. {
  190. m_value.internal = internal;
  191. }
  192. explicit Display(Box box)
  193. : m_type(Type::Box)
  194. {
  195. m_value.box = box;
  196. }
  197. private:
  198. Type m_type {};
  199. union {
  200. struct {
  201. Outside outside;
  202. Inside inside;
  203. ListItem list_item;
  204. } outside_inside;
  205. Internal internal;
  206. Box box;
  207. } m_value {};
  208. };
  209. }