/
box_builder.rs
200 lines (176 loc) · 6.1 KB
/
box_builder.rs
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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
#[doc="Creates CSS boxes from a DOM."]
import dom::base::{ElementData, HTMLDivElement, HTMLImageElement, Element, Text, Node};
import dom::style::{DisplayType, DisBlock, DisInline, DisNone};
import dom::rcu::ReaderMethods;
import gfx::geometry;
import layout::base::{BlockBox, Box, BoxKind, BoxTreeReadMethods, BoxTreeWriteMethods, InlineBox};
import layout::base::{IntrinsicBox, NodeMethods, NodeTreeReadMethods, TextBox};
import layout::base::{Appearance, BTree, NTree};
import layout::style::style::{style_methods};
import layout::text::text_box;
import util::tree;
import option::is_none;
export box_builder_methods;
enum ctxt = {
// The parent node that we're scanning.
parent_node: Node,
// The parent box that these boxes will be added to.
parent_box: @Box,
//
// The current anonymous box that we're currently appending inline nodes to.
//
// See CSS2 9.2.1.1.
//
mut anon_box: option<@Box>
};
fn create_context(parent_node: Node, parent_box: @Box) -> ctxt {
ret ctxt({
parent_node: parent_node,
parent_box: parent_box,
mut anon_box: none
});
}
impl methods for ctxt {
#[doc="
Constructs boxes for the parent's children, when the parent's 'display' attribute is 'block'.
"]
fn construct_boxes_for_block_children() {
for NTree.each_child(self.parent_node) |kid| {
// Create boxes for the child. Get its primary box.
let kid_box = kid.construct_boxes();
// Determine the child's display.
let disp = kid.get_specified_style().display_type;
if disp != some(DisInline) {
self.finish_anonymous_box_if_necessary();
}
// Add the child's box to the current enclosing box or the current anonymous box.
alt kid.get_specified_style().display_type {
some(DisBlock) {
BTree.add_child(self.parent_box, kid_box);
}
some(DisInline) {
let anon_box = alt self.anon_box {
none {
//
// The anonymous box inherits the attributes of its parents for now, so
// that properties of intrinsic boxes are not spread to their parenting
// anonymous box.
//
// TODO: check what CSS actually specifies
//
let b = @Box(self.parent_node, InlineBox);
self.anon_box = some(b);
b
}
some(b) { b }
};
BTree.add_child(anon_box, kid_box);
}
some(DisNone) {
// Nothing to do.
}
_ { //hack for now
}
}
}
}
#[doc="
Constructs boxes for the parent's children, when the parent's 'display'
attribute is 'inline'.
"]
fn construct_boxes_for_inline_children() {
for NTree.each_child(self.parent_node) |kid| {
// Construct boxes for the child. Get its primary box.
let kid_box = kid.construct_boxes();
// Determine the child's display.
let disp = kid.get_specified_style().display_type;
if disp != some(DisInline) {
// TODO
}
// Add the child's box to the current enclosing box.
alt kid.get_specified_style().display_type {
some(DisBlock) {
// TODO
#warn("TODO: non-inline display found inside inline box");
BTree.add_child(self.parent_box, kid_box);
}
some(DisInline) {
BTree.add_child(self.parent_box, kid_box);
}
some(DisNone) {
// Nothing to do.
}
_ { //hack for now
}
}
}
}
#[doc="Constructs boxes for the parent's children."]
fn construct_boxes_for_children() {
#debug("parent node:");
self.parent_node.dump();
alt self.parent_node.get_specified_style().display_type {
some(DisBlock) { self.construct_boxes_for_block_children(); }
some(DisInline) { self.construct_boxes_for_inline_children(); }
some(DisNone) { /* Nothing to do. */ }
_ { //hack for now
}
}
self.finish_anonymous_box_if_necessary();
assert is_none(self.anon_box);
}
#[doc="
Flushes the anonymous box we're creating if it exists. This appends the
anonymous box to the block.
"]
fn finish_anonymous_box_if_necessary() {
alt copy self.anon_box {
none { /* Nothing to do. */ }
some(b) { BTree.add_child(self.parent_box, b); }
}
self.anon_box = none;
}
}
trait box_builder_priv {
fn determine_box_kind() -> BoxKind;
}
impl box_builder_priv of box_builder_priv for Node {
#[doc="
Determines the kind of box that this node needs. Also, for images, computes the intrinsic
size.
"]
fn determine_box_kind() -> BoxKind {
alt self.read(|n| copy n.kind) {
~Text(string) {
TextBox(@text_box(copy string))
}
~Element(element) {
alt *element.kind {
HTMLDivElement { BlockBox }
HTMLImageElement({size}) { IntrinsicBox(@size) }
UnknownElement { InlineBox }
}
}
}
}
}
trait box_builder_methods {
fn construct_boxes() -> @Box;
}
impl box_builder_methods of box_builder_methods for Node {
#[doc="Creates boxes for this node. This is the entry point."]
fn construct_boxes() -> @Box {
let box_kind = self.determine_box_kind();
let my_box = @Box(self, box_kind);
alt box_kind {
BlockBox | InlineBox {
let cx = create_context(self, my_box);
cx.construct_boxes_for_children();
}
_ {
// Nothing to do.
}
}
ret my_box;
}
}