Skip to content

Commit

Permalink
vaev-layout: implement table wrapper as BFC
Browse files Browse the repository at this point in the history
  • Loading branch information
pauloamed committed Dec 4, 2024
1 parent c02cd2e commit 7872021
Show file tree
Hide file tree
Showing 6 changed files with 218 additions and 91 deletions.
3 changes: 3 additions & 0 deletions src/web/vaev-layout/base.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ struct Input {
Vec2Px availableSpace = {};
Vec2Px containingBlock = {};

// To be used between table wrapper and table box
Opt<Px> capmin = NONE;

Input withCommit(Commit c) const {
auto copy = *this;
copy.commit = c;
Expand Down
41 changes: 36 additions & 5 deletions src/web/vaev-layout/block.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,35 @@ namespace Vaev::Layout {

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

Px computeCAPMIN(Tree &tree, Box &box, Input input, Px inlineSize) {
Px capmin{};
for (auto &c : box.children()) {
if (c.style->display != Display::TABLE_BOX) {
auto margin = computeMargins(
tree, c,
{
.containingBlock = {inlineSize, input.knownSize.y.unwrapOr(0_px)},
}
);

auto minContentContrib = computeIntrinsicSize(
tree, c, IntrinsicSize::MIN_CONTENT, input.containingBlock
);

capmin = max(
capmin,
minContentContrib.width + margin.horizontal()
);
}
}

return capmin;
}

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

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

Expand Down Expand Up @@ -43,17 +71,20 @@ struct BlockFormatingContext {

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

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

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

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

inlineSize = max(inlineSize, ouput.size.x + margin.start + margin.end);
inlineSize = max(inlineSize, output.size.x + margin.horizontal());
}

return Output::fromSize({
Expand Down
28 changes: 24 additions & 4 deletions src/web/vaev-layout/builder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -215,16 +215,36 @@ static void _buildTableChildren(Style::Computer &c, Vec<Strong<Markup::Node>> co

tableBox.style->display = Display::Internal::TABLE_BOX;

bool captionsOnTop = tableBox.style->table->captionSide == CaptionSide::TOP;

if (captionsOnTop) {
for (auto &child : children) {
if (auto el = child->is<Markup::Element>()) {
if (el->tagName == Html::CAPTION) {
_buildNode(c, *el, tableWrapperBox);
}
}
}
}

for (auto &child : children) {
if (auto el = child->is<Markup::Element>()) {
if (el->tagName == Html::CAPTION) {
_buildNode(c, *child, tableWrapperBox);
} else {
_buildNode(c, *child, tableBox);
if (el->tagName != Html::CAPTION) {
_buildNode(c, *el, tableBox);
}
}
}
tableWrapperBox.add(std::move(tableBox));

if (not captionsOnTop) {
for (auto &child : children) {
if (auto el = child->is<Markup::Element>()) {
if (el->tagName == Html::CAPTION) {
_buildNode(c, *el, tableWrapperBox);
}
}
}
}
}

static void _buildTable(Style::Computer &c, Strong<Style::Computed> style, Markup::Element const &el, Box &parent) {
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
93 changes: 13 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,7 @@ struct TableFormatingContext {
for (auto x : maxColWidth)
sumMaxColWidths += x;

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 +853,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 +890,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
Loading

0 comments on commit 7872021

Please sign in to comment.