Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
sleepy-monax committed Dec 3, 2024
1 parent a5b8438 commit cd5a32a
Show file tree
Hide file tree
Showing 7 changed files with 471 additions and 10 deletions.
59 changes: 59 additions & 0 deletions src/web/vaev-base/page.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#pragma once

#include <karm-base/opt.h>

namespace Vaev {

// https://drafts.csswg.org/css-page/#marks
enum struct PageMarks {
NONE,
CROSS,
BOX,

_LEN,
};

// https://drafts.csswg.org/css-page/#margin-boxes
#define FOREACH_PAGE_MARGIN(ITER) \
ITER(TOP, "top") \
ITER(TOP_LEFT_CORNER, "top-left-corner") \
ITER(TOP_LEFT, "top-left") \
ITER(TOP_CENTER, "top-center") \
ITER(TOP_RIGHT, "top-right") \
ITER(TOP_RIGHT_CORNER, "top-right-corner") \
ITER(RIGHT, "right") \
ITER(RIGHT_TOP, "right-top") \
ITER(RIGHT_MIDDLE, "right-middle") \
ITER(RIGHT_BOTTOM, "right-bottom") \
ITER(BOTTOM, "bottom") \
ITER(BOTTOM_RIGHT_CORNER, "bottom-right-corner") \
ITER(BOTTOM_RIGHT, "bottom-right") \
ITER(BOTTOM_CENTER, "bottom-center") \
ITER(BOTTOM_LEFT, "bottom-left") \
ITER(BOTTOM_LEFT_CORNER, "bottom-left-corner") \
ITER(LEFT, "left") \
ITER(LEFT_BOTTOM, "left-bottom") \
ITER(LEFT_MIDDLE, "left-middle") \
ITER(LEFT_TOP, "left-top")

enum struct PageMargin {
#define ITER(ID, ...) ID,
FOREACH_PAGE_MARGIN(ITER)
#undef ITER
_LEN,
};

// https://drafts.csswg.org/css-page/#page-orientation-prop
enum struct PageOrientation {
UPRIGHT,
ROTATE_LEFT,
ROTATE_RIGHT,

_LEN
};

struct Page {
Opt<PageMargin> margin;
};

} // namespace Vaev
262 changes: 252 additions & 10 deletions src/web/vaev-driver/render.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <vaev-layout/layout.h>
#include <vaev-layout/paint.h>
#include <vaev-layout/positioned.h>
#include <vaev-layout/values.h>
#include <vaev-markup/dom.h>
#include <vaev-style/computer.h>

