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
|
import unicode
import types/enums
import html/dom
import css/box
import css/style
import io/buffer
import io/cell
import utils/twtstr
proc generateGrids(text: Text, maxwidth: int, maxheight: int, x: int, y: int, fromx: int = x): seq[CSSRowBox] =
var r: Rune
var rowbox: CSSRowBox
var i = 0
var whitespace = false
if fromx > x:
let m = fromx - x + maxwidth
var w = 0
while i < text.data.len:
let pi = i
fastRuneAt(text.data, i, r)
let rw = r.width()
if rw + w > m:
i = pi
break
else:
if r.isWhitespace():
if not whitespace:
whitespace = true
rowbox.runes.add(Rune(' '))
inc rowbox.width
w += rw
else:
if whitespace:
whitespace = false
rowbox.runes.add(r)
inc rowbox.width
w += rw
result.add(rowbox)
if i < text.data.len:
rowbox = CSSRowBox()
var w = 0
while i < text.data.len:
let pi = i
fastRuneAt(text.data, i, r)
let rw = r.width()
if rw + w > maxwidth:
i = pi
w = 0
result.add(rowbox)
rowbox = CSSRowBox()
else:
rowbox.runes.add(r)
inc rowbox.width
w += rw
if rowbox.width > 0:
result.add(rowbox)
proc generateBox(text: Text, maxwidth: int, maxheight: int, x: int, y: int, fromx: int): CSSInlineBox =
new(result)
result.content = text.generateGrids(maxwidth, maxheight, x, y, fromx)
result.fromx = fromx
result.innerEdge.x1 = x
result.innerEdge.y1 = y
var height = 0
var width = 0
for grid in result.content:
inc height
width = max(width, grid.width)
height = min(height, maxheight)
width = min(width, maxwidth)
result.innerEdge.x2 = x + width
result.innerEdge.y2 = y + height
proc generateBox(elem: Element, maxwidth: int, maxheight: int, x: int = 0, y: int = 0, fromx: int = x): CSSBox
proc generateChildBoxes(elem: Element, maxwidth: int, maxheight: int, x: int, y: int, fromx: int = 0): seq[CSSBox] =
var cx = fromx
var cy = y
for child in elem.childNodes:
case child.nodeType
of TEXT_NODE:
let box = Text(child).generateBox(maxwidth, maxheight, x, cy, cx)
if box != nil:
result.add(box)
cy += box.h
if box.content.len > 0:
cx = box.content[^1].width
of ELEMENT_NODE:
let box = Element(child).generateBox(maxwidth, maxheight, x, cy, cx)
if box != nil:
result.add(box)
else:
discard
proc generateBox(elem: Element, maxwidth: int, maxheight: int, x: int = 0, y: int = 0, fromx: int = x): CSSBox =
if elem.cssvalues[RULE_DISPLAY].display == DISPLAY_NONE:
return nil
result = CSSBlockBox()
result.innerEdge.x1 = x
result.innerEdge.y1 = y
var width = 0
var height = 0
for box in elem.generateChildBoxes(maxwidth, maxheight, x, y, fromx):
result.children.add(box)
height += box.h
height = min(height, maxheight)
width = max(width, box.w)
width = min(width, maxwidth)
result.innerEdge.x2 = x + width
result.innerEdge.y2 = y + height
proc alignBoxes*(buffer: Buffer) =
buffer.rootbox = buffer.document.root.generateBox(buffer.width, buffer.height)
|