Skip to content

Commit

Permalink
remove golbal dicts in favour of input (more functioal approach)
Browse files Browse the repository at this point in the history
  • Loading branch information
pauloamed committed Nov 25, 2024
1 parent 9411784 commit 98db090
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 134 deletions.
16 changes: 12 additions & 4 deletions src/vaev-driver/render.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,8 @@ Vec<Strong<Scene::Page>> print(Markup::Document const &dom, Style::Media const &

auto root = Layout::Frag();

Layout::Breakpoint prevBreakpoint{.endIdx = 0}, currBreakpoint;

while (true) {
tree.fc.createNextFragmentainer();
tree.fc.isDiscoveryMode = true;
Expand All @@ -162,15 +164,18 @@ Vec<Strong<Scene::Page>> print(Markup::Document const &dom, Style::Media const &
.knownSize = {vp.small.width, NONE},
.availableSpace = {vp.small.width, 0_px},
.containingBlock = {vp.small.width, vp.small.height},
.bt = Layout::BreakpointTraverser(&prevBreakpoint),
}
);

// tree.fc.breakStack = {&outDiscovery.breakpoint.unwrap()};
if (outDiscovery.completelyLaidOut) {
tree.fc.visitedWholeBox.put(&tree.root, true);
// tree.fc.breakStack = {nullptr};
currBreakpoint = Layout::Breakpoint::buildClassB(1, false);
} else {
currBreakpoint = outDiscovery.breakpoint.unwrap();
}

tree.fc.pushFlagsVisitedWholeBox(tree.root);

tree.fc.isDiscoveryMode = false;
auto outReal = Layout::layout(
tree,
Expand All @@ -180,11 +185,14 @@ Vec<Strong<Scene::Page>> print(Markup::Document const &dom, Style::Media const &
.knownSize = {vp.small.width, NONE},
.availableSpace = {vp.small.width, 0_px},
.containingBlock = {vp.small.width, vp.small.height},
.bt = Layout::BreakpointTraverser(&prevBreakpoint, &currBreakpoint),
}
);

if (tree.fc.getStartPosition(tree.root) == 1)
if (outReal.completelyLaidOut)
break;

std::swap(prevBreakpoint, currBreakpoint);
}

