#![warn(missing_docs)]
#![no_std]
#[macro_use]
extern crate alloc;
#[allow(unused_imports)]
#[macro_use]
extern crate log;
#[allow(unused_imports)]
use alloc::{boxed::Box, vec::Vec};
use core::{
cell::{RefCell, RefMut},
fmt,
};
use float_pigment_css::typing::{
AlignContent, AlignItems, AlignSelf, BoxSizing, Direction, Display, FlexDirection, FlexWrap,
GridAutoFlow, JustifyContent, JustifyItems, JustifySelf, Position, TextAlign, WritingMode,
};
pub use unit::SizingMode;
mod algo;
mod cache;
mod special_positioned;
mod types;
mod unit;
pub(crate) use cache::*;
pub use special_positioned::is_independent_positioning;
pub(crate) use special_positioned::*;
pub use types::*;
pub(crate) use unit::*;
#[allow(missing_docs)]
pub trait ScreenQuery<L: LengthNum> {
fn screen_width(&self) -> L;
fn screen_height(&self) -> L;
}
pub trait LayoutTreeNode: Sized {
type Length: LengthNum;
type LengthCustom: PartialEq + core::fmt::Debug + Clone;
type TreeVisitor: LayoutTreeVisitor<Self>;
type Style: LayoutStyle<Self::Length, Self::LengthCustom>;
type InlineUnit: InlineUnit<Self, Env = Self::Env>;
type InlineMeasure: InlineMeasure<Self, InlineUnit = Self::InlineUnit, Env = Self::Env>;
type Env: ScreenQuery<Self::Length>;
fn layout_node(&self) -> &LayoutNode<Self>;
fn tree_visitor(&self) -> &Self::TreeVisitor;
fn style(&self) -> &Self::Style;
fn resolve_custom_length(
&self,
custom: &Self::LengthCustom,
owner: Self::Length,
) -> Self::Length;
fn should_measure(&self, env: &mut Self::Env) -> bool;
#[allow(clippy::too_many_arguments)]
fn measure_block_size(
&self,
env: &mut Self::Env,
req_size: OptionSize<Self::Length>,
min: Size<Self::Length>,
max: Size<Self::Length>,
max_content: OptionSize<Self::Length>,
update_position: bool,
sizing_mode: SizingMode,
) -> MeasureResult<Self::Length>;
#[allow(clippy::too_many_arguments)]
fn measure_inline_unit(
&self,
env: &mut Self::Env,
req_size: OptionSize<Self::Length>,
min: Size<Self::Length>,
max: Size<Self::Length>,
max_content: OptionSize<Self::Length>,
sizing_mode: SizingMode,
) -> MeasureResult<Self::Length>;
fn size_updated(
&self,
_env: &mut Self::Env,
_size: Size<Self::Length>,
_computed_style: &ComputedStyle<Self::Length>,
) {
}
}
pub trait LayoutTreeVisitor<T: LayoutTreeNode> {
fn parent(&self) -> Option<&T>;
fn for_each_child<'a, 'b: 'a, F>(&'b self, f: F)
where
F: FnMut(&'a T, usize),
T: 'a;
fn children_len(&self) -> usize;
fn child_at(&self, index: usize) -> Option<&T>;
fn dirty_marked(&self) {}
fn children_iter<'a, 'b: 'a>(&'b self) -> impl Iterator<Item = &'a T>
where
T: 'a;
}
#[allow(missing_docs)]
pub trait LayoutStyle<L: LengthNum, T: PartialEq + Clone = i32> {
fn display(&self) -> Display;
fn position(&self) -> Position;
fn direction(&self) -> Direction;
fn writing_mode(&self) -> WritingMode;
fn flex_direction(&self) -> FlexDirection;
fn flex_wrap(&self) -> FlexWrap;
fn align_items(&self) -> AlignItems;
fn align_self(&self) -> AlignSelf;
fn align_content(&self) -> AlignContent;
fn justify_content(&self) -> JustifyContent;
fn left(&self) -> DefLength<L, T>;
fn right(&self) -> DefLength<L, T>;
fn top(&self) -> DefLength<L, T>;
fn bottom(&self) -> DefLength<L, T>;
fn border_left(&self) -> DefLength<L, T>;
fn border_right(&self) -> DefLength<L, T>;
fn border_top(&self) -> DefLength<L, T>;
fn border_bottom(&self) -> DefLength<L, T>;
fn margin_left(&self) -> DefLength<L, T>;
fn margin_right(&self) -> DefLength<L, T>;
fn margin_top(&self) -> DefLength<L, T>;
fn margin_bottom(&self) -> DefLength<L, T>;
fn padding_left(&self) -> DefLength<L, T>;
fn padding_right(&self) -> DefLength<L, T>;
fn padding_top(&self) -> DefLength<L, T>;
fn padding_bottom(&self) -> DefLength<L, T>;
fn flex_grow(&self) -> f32;
fn flex_shrink(&self) -> f32;
fn flex_basis(&self) -> DefLength<L, T>;
fn width(&self) -> DefLength<L, T>;
fn height(&self) -> DefLength<L, T>;
fn min_width(&self) -> DefLength<L, T>;
fn min_height(&self) -> DefLength<L, T>;
fn max_width(&self) -> DefLength<L, T>;
fn max_height(&self) -> DefLength<L, T>;
fn aspect_ratio(&self) -> Option<f32>;
fn box_sizing(&self) -> BoxSizing;
fn order(&self) -> i32;
fn text_align(&self) -> TextAlign {
TextAlign::Start
}
fn column_gap(&self) -> DefLength<L, T> {
DefLength::Undefined
}
fn row_gap(&self) -> DefLength<L, T> {
DefLength::Undefined
}
fn grid_template_rows(&self) -> LayoutGridTemplate<L, T> {
LayoutGridTemplate::None
}
fn grid_template_columns(&self) -> LayoutGridTemplate<L, T> {
LayoutGridTemplate::None
}
fn grid_auto_flow(&self) -> GridAutoFlow {
GridAutoFlow::Row
}
fn grid_auto_rows(&self) -> LayoutGridAuto<L, T> {
LayoutGridAuto::default()
}
fn grid_auto_columns(&self) -> LayoutGridAuto<L, T> {
LayoutGridAuto::default()
}
fn justify_items(&self) -> JustifyItems {
JustifyItems::Stretch
}
fn justify_self(&self) -> JustifySelf {
JustifySelf::Auto
}
}
pub struct LayoutNode<T: LayoutTreeNode> {
unit: RefCell<LayoutUnit<T>>,
}
impl<T: LayoutTreeNode> fmt::Debug for LayoutNode<T> {
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
Ok(())
}
}
impl<T: LayoutTreeNode> Default for LayoutNode<T> {
fn default() -> Self {
Self {
unit: RefCell::new(LayoutUnit::new()),
}
}
}
impl<T: LayoutTreeNode> LayoutNode<T> {
#[inline]
pub fn new() -> Self {
Self::default()
}
#[inline]
pub fn mark_dirty(&self, node: &T::TreeVisitor) -> bool {
let ret = self.unit.borrow_mut().mark_dirty(node);
node.dirty_marked();
ret
}
#[inline]
pub fn result(&self) -> Rect<T::Length> {
self.unit.borrow().result()
}
#[inline]
pub fn result_padding_rect(&self) -> Rect<T::Length> {
self.unit.borrow().result_padding_rect()
}
#[inline]
pub fn result_content_rect(&self) -> Rect<T::Length> {
self.unit.borrow().result_content_rect()
}
#[inline]
pub fn computed_style(&self) -> ComputedStyle<T::Length> {
self.unit.borrow().computed_style()
}
#[inline]
pub fn layout_algorithm(&self) -> LayoutAlgorithm {
self.unit.borrow().layout_algorithm
}
#[inline]
pub fn update(&self, env: &mut T::Env, node: &T, available_size: OptionSize<T::Length>) {
self.unit.borrow_mut().compute(env, node, available_size)
}
#[inline]
pub fn update_with_containing_size(
&self,
env: &mut T::Env,
node: &T,
available_size: OptionSize<T::Length>,
containing_size: OptionSize<T::Length>,
) {
self.unit.borrow_mut().compute_with_containing_size(
env,
node,
available_size,
containing_size,
)
}
#[inline]
pub(crate) fn unit(&self) -> RefMut<'_, LayoutUnit<T>> {
self.unit.borrow_mut()
}
}
pub trait InlineMeasure<T: LayoutTreeNode> {
type InlineUnit: InlineUnit<T, Env = Self::Env>;
type Env;
#[allow(clippy::type_complexity)]
fn block_size(
env: &mut Self::Env,
block_node: &T,
inline_nodes: Vec<InlineUnitMetadata<T>>,
req_size: OptionSize<T::Length>,
max_content_with_max_size: OptionSize<T::Length>,
update_position: bool,
sizing_mode: SizingMode,
) -> (
Size<T::Length>,
Vec<(Point<T::Length>, MeasureResult<T::Length>)>,
);
}
#[allow(missing_docs)]
#[derive(Debug)]
pub struct InlineUnitMetadata<T: LayoutTreeNode> {
pub unit: T::InlineUnit,
pub margin: EdgeOption<T::Length>,
}
pub trait InlineUnit<T: LayoutTreeNode> {
type Env;
fn new(env: &mut Self::Env, node: &T, result: MeasureResult<T::Length>) -> Self;
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct MeasureResult<L: LengthNum> {
pub size: Size<L>,
pub first_baseline_ascent: Vector<L>,
pub last_baseline_ascent: Vector<L>,
}
#[allow(missing_docs)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct ComputedStyle<L: LengthNum> {
pub margin: Edge<L>,
pub padding: Edge<L>,
pub border: Edge<L>,
}
impl<L: LengthNum> Default for ComputedStyle<L> {
fn default() -> Self {
Self {
margin: Edge {
left: L::zero(),
right: L::zero(),
top: L::zero(),
bottom: L::zero(),
},
border: Edge {
left: L::zero(),
right: L::zero(),
top: L::zero(),
bottom: L::zero(),
},
padding: Edge {
left: L::zero(),
right: L::zero(),
top: L::zero(),
bottom: L::zero(),
},
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum LayoutAlgorithm {
None,
Inline,
InlineMeasure,
Block,
InlineBlock,
BlockMeasure,
Flex,
InlineFlex,
Grid,
InlineGrid,
}