1
extern crate boxrs;
2
extern crate image;
3

            
4
use std::default::Default;
5
use std::env;
6
use std::fs::File;
7
use std::io::Read;
8

            
9
use boxrs::css::Color;
10

            
11
fn main() {
12
    let mut args = env::args().skip(1);
13
    let html_filename = args.next().expect("HTML file provided as first argument");
14
    let css_filename = args.next().expect("CSS file provided as second argument");
15

            
16
    let html = read_source(&html_filename);
17
    let css = read_source(&css_filename);
18

            
19
    // Since we don't have an actual window, hard-code the "viewport" size.
20
    let width = 800;
21
    let height = 600;
22

            
23
    let mut viewport: boxrs::layout::Dimensions = Default::default();
24
    viewport.content.width = width as f32;
25
    viewport.content.height = height as f32;
26

            
27
    // Parsing and rendering:
28
    let root_node = boxrs::parse_html(&html);
29
    let stylesheet = boxrs::parse_css(&css);
30
    let style_root = boxrs::build_style_tree(&root_node, &stylesheet);
31
    let layout_root = boxrs::build_layout_tree(&style_root, viewport);
32
    let display_list = boxrs::build_display_list(&layout_root);
33

            
34
    let filename = "output.png";
35

            
36
    // Rasterize:
37
    let background = Color {
38
        r: 255,
39
        g: 255,
40
        b: 255,
41
        a: 255,
42
    };
43
    let mut canvas = vec![background; width * height];
44

            
45
    for item in display_list {
46
        match item {
47
            boxrs::painting::DisplayCommand::SolidColor(color, rect) => {
48
                // Clip the rectangle to the canvas boundaries.
49
                let x0 = rect.x.clamp(0.0, width as f32) as usize;
50
                let y0 = rect.y.clamp(0.0, height as f32) as usize;
51
                let x1 = (rect.x + rect.width).clamp(0.0, width as f32) as usize;
52
                let y1 = (rect.y + rect.height).clamp(0.0, height as f32) as usize;
53

            
54
                for y in y0..y1 {
55
                    for x in x0..x1 {
56
                        // TODO: alpha compositing with existing pixel
57
                        canvas[y * width + x] = color.clone();
58
                    }
59
                }
60
            }
61
        }
62
    }
63

            
64
    let img = image::ImageBuffer::from_fn(width as u32, height as u32, move |x, y| {
65
        let color = &canvas[(y * width as u32 + x) as usize];
66
        image::Rgba([color.r, color.g, color.b, color.a])
67
    });
68

            
69
    let result = img.save(filename);
70

            
71
    match result {
72
        Ok(_) => println!("Saved output as {}", filename),
73
        Err(_) => println!("Error saving output as {}", filename),
74
    }
75
}
76

            
77
fn read_source(filename: &str) -> String {
78
    let mut s = String::new();
79
    File::open(filename)
80
        .unwrap()
81
        .read_to_string(&mut s)
82
        .unwrap();
83
    s
84
}
85

            
86
trait Clamp {
87
    fn clamp(self, lower: Self, upper: Self) -> Self;
88
}
89
impl Clamp for f32 {
90
    fn clamp(self, lower: f32, upper: f32) -> f32 {
91
        self.max(lower).min(upper)
92
    }
93
}