Vec<Strong<Scene::Page>> pages;
Expand Down
16 changes: 9 additions & 7 deletions src/vaev-layout/block.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ void maybeProcessChildBreakpoint(FragmentationContext &fc, Breakpoint &currentBr
// BREAK CLASS X (recursive case)
currentBreakpoint.overrideIfBetter(
Breakpoint::buildFromChild(
maybeChildBreakpoint.unwrap(),
std::move(maybeChildBreakpoint.unwrap()),
childIndex + 1,
currBoxIsBreakAvoid
)
Expand Down Expand Up @@ -66,7 +66,6 @@ Res<None, Output> processBreakpointsAfterChild(FragmentationContext &fc, Breakpo
childBox.style->break_->after == BreakBetween::AVOID or
(not isLastChild and parentBox.children()[childIndex + 1].style->break_->before == BreakBetween::AVOID);

fc.visitedWholeBox.put(&childBox, true); // FIXME
currentBreakpoint.overrideIfBetter(
Breakpoint::buildClassB(
childIndex + 1,
Expand All @@ -80,16 +79,18 @@ Res<None, Output> processBreakpointsAfterChild(FragmentationContext &fc, Breakpo
return Output{
.size = currentBoxSize,
.completelyLaidOut = false,
.breakpoint = Breakpoint::buildForced(childIndex + 1)
.breakpoint = Breakpoint::buildForced(
childIndex + 1
)
};
}

return Ok(NONE);
}

Res<None, Output> processBreakpointsBeforeChild(usize endAt, Vec2Px currentSize, bool forcedBreakBefore, bool isFirstChild) {
Res<None, Output> processBreakpointsBeforeChild(usize endAt, Vec2Px currentSize, bool forcedBreakBefore, usize startAt) {
// FORCED BREAK
if (forcedBreakBefore and not isFirstChild) {
if (forcedBreakBefore and not(startAt == endAt)) {
return Output{
.size = currentSize,
.completelyLaidOut = false,
Expand Down Expand Up @@ -126,7 +127,7 @@ struct BlockFormatingContext {
i,
Vec2Px{inlineSize, blockSize},
c.style->break_->before == BreakBetween::PAGE,
i == startAt
startAt
)
);

Expand All @@ -138,7 +139,8 @@ struct BlockFormatingContext {
.fragment = input.fragment,
.availableSpace = {inlineSize, 0_px},
.containingBlock = {inlineSize, input.knownSize.y.unwrapOr(0_px)},
.ancestralsBorderPadding = input.ancestralsBorderPadding
.bt = input.bt.traverseInsideUsingIthChild(i),
.ancestralsBorderPadding = input.ancestralsBorderPadding,
};

auto margin = computeMargins(tree, c, childInput);
Expand Down
48 changes: 0 additions & 48 deletions src/vaev-layout/fragmentainer.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,6 @@ struct FragmentationContext {

Vec2Px defaultSize = {Limits<Px>::MAX, Limits<Px>::MAX};

// TODO: discuss this being global with team
// TODO: merge maps into map of tuples (better memory access pattern)
Map<Box *, usize> layoutUntilComitted, layoutUntilNotComitted;

FragmentationContext() {}

FragmentationContext(Vec2Px defaultSize) : defaultSize(defaultSize) {}
Expand All @@ -47,28 +43,6 @@ struct FragmentationContext {
// NOTE: a bit rudimentar, but necessary while some displays do not have fragmentation implemented
usize monolithicCount = 0;

Map<Box *, bool> visitedWholeBox;

void _pushFlagsVisitedWholeBox(Box &b, bool subtreeIsActive) {
if (subtreeIsActive) {
setDiscoveredEndPosition(b, b.children().len());
}

if (b.children().len() == 0)
return;

bool meOrsiblingToRightIsFull = subtreeIsActive;
for (usize i = b.children().len(); i >= 1; --i) {
meOrsiblingToRightIsFull |= visitedWholeBox.has(&(b.children()[i - 1]));
_pushFlagsVisitedWholeBox(b.children()[i - 1], meOrsiblingToRightIsFull);
}
}

void pushFlagsVisitedWholeBox(Box &root) {
_pushFlagsVisitedWholeBox(root, visitedWholeBox.has(&root));
visitedWholeBox.clear();
}

void enterMonolithicBox() {
monolithicCount++;
}
Expand All @@ -92,28 +66,6 @@ struct FragmentationContext {
bool allowBreak() {
return not hasInfiniteDimensions() and monolithicCount == 0;
}

usize getStartPosition(Box &box) {
if (not layoutUntilComitted.has(&box))
return 0;
else
return layoutUntilComitted.get(&box);
}

usize getDiscoveredEndPosition(Box &box) {
// FIXME: this should not exist once all formatting contexts implement fragmentation
if (not layoutUntilNotComitted.has(&box))
return 0;
return layoutUntilNotComitted.get(&box);
}

void setDiscoveredEndPosition(Box &box, usize pos) {
layoutUntilNotComitted.put(&box, pos);
}

void setLaidOutEndPosition(Box &box, usize pos) {
layoutUntilComitted.put(&box, pos);
}
};

} // namespace Vaev::Layout
166 changes: 104 additions & 62 deletions src/vaev-layout/input_output.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,66 +5,14 @@

namespace Vaev::Layout {

/// Input to the layout algorithm.
struct Input {
/// Parent fragment where the layout will be attached.
MutCursor<Frag> fragment = nullptr;
IntrinsicSize intrinsic = IntrinsicSize::AUTO;
Math::Vec2<Opt<Px>> knownSize = {};
Vec2Px position = {};
Vec2Px availableSpace = {};
Vec2Px containingBlock = {};

// TODO: instead of stringing this around, maybe change this (and check method of fragmentainer) to a
// "availableSpaceInFragmentainer" parameter
Vec2Px ancestralsBorderPadding = {};

Input withFragment(MutCursor<Frag> f) const {
auto copy = *this;
copy.fragment = f;
return copy;
}

Input withIntrinsic(IntrinsicSize i) const {
auto copy = *this;
copy.intrinsic = i;
return copy;
}

Input withKnownSize(Math::Vec2<Opt<Px>> size) const {
auto copy = *this;
copy.knownSize = size;
return copy;
}

Input withPosition(Vec2Px pos) const {
auto copy = *this;
copy.position = pos;
return copy;
}

Input withAvailableSpace(Vec2Px space) const {
auto copy = *this;
copy.availableSpace = space;
return copy;
}

Input withContainingBlock(Vec2Px block) const {
auto copy = *this;
copy.containingBlock = block;
return copy;
}
};

// NOTE: all these comments might be erased once we are secure on the strucutre and have proper documentation

// TODO: consider adding classification for breakpoints, what would make appeal computing easier and less error prone
struct Breakpoint {
static usize const AVOID_APPEAL = 1;
static usize const CLASS_B_APPEAL = 2;

// only children with (index < endChildren) will be laid out
usize endChildren = 0;
usize endIdx = 0;

// appeal = 0: an overflow occured; we want the earliest breakpoint possible
// appeal > 0: no overflow occured: we want the latest breakpoint possible with biggest appeal
Expand All @@ -74,6 +22,8 @@ struct Breakpoint {
// attribution could should be encapsulated in this class, instead of exposed to code
usize appeal = 0;

Vec<Breakpoint> child = {};

void overrideIfBetter(Breakpoint &&BPWithMoreContent) {
if (appeal == 0 and BPWithMoreContent.appeal == 0)
return;
Expand All @@ -83,21 +33,26 @@ struct Breakpoint {
}

void repr(Io::Emit &e) const {
e("(endChildren: {} appeal: {})", endChildren, appeal);
e("(end: {} appeal: {}", endIdx, appeal);
if (child.len() == 0)
e("; no child)");
else
e("; child : {})", child[0]);
}

static Breakpoint buildForced(usize endIndex) {
static Breakpoint buildForced(usize endIdx) {
return Breakpoint{
.endChildren = endIndex,
.endIdx = endIdx,
// since this is a FORCED break, it will have maximum appeal
.appeal = Limits<usize>::MAX
};
}

static Breakpoint buildFromChild(Breakpoint childBreakpoint, usize endIndex, bool isAvoid) {
static Breakpoint buildFromChild(Breakpoint &&childBreakpoint, usize endIdx, bool isAvoid) {
Breakpoint b{
.endChildren = endIndex,
.appeal = childBreakpoint.appeal
.endIdx = endIdx,
.appeal = childBreakpoint.appeal,
.child = {std::move(childBreakpoint)}
};

if (isAvoid)
Expand All @@ -106,9 +61,9 @@ struct Breakpoint {
return b;
}

static Breakpoint buildClassB(usize endIndex, bool isAvoid) {
static Breakpoint buildClassB(usize endIdx, bool isAvoid) {
Breakpoint b{
.endChildren = endIndex,
.endIdx = endIdx,
.appeal = isAvoid ? AVOID_APPEAL : CLASS_B_APPEAL
};

Expand All @@ -118,12 +73,99 @@ struct Breakpoint {
static Breakpoint buildOverflow() {
// this is a placeholder breakpoint and should be overriden
return {
.endChildren = 0,
.endIdx = 0,
.appeal = 0
};
}
};

struct BreakpointTraverser {
MutCursor<Breakpoint> prevIteration, currIteration;

BreakpointTraverser(
MutCursor<Breakpoint> prev = nullptr,
MutCursor<Breakpoint> curr = nullptr
) : prevIteration(prev), currIteration(curr) {}

BreakpointTraverser traverseInsideUsingIthChild(usize i) {
BreakpointTraverser deeperBPT;
if (prevIteration and prevIteration->child.len() > 0 and i + 1 == prevIteration->endIdx) {
deeperBPT.prevIteration = &prevIteration->child[0];
}

if (currIteration and currIteration->child.len() > 0 and i + 1 == currIteration->endIdx) {
deeperBPT.currIteration = &currIteration->child[0];
}

return deeperBPT;
}

Opt<usize> getStart() {
if (prevIteration == nullptr)
return NONE;
return prevIteration->endIdx - (prevIteration->child.len() ? 1 : 0);
}

Opt<usize> getEnd() {
if (currIteration == nullptr)
return NONE;
return currIteration->endIdx;
}
};

/// Input to the layout algorithm.
struct Input {
/// Parent fragment where the layout will be attached.
MutCursor<Frag> fragment = nullptr;
IntrinsicSize intrinsic = IntrinsicSize::AUTO;
Math::Vec2<Opt<Px>> knownSize = {};
Vec2Px position = {};
Vec2Px availableSpace = {};
Vec2Px containingBlock = {};

BreakpointTraverser bt = {};

// TODO: instead of stringing this around, maybe change this (and check method of fragmentainer) to a
// "availableSpaceInFragmentainer" parameter
Vec2Px ancestralsBorderPadding = {};

Input withFragment(MutCursor<Frag> f) const {
auto copy = *this;
copy.fragment = f;
return copy;
}

Input withIntrinsic(IntrinsicSize i) const {
auto copy = *this;
copy.intrinsic = i;
return copy;
}

Input withKnownSize(Math::Vec2<Opt<Px>> size) const {
auto copy = *this;
copy.knownSize = size;
return copy;
}

Input withPosition(Vec2Px pos) const {
auto copy = *this;
copy.position = pos;
return copy;
}

Input withAvailableSpace(Vec2Px space) const {
auto copy = *this;
copy.availableSpace = space;
return copy;
}

Input withContainingBlock(Vec2Px block) const {
auto copy = *this;
copy.containingBlock = block;
return copy;
}
};

struct Output {
// size of subtree maximizing displayed content while respecting
// - endchild constraint or
Expand Down
Loading

0 comments on commit 98db090

Please sign in to comment.