Expand Down Expand Up @@ -124,32 +125,273 @@ Vec<Strong<Scene::Page>> print(Markup::Document const &dom, Style::Media const &

Style::Computer computer{media, stylebook};

Vec<Strong<Scene::Page>> pages;

Layout::Resolver resolver{};
auto pageStyle = computer.computeForPage(pages.len());
RectPx pageRect{
0_px,
0_px,
media.width,
media.height,
};
auto page = makeStrong<Scene::Page>(pageRect.size().cast<isize>());

InsetsPx pageMargin = {
resolver.resolve(pageStyle->margin->top, pageRect.height),
resolver.resolve(pageStyle->margin->end, pageRect.width),
resolver.resolve(pageStyle->margin->bottom, pageRect.height),
resolver.resolve(pageStyle->margin->start, pageRect.width),
};

RectPx pageContent = pageRect.shrink(pageMargin);

// MARK: Top Left Corner ---------------------------------------------------

auto topLeftMarginCornerRect = RectPx::fromTwoPoint(
pageRect.topStart(),
pageContent.topStart()
);
Layout::Tree topLeftMarginCornerTree{
.root = Layout::buildForPseudoElement(computer.computeFor(pages.len(), PageMargin::TOP_LEFT_CORNER)),
.viewport = Layout::Viewport{.small = topLeftMarginCornerRect.size()}
};
Layout::layout(
topLeftMarginCornerTree,
topLeftMarginCornerTree.root,
{
.commit = Layout::Commit::YES,
.knownSize = topLeftMarginCornerRect.size().cast<Opt<Px>>(),
.position = topLeftMarginCornerRect.topStart(),
.availableSpace = topLeftMarginCornerRect.size(),
.containingBlock = topLeftMarginCornerRect.size(),
}
);
Layout::paint(topLeftMarginCornerTree.root, *page);

// MARK: Top Right Corner --------------------------------------------------

auto topRightMarginCornerRect = RectPx::fromTwoPoint(
pageRect.topEnd(),
pageContent.topEnd()
);
Layout::Tree topRightMarginCornerTree{
.root = Layout::buildForPseudoElement(computer.computeFor(pages.len(), PageMargin::TOP_RIGHT_CORNER)),
.viewport = Layout::Viewport{.small = topRightMarginCornerRect.size()}
};
Layout::layout(
topRightMarginCornerTree,
topRightMarginCornerTree.root,
{
.commit = Layout::Commit::YES,
.knownSize = topRightMarginCornerRect.size().cast<Opt<Px>>(),
.position = topRightMarginCornerRect.topStart(),
.availableSpace = topRightMarginCornerRect.size(),
.containingBlock = topRightMarginCornerRect.size(),
}
);
Layout::paint(topRightMarginCornerTree.root, *page);

// MARK: Bottom Left Corner ------------------------------------------------

auto bottomLeftMarginCornerRect = RectPx::fromTwoPoint(
pageRect.bottomStart(),
pageContent.bottomStart()
);
Layout::Tree bottomLeftMarginCornerTree{
.root = Layout::buildForPseudoElement(computer.computeFor(pages.len(), PageMargin::BOTTOM_LEFT_CORNER)),
.viewport = Layout::Viewport{.small = bottomLeftMarginCornerRect.size()}
};
Layout::layout(
bottomLeftMarginCornerTree,
bottomLeftMarginCornerTree.root,
{
.commit = Layout::Commit::YES,
.knownSize = bottomLeftMarginCornerRect.size().cast<Opt<Px>>(),
.position = bottomLeftMarginCornerRect.topStart(),
.availableSpace = bottomLeftMarginCornerRect.size(),
.containingBlock = bottomLeftMarginCornerRect.size(),
}
);
Layout::paint(bottomLeftMarginCornerTree.root, *page);

// MARK: Bottom Right Corner -----------------------------------------------

auto bottomRightMarginCornerRect = RectPx::fromTwoPoint(
pageRect.bottomEnd(),
pageContent.bottomEnd()
);
Layout::Tree bottomRightMarginCornerTree{
.root = Layout::buildForPseudoElement(computer.computeFor(pages.len(), PageMargin::BOTTOM_RIGHT_CORNER)),
.viewport = Layout::Viewport{.small = bottomRightMarginCornerRect.size()}
};
Layout::layout(
bottomRightMarginCornerTree,
bottomRightMarginCornerTree.root,
{
.commit = Layout::Commit::YES,
.knownSize = bottomRightMarginCornerRect.size().cast<Opt<Px>>(),
.position = bottomRightMarginCornerRect.topStart(),
.availableSpace = bottomRightMarginCornerRect.size(),
.containingBlock = bottomRightMarginCornerRect.size(),
}
);
Layout::paint(bottomRightMarginCornerTree.root, *page);

// MARK: Top ---------------------------------------------------------------

auto topRect = RectPx::fromTwoPoint(
topLeftMarginCornerRect.topEnd(),
topRightMarginCornerRect.bottomStart()
);

auto topBox = Layout::buildForPseudoElement(computer.computeFor(pages.len(), PageMargin::TOP));
topBox.add(Layout::buildForPseudoElement(computer.computeFor(pages.len(), PageMargin::TOP_LEFT)));
topBox.add(Layout::buildForPseudoElement(computer.computeFor(pages.len(), PageMargin::TOP_CENTER)));
topBox.add(Layout::buildForPseudoElement(computer.computeFor(pages.len(), PageMargin::TOP_RIGHT)));

Layout::Tree topTree{
.root = std::move(topBox),
.viewport = Layout::Viewport{.small = topRect.size()}
};

Layout::layout(
topTree,
topTree.root,
{
.commit = Layout::Commit::YES,
.knownSize = topRect.size().cast<Opt<Px>>(),
.position = topRect.topStart(),
.availableSpace = topRect.size(),
.containingBlock = topRect.size(),
}
);
Layout::paint(topTree.root, *page);

// MARK: Bottom ------------------------------------------------------------

auto bottomRect = RectPx::fromTwoPoint(
bottomLeftMarginCornerRect.topEnd(),
bottomRightMarginCornerRect.bottomStart()
);

auto bottomBox = Layout::buildForPseudoElement(computer.computeFor(pages.len(), PageMargin::BOTTOM));
bottomBox.add(Layout::buildForPseudoElement(computer.computeFor(pages.len(), PageMargin::BOTTOM_LEFT)));
bottomBox.add(Layout::buildForPseudoElement(computer.computeFor(pages.len(), PageMargin::BOTTOM_CENTER)));
bottomBox.add(Layout::buildForPseudoElement(computer.computeFor(pages.len(), PageMargin::BOTTOM_RIGHT)));

Layout::Tree bottomTree{
.root = std::move(bottomBox),
.viewport = Layout::Viewport{.small = bottomRect.size()}
};

Layout::layout(
bottomTree,
bottomTree.root,
{
.commit = Layout::Commit::YES,
.knownSize = bottomRect.size().cast<Opt<Px>>(),
.position = bottomRect.topStart(),
.availableSpace = bottomRect.size(),
.containingBlock = bottomRect.size(),
}
);

Layout::paint(bottomTree.root, *page);

// MARK: Left --------------------------------------------------------------
auto leftRect = RectPx::fromTwoPoint(
topLeftMarginCornerRect.bottomEnd(),
bottomLeftMarginCornerRect.topStart()
);

auto leftBox = Layout::buildForPseudoElement(computer.computeFor(pages.len(), PageMargin::LEFT));
leftBox.add(Layout::buildForPseudoElement(computer.computeFor(pages.len(), PageMargin::LEFT_TOP)));
leftBox.add(Layout::buildForPseudoElement(computer.computeFor(pages.len(), PageMargin::LEFT_MIDDLE)));
leftBox.add(Layout::buildForPseudoElement(computer.computeFor(pages.len(), PageMargin::LEFT_BOTTOM)));

Layout::Tree leftTree{
.root = std::move(leftBox),
.viewport = Layout::Viewport{.small = leftRect.size()}
};

Layout::layout(
leftTree,
leftTree.root,
{
.commit = Layout::Commit::YES,
.knownSize = leftRect.size().cast<Opt<Px>>(),
.position = leftRect.topStart(),
.availableSpace = leftRect.size(),
.containingBlock = leftRect.size(),
}
);

Layout::paint(leftTree.root, *page);

// MARK: Right -------------------------------------------------------------

auto rightRect = RectPx::fromTwoPoint(
topRightMarginCornerRect.bottomEnd(),
bottomRightMarginCornerRect.topStart()
);

auto rightBox = Layout::buildForPseudoElement(computer.computeFor(pages.len(), PageMargin::RIGHT));
rightBox.add(Layout::buildForPseudoElement(computer.computeFor(pages.len(), PageMargin::RIGHT_TOP)));
rightBox.add(Layout::buildForPseudoElement(computer.computeFor(pages.len(), PageMargin::RIGHT_MIDDLE)));
rightBox.add(Layout::buildForPseudoElement(computer.computeFor(pages.len(), PageMargin::RIGHT_BOTTOM)));

Layout::Tree rightTree{
.root = std::move(rightBox),
.viewport = Layout::Viewport{.small = rightRect.size()}
};

Layout::layout(
rightTree,
rightTree.root,
{
.commit = Layout::Commit::YES,
.knownSize = rightRect.size().cast<Opt<Px>>(),
.position = rightRect.topStart(),
.availableSpace = rightRect.size(),
.containingBlock = rightRect.size(),
}
);

Layout::paint(rightTree.root, *page);

// MARK: Page Content ------------------------------------------------------

Layout::Viewport vp{
.small = {
.small = pageContent.size(),
.large = {
Px{media.width},
Px{media.height},
},
.dynamic = {
Px{media.width},
Px{media.height},
},
};

Layout::Tree tree = {
Layout::Tree contentTree = {
Layout::build(computer, dom),
vp,
};

Layout::layout(
tree,
tree.root,
contentTree,
contentTree.root,
{
.commit = Layout::Commit::YES,
.knownSize = {vp.small.width, NONE},
.availableSpace = {vp.small.width, 0_px},
.containingBlock = {vp.small.width, vp.small.height},
.knownSize = {pageContent.width, NONE},
.position = pageContent.topStart(),
.availableSpace = pageContent.size(),
.containingBlock = pageContent.size(),
}
);

Vec<Strong<Scene::Page>> pages;
auto page = makeStrong<Scene::Page>(vp.small.size().cast<isize>());
Layout::paint(tree.root, *page);
Layout::paint(contentTree.root, *page);
page->prepare();
pages.pushBack(page);

Expand Down
25 changes: 25 additions & 0 deletions src/web/vaev-layout/builder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -282,4 +282,29 @@ Box build(Style::Computer &c, Markup::Document const &doc) {
return root;
}

Box buildForPseudoElement(Strong<Style::Computed> style) {
auto fontFace = _lookupFontface(*style);

// FIXME: We should pass this around from the top in order to properly resolve rems
Resolver resolver{
.rootFont = Text::Font{fontFace, 16},
.boxFont = Text::Font{fontFace, 16},
};
Text::ProseStyle proseStyle{
.font = {
fontFace,
resolver.resolve(style->font->size).cast<f64>(),
},
.multiline = true,
};

if (style->content) {
auto prose = makeStrong<Text::Prose>(proseStyle);
prose->append(style->content.str());
return {style, fontFace, prose};
} else {
return {style, fontFace};
}
}

} // namespace Vaev::Layout
2 changes: 2 additions & 0 deletions src/web/vaev-layout/builder.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@ namespace Vaev::Layout {

Box build(Style::Computer &c, Markup::Document const &doc);

Box buildForPseudoElement(Strong<Style::Computed> style);

} // namespace Vaev::Layout
1 change: 1 addition & 0 deletions src/web/vaev-style/computed.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ struct Computed {

Color color;
Number opacity;
String content = ""s;

AlignProps aligns;
Math::Vec2<CalcValue<PercentOr<Length>>> gaps;
Expand Down
Loading

0 comments on commit cd5a32a

Please sign in to comment.