Skip to content

Commit bc0f3b2

Browse files
committed
vaev-style: Add running positions, content element() and counter = page to allow beautiful margins.
1 parent 4fab3cf commit bc0f3b2

File tree

13 files changed

+425
-99
lines changed

13 files changed

+425
-99
lines changed

src/vaev-engine/driver/print.cpp

Lines changed: 96 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ import :css;
1919

2020
namespace Vaev::Driver {
2121

22-
void _paintCornerMargin(Style::PageSpecifiedValues& pageStyle, Scene::Stack& stack, RectAu const& rect, Style::PageArea area) {
22+
void _paintCornerMargin(Style::PageSpecifiedValues& pageStyle, Scene::Stack& stack, RectAu const& rect, Style::PageArea area, usize& currentPage, Map<String, Vec<Layout::RunningPositionInfo>>& runningPosition) {
2323
Layout::Tree tree{
24-
.root = Layout::buildForPseudoElement(pageStyle.area(area)),
24+
.root = Layout::buildForPseudoElement(pageStyle.area(area), currentPage, runningPosition),
2525
.viewport = Layout::Viewport{.small = rect.size()}
2626
};
2727
auto [_, frag] = Layout::layoutCreateFragment(
@@ -36,10 +36,10 @@ void _paintCornerMargin(Style::PageSpecifiedValues& pageStyle, Scene::Stack& sta
3636
Layout::paint(frag, stack);
3737
}
3838

39-
void _paintMainMargin(Style::PageSpecifiedValues& pageStyle, Scene::Stack& stack, RectAu const& rect, Style::PageArea mainArea, Array<Style::PageArea, 3> subAreas) {
40-
auto box = Layout::buildForPseudoElement(pageStyle.area(mainArea));
39+
void _paintMainMargin(Style::PageSpecifiedValues& pageStyle, Scene::Stack& stack, RectAu const& rect, Style::PageArea mainArea, Array<Style::PageArea, 3> subAreas, usize& currentPage, Map<String, Vec<Layout::RunningPositionInfo>>& runningPosition) {
40+
auto box = Layout::buildForPseudoElement(pageStyle.area(mainArea), currentPage, runningPosition);
4141
for (auto subArea : subAreas) {
42-
box.add(Layout::buildForPseudoElement(pageStyle.area(subArea)));
42+
box.add(Layout::buildForPseudoElement(pageStyle.area(subArea), currentPage, runningPosition));
4343
}
4444
Layout::Tree tree{
4545
.root = std::move(box),
@@ -57,18 +57,18 @@ void _paintMainMargin(Style::PageSpecifiedValues& pageStyle, Scene::Stack& stack
5757
Layout::paint(frag, stack);
5858
}
5959

60-
void _paintMargins(Style::PageSpecifiedValues& pageStyle, RectAu pageRect, RectAu pageContent, Scene::Stack& stack) {
60+
void _paintMargins(Style::PageSpecifiedValues& pageStyle, RectAu pageRect, RectAu pageContent, Scene::Stack& stack, usize& currentPage, Map<String, Vec<Layout::RunningPositionInfo>>& runningPosition) {
6161
// Compute all corner rects
6262
auto topLeftMarginCornerRect = RectAu::fromTwoPoint(pageRect.topStart(), pageContent.topStart());
6363
auto topRightMarginCornerRect = RectAu::fromTwoPoint(pageRect.topEnd(), pageContent.topEnd());
6464
auto bottomLeftMarginCornerRect = RectAu::fromTwoPoint(pageRect.bottomStart(), pageContent.bottomStart());
6565
auto bottomRightMarginCornerRect = RectAu::fromTwoPoint(pageRect.bottomEnd(), pageContent.bottomEnd());
6666

6767
// Paint corners
68-
_paintCornerMargin(pageStyle, stack, topLeftMarginCornerRect, Style::PageArea::TOP_LEFT_CORNER);
69-
_paintCornerMargin(pageStyle, stack, topRightMarginCornerRect, Style::PageArea::TOP_RIGHT_CORNER);
70-
_paintCornerMargin(pageStyle, stack, bottomLeftMarginCornerRect, Style::PageArea::BOTTOM_LEFT_CORNER);
71-
_paintCornerMargin(pageStyle, stack, bottomRightMarginCornerRect, Style::PageArea::BOTTOM_RIGHT_CORNER);
68+
_paintCornerMargin(pageStyle, stack, topLeftMarginCornerRect, Style::PageArea::TOP_LEFT_CORNER, currentPage, runningPosition);
69+
_paintCornerMargin(pageStyle, stack, topRightMarginCornerRect, Style::PageArea::TOP_RIGHT_CORNER, currentPage, runningPosition);
70+
_paintCornerMargin(pageStyle, stack, bottomLeftMarginCornerRect, Style::PageArea::BOTTOM_LEFT_CORNER, currentPage, runningPosition);
71+
_paintCornerMargin(pageStyle, stack, bottomRightMarginCornerRect, Style::PageArea::BOTTOM_RIGHT_CORNER, currentPage, runningPosition);
7272

7373
// Compute main area rects
7474
auto topRect = RectAu::fromTwoPoint(topLeftMarginCornerRect.topEnd(), topRightMarginCornerRect.bottomStart());
@@ -77,10 +77,10 @@ void _paintMargins(Style::PageSpecifiedValues& pageStyle, RectAu pageRect, RectA
7777
auto rightRect = RectAu::fromTwoPoint(topRightMarginCornerRect.bottomEnd(), bottomRightMarginCornerRect.topStart());
7878

7979
// Paint main areas
80-
_paintMainMargin(pageStyle, stack, topRect, Style::PageArea::TOP, {Style::PageArea::TOP_LEFT, Style::PageArea::TOP_CENTER, Style::PageArea::TOP_RIGHT});
81-
_paintMainMargin(pageStyle, stack, bottomRect, Style::PageArea::BOTTOM, {Style::PageArea::BOTTOM_LEFT, Style::PageArea::BOTTOM_CENTER, Style::PageArea::BOTTOM_RIGHT});
82-
_paintMainMargin(pageStyle, stack, leftRect, Style::PageArea::LEFT, {Style::PageArea::LEFT_TOP, Style::PageArea::LEFT_MIDDLE, Style::PageArea::LEFT_BOTTOM});
83-
_paintMainMargin(pageStyle, stack, rightRect, Style::PageArea::RIGHT, {Style::PageArea::RIGHT_TOP, Style::PageArea::RIGHT_MIDDLE, Style::PageArea::RIGHT_BOTTOM});
80+
_paintMainMargin(pageStyle, stack, topRect, Style::PageArea::TOP, {Style::PageArea::TOP_LEFT, Style::PageArea::TOP_CENTER, Style::PageArea::TOP_RIGHT}, currentPage, runningPosition);
81+
_paintMainMargin(pageStyle, stack, bottomRect, Style::PageArea::BOTTOM, {Style::PageArea::BOTTOM_LEFT, Style::PageArea::BOTTOM_CENTER, Style::PageArea::BOTTOM_RIGHT}, currentPage, runningPosition);
82+
_paintMainMargin(pageStyle, stack, leftRect, Style::PageArea::LEFT, {Style::PageArea::LEFT_TOP, Style::PageArea::LEFT_MIDDLE, Style::PageArea::LEFT_BOTTOM}, currentPage, runningPosition);
83+
_paintMainMargin(pageStyle, stack, rightRect, Style::PageArea::RIGHT, {Style::PageArea::RIGHT_TOP, Style::PageArea::RIGHT_MIDDLE, Style::PageArea::RIGHT_BOTTOM}, currentPage, runningPosition);
8484
}
8585

8686
static Style::Media _constructMedia(Print::Settings const& settings) {
@@ -122,48 +122,32 @@ static Style::Media _constructMedia(Print::Settings const& settings) {
122122
};
123123
}
124124

125-
export Generator<Print::Page> print(Gc::Ref<Dom::Document> dom, Print::Settings const& settings) {
126-
auto media = _constructMedia(settings);
127-
128-
Text::FontBook fontBook;
129-
if (not fontBook.loadAll())
130-
logWarn("not all fonts were properly loaded into fontbook");
131-
132-
Style::Computer computer{
133-
media, *dom->styleSheets, fontBook
134-
};
135-
computer.build();
136-
computer.styleDocument(*dom);
137-
138-
// MARK: Page and Margins --------------------------------------------------
139-
140-
Style::SpecifiedValues initialStyle = Style::SpecifiedValues::initial();
141-
initialStyle.color = Gfx::BLACK;
142-
initialStyle.setCustomProp("-vaev-url", {Css::Token::string(Io::format("\"{}\"", dom->url()))});
143-
initialStyle.setCustomProp("-vaev-title", {Css::Token::string(Io::format("\"{}\"", dom->title()))});
144-
initialStyle.setCustomProp("-vaev-datetime", {Css::Token::string(Io::format("\"{}\"", Sys::now()))});
145-
146-
// MARK: Page Content ------------------------------------------------------
125+
struct PageLayoutInfos {
126+
RectAu pageRect;
127+
Rc<Style::PageSpecifiedValues> pageStyle;
128+
RectAu pageContent;
147129

148-
Layout::Tree contentTree = {
149-
Layout::build(dom),
150-
};
151-
auto canvasColor = fixupBackgrounds(computer, dom, contentTree);
130+
PageLayoutInfos(RectAu pageRect, Rc<Style::PageSpecifiedValues> pageStyle, RectAu pageContent) : pageRect{pageRect}, pageStyle{pageStyle}, pageContent{pageContent} {}
131+
};
152132

133+
Pair<Vec<Layout::Breakpoint>, Vec<PageLayoutInfos>> collectBreakPointsAndRunningPositions(auto& runningPosition, Layout::Tree& contentTree, auto& media, auto& settings, auto& computer, auto& initialStyle) {
134+
usize pageNumber = 0;
153135
Layout::Breakpoint prevBreakpoint{
154136
.endIdx = 0,
155137
.advance = Layout::Breakpoint::Advance::WITHOUT_CHILDREN
156138
};
157139

158-
usize pageNumber = 0;
140+
Vec<Layout::Breakpoint> breakpoints = {prevBreakpoint};
141+
Vec<PageLayoutInfos> pageInfos = {};
142+
159143
while (true) {
160144
Style::Page page{
161145
.name = ""s,
162146
.number = pageNumber++,
163147
.blank = false,
164148
};
165149

166-
auto pageStyle = computer.computeFor(initialStyle, page);
150+
Rc<Style::PageSpecifiedValues> pageStyle = computer.computeFor(initialStyle, page);
167151
RectAu pageRect{
168152
media.width / Au{media.resolution.toDppx()},
169153
media.height / Au{media.resolution.toDppx()}
@@ -184,31 +168,32 @@ export Generator<Print::Page> print(Gc::Ref<Dom::Document> dom, Print::Settings
184168
resolver.resolve(pageStyle->style->margin->start, pageRect.width),
185169
};
186170
} else if (settings.margins == Print::Margins::CUSTOM) {
187-
pageMargin = settings.margins.custom.cast<Au>();
171+
pageMargin = settings.margins.custom.template cast<Au>();
188172
} else if (settings.margins == Print::Margins::MINIMUM) {
189173
pageMargin = {};
190174
}
191175

192176
RectAu pageContent = pageRect.shrink(pageMargin);
193177

178+
pageInfos.pushBack({pageRect, pageStyle, pageContent});
179+
194180
Layout::Viewport vp{
195181
.small = pageContent.size(),
196182
};
197183

198184
contentTree.viewport = vp;
199185
contentTree.fc = {pageContent.size()};
200186

201-
if (settings.headerFooter and settings.margins != Print::Margins::NONE)
202-
_paintMargins(*pageStyle, pageRect, pageContent, *pageStack);
203-
204187
Layout::Input pageLayoutInput{
205188
.knownSize = {pageContent.width, NONE},
206189
.position = pageContent.topStart(),
207190
.availableSpace = pageContent.size(),
208191
.containingBlock = pageContent.size(),
192+
.page = page,
209193
};
210-
194+
pageLayoutInput.runningPosition = {&runningPosition};
211195
contentTree.fc.enterDiscovery();
196+
212197
auto outDiscovery = Layout::layout(
213198
contentTree,
214199
pageLayoutInput.withBreakpointTraverser(Layout::BreakpointTraverser(&prevBreakpoint))
@@ -220,21 +205,79 @@ export Generator<Print::Page> print(Gc::Ref<Dom::Document> dom, Print::Settings
220205
: outDiscovery.breakpoint.unwrap();
221206

222207
contentTree.fc.leaveDiscovery();
208+
209+
breakpoints.pushBack(currBreakpoint);
210+
if (outDiscovery.completelyLaidOut)
211+
break;
212+
213+
prevBreakpoint = std::move(currBreakpoint);
214+
}
215+
216+
return {breakpoints, pageInfos};
217+
}
218+
219+
export Generator<Print::Page> print(Gc::Ref<Dom::Document> dom, Print::Settings const& settings) {
220+
auto media = _constructMedia(settings);
221+
222+
Text::FontBook fontBook;
223+
if (not fontBook.loadAll())
224+
logWarn("not all fonts were properly loaded into fontbook");
225+
226+
Style::Computer computer{
227+
media, *dom->styleSheets, fontBook
228+
};
229+
computer.build();
230+
computer.styleDocument(*dom);
231+
232+
// MARK: Page and Margins --------------------------------------------------
233+
234+
Style::SpecifiedValues initialStyle = Style::SpecifiedValues::initial();
235+
initialStyle.color = Gfx::BLACK;
236+
initialStyle.setCustomProp("-vaev-url", {Css::Token::string(Io::format("\"{}\"", dom->url()))});
237+
initialStyle.setCustomProp("-vaev-title", {Css::Token::string(Io::format("\"{}\"", dom->title()))});
238+
initialStyle.setCustomProp("-vaev-datetime", {Css::Token::string(Io::format("\"{}\"", Sys::now()))});
239+
240+
// MARK: Page Content ------------------------------------------------------
241+
242+
Layout::Tree contentTree = {
243+
Layout::build(dom),
244+
};
245+
auto canvasColor = fixupBackgrounds(computer, dom, contentTree);
246+
247+
Map<String, Vec<Layout::RunningPositionInfo>> runningPosition = {}; // Mapping the different Running positions to their respective names and their page.
248+
249+
auto [breakpoints, pageInfos] = collectBreakPointsAndRunningPositions(runningPosition, contentTree, media, settings, computer, initialStyle);
250+
251+
for (usize pageNumber = 0; pageNumber < breakpoints.len() - 1; pageNumber++) {
252+
Style::Page page{
253+
.name = ""s,
254+
.number = pageNumber,
255+
.blank = false,
256+
};
257+
258+
auto pageStack = makeRc<Scene::Stack>();
259+
260+
Layout::Input pageLayoutInput{
261+
.knownSize = {pageInfos[pageNumber].pageContent.width, NONE},
262+
.position = pageInfos[pageNumber].pageContent.topStart(),
263+
.availableSpace = pageInfos[pageNumber].pageContent.size(),
264+
.containingBlock = pageInfos[pageNumber].pageContent.size(),
265+
.page = page,
266+
};
267+
223268
auto [outFragmentation, fragment] = Layout::layoutCreateFragment(
224269
contentTree,
225270
pageLayoutInput
226-
.withBreakpointTraverser(Layout::BreakpointTraverser(&prevBreakpoint, &currBreakpoint))
271+
.withBreakpointTraverser(Layout::BreakpointTraverser(&breakpoints[pageNumber], &breakpoints[pageNumber + 1]))
227272
);
228273

274+
if (settings.headerFooter and settings.margins != Print::Margins::NONE)
275+
_paintMargins(*pageInfos[pageNumber].pageStyle, pageInfos[pageNumber].pageRect, pageInfos[pageNumber].pageContent, *pageStack, page.number, runningPosition);
276+
229277
Layout::paint(fragment, *pageStack);
230278
pageStack->prepare();
231279

232280
co_yield Print::Page(settings.paper, makeRc<Scene::Clear>(makeRc<Scene::Transform>(pageStack, Math::Trans2f::scale(media.resolution.toDppx())), canvasColor));
233-
234-
if (outFragmentation.completelyLaidOut)
235-
break;
236-
237-
prevBreakpoint = std::move(currBreakpoint);
238281
}
239282
}
240283

src/vaev-engine/layout/base.cpp

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,7 @@ export struct Attrs {
352352
}
353353
};
354354

355-
struct Box : Meta::NoCopy {
355+
struct Box {
356356
Rc<Style::SpecifiedValues> style;
357357
Rc<Text::Fontface> fontFace;
358358
Content content = NONE;
@@ -658,6 +658,21 @@ void SVG::GroupFrag::computeBoundingBoxes(SVG::GroupFrag* group) {
658658
group->_strokeBoundingBox = strokeBoundingBox;
659659
}
660660

661+
// MARK: RunningPos ------------------------------------------------------------
662+
663+
export struct RunningPositionInfo {
664+
usize page;
665+
RunningPosition running;
666+
Box structure;
667+
668+
RunningPositionInfo(usize page, RunningPosition running, Box structure) : page(page), running(running), structure(structure) {
669+
}
670+
671+
void repr(Io::Emit& e) const {
672+
e("runningPosInfos '\nrunning:{} \npage:{} \nstructure:{}'", running, page, structure);
673+
}
674+
};
675+
661676
// MARK: Input & Output --------------------------------------------------------
662677

663678
export enum struct IntrinsicSize {
@@ -680,6 +695,12 @@ export struct Input {
680695
Vec2Au position = {};
681696
Vec2Au availableSpace = {};
682697
Vec2Au containingBlock = {};
698+
MutCursor<Map<String, Vec<RunningPositionInfo>>> runningPosition = nullptr;
699+
Style::Page page = {
700+
.name = ""s,
701+
.number = 0,
702+
.blank = false,
703+
};
683704

684705
BreakpointTraverser breakpointTraverser = {};
685706

0 commit comments

Comments
 (0)