-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
Before there was no concept of fragments and the layout step was taking the box tree as input and saving the used layout metrics into boxes themselves. This commit introduces the concept of Fragments, Fragmentainers and Fragmentation Context (https://drafts.csswg.org/css-break-4/#fragmentation-model). Currently, only pages, the block formatting context, and PDF under the 'print' command are supported. The commit mechanism was changed from an enum (yes/no) to support these new concepts. Now, since layouting the box tree generates the Fragment tree, a layout call that should commit a Fragment for a Box into the Fragment tree will: - create the said Fragment - pass a reference to the said Fragment to it child call - add the created Fragment to the list of children of its parent in the Fragment tree by using the passed reference To Fragment, breakpoints with appeal were implemented, following Chrome, https://chromium.googlesource.com/chromium/src/+/refs/heads/main/third_party/blink/renderer/core/layout/block_fragmentation_tutorial.md and its golden rule > Break at the breakpoint with the highest appeal (primary criterion) that also fits as much content as possible (secondary criterion). Co-authored-by: Paulo Medeiros <[email protected]> Co-authored-by: Nicolas Van Bossuyt <[email protected]>
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -87,26 +87,30 @@ RenderResult render(Markup::Document const &dom, Style::Media const &media, Vec2 | |
|
||
start = Sys::now(); | ||
|
||
Layout::layout( | ||
auto root = Layout::Frag(); | ||
|
||
tree.fc.createNextFragmentainer(); | ||
tree.fc.isDiscoveryMode = false; | ||
auto outDiscovery = Layout::layout( | ||
tree, | ||
tree.root, | ||
{ | ||
.commit = Layout::Commit::YES, | ||
.fragment = &root, | ||
.knownSize = {vp.small.width, NONE}, | ||
.availableSpace = {vp.small.width, 0_px}, | ||
.containingBlock = {vp.small.width, vp.small.height}, | ||
} | ||
); | ||
Layout::layoutPositioned(tree, tree.root, {vp.small.width, vp.small.height}); | ||
|
||
Layout::layoutPositioned(tree, root.children[0], {vp.small.width, vp.small.height}); | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
pauloamed
Author
Contributor
|
||
|
||
auto sceneRoot = makeStrong<Scene::Stack>(); | ||
|
||
elapsed = Sys::now() - start; | ||
logDebugIf(DEBUG_RENDER, "layout tree layout time: {}", elapsed); | ||
|
||
auto paintStart = Sys::now(); | ||
|
||
Layout::paint(tree.root, *sceneRoot); | ||
Layout::paint(root.children[0], *sceneRoot); | ||
sceneRoot->prepare(); | ||
|
||
elapsed = Sys::now() - paintStart; | ||
|
@@ -115,11 +119,12 @@ RenderResult render(Markup::Document const &dom, Style::Media const &media, Vec2 | |
return { | ||
std::move(stylebook), | ||
makeStrong<Layout::Box>(std::move(tree.root)), | ||
sceneRoot, | ||
{sceneRoot}, | ||
makeStrong<Layout::Frag>(root) | ||
}; | ||
} | ||
|
||
RenderResult render(Markup::Document &dom, Style::Media const &media, Print::PaperStock paper) { | ||
RenderResult print(Markup::Document &dom, Style::Media const &media, Vec2Px dimensions) { | ||
Style::StyleBook stylebook; | ||
stylebook.add( | ||
fetchStylesheet("bundle://vaev-view/user-agent.css"_url) | ||
|
@@ -134,36 +139,66 @@ RenderResult render(Markup::Document &dom, Style::Media const &media, Print::Pap | |
Style::Computer computer{media, stylebook}; | ||
|
||
Layout::Viewport vp{ | ||
.small = { | ||
Px{paper.width}, | ||
Px{paper.height}, | ||
}, | ||
.small = dimensions, | ||
}; | ||
|
||
Layout::Tree tree = { | ||
Layout::build(computer, dom), | ||
vp, | ||
Layout::FragmentationContext(dimensions) | ||
}; | ||
|
||
Layout::layout( | ||
tree, | ||
tree.root, | ||
{ | ||
.commit = Layout::Commit::YES, | ||
.knownSize = {vp.small.width, NONE}, | ||
.availableSpace = {vp.small.width, 0_px}, | ||
.containingBlock = {vp.small.width, vp.small.height}, | ||
auto root = Layout::Frag(); | ||
|
||
while (true) { | ||
tree.fc.createNextFragmentainer(); | ||
tree.fc.isDiscoveryMode = true; | ||
auto outDiscovery = Layout::layout( | ||
tree, | ||
tree.root, | ||
{ | ||
.knownSize = {vp.small.width, NONE}, | ||
.availableSpace = {vp.small.width, 0_px}, | ||
.containingBlock = {vp.small.width, vp.small.height}, | ||
} | ||
); | ||
|
||
if (outDiscovery.completelyLaidOut) { | ||
tree.fc.visitedWholeBox.put(&tree.root, true); | ||
} | ||
); | ||
|
||
auto sceneRoot = makeStrong<Scene::Page>(); | ||
Layout::paint(tree.root, *sceneRoot); | ||
sceneRoot->prepare(); | ||
tree.fc.pushFlagsVisitedWholeBox(tree.root); | ||
|
||
tree.fc.isDiscoveryMode = false; | ||
auto outReal = Layout::layout( | ||
tree, | ||
tree.root, | ||
{ | ||
.fragment = &root, | ||
.knownSize = {vp.small.width, NONE}, | ||
.availableSpace = {vp.small.width, 0_px}, | ||
.containingBlock = {vp.small.width, vp.small.height}, | ||
} | ||
); | ||
|
||
if (tree.fc.getStartPosition(tree.root) == 1) | ||
break; | ||
} | ||
|
||
Vec<Strong<Scene::Node>> scenes; | ||
for (auto &c : root.children) { | ||
auto scenePage = makeStrong<Scene::Page>(); | ||
Layout::paint(c, *scenePage); | ||
scenePage->prepare(); | ||
|
||
scenes.pushBack(scenePage); | ||
} | ||
|
||
return { | ||
std::move(stylebook), | ||
makeStrong<Layout::Box>(std::move(tree.root)), | ||
sceneRoot, | ||
scenes, | ||
makeStrong<Layout::Frag>(root) | ||
}; | ||
} | ||
|
||
|
root.children[0] is the Frag for the root of the box tree.
root (frag) does not have a box attached to it and breaks the layout positioned method