Skip to main content

oxidize_html/
painter.rs

1use crate::{DrawCommand, LayoutNode, NodeContent, Point, Rect, TextAlign};
2
3pub fn paint(node: &LayoutNode, commands: &mut Vec<DrawCommand>) {
4    if let Some(bg) = node.style.background_color {
5        commands.push(DrawCommand::FillRect {
6            rect: node.rect,
7            color: bg,
8        });
9    }
10
11    paint_borders(node, commands);
12
13    if let Some(origin) = node.bullet_origin {
14        commands.push(DrawCommand::DrawText {
15            text: "•".to_string(),
16            origin,
17            color: node.style.color,
18            font_size: node.style.font_size,
19        });
20    }
21
22    match &node.content {
23        NodeContent::Box => {}
24        NodeContent::Hr => {
25            commands.push(DrawCommand::DrawLine {
26                start: Point {
27                    x: node.rect.x,
28                    y: node.rect.y + node.rect.height / 2.0,
29                },
30                end: Point {
31                    x: node.rect.right(),
32                    y: node.rect.y + node.rect.height / 2.0,
33                },
34                color: node.style.border.top.color,
35                width: node.style.border.top.width.max(1.0),
36            });
37        }
38        NodeContent::Text(layout) => {
39            for (index, line) in layout.lines.iter().enumerate() {
40                let y = node.rect.y + (index as f32 * layout.line_height);
41                let line_width = line.chars().count() as f32 * layout.font_size * 0.55;
42                let x = match node.style.text_align {
43                    TextAlign::Left => node.rect.x,
44                    TextAlign::Center => node.rect.x + (node.rect.width - line_width) / 2.0,
45                    TextAlign::Right => node.rect.x + node.rect.width - line_width,
46                };
47                commands.push(DrawCommand::DrawText {
48                    text: line.clone(),
49                    origin: Point { x, y },
50                    color: node.style.color,
51                    font_size: layout.font_size,
52                });
53            }
54        }
55        NodeContent::Image {
56            width,
57            height,
58            source,
59        } => {
60            let rect = Rect {
61                x: node.rect.x,
62                y: node.rect.y,
63                width: *width,
64                height: *height,
65            };
66            if matches!(source, crate::image::ImageSource::Invalid) {
67                commands.push(DrawCommand::DrawImagePlaceholder { rect });
68            } else {
69                commands.push(DrawCommand::DrawImage {
70                    rect,
71                    source: source.clone(),
72                });
73            }
74        }
75    }
76
77    if let Some(href) = &node.style.href {
78        commands.push(DrawCommand::Link {
79            rect: node.rect,
80            href: href.clone(),
81        });
82    }
83
84    for child in &node.children {
85        paint(child, commands);
86    }
87}
88
89fn paint_borders(node: &LayoutNode, commands: &mut Vec<DrawCommand>) {
90    let border = node.style.border;
91    if border.top.width > 0.0 {
92        commands.push(DrawCommand::DrawLine {
93            start: Point {
94                x: node.rect.x,
95                y: node.rect.y,
96            },
97            end: Point {
98                x: node.rect.right(),
99                y: node.rect.y,
100            },
101            color: border.top.color,
102            width: border.top.width,
103        });
104    }
105    if border.right.width > 0.0 {
106        commands.push(DrawCommand::DrawLine {
107            start: Point {
108                x: node.rect.right(),
109                y: node.rect.y,
110            },
111            end: Point {
112                x: node.rect.right(),
113                y: node.rect.bottom(),
114            },
115            color: border.right.color,
116            width: border.right.width,
117        });
118    }
119    if border.bottom.width > 0.0 {
120        commands.push(DrawCommand::DrawLine {
121            start: Point {
122                x: node.rect.x,
123                y: node.rect.bottom(),
124            },
125            end: Point {
126                x: node.rect.right(),
127                y: node.rect.bottom(),
128            },
129            color: border.bottom.color,
130            width: border.bottom.width,
131        });
132    }
133    if border.left.width > 0.0 {
134        commands.push(DrawCommand::DrawLine {
135            start: Point {
136                x: node.rect.x,
137                y: node.rect.y,
138            },
139            end: Point {
140                x: node.rect.x,
141                y: node.rect.bottom(),
142            },
143            color: border.left.color,
144            width: border.left.width,
145        });
146    }
147}