Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
pauloamed committed Dec 3, 2024
1 parent c02cd2e commit 3e45313
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 113 deletions.
148 changes: 118 additions & 30 deletions src/web/vaev-layout/block.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,76 @@ namespace Vaev::Layout {

// https://www.w3.org/TR/CSS22/visuren.html#normal-flow
struct BlockFormatingContext {
Output run(Tree &tree, Box &box, Input input) {

Vec<MutCursor<Box>> captionBoxes(Box &box) {
Vec<MutCursor<Box>> captionBoxes;
for (auto &c : box.children()) {
if (c.style->display != Display::TABLE_BOX) {
captionBoxes.pushBack(&c);
}
}
return captionBoxes;
}

Px computeCAPMIN(Tree &tree, Box &box, Input input) {
Px capmin{};
for (auto &c : captionBoxes(box)) {
if (c->style->display != Display::TABLE_BOX) {
Px minContentContrib =
computeIntrinsicSize(
tree, *c, IntrinsicSize::MIN_CONTENT, input.containingBlock
)
.width;
capmin = max(
capmin,
minContentContrib
);
}
}
return capmin;
}

Tuple<Output, InsetsPx> layoutBlockChild(Tree &tree, Box &box, Input &input, Box &c, Px inlineSize, Px blockSize) {
// TODO: Implement floating
// if (c.style->float_ != Float::NONE)
// continue;

Input childInput = {
.commit = input.commit,
.intrinsic = input.intrinsic,
.availableSpace = {inlineSize, 0_px},
.containingBlock = {inlineSize, input.knownSize.y.unwrapOr(0_px)},
};

auto margin = computeMargins(tree, c, childInput);

Opt<Px> childInlineSize = NONE;
if (c.style->sizing->width == Size::AUTO) {
childInlineSize = inlineSize - margin.horizontal();
}

if (c.style->position != Position::ABSOLUTE) {
blockSize += margin.top;
if (input.commit == Commit::YES or input.knownSize.x)
childInput.knownSize.width = childInlineSize;
}

childInput.position = input.position + Vec2Px{margin.start, blockSize};

if (c.style->display == Display::Internal::TABLE_BOX) {
childInput.capmin = computeCAPMIN(tree, box, input);
}

auto output = layout(
tree,
c,
childInput
);

return {output, margin};
}

Output runBlock(Tree &tree, Box &box, Input input) {
Px blockSize = 0_px;
Px inlineSize = input.knownSize.width.unwrapOr(0_px);

Expand All @@ -17,50 +86,69 @@ struct BlockFormatingContext {
inlineSize = run(tree, box, input.withCommit(Commit::NO)).width();

for (auto &c : box.children()) {
// TODO: Implement floating
// if (c.style->float_ != Float::NONE)
// continue;

Input childInput = {
.commit = input.commit,
.intrinsic = input.intrinsic,
.availableSpace = {inlineSize, 0_px},
.containingBlock = {inlineSize, input.knownSize.y.unwrapOr(0_px)},
};

auto margin = computeMargins(tree, c, childInput);

Opt<Px> childInlineSize = NONE;
if (c.style->sizing->width == Size::AUTO) {
childInlineSize = inlineSize - margin.horizontal();
auto [output, margin] = layoutBlockChild(tree, box, input, c, inlineSize, blockSize);
if (c.style->position != Position::ABSOLUTE) {
blockSize += output.size.y + margin.bottom;
}

if (c.style->position != Position::ABSOLUTE) {
blockSize += margin.top;
if (input.commit == Commit::YES or input.knownSize.x)
childInput.knownSize.width = childInlineSize;
inlineSize = max(inlineSize, output.size.x + margin.horizontal());
}

return Output::fromSize({
inlineSize,
blockSize,
});
}

Output runTableWrapper(Tree &tree, Box &box, Input input) {

Px blockSize = 0_px;
Px inlineSize = input.knownSize.width.unwrapOr(0_px);

MutCursor<Box> tableBox;
for (auto &c : box.children()) {
if (c.style->display == Display::Internal::TABLE_BOX) {
tableBox = &c;
break;
}
}

childInput.position = input.position + Vec2Px{margin.start, blockSize};
input.knownSize.x = NONE;

auto ouput = layout(
tree,
c,
childInput
);
auto [outputInlineSize, marginInlineSize] = layoutBlockChild(tree, box, input, *tableBox, inlineSize, blockSize);
inlineSize = outputInlineSize.width() + marginInlineSize.horizontal();

if (c.style->position != Position::ABSOLUTE) {
blockSize += ouput.size.y + margin.bottom;
logDebug("inline size {}", inlineSize);

if (box.style->table->captionSide == CaptionSide::TOP) {
for (auto c : captionBoxes(box)) {
auto [output, margin] = layoutBlockChild(tree, box, input, *c, inlineSize, blockSize);
blockSize += output.size.y + margin.bottom;
}
}

auto [output, margin] = layoutBlockChild(tree, box, input, *tableBox, inlineSize, blockSize);
blockSize += output.size.y + margin.bottom;

inlineSize = max(inlineSize, ouput.size.x + margin.start + margin.end);
if (box.style->table->captionSide == CaptionSide::BOTTOM) {
for (auto c : captionBoxes(box)) {
auto [output, margin] = layoutBlockChild(tree, box, input, *c, inlineSize, blockSize);
blockSize += output.size.y + margin.bottom;
}
}

return Output::fromSize({
inlineSize,
blockSize,
});
}

Output run(Tree &tree, Box &box, Input input) {
if (box.style->display == Display::Inside::TABLE)
return runTableWrapper(tree, box, input);
else
return runBlock(tree, box, input);
}
};

Output blockLayout(Tree &tree, Box &box, Input input) {
Expand Down
5 changes: 3 additions & 2 deletions src/web/vaev-layout/layout.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,15 @@ Output _contentLayout(Tree &tree, Box &box, Input input) {
display == Display::FLOW or
display == Display::FLOW_ROOT or
display == Display::TABLE_CELL or
display == Display::TABLE_CAPTION
display == Display::TABLE_CAPTION or
display == Display::TABLE
) {
return blockLayout(tree, box, input);
} else if (display == Display::FLEX) {
return flexLayout(tree, box, input);
} else if (display == Display::GRID) {
return gridLayout(tree, box, input);
} else if (display == Display::TABLE) {
} else if (display == Display::TABLE_BOX) {
return tableLayout(tree, box, input);
} else if (display == Display::INTERNAL) {
return Output{};
Expand Down
94 changes: 14 additions & 80 deletions src/web/vaev-layout/table.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,6 @@ struct TableFormatingContext {
Vec<TableGroup> rowGroups;
Vec<TableGroup> colGroups;

Vec<usize> captionsIdxs;
Box &wrapperBox;
Box &tableBox;

// Table forming algorithm
Expand Down Expand Up @@ -129,23 +127,15 @@ struct TableFormatingContext {
InsetsPx boxBorder;
Vec2Px spacing;

TableFormatingContext(Tree &tree, Box &tableWrapperBox)
: wrapperBox(tableWrapperBox),
tableBox(findTableBox(tableWrapperBox)),
TableFormatingContext(Tree &tree, Box &tableBox)
: tableBox(tableBox),
boxBorder(computeBorders(tree, tableBox)),
spacing(
{
resolve(tree, tableBox, tableBox.style->table->spacing.horizontal),
resolve(tree, tableBox, tableBox.style->table->spacing.vertical),
}
) {

for (usize i = 0; i < tableWrapperBox.children().len(); ++i) {
auto &child = tableWrapperBox.children()[i];
if (child.style->display == Display::Internal::TABLE_CAPTION) {
captionsIdxs.pushBack(i);
}
}
}

// https://html.spec.whatwg.org/multipage/tables.html#algorithm-for-growing-downward-growing-cells
Expand Down Expand Up @@ -393,14 +383,6 @@ struct TableFormatingContext {
numOfFooterRows = grid.size.y - ystartFooterRows;
}

Box &findTableBox(Box &tableWrapperBox) {
for (auto &child : tableWrapperBox.children())
if (child.style->display != Display::Internal::TABLE_CAPTION)
return child;

panic("table box not found in box tree");
}

void buildBordersGrid(Tree &tree) {
bordersGrid.borders.clear();
bordersGrid.borders.resize(grid.size.x * grid.size.y);
Expand Down Expand Up @@ -478,11 +460,12 @@ struct TableFormatingContext {
tableUsedWidth =
tableBox.style->sizing->width == Size::AUTO
? 0_px
: resolve(tree, tableBox, tableBox.style->sizing->width.value, input.availableSpace.x);
: resolve(tree, tableBox, tableBox.style->sizing->width.value, input.availableSpace.x) -
boxBorder.horizontal(); // NOTE: maybe remove this after borderbox param is clearer

auto [columnBorders, sumBorders] = getColumnBorders();

Px fixedWidthToAccount = boxBorder.horizontal() + Px{grid.size.x + 1} * spacing.x;
Px fixedWidthToAccount = Px{grid.size.x + 1} * spacing.x;

Vec<Opt<Px>> colWidthOrNone{};
colWidthOrNone.resize(grid.size.x);
Expand Down Expand Up @@ -566,19 +549,6 @@ struct TableFormatingContext {
// https://www.w3.org/TR/css-tables-3/#intrinsic-percentage-width-of-a-column-based-on-cells-of-span-up-to-1
// We will need a way to retrieve the percentage value, which is also not yet implemented.

Px capmin{0};
for (auto i : captionsIdxs) {
auto captionOutput = layout(
tree,
wrapperBox.children()[i],
Input{
.commit = Commit::NO,
.intrinsic = IntrinsicSize::MIN_CONTENT,
}
);
capmin = max(capmin, captionOutput.size.x);
}

auto getCellMinMaxWidth = [](Tree &tree, Box &box, Input &input, TableCell &cell) -> Pair<Px> {
auto cellMinOutput = layout(
tree,
Expand Down Expand Up @@ -724,6 +694,8 @@ struct TableFormatingContext {
for (auto x : maxColWidth)
sumMaxColWidths += x;

Px capmin = 0_px;
// Px capmin = input.capmin.unwrap();
// TODO: should minColWidth or maxColWidth be forcelly used if input is MIN_CONTENT or MAX_CONTENT respectivelly?
if (tableBox.style->sizing->width != Size::AUTO) {
// TODO: how to resolve percentage if case of table width?
Expand Down Expand Up @@ -882,22 +854,8 @@ struct TableFormatingContext {
PrefixSum<Px> colWidthPref{colWidth}, rowHeightPref{rowHeight};
Px currPositionX{input.position.x};

// table box
layout(
tree,
tableBox,
{
.commit = Commit::YES,
.knownSize = {
tableBoxSize.x + boxBorder.horizontal(),
tableBoxSize.y + boxBorder.vertical(),
},
.position = {currPositionX, currPositionY},
}
);

currPositionX += boxBorder.start + spacing.x;
currPositionY += boxBorder.top + spacing.y;
currPositionX += spacing.x;
currPositionY += spacing.y;
// cells
for (usize i = 0; i < grid.size.y; currPositionY += rowHeight[i] + spacing.y, i++) {
Px innnerCurrPositionX = Px{currPositionX};
Expand Down Expand Up @@ -933,48 +891,24 @@ struct TableFormatingContext {
}
}

void runCaptions(Tree &tree, Input input, Px tableUsedWidth, Px &currPositionY, Px &captionsHeight) {
for (auto i : captionsIdxs) {
auto cellOutput = layout(
tree,
wrapperBox.children()[i],
{
.commit = input.commit,
.knownSize = {tableUsedWidth, NONE},
.position = {input.position.x, currPositionY},
}
);
captionsHeight += cellOutput.size.y;
currPositionY += captionsHeight;
}
}

Output run(Tree &tree, Input input) {
Px currPositionY{input.position.y}, captionsHeight{0};
if (tableBox.style->table->captionSide == CaptionSide::TOP) {
runCaptions(tree, input, tableUsedWidth, currPositionY, captionsHeight);
}

Px currPositionY{input.position.y};
if (input.commit == Commit::YES) {
runTableBox(tree, input, currPositionY);
}

if (tableBox.style->table->captionSide == CaptionSide::BOTTOM) {
runCaptions(tree, input, tableUsedWidth, currPositionY, captionsHeight);
}

return Output::fromSize({
tableUsedWidth + boxBorder.horizontal(),
tableBoxSize.y + captionsHeight + boxBorder.vertical(),
tableUsedWidth,
tableBoxSize.y,
});
}
};

Output tableLayout(Tree &tree, Box &wrapper, Input input) {
Output tableLayout(Tree &tree, Box &box, Input input) {
// TODO: - vertical and horizontal alignment
// - borders collapse

TableFormatingContext table(tree, wrapper);
TableFormatingContext table(tree, box);
table.build(tree, input);
return table.run(tree, input);
}
Expand Down
2 changes: 1 addition & 1 deletion src/web/vaev-view/view.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ struct View : public Ui::View<View> {
Math::Vec2i size(Math::Vec2i size, Ui::Hint) override {
// FIXME: This is wasteful, we should cache the result
auto media = _constructMedia(size);
auto [_, layout, _] = Driver::render(*_dom, media, {.small = size.cast<Px>()});
auto [_, layout, __] = Driver::render(*_dom, media, {.small = size.cast<Px>()});

return {
layout->layout.borderBox().width.cast<isize>(),
Expand Down

0 comments on commit 3e45313

Please sign in to comment.