blitz_dom/layout/
damage.rs

1use crate::{BaseDocument, net::ImageHandler, node::BackgroundImageData, util::ImageType};
2use blitz_traits::net::Request;
3use style::properties::generated::longhands::position::computed_value::T as Position;
4use style::servo::url::ComputedUrl;
5use style::values::generics::image::Image as StyloImage;
6
7impl BaseDocument {
8    /// Walk the whole tree, converting styles to layout
9    pub fn flush_styles_to_layout(&mut self, node_id: usize) {
10        let doc_id = self.id();
11
12        let display = {
13            let node = self.nodes.get_mut(node_id).unwrap();
14            let stylo_element_data = node.stylo_element_data.borrow();
15            let primary_styles = stylo_element_data
16                .as_ref()
17                .and_then(|data| data.styles.get_primary());
18
19            let Some(style) = primary_styles else {
20                return;
21            };
22
23            node.style = stylo_taffy::to_taffy_style(style);
24            node.display_constructed_as = style.clone_display();
25
26            // Flush background image from style to dedicated storage on the node
27            // TODO: handle multiple background images
28            if let Some(elem) = node.data.downcast_element_mut() {
29                let style_bgs = &style.get_background().background_image.0;
30                let elem_bgs = &mut elem.background_images;
31
32                let len = style_bgs.len();
33                elem_bgs.resize_with(len, || None);
34
35                for idx in 0..len {
36                    let background_image = &style_bgs[idx];
37                    let new_bg_image = match background_image {
38                        StyloImage::Url(ComputedUrl::Valid(new_url)) => {
39                            let old_bg_image = elem_bgs[idx].as_ref();
40                            let old_bg_image_url = old_bg_image.map(|data| &data.url);
41                            if old_bg_image_url.is_some_and(|old_url| **new_url == **old_url) {
42                                break;
43                            }
44
45                            self.net_provider.fetch(
46                                doc_id,
47                                Request::get((**new_url).clone()),
48                                Box::new(ImageHandler::new(node_id, ImageType::Background(idx))),
49                            );
50
51                            let bg_image_data = BackgroundImageData::new(new_url.clone());
52                            Some(bg_image_data)
53                        }
54                        _ => None,
55                    };
56
57                    // Element will always exist due to resize_with above
58                    elem_bgs[idx] = new_bg_image;
59                }
60            }
61
62            // Clear Taffy cache
63            // TODO: smarter cache invalidation
64            node.cache.clear();
65
66            node.style.display
67        };
68
69        // If the node has children, then take those children and...
70        let children = self.nodes[node_id].layout_children.borrow_mut().take();
71        if let Some(mut children) = children {
72            // Recursively call flush_styles_to_layout on each child
73            for child in children.iter() {
74                self.flush_styles_to_layout(*child);
75            }
76
77            // If the node is a Flexbox or Grid node then sort by css order property
78            if matches!(display, taffy::Display::Flex | taffy::Display::Grid) {
79                children.sort_by(|left, right| {
80                    let left_node = self.nodes.get(*left).unwrap();
81                    let right_node = self.nodes.get(*right).unwrap();
82                    left_node.order().cmp(&right_node.order())
83                });
84            }
85
86            // Put children back
87            *self.nodes[node_id].layout_children.borrow_mut() = Some(children);
88
89            // Sort paint_children in place
90            self.nodes[node_id]
91                .paint_children
92                .borrow_mut()
93                .as_mut()
94                .unwrap()
95                .sort_by(|left, right| {
96                    let left_node = self.nodes.get(*left).unwrap();
97                    let right_node = self.nodes.get(*right).unwrap();
98                    left_node
99                        .z_index()
100                        .cmp(&right_node.z_index())
101                        .then_with(|| {
102                            fn position_to_order(pos: Position) -> u8 {
103                                match pos {
104                                    Position::Static | Position::Relative | Position::Sticky => 0,
105                                    Position::Absolute | Position::Fixed => 1,
106                                }
107                            }
108                            let left_position = left_node
109                                .primary_styles()
110                                .map(|s| position_to_order(s.clone_position()))
111                                .unwrap_or(0);
112                            let right_position = right_node
113                                .primary_styles()
114                                .map(|s| position_to_order(s.clone_position()))
115                                .unwrap_or(0);
116
117                            left_position.cmp(&right_position)
118                        })
119                })
120        }
121    }
122
123    pub(crate) fn invalidate_inline_contexts(&mut self) {
124        let root_node_id = self.root_node().id;
125        let scale = self.viewport.scale();
126        self.iter_subtree_mut(root_node_id, |node_id, doc| {
127            let node = &mut doc.nodes[node_id];
128            let Some(element) = node.data.downcast_element_mut() else {
129                return;
130            };
131
132            if let Some(input) = element.text_input_data_mut() {
133                input.editor.set_scale(scale);
134                let mut font_ctx = doc.font_ctx.lock().unwrap();
135                input
136                    .editor
137                    .refresh_layout(&mut font_ctx, &mut doc.layout_ctx);
138            }
139        });
140    }
141}