accessibility_tree/layout/
mod.rs

1use crate::dom;
2use crate::geom::flow_relative::{Rect, Sides, Vec2};
3use crate::geom::Length;
4use crate::style::values::*;
5use crate::style::{style_for_element, ComputedValues};
6use std::convert::TryInto;
7use std::sync::Arc;
8
9mod dom_traversal;
10mod element_data;
11mod flow;
12mod fragments;
13mod positioned;
14mod replaced;
15
16use dom_traversal::*;
17use flow::*;
18use positioned::*;
19use replaced::*;
20
21pub use element_data::*;
22pub use fragments::*;
23
24/// <https://drafts.csswg.org/css-display/#independent-formatting-context>
25#[derive(Debug)]
26pub enum IndependentFormattingContext {
27    Flow(BlockFormattingContext),
28
29    // Not called FC in specs, but behaves close enough
30    Replaced(ReplacedContent),
31    // Other layout modes go here
32}
33
34enum NonReplacedIFC<'a> {
35    Flow(&'a BlockFormattingContext),
36}
37
38impl IndependentFormattingContext {
39    fn construct<'a>(
40        context: &'a Context<'a>,
41        style: &'a Arc<ComputedValues>,
42        display_inside: DisplayInside,
43        contents: Contents,
44    ) -> Self {
45        match contents.try_into() {
46            Ok(non_replaced) => match display_inside {
47                DisplayInside::Flow | DisplayInside::FlowRoot => {
48                    IndependentFormattingContext::Flow(BlockFormattingContext::construct(
49                        context,
50                        style,
51                        non_replaced,
52                    ))
53                }
54            },
55            Err(replaced) => IndependentFormattingContext::Replaced(replaced),
56        }
57    }
58
59    fn as_replaced(&self) -> Result<&ReplacedContent, NonReplacedIFC> {
60        match self {
61            IndependentFormattingContext::Replaced(r) => Ok(r),
62            IndependentFormattingContext::Flow(f) => Err(NonReplacedIFC::Flow(f)),
63        }
64    }
65
66    fn layout<'a>(
67        &'a self,
68        containing_block: &ContainingBlock,
69        tree_rank: usize,
70        absolutely_positioned_fragments: &mut Vec<AbsolutelyPositionedFragment<'a>>,
71    ) -> FlowChildren {
72        match self.as_replaced() {
73            Ok(replaced) => match *replaced {},
74            Err(ifc) => ifc.layout(containing_block, tree_rank, absolutely_positioned_fragments),
75        }
76    }
77}
78
79impl<'a> NonReplacedIFC<'a> {
80    fn layout(
81        &self,
82        containing_block: &ContainingBlock,
83        tree_rank: usize,
84        absolutely_positioned_fragments: &mut Vec<AbsolutelyPositionedFragment<'a>>,
85    ) -> FlowChildren {
86        match self {
87            NonReplacedIFC::Flow(bfc) => {
88                bfc.layout(containing_block, tree_rank, absolutely_positioned_fragments)
89            }
90        }
91    }
92}
93
94pub struct ContainingBlock {
95    inline_size: Length,
96    block_size: LengthOrAuto,
97    mode: (WritingMode, Direction),
98}
99
100pub struct DefiniteContainingBlock {
101    size: Vec2<Length>,
102    mode: (WritingMode, Direction),
103}
104
105/// https://drafts.csswg.org/css2/visuren.html#relative-positioning
106fn relative_adjustement(
107    style: &ComputedValues,
108    inline_size: Length,
109    block_size: LengthOrAuto,
110) -> Vec2<Length> {
111    if !style.box_.position.is_relatively_positioned() {
112        return Vec2::zero();
113    }
114    fn adjust(start: LengthOrAuto, end: LengthOrAuto) -> Length {
115        match (start, end) {
116            (LengthOrAuto::Auto, LengthOrAuto::Auto) => Length::zero(),
117            (LengthOrAuto::Auto, LengthOrAuto::Length(end)) => -end,
118            (LengthOrAuto::Length(start), _) => start,
119        }
120    }
121    let block_size = block_size.auto_is(Length::zero);
122    let box_offsets = style.box_offsets().map_inline_and_block_axes(
123        |v| v.percentage_relative_to(inline_size),
124        |v| v.percentage_relative_to(block_size),
125    );
126    Vec2 {
127        inline: adjust(box_offsets.inline_start, box_offsets.inline_end),
128        block: adjust(box_offsets.block_start, box_offsets.block_end),
129    }
130}
131
132// FIXME: use std::mem::take when it’s stable
133// https://github.com/rust-lang/rust/issues/61129
134fn take<T>(x: &mut T) -> T
135where
136    T: Default,
137{
138    std::mem::replace(x, Default::default())
139}