-
Notifications
You must be signed in to change notification settings - Fork 43
Expand file tree
/
Copy pathrunning-position.cpp
More file actions
119 lines (93 loc) 路 3.37 KB
/
Copy pathrunning-position.cpp
File metadata and controls
119 lines (93 loc) 路 3.37 KB
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
export module Vaev.Engine:layout.runningPosition;
import Karm.Core;
import Karm.Math;
import :values.insets;
import :values.content;
import :layout.box;
using namespace Karm;
namespace Vaev::Layout {
// MARK: RunningPos ------------------------------------------------------------
export struct RunningPositionInfo {
usize page;
RunningPosition running;
Gc::Ref<Dom::Element> element;
RunningPositionInfo(usize page, RunningPosition running, Gc::Ref<Dom::Element> element)
: page(page), running(running), element(element) {
}
void repr(Io::Emit& e) const {
e("runningPosInfos \nrunning:{} \npage:{} \nelement:{}", running, page, element);
}
};
// Mapping the different Running positions to their respective names and their page.
struct Runnings {
Map<CustomIdent, Vec<RunningPositionInfo>> content;
void add(usize pageNumber, Box& box) {
auto& style = box.style;
if (auto position = style->position.is<RunningPosition>()) {
auto const origin = box.origin;
if (box.origin == nullptr)
return;
RunningPositionInfo info = {pageNumber, *position, origin.upgrade()};
content.getOrDefault(position->customIdent)
.pushBack(std::move(info));
}
}
// https://www.w3.org/TR/css-gcpm-3/#using-named-strings
Res<RunningPositionInfo> match(ElementContent elt, usize currentPage = 0) {
auto id = elt.customIdent;
if (not content.has(id)) {
return Error::notFound("element not found");
}
auto const& list = content.get(id);
switch (elt.target) {
case ElementContent::Target::UNDEFINED:
return Ok(list[0]);
case ElementContent::Target::START:
for (usize i = 0; i < list.len(); i++) {
auto elt = list[i];
if (elt.page == currentPage and i > 0) {
return Ok(list[i - 1]);
}
}
return Ok(list[0]);
case ElementContent::Target::FIRST:
case ElementContent::Target::FIRST_EXCEPT: {
auto elements = _searchPage(list, currentPage);
return Ok(elements[0]);
}
case ElementContent::Target::LAST: {
auto elements = _searchPage(list, currentPage);
return Ok(elements[elements.len() - 1]);
}
}
}
Slice<RunningPositionInfo> _searchPage(Slice<RunningPositionInfo> list, usize page) {
// binary search of all running positions that match the page
auto res = search(list, [&](RunningPositionInfo const& info) {
if (info.page == page) {
return std::strong_ordering::equal;
}
return info.page <=> page;
});
if (not res) {
return sub(list, 0, 1);
}
// a random element of the page
auto index = res.take();
// search left side for first element of the page
usize l = index;
while (l > 0 and list[l - 1].page == page) {
l--;
}
// search right side for last element of the page
usize r = index;
while (r < list.len() - 1 and list[r + 1].page == page) {
r++;
}
return sub(list, l, r + 1);
}
void repr(Io::Emit& e) const {
e("{}", content);
}
};
} // namespace Vaev::Layout