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
106
107
108
109
110
|
#[doc="Constructs a DOM tree from an incoming token stream."]
import dom::rcu::writer_methods;
import dom::base::{Attr, Element, ElementData, ElementKind, HTMLDivElement, HTMLHeadElement};
import dom::base::{HTMLImageElement, Node, NodeScope, Text, UnknownElement, rd_tree_ops};
import dom::base::{wr_tree_ops};
import dom = dom::base;
import dvec::extensions;
import geom::size::Size2D;
import gfx::geometry;
import gfx::geometry::au;
import parser = parser::lexer::html;
import parser::token;
fn link_up_attribute(scope: NodeScope, node: 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 {
Element(element) {
element.attrs.push(~Attr(copy key, copy value));
alt *element.kind {
HTMLImageElement(img) if key == "width" {
alt int::from_str(value) {
none {
// Drop on the floor.
}
some(s) { img.size.width = geometry::px_to_au(s); }
}
}
HTMLImageElement(img) if key == "height" {
alt int::from_str(value) {
none {
// Drop on the floor.
}
some(s) {
img.size.height = geometry::px_to_au(s);
}
}
}
HTMLDivElement | HTMLImageElement(*) | HTMLHeadElement | UnknownElement {
// Drop on the floor.
}
}
}
Text(*) {
fail "attempt to link up an attribute to a text node"
}
}
}
}
fn build_element_kind(tag_name: str) -> ~ElementKind {
alt tag_name {
"div" { ~HTMLDivElement }
"img" {
~HTMLImageElement({
mut size: Size2D(geometry::px_to_au(100),
geometry::px_to_au(100))
})
}
"head" { ~HTMLHeadElement }
_ { ~UnknownElement }
}
}
fn build_dom(scope: NodeScope, stream: port<token>) -> Node {
// The current reference node.
let mut cur = scope.new_node(Element(ElementData("html", ~HTMLDivElement)));
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_kind = build_element_kind(tag_name);
let new_node = scope.new_node(Element(ElementData(tag_name, element_kind)));
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 s <- s;
let new_node = scope.new_node(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;
}
|