aboutsummaryrefslogtreecommitdiffstats
path: root/src/servo/parser/html_builder.rs
blob: 9fa87ffb2bf5215f9ba4d424cfd947efa13fadae (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#[doc="Constructs a DOM tree from an incoming token stream."]

import dom::rcu::writer_methods;
import dom::base::{attr, element, element_subclass, es_div, es_head, es_img};
import dom::base::{es_unknown, methods, nk_element, nk_text, rd_tree_ops};
import dom::base::{wr_tree_ops};
import dom = dom::base;
import parser = parser::lexer::html;
import parser::token;
import gfx::geom;
import dvec::extensions;

fn link_up_attribute(scope: dom::node_scope, node: dom::node, key: str,
                     value: str) {
    // TODO: Implement atoms so that we don't always perform string
    // comparisons.
    scope.rd(node) {
        |node_contents|
        alt *node_contents.kind {
            dom::nk_element(element) {
                element.attrs.push(~attr(key, value));
                alt *element.subclass {
                    es_img(img) if key == "width" {
                        alt int::from_str(value) {
                            none { /* drop on the floor */ }
                            some(s) { img.size.width = geom::px_to_au(s); }
                        }
                    }
                    es_img(img) if key == "height" {
                        alt int::from_str(value) {
                            none { /* drop on the floor */ }
                            some(s) { img.size.height = geom::px_to_au(s); }
                        }
                    }
                    es_div | es_img(*) | es_head | es_unknown {
                        // Drop on the floor.
                    }
                }
            }
            dom::nk_text(*) {
                fail "attempt to link up an attribute to a text node"
            }
        }
    }
}

fn build_element_subclass(tag_name: str) -> ~element_subclass {
    alt tag_name {
        "div" { ret ~es_div; }
        "img" {
            ret ~es_img({mut size: {
                width: geom::px_to_au(100),
                height: geom::px_to_au(100)
            }});
        }
        "head" { ret ~es_head; }
        _ { ret ~es_unknown; }
    }
}

fn build_dom(scope: dom::node_scope,
             stream: port<token>) -> dom::node {
    // The current reference node.
    let mut cur = scope.new_node(dom::nk_element(element("html", ~es_div)));
    loop {
        let token = stream.recv();
        alt token {
            parser::to_eof { break; }
            parser::to_start_opening_tag(tag_name) {
                #debug["starting tag %s", tag_name];
                let element_subclass = build_element_subclass(tag_name);
                let new_node =
                    scope.new_node(dom::nk_element(element(tag_name,
                                                           element_subclass)));
                scope.add_child(cur, new_node);
                cur = new_node;
            }
            parser::to_attr(key, value) {
                #debug["attr: %? = %?", key, value];
                link_up_attribute(scope, cur, key, value);
            }
            parser::to_end_opening_tag {
                #debug("end opening tag");
            }
            parser::to_end_tag(_) | parser::to_self_close_tag {
                // TODO: Assert that the closing tag has the right name.
                // TODO: Fail more gracefully (i.e. according to the HTML5
                //       spec) if we close more tags than we open.
                cur = scope.get_parent(cur).get();
            }
            parser::to_text(s) if !s.is_whitespace() {
                let new_node = scope.new_node(dom::nk_text(s));
                scope.add_child(cur, new_node);
            }
            parser::to_text(_) {
                // FIXME: Whitespace should not be ignored.
            }
            parser::to_doctype {
                // TODO: Do something here...
            }
        }
    }
    ret cur;
}