Skip to content

Commit 2657485

Browse files
committed
(wip) vaev-layout,style: Add SVG groups and integration with transforms.
to test the tiger, user needs to manually set the transform-origin to 0
1 parent 6f1e085 commit 2657485

File tree

11 files changed

+576
-76
lines changed

11 files changed

+576
-76
lines changed

src/vaev-dom/defs/ns-svg-attr-names.inc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,9 @@ ATTR(SYSTEM_LANGUAGE, systemLanguage)
7777
ATTR(TABLE_VALUES, tableValues)
7878
ATTR(TARGET_X, targetX)
7979
ATTR(TARGET_Y, targetY)
80+
ATTR(TRANSFORM, transform)
81+
ATTR(TRANSFORM_ORIGIN, transform-origin)
82+
ATTR(TRANSFORM_BOX, transform-box)
8083
ATTR(TEXT_LENGTH, textLength)
8184
ATTR(VERSION, version)
8285
ATTR(VIEW_BOX, viewBox)

src/vaev-layout/base.cpp

Lines changed: 81 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -286,21 +286,31 @@ export struct InlineBox {
286286
}
287287
};
288288

289-
struct SVGRoot {
290-
using Element = Union<SVG::Shape, SVGRoot, ::Box<Box>>;
291-
Vec<Element> elements;
289+
struct SVGRoot;
290+
291+
namespace SVG {
292+
293+
struct Group {
294+
using Element = Union<Shape, SVGRoot, Karm::Box<Vaev::Layout::Box>, Group>;
295+
Vec<Element> elements = {};
292296

293-
Opt<ViewBox> viewBox;
294297
Rc<Style::SpecifiedStyle> style;
295298

296-
void add(Element&& element) {
297-
elements.pushBack(std::move(element));
298-
}
299+
Group(Rc<Style::SpecifiedStyle> style)
300+
: style(style) {}
299301

300-
void add(Box&& box);
302+
void add(Element&& element);
303+
void add(Vaev::Layout::Box&& box);
304+
305+
void repr(Io::Emit& e) const;
306+
};
307+
} // namespace SVG
308+
309+
struct SVGRoot : SVG::Group {
310+
Opt<ViewBox> viewBox;
301311

302312
SVGRoot(Rc<Style::SpecifiedStyle> style)
303-
: viewBox(style->svg->viewBox), style(style) {}
313+
: SVG::Group(style), viewBox(style->svg->viewBox) {}
304314

305315
void repr(Io::Emit& e) const {
306316
e("(SVG {} viewBox:{}", SVG::buildRectangle(*style), viewBox);
@@ -313,6 +323,16 @@ struct SVGRoot {
313323
}
314324
};
315325

326+
void SVG::Group::repr(Io::Emit& e) const {
327+
e("(Group {} ");
328+
e.indentNewline();
329+
for (auto const& el : elements) {
330+
e("{}", el);
331+
e.newline();
332+
}
333+
e(")");
334+
}
335+
316336
export using Content = Union<
317337
None,
318338
Vec<Box>,
@@ -392,8 +412,12 @@ struct Box : Meta::NoCopy {
392412
}
393413
};
394414

395-
void SVGRoot::add(Box&& box) {
396-
add(makeBox<Box>(std::move(box)));
415+
void SVG::Group::add(Element&& element) {
416+
elements.pushBack(std::move(element));
417+
}
418+
419+
void SVG::Group::add(Vaev::Layout::Box&& box) {
420+
add(Element{makeBox<Vaev::Layout::Box>(std::move(box))});
397421
}
398422

399423
void InlineBox::add(Box&& b) {
@@ -452,28 +476,62 @@ export struct Metrics {
452476
};
453477

454478
export struct Frag;
479+
struct SVGRootFrag;
480+
481+
namespace SVG {
455482

456-
struct SVGRootFrag {
457-
using Element = Union<SVG::ShapeFrag, SVGRootFrag, ::Box<Frag>>;
483+
struct GroupFrag : SVG::Frag {
484+
using Element = Union<SVG::ShapeFrag, SVGRootFrag, ::Box<Vaev::Layout::Frag>, GroupFrag>;
458485
Vec<Element> elements = {};
459486

487+
RectAu _objectBoundingBox{};
488+
RectAu _strokeBoundingBox{};
489+
490+
Karm::Cursor<Group> box;
491+
492+
GroupFrag(Karm::Cursor<Group> group)
493+
: box(group) {}
494+
495+
void _computeBoundingBoxes(SVG::GroupFrag* group);
496+
497+
RectAu objectBoundingBox() override {
498+
return _objectBoundingBox;
499+
}
500+
501+
RectAu strokeBoundingBox() override {
502+
return _strokeBoundingBox;
503+
}
504+
505+
Style::SpecifiedStyle const& style() override {
506+
return *box->style;
507+
}
508+
509+
void add(Element&& element);
510+
511+
void repr(Io::Emit& e) const {
512+
e("(GroupFrag)");
513+
}
514+
};
515+
} // namespace SVG
516+
517+
struct SVGRootFrag : SVG::GroupFrag {
460518
// NOTE: SVG viewports have these intrinsic transformations; choosing to store these transforms is more compliant
461519
// and somewhat rendering-friendly but makes it harder to debug
462520
Math::Trans2f transf;
463521
SVG::Rectangle<Au> boundingBox;
464522

523+
SVGRootFrag(Karm::Cursor<SVG::Group> group, Math::Trans2f transf, SVG::Rectangle<Au> boundingBox)
524+
: SVG::GroupFrag(group), transf(transf), boundingBox(boundingBox) {
525+
}
526+
465527
static SVGRootFrag build(SVGRoot const& box, Vec2Au position, Vec2Au viewportSize) {
466528
SVG::Rectangle<Karm::Au> rect{position.x, position.y, viewportSize.x, viewportSize.y};
467529

468530
Math::Trans2f transf =
469531
box.viewBox ? SVG::computeEquivalentTransformOfSVGViewport(*box.viewBox, position, viewportSize)
470532
: Math::Trans2f::translate(position.cast<f64>());
471533

472-
return {{}, transf, rect};
473-
}
474-
475-
void add(Element&& el) {
476-
elements.pushBack(std::move(el));
534+
return SVGRootFrag{&box, transf, rect};
477535
}
478536

479537
void repr(Io::Emit& e) const {
@@ -532,9 +590,13 @@ export struct Frag {
532590
}
533591
};
534592

593+
void SVG::GroupFrag::add(Element&& el) {
594+
elements.pushBack(std::move(el));
595+
}
596+
535597
void SVGRootFrag::offsetBoxFrags(Vec2Au d) {
536598
for (auto& element : elements) {
537-
if (auto frag = element.is<::Box<Frag>>()) {
599+
if (auto frag = element.is<::Box<Vaev::Layout::Frag>>()) {
538600
(*frag)->offset(d);
539601
} else if (auto nestedRoot = element.is<SVGRootFrag>()) {
540602
nestedRoot->offsetBoxFrags(d);

src/vaev-layout/builder.cpp

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -426,20 +426,22 @@ static void _buildInputProse(BuilderContext bc, Gc::Ref<Dom::Element> el) {
426426
bc.content() = InlineBox{prose};
427427
}
428428

429-
void buildSVGChildren(Style::Computer& computer, Rc<Style::SpecifiedStyle> parentStyle, Gc::Ref<Dom::Element> el, SVGRoot& svgRoot);
430429
static void buildBlockFlowFromElement(BuilderContext bc, Gc::Ref<Dom::Element> el);
430+
void buildSVGAggregate(Style::Computer& computer, Rc<Style::SpecifiedStyle> parentStyle, Gc::Ref<Dom::Element> el, SVG::Group* group);
431431

432-
void buildSVGElement(Style::Computer& computer, Rc<Style::SpecifiedStyle> parentStyle, Gc::Ref<Dom::Element> el, SVGRoot& svgRoot) {
432+
void buildSVGElement(Style::Computer& computer, Rc<Style::SpecifiedStyle> parentStyle, Gc::Ref<Dom::Element> el, SVG::Group* group) {
433433
auto style = computer.computeFor(*parentStyle, *el);
434434

435435
if (SVG::isShape(el->tagName)) {
436-
svgRoot.add(SVG::Shape::build(style, el->tagName));
436+
group->add(SVG::Shape::build(style, el->tagName));
437437
} else if (el->tagName == Svg::G) {
438-
buildSVGChildren(computer, style, el, svgRoot);
438+
SVG::Group nestedGroup{style};
439+
buildSVGAggregate(computer, style, el, &nestedGroup);
440+
group->add(std::move(nestedGroup));
439441
} else if (el->tagName == Svg::SVG) {
440442
SVGRoot newSvgRoot{style};
441-
buildSVGChildren(computer, style, el, newSvgRoot);
442-
svgRoot.add(std::move(newSvgRoot));
443+
buildSVGAggregate(computer, style, el, &newSvgRoot);
444+
group->add(std::move(newSvgRoot));
443445
} else if (el->tagName == Svg::FOREIGN_OBJECT) {
444446
auto font = _lookupFontface(computer.fontBook, *style);
445447

@@ -456,25 +458,25 @@ void buildSVGElement(Style::Computer& computer, Rc<Style::SpecifiedStyle> parent
456458

457459
buildBlockFlowFromElement(bc, *el);
458460

459-
svgRoot.add(std::move(box));
461+
group->add(std::move(box));
460462
} else {
461463
// TODO
462464
logWarn("cannot build element into svg tree: {}", el->tagName);
463465
}
464466
}
465467

466-
void buildSVGChildren(Style::Computer& computer, Rc<Style::SpecifiedStyle> parentStyle, Gc::Ref<Dom::Element> el, SVGRoot& svgRoot) {
468+
void buildSVGAggregate(Style::Computer& computer, Rc<Style::SpecifiedStyle> parentStyle, Gc::Ref<Dom::Element> el, SVG::Group* group) {
467469
for (auto child = el->firstChild(); child; child = child->nextSibling()) {
468470
if (auto el = child->is<Dom::Element>()) {
469-
buildSVGElement(computer, parentStyle, *el, svgRoot);
471+
buildSVGElement(computer, parentStyle, *el, group);
470472
}
471473
// TODO: process text into svg tree
472474
}
473475
}
474476

475477
SVGRoot _buildSVG(Style::Computer& computer, Gc::Ref<Dom::Element> el, Rc<Style::SpecifiedStyle> rootStyle) {
476478
SVGRoot svgRoot{rootStyle};
477-
buildSVGChildren(computer, rootStyle, el, svgRoot);
479+
buildSVGAggregate(computer, rootStyle, el, &svgRoot);
478480
return svgRoot;
479481
}
480482

0 commit comments

Comments
 (0)