diff --git a/src/main.cpp b/src/main.cpp index ceacb1b6..1e1266e9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -157,7 +157,7 @@ Async::Task<> renderAsync( }; auto media = constructMediaForRender(options.scale, imageSize); - auto [style, layout, paint, frags] = Vaev::Driver::render(*dom, media, {.small = imageSize}); + auto [style, layout, paint, frags, canvasColor] = Vaev::Driver::render(*dom, media, {.small = imageSize}); auto image = Gfx::Surface::alloc( imageSize.cast() * options.density.toDppx(), @@ -166,7 +166,7 @@ Async::Task<> renderAsync( Gfx::CpuCanvas g; g.begin(*image); - g.clear(Gfx::WHITE); + g.clear(canvasColor); g.scale(options.density.toDppx()); paint->paint(g); if (options.wireframe) diff --git a/src/web/vaev-base/color.h b/src/web/vaev-base/color.h index bdf51c7b..5df098af 100644 --- a/src/web/vaev-base/color.h +++ b/src/web/vaev-base/color.h @@ -169,6 +169,10 @@ struct ColorSpace { return Gfx::WHITE; } + + constexpr bool operator==(ColorSpace const& other) const { + return type == other.type; + } }; // MARK: Color ----------------------------------------------------------------- @@ -199,6 +203,8 @@ struct ColorMix { if (perc) e(" {}", *perc); } + + bool operator==(Side const& other) const = default; }; ColorSpace colorSpace; @@ -208,6 +214,8 @@ struct ColorMix { void repr(Io::Emit& e) const { e("(color-mix {} {} {})", colorSpace, lhs, rhs); } + + bool operator==(ColorMix const& other) const = default; }; inline constexpr Gfx::Color TRANSPARENT = Gfx::Color::fromRgba(0, 0, 0, 0); diff --git a/src/web/vaev-driver/render.cpp b/src/web/vaev-driver/render.cpp index 1dcd640e..0addce5e 100644 --- a/src/web/vaev-driver/render.cpp +++ b/src/web/vaev-driver/render.cpp @@ -20,6 +20,7 @@ export struct RenderResult { Rc layout; Rc scenes; Rc frag; + Gfx::Color canvasColor; }; export RenderResult render(Gc::Ref dom, Style::Media const& media, Layout::Viewport viewport) { @@ -43,11 +44,15 @@ export RenderResult render(Gc::Ref dom, Style::Media const& media Style::Computer computer{media, stylebook, fontBook}; computer.loadFontFaces(); + Layout::Tree tree = { Layout::build(computer, dom), - viewport, + viewport }; + auto canvasColor = Layout::BGSearch(computer, dom, tree); + + elapsed = Sys::now() - start; logDebugIf(DEBUG_RENDER, "layout tree build time: {}", elapsed); @@ -79,7 +84,8 @@ export RenderResult render(Gc::Ref dom, Style::Media const& media std::move(stylebook), makeRc(std::move(tree.root)), sceneRoot, - makeRc(std::move(root)) + makeRc(std::move(root)), + canvasColor }; } diff --git a/src/web/vaev-layout/backgroundCanvas.cpp b/src/web/vaev-layout/backgroundCanvas.cpp new file mode 100644 index 00000000..27ab4143 --- /dev/null +++ b/src/web/vaev-layout/backgroundCanvas.cpp @@ -0,0 +1,64 @@ +module; + +#include +#include +#include +#include +#include + +export module Vaev.Layout:backgroundCanvas; + +import :values; + +namespace Vaev::Layout { + +Gfx::Color ColorToGfx(Color color) { + if (auto isRes = color.is()) { + return *isRes; + } else { + logWarn("color was not a Gfx color"); + return Gfx::WHITE; + } +} + +void patchBackgrounds(MutSlice& children, const Color color) { + for (auto& child : children) { + if (child.style->backgrounds->color == color) { + child.style->backgrounds.cow().color = Gfx::ALPHA; + } + } +} + +export Gfx::Color BGSearch(Style::Computer& c, Gc::Ref doc, Layout::Tree& tree) { + auto el = doc->documentElement(); + if (!el) { + return Gfx::WHITE; + } + + auto style = c.computeFor(Style::Computed::initial(), *el); + if (style->backgrounds->color != Gfx::ALPHA) { + tree.root.style->backgrounds.cow().color = Gfx::ALPHA; + return ColorToGfx(style->backgrounds->color); + } + + for (auto child = el->firstChild(); child; child = child->nextSibling()) { + if (auto isRes = child->is()) { + if (isRes->tagName != Html::BODY) { + continue; + } + + auto childStyle = c.computeFor(*style, *isRes); + if (childStyle->backgrounds->color != Gfx::ALPHA) { + auto children = tree.root.children(); + patchBackgrounds(children,childStyle->backgrounds->color); + return ColorToGfx(childStyle->backgrounds->color); + } else { + return Gfx::WHITE; + } + } + } + + return Gfx::WHITE; +} + +} // namespace Vaev::Layout diff --git a/src/web/vaev-layout/builder.cpp b/src/web/vaev-layout/builder.cpp index 77f55d60..e57b137e 100644 --- a/src/web/vaev-layout/builder.cpp +++ b/src/web/vaev-layout/builder.cpp @@ -275,6 +275,7 @@ static void _buildElement(Style::Computer& c, Gc::Ref el, Box& par } auto style = c.computeFor(*parent.style, el); + auto font = _lookupFontface(c.fontBook, *style); auto display = style->display; @@ -295,12 +296,11 @@ static void _buildNode(Style::Computer& c, Gc::Ref node, Box& parent) _buildElement(c, *el, parent); } else if (auto text = node->is()) { _buildRun(c, *text, parent); - } else if (auto doc = node->is()) { - _buildChildren(c, *doc, parent); } } export Box build(Style::Computer& c, Gc::Ref doc) { + if (auto el = doc->documentElement()) { auto style = c.computeFor(Style::Computed::initial(), *el); auto font = _lookupFontface(c.fontBook, *style); diff --git a/src/web/vaev-layout/mod.cpp b/src/web/vaev-layout/mod.cpp index f581cda0..3ae73495 100644 --- a/src/web/vaev-layout/mod.cpp +++ b/src/web/vaev-layout/mod.cpp @@ -13,3 +13,4 @@ export import :replaced; export import :table; export import :values; export import :writing; +export import :backgroundCanvas; diff --git a/src/web/vaev-view/view.cpp b/src/web/vaev-view/view.cpp index 831bf97d..31d46221 100644 --- a/src/web/vaev-view/view.cpp +++ b/src/web/vaev-view/view.cpp @@ -71,6 +71,7 @@ struct View : public Ui::View { } void paint(Gfx::Canvas& g, Math::Recti rect) override { + // Painting browser's viewport. auto viewport = bound().size(); if (not _renderResult) { auto media = _constructMedia(viewport); @@ -82,10 +83,11 @@ struct View : public Ui::View { g.origin(bound().xy.cast()); g.clip(viewport); - auto [_, layout, paint, frag] = *_renderResult; - g.clear(rect, Gfx::WHITE); + auto [_, layout, paint, frag, canvasColor] = *_renderResult; + auto paintRect = rect.offset(-bound().xy); + g.clear(paintRect, canvasColor); - paint->paint(g, rect.offset(-bound().xy).cast()); + paint->paint(g, paintRect.cast()); if (_props.wireframe) Layout::wireframe(*frag, g); @@ -100,7 +102,7 @@ struct View : public Ui::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, _, frag] = Driver::render(*_dom, media, {.small = size.cast()}); + auto [_, layout, _, frag, _] = Driver::render(*_dom, media, {.small = size.cast()}); return { frag->metrics.borderBox().width.cast(), diff --git a/tests/css/colors/stupid-backgrounds.xhtml b/tests/css/colors/stupid-backgrounds.xhtml new file mode 100644 index 00000000..b3d7b0ae --- /dev/null +++ b/tests/css/colors/stupid-backgrounds.xhtml @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + +