1#![warn(missing_docs)]
41#![no_std]
42
43#[macro_use]
44extern crate alloc;
45#[allow(unused_imports)]
46#[macro_use]
47extern crate log;
48
49#[allow(unused_imports)]
50use alloc::{boxed::Box, vec::Vec};
51use core::{
52 cell::{RefCell, RefMut},
53 fmt,
54};
55
56use float_pigment_css::typing::{
57 AlignContent, AlignItems, AlignSelf, BoxSizing, Direction, Display, FlexDirection, FlexWrap,
58 GridAutoFlow, JustifyContent, JustifyItems, JustifySelf, Position, TextAlign, WritingMode,
59};
60
61pub use unit::SizingMode;
62
63mod algo;
64mod cache;
65mod special_positioned;
66mod types;
67mod unit;
68
69pub(crate) use cache::*;
70pub use special_positioned::is_independent_positioning;
71pub(crate) use special_positioned::*;
72pub use types::*;
73pub(crate) use unit::*;
74
75#[allow(missing_docs)]
77pub trait ScreenQuery<L: LengthNum> {
78 fn screen_width(&self) -> L;
79 fn screen_height(&self) -> L;
80}
81
82pub trait LayoutTreeNode: Sized {
86 type Length: LengthNum;
91
92 type LengthCustom: PartialEq + core::fmt::Debug + Clone;
96
97 type TreeVisitor: LayoutTreeVisitor<Self>;
101
102 type Style: LayoutStyle<Self::Length, Self::LengthCustom>;
104
105 type InlineUnit: InlineUnit<Self, Env = Self::Env>;
110
111 type InlineMeasure: InlineMeasure<Self, InlineUnit = Self::InlineUnit, Env = Self::Env>;
116
117 type Env: ScreenQuery<Self::Length>;
119
120 fn layout_node(&self) -> &LayoutNode<Self>;
122
123 fn tree_visitor(&self) -> &Self::TreeVisitor;
125
126 fn style(&self) -> &Self::Style;
128
129 fn resolve_custom_length(
133 &self,
134 custom: &Self::LengthCustom,
135 owner: Self::Length,
136 ) -> Self::Length;
137
138 fn should_measure(&self, env: &mut Self::Env) -> bool;
145
146 #[allow(clippy::too_many_arguments)]
152 fn measure_block_size(
153 &self,
154 env: &mut Self::Env,
155 req_size: OptionSize<Self::Length>,
156 min: Size<Self::Length>,
157 max: Size<Self::Length>,
158 max_content: OptionSize<Self::Length>,
159 update_position: bool,
160 sizing_mode: SizingMode,
161 ) -> MeasureResult<Self::Length>;
162
163 #[allow(clippy::too_many_arguments)]
168 fn measure_inline_unit(
169 &self,
170 env: &mut Self::Env,
171 req_size: OptionSize<Self::Length>,
172 min: Size<Self::Length>,
173 max: Size<Self::Length>,
174 max_content: OptionSize<Self::Length>,
175 sizing_mode: SizingMode,
176 ) -> MeasureResult<Self::Length>;
177
178 fn size_updated(
183 &self,
184 _env: &mut Self::Env,
185 _size: Size<Self::Length>,
186 _computed_style: &ComputedStyle<Self::Length>,
187 ) {
188 }
189}
190
191pub trait LayoutTreeVisitor<T: LayoutTreeNode> {
193 fn parent(&self) -> Option<&T>;
195
196 fn for_each_child<'a, 'b: 'a, F>(&'b self, f: F)
198 where
199 F: FnMut(&'a T, usize),
200 T: 'a;
201
202 fn children_len(&self) -> usize;
204
205 fn child_at(&self, index: usize) -> Option<&T>;
207
208 fn dirty_marked(&self) {}
213
214 fn children_iter<'a, 'b: 'a>(&'b self) -> impl Iterator<Item = &'a T>
216 where
217 T: 'a;
218}
219
220#[allow(missing_docs)]
224pub trait LayoutStyle<L: LengthNum, T: PartialEq + Clone = i32> {
225 fn display(&self) -> Display;
226 fn position(&self) -> Position;
227 fn direction(&self) -> Direction;
228 fn writing_mode(&self) -> WritingMode;
229 fn flex_direction(&self) -> FlexDirection;
230 fn flex_wrap(&self) -> FlexWrap;
231 fn align_items(&self) -> AlignItems;
232 fn align_self(&self) -> AlignSelf;
233 fn align_content(&self) -> AlignContent;
234 fn justify_content(&self) -> JustifyContent;
235 fn left(&self) -> DefLength<L, T>;
236 fn right(&self) -> DefLength<L, T>;
237 fn top(&self) -> DefLength<L, T>;
238 fn bottom(&self) -> DefLength<L, T>;
239 fn border_left(&self) -> DefLength<L, T>;
240 fn border_right(&self) -> DefLength<L, T>;
241 fn border_top(&self) -> DefLength<L, T>;
242 fn border_bottom(&self) -> DefLength<L, T>;
243 fn margin_left(&self) -> DefLength<L, T>;
244 fn margin_right(&self) -> DefLength<L, T>;
245 fn margin_top(&self) -> DefLength<L, T>;
246 fn margin_bottom(&self) -> DefLength<L, T>;
247 fn padding_left(&self) -> DefLength<L, T>;
248 fn padding_right(&self) -> DefLength<L, T>;
249 fn padding_top(&self) -> DefLength<L, T>;
250 fn padding_bottom(&self) -> DefLength<L, T>;
251 fn flex_grow(&self) -> f32;
252 fn flex_shrink(&self) -> f32;
253 fn flex_basis(&self) -> DefLength<L, T>;
254 fn width(&self) -> DefLength<L, T>;
255 fn height(&self) -> DefLength<L, T>;
256 fn min_width(&self) -> DefLength<L, T>;
257 fn min_height(&self) -> DefLength<L, T>;
258 fn max_width(&self) -> DefLength<L, T>;
259 fn max_height(&self) -> DefLength<L, T>;
260 fn aspect_ratio(&self) -> Option<f32>;
261 fn box_sizing(&self) -> BoxSizing;
262 fn order(&self) -> i32;
263 fn text_align(&self) -> TextAlign {
264 TextAlign::Start
265 }
266 fn column_gap(&self) -> DefLength<L, T> {
267 DefLength::Undefined
268 }
269 fn row_gap(&self) -> DefLength<L, T> {
270 DefLength::Undefined
271 }
272 fn grid_template_rows(&self) -> LayoutGridTemplate<L, T> {
273 LayoutGridTemplate::None
274 }
275 fn grid_template_columns(&self) -> LayoutGridTemplate<L, T> {
276 LayoutGridTemplate::None
277 }
278 fn grid_auto_flow(&self) -> GridAutoFlow {
279 GridAutoFlow::Row
280 }
281 fn grid_auto_rows(&self) -> LayoutGridAuto<L, T> {
284 LayoutGridAuto::default()
285 }
286 fn grid_auto_columns(&self) -> LayoutGridAuto<L, T> {
289 LayoutGridAuto::default()
290 }
291 fn justify_items(&self) -> JustifyItems {
292 JustifyItems::Stretch
293 }
294 fn justify_self(&self) -> JustifySelf {
295 JustifySelf::Auto
296 }
297}
298
299pub struct LayoutNode<T: LayoutTreeNode> {
301 unit: RefCell<LayoutUnit<T>>,
302}
303
304impl<T: LayoutTreeNode> fmt::Debug for LayoutNode<T> {
305 fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
306 Ok(())
307 }
308}
309
310impl<T: LayoutTreeNode> Default for LayoutNode<T> {
311 fn default() -> Self {
312 Self {
313 unit: RefCell::new(LayoutUnit::new()),
314 }
315 }
316}
317
318impl<T: LayoutTreeNode> LayoutNode<T> {
319 #[inline]
321 pub fn new() -> Self {
322 Self::default()
323 }
324
325 #[inline]
327 pub fn mark_dirty(&self, node: &T::TreeVisitor) -> bool {
328 let ret = self.unit.borrow_mut().mark_dirty(node);
329 node.dirty_marked();
330 ret
331 }
332
333 #[inline]
335 pub fn result(&self) -> Rect<T::Length> {
336 self.unit.borrow().result()
337 }
338
339 #[inline]
341 pub fn result_padding_rect(&self) -> Rect<T::Length> {
342 self.unit.borrow().result_padding_rect()
343 }
344
345 #[inline]
347 pub fn result_content_rect(&self) -> Rect<T::Length> {
348 self.unit.borrow().result_content_rect()
349 }
350
351 #[inline]
353 pub fn computed_style(&self) -> ComputedStyle<T::Length> {
354 self.unit.borrow().computed_style()
355 }
356
357 #[inline]
362 pub fn update(&self, env: &mut T::Env, node: &T, available_size: OptionSize<T::Length>) {
363 self.unit.borrow_mut().compute(env, node, available_size)
364 }
365
366 #[inline]
373 pub fn update_with_containing_size(
374 &self,
375 env: &mut T::Env,
376 node: &T,
377 available_size: OptionSize<T::Length>,
378 containing_size: OptionSize<T::Length>,
379 ) {
380 self.unit.borrow_mut().compute_with_containing_size(
381 env,
382 node,
383 available_size,
384 containing_size,
385 )
386 }
387
388 #[inline]
389 pub(crate) fn unit(&self) -> RefMut<'_, LayoutUnit<T>> {
390 self.unit.borrow_mut()
391 }
392}
393
394pub trait InlineMeasure<T: LayoutTreeNode> {
398 type InlineUnit: InlineUnit<T, Env = Self::Env>;
400
401 type Env;
403
404 #[allow(clippy::type_complexity)]
415 fn block_size(
416 env: &mut Self::Env,
417 block_node: &T,
418 inline_nodes: Vec<InlineUnitMetadata<T>>,
419 req_size: OptionSize<T::Length>,
420 max_content_with_max_size: OptionSize<T::Length>,
421 update_position: bool,
422 sizing_mode: SizingMode,
423 ) -> (
424 Size<T::Length>,
425 Vec<(Point<T::Length>, MeasureResult<T::Length>)>,
426 );
427}
428
429#[allow(missing_docs)]
431#[derive(Debug)]
432pub struct InlineUnitMetadata<T: LayoutTreeNode> {
433 pub unit: T::InlineUnit,
434 pub margin: EdgeOption<T::Length>,
435}
436
437pub trait InlineUnit<T: LayoutTreeNode> {
439 type Env;
441
442 fn new(env: &mut Self::Env, node: &T, result: MeasureResult<T::Length>) -> Self;
444}
445
446#[derive(Debug, Clone, Copy, PartialEq)]
448pub struct MeasureResult<L: LengthNum> {
449 pub size: Size<L>,
451
452 pub first_baseline_ascent: Vector<L>,
454
455 pub last_baseline_ascent: Vector<L>,
457}
458
459#[allow(missing_docs)]
461#[derive(Debug, Clone, Copy, PartialEq)]
462pub struct ComputedStyle<L: LengthNum> {
463 pub margin: Edge<L>,
464 pub padding: Edge<L>,
465 pub border: Edge<L>,
466}
467
468impl<L: LengthNum> Default for ComputedStyle<L> {
469 fn default() -> Self {
470 Self {
471 margin: Edge {
472 left: L::zero(),
473 right: L::zero(),
474 top: L::zero(),
475 bottom: L::zero(),
476 },
477 border: Edge {
478 left: L::zero(),
479 right: L::zero(),
480 top: L::zero(),
481 bottom: L::zero(),
482 },
483 padding: Edge {
484 left: L::zero(),
485 right: L::zero(),
486 top: L::zero(),
487 bottom: L::zero(),
488 },
489 }
490 }
491}