layout.rs 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. use std::cell::RefCell;
  2. use std::rc::Rc;
  3. use dioxus_core::*;
  4. use dioxus_native_core::layout_attributes::apply_layout_attributes;
  5. use dioxus_native_core::node_ref::{AttributeMask, NodeMask, NodeView};
  6. use dioxus_native_core::real_dom::OwnedAttributeView;
  7. use dioxus_native_core::state::ChildDepState;
  8. use dioxus_native_core_macro::sorted_str_slice;
  9. use taffy::prelude::*;
  10. #[derive(Debug, Clone, Copy, PartialEq)]
  11. pub(crate) enum PossiblyUninitalized<T> {
  12. Uninitalized,
  13. Initialized(T),
  14. }
  15. impl<T> PossiblyUninitalized<T> {
  16. pub fn unwrap(self) -> T {
  17. match self {
  18. Self::Initialized(i) => i,
  19. _ => panic!(),
  20. }
  21. }
  22. pub fn ok(self) -> Option<T> {
  23. match self {
  24. Self::Initialized(i) => Some(i),
  25. _ => None,
  26. }
  27. }
  28. }
  29. impl<T> Default for PossiblyUninitalized<T> {
  30. fn default() -> Self {
  31. Self::Uninitalized
  32. }
  33. }
  34. #[derive(Clone, PartialEq, Default, Debug)]
  35. pub(crate) struct TaffyLayout {
  36. pub style: Style,
  37. pub node: PossiblyUninitalized<Node>,
  38. }
  39. impl ChildDepState for TaffyLayout {
  40. type Ctx = Rc<RefCell<Taffy>>;
  41. type DepState = Self;
  42. // use tag to force this to be called when a node is built
  43. const NODE_MASK: NodeMask =
  44. NodeMask::new_with_attrs(AttributeMask::Static(SORTED_LAYOUT_ATTRS))
  45. .with_text()
  46. .with_tag();
  47. /// Setup the layout
  48. fn reduce<'a>(
  49. &mut self,
  50. node: NodeView,
  51. children: impl Iterator<Item = &'a Self::DepState>,
  52. ctx: &Self::Ctx,
  53. ) -> bool
  54. where
  55. Self::DepState: 'a,
  56. {
  57. let mut changed = false;
  58. let mut taffy = ctx.borrow_mut();
  59. let mut style = Style::default();
  60. if let Some(text) = node.text() {
  61. let char_len = text.chars().count();
  62. style = Style {
  63. size: Size {
  64. // characters are 1 point tall
  65. height: Dimension::Points(1.0),
  66. // text is as long as it is declared
  67. width: Dimension::Points(char_len as f32),
  68. },
  69. ..Default::default()
  70. };
  71. if let PossiblyUninitalized::Initialized(n) = self.node {
  72. if self.style != style {
  73. taffy.set_style(n, style).unwrap();
  74. }
  75. } else {
  76. self.node = PossiblyUninitalized::Initialized(taffy.new_node(style, &[]).unwrap());
  77. changed = true;
  78. }
  79. } else {
  80. // gather up all the styles from the attribute list
  81. if let Some(attributes) = node.attributes() {
  82. for OwnedAttributeView {
  83. attribute, value, ..
  84. } in attributes
  85. {
  86. assert!(SORTED_LAYOUT_ATTRS
  87. .binary_search(&attribute.name.as_ref())
  88. .is_ok());
  89. if let Some(text) = value.as_text() {
  90. apply_layout_attributes(&attribute.name, text, &mut style);
  91. }
  92. }
  93. }
  94. // the root node fills the entire area
  95. if node.id() == ElementId(0) {
  96. apply_layout_attributes("width", "100%", &mut style);
  97. apply_layout_attributes("height", "100%", &mut style);
  98. }
  99. // Set all direct nodes as our children
  100. let mut child_layout = vec![];
  101. for l in children {
  102. child_layout.push(l.node.unwrap());
  103. }
  104. if let PossiblyUninitalized::Initialized(n) = self.node {
  105. if self.style != style {
  106. taffy.set_style(n, style).unwrap();
  107. }
  108. if taffy.children(n).unwrap() != child_layout {
  109. taffy.set_children(n, &child_layout).unwrap();
  110. }
  111. } else {
  112. self.node = PossiblyUninitalized::Initialized(
  113. taffy.new_node(style, &child_layout).unwrap(),
  114. );
  115. changed = true;
  116. }
  117. }
  118. if self.style != style {
  119. changed = true;
  120. self.style = style;
  121. }
  122. changed
  123. }
  124. }
  125. // these are the attributes in layout_attiributes in native-core
  126. const SORTED_LAYOUT_ATTRS: &[&str] = &sorted_str_slice!([
  127. "align-content",
  128. "align-items",
  129. "align-self",
  130. "animation",
  131. "animation-delay",
  132. "animation-direction",
  133. "animation-duration",
  134. "animation-fill-mode",
  135. "animation-iteration-count",
  136. "animation-name",
  137. "animation-play-state",
  138. "animation-timing-function",
  139. "backface-visibility",
  140. "border",
  141. "border-bottom",
  142. "border-bottom-color",
  143. "border-bottom-left-radius",
  144. "border-bottom-right-radius",
  145. "border-bottom-style",
  146. "border-bottom-width",
  147. "border-collapse",
  148. "border-color",
  149. "border-image",
  150. "border-image-outset",
  151. "border-image-repeat",
  152. "border-image-slice",
  153. "border-image-source",
  154. "border-image-width",
  155. "border-left",
  156. "border-left-color",
  157. "border-left-style",
  158. "border-left-width",
  159. "border-radius",
  160. "border-right",
  161. "border-right-color",
  162. "border-right-style",
  163. "border-right-width",
  164. "border-spacing",
  165. "border-style",
  166. "border-top",
  167. "border-top-color",
  168. "border-top-left-radius",
  169. "border-top-right-radius",
  170. "border-top-style",
  171. "border-top-width",
  172. "border-width",
  173. "bottom",
  174. "box-shadow",
  175. "box-sizing",
  176. "caption-side",
  177. "clear",
  178. "clip",
  179. "column-count",
  180. "column-fill",
  181. "column-gap",
  182. "column-rule",
  183. "column-rule-color",
  184. "column-rule-style",
  185. "column-rule-width",
  186. "column-span",
  187. "column-width",
  188. "columns",
  189. "content",
  190. "counter-increment",
  191. "counter-reset",
  192. "cursor",
  193. "direction",
  194. "ltr",
  195. "rtl",
  196. "display",
  197. "empty-cells",
  198. "flex",
  199. "flex-basis",
  200. "flex-direction",
  201. "flex-flow",
  202. "flex-grow",
  203. "flex-shrink",
  204. "flex-wrap",
  205. "float",
  206. "height",
  207. "justify-content",
  208. "flex-start",
  209. "flex-end",
  210. "center",
  211. "space-between",
  212. "space-around",
  213. "space-evenly",
  214. "left",
  215. "letter-spacing",
  216. "line-height",
  217. "list-style",
  218. "list-style-image",
  219. "list-style-position",
  220. "list-style-type",
  221. "margin",
  222. "margin-bottom",
  223. "margin-left",
  224. "margin-right",
  225. "margin-top",
  226. "max-height",
  227. "max-width",
  228. "min-height",
  229. "min-width",
  230. "opacity",
  231. "order",
  232. "outline",
  233. "outline-color",
  234. "outline-offset",
  235. "outline-style",
  236. "outline-width",
  237. "overflow",
  238. "overflow-x",
  239. "overflow-y",
  240. "padding",
  241. "padding-bottom",
  242. "padding-left",
  243. "padding-right",
  244. "padding-top",
  245. "page-break-after",
  246. "page-break-before",
  247. "page-break-inside",
  248. "perspective",
  249. "perspective-origin",
  250. "position",
  251. "static",
  252. "relative",
  253. "fixed",
  254. "absolute",
  255. "sticky",
  256. "pointer-events",
  257. "quotes",
  258. "resize",
  259. "right",
  260. "tab-size",
  261. "table-layout",
  262. "top",
  263. "transform",
  264. "transform-origin",
  265. "transform-style",
  266. "transition",
  267. "transition-delay",
  268. "transition-duration",
  269. "transition-property",
  270. "transition-timing-function",
  271. "vertical-align",
  272. "visibility",
  273. "white-space",
  274. "width",
  275. "word-break",
  276. "word-spacing",
  277. "word-wrap",
  278. "z-index"
  279. ]);