Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 14 additions & 13 deletions src/vaev-browser/inspect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ Ui::Child node(Gc::Ref<Dom::Node> n, InspectState const& s, Ui::Action<Inspector
return Ui::vflow(children);
}

Ui::Child computedStyles(InspectState const& s, Ui::Action<InspectorAction> send) {
Ui::Child computedStyles(Gc::Ref<Dom::Document> dom, InspectState const& s, Ui::Action<InspectorAction> send) {
auto content = Ui::labelMedium("No element selected") |
Ui::insets({8, 16}) |
Ui::center();
Expand All @@ -171,16 +171,16 @@ Ui::Child computedStyles(InspectState const& s, Ui::Action<InspectorAction> send
if (auto el = s.selectedNode->is<Dom::Element>()) {
Ui::Children children;

Style::StyleProp::any([&]<typename T>() {
if constexpr (requires { T::load; }) {
if (s.filter and startWith(T::name(), s.filter) == Match::NO)
return;
children.pushBack(
Ui::text(Ui::TextStyles::codeSmall(), "{}: {}", T::name(), T::load(*el->specifiedValues())) |
Ui::insets({4, 8})
);
}
});
for (auto const& [name, registration] : dom->registeredPropertySet.registrations().iterUnordered()) {
if (s.filter and startWith(name.str(), s.filter) == Match::NO)
continue;

auto property = registration->load(*el->specifiedValues());
children.pushBack(
Ui::text(Ui::TextStyles::codeSmall(), "{}: {}", name, *property) |
Ui::insets({4, 8})
);
}

content = Ui::vflow(children) | Ui::vhscroll();
}
Expand All @@ -197,9 +197,10 @@ Ui::Child computedStyles(InspectState const& s, Ui::Action<InspectorAction> send
}

export Ui::Child inspect(Rc<Dom::Window> window, InspectState const& s, Ui::Action<InspectorAction> send) {
auto document = window->document().upgrade();
return Ui::vflow(
node(window->document().upgrade(), s, send) | Ui::vscroll() | Ui::grow(),
computedStyles(s, send) | Kr::resizable(Kr::ResizeHandle::TOP, {128}, NONE)
node(document, s, send) | Ui::vscroll() | Ui::grow(),
computedStyles(document, s, send) | Kr::resizable(Kr::ResizeHandle::TOP, {128}, NONE)
);
}

Expand Down
16 changes: 8 additions & 8 deletions src/vaev-engine/css/lexer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -207,19 +207,21 @@ static auto const RE_NUMBER = Re::chain(

export struct Lexer {
Io::SScan _scan;
Token _curr;

Lexer(Str text) : _scan(text) {
_curr = _next(_scan);
}

Lexer(Io::SScan const& scan)
: _scan(scan) {
_curr = _next(_scan);
}

Token peek() const {
return _curr;
Token peek(usize offset = 1) const {
Io::SScan scan = _scan;
Token res = Token::NIL;
for (auto _ : range(offset)) {
res = _next(scan);
}
return res;
}

Token _nextIdent(Io::SScan& s) const {
Expand Down Expand Up @@ -392,9 +394,7 @@ export struct Lexer {
}

Token next() {
auto res = _curr;
_curr = _next(_scan);
return res;
return _next(_scan);
}

bool ended() const {
Expand Down
56 changes: 50 additions & 6 deletions src/vaev-engine/css/parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ export struct Sst;

export using Content = Vec<Sst>;

export enum struct Important : u8 {
UNSET,
YES,
};

#define FOREACH_SST(SST) \
SST(RULE) \
SST(FUNC) \
Expand All @@ -40,13 +45,19 @@ export struct Sst {
Token token = Token(Token::NIL);
Opt<Box<Sst>> prefix{};
Content content{};
Important important = Important::UNSET;

Sst(Type type) : type(type) {}

Sst(Token token) : type(TOKEN), token(token) {}

Sst(Content content) : type(LIST), content(content) {}

// https://drafts.csswg.org/css-variables-2/#guaranteed-invalid
static Sst guaranteedInvalid() {
return Token::badString("");
}

void repr(Io::Emit& e) const {
if (type == TOKEN) {
e("{}", token);
Expand Down Expand Up @@ -200,18 +211,48 @@ Sst consumeAtRule(Lexer& lex) {
}
}

export Content consumeDeclarationValue(Lexer& lex) {
Important consumeImportant(Lexer& lex) {
if (lex.peek() != Css::Token::delim("!"))
return Important::UNSET;
lex.next();

auto copy = lex;
eatWhitespace(copy);
if (copy.next() != Css::Token::ident("important"))
return Important::UNSET;
lex = copy;
return Important::YES;
}

export bool endedDeclarationValue(Lexer& lex) {
return lex.peek() == Token::END_OF_FILE or
lex.peek() == Token::SEMICOLON or
lex.peek() == Token::RIGHT_CURLY_BRACKET;
}

export Tuple<Content, Important> consumeDeclarationValue(Lexer& lex) {
Content value;

// 3. While the next input token is a <whitespace-token>, consume the next input token.
eatWhitespace(lex);

// 4. As long as the next input token is anything other than an <EOF-token>,
// consume a component value and append it to the declaration’s value.
while ((lex.peek() != Token::END_OF_FILE and lex.peek() != Token::SEMICOLON and lex.peek() != Token::RIGHT_CURLY_BRACKET)) {
value.pushBack(consumeComponentValue(lex));
eatWhitespace(lex);
while (not endedDeclarationValue(lex)) {
// 5. If the last two non-<whitespace-token>s in the declaration’s
// value are a <delim-token> with the value "!" followed by an
// <ident-token> with a value that is an ASCII case-insensitive match
// for "important", remove them from the declaration’s value
// and set the declaration’s important flag to true.
if (consumeImportant(lex) == Important::YES) {
eatWhitespace(lex);
return {std::move(value), Important::UNSET};
} else {
value.pushBack(consumeComponentValue(lex));
eatWhitespace(lex);
}
}
return value;
return {std::move(value), Important::UNSET};
}

// https://www.w3.org/TR/css-syntax-3/#consume-style-block
Expand Down Expand Up @@ -286,6 +327,7 @@ Content consumeDeclarationBlock(Lexer& lex) {
return res;
}

// https://www.w3.org/TR/css-syntax-3/#consume-declaration
export Opt<Sst> consumeDeclaration(Lexer& lex) {
Sst decl{Sst::DECL};
decl.token = lex.next();
Expand All @@ -303,7 +345,9 @@ export Opt<Sst> consumeDeclaration(Lexer& lex) {
lex.next();

// Parse the declaration’s value.
decl.content = consumeDeclarationValue(lex);
auto [content, important] = consumeDeclarationValue(lex);
decl.content = std::move(content);
decl.important = important;

return decl;
}
Expand Down
9 changes: 9 additions & 0 deletions src/vaev-engine/dom/document.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,17 @@ import Karm.Ref;
import Karm.Font;
import :dom.node;
import :dom.element;
import :props.base;
import :props.registry;

namespace Vaev::Style {
export struct StyleSheetList;
} // namespace Vaev::Style

namespace Vaev::Dom {

export struct Window;

export enum struct QuirkMode {
NO,
LIMITED,
Expand All @@ -29,7 +33,12 @@ export struct Document : Node {
String xmlEncoding;
String xmlStandalone = "no"s; // https://www.w3.org/TR/xml/#NT-SDDecl

// https://drafts.csswg.org/cssom/#dom-documentorshadowroot-stylesheets
Gc::Ptr<Style::StyleSheetList> styleSheets;

// https://drafts.css-houdini.org/css-properties-values-api/#dom-window-registeredpropertyset-slot
Style::PropertyRegistry registeredPropertySet = Style::defaultRegistry();

Opt<Rc<Font::Database>> fontDatabase;

Document(Ref::Url url)
Expand Down
7 changes: 6 additions & 1 deletion src/vaev-engine/dom/window.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,12 @@ export struct Window {
}

void computeStyle() {
Style::Computer computer{_media, *_document->styleSheets, *_document->fontDatabase};
Style::Computer computer{
_media,
_document->registeredPropertySet,
*_document->styleSheets,
*_document->fontDatabase,
};
computer.build();
computer.styleDocument(*_document);
}
Expand Down
5 changes: 4 additions & 1 deletion src/vaev-engine/driver/print.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,10 @@ export Generator<Print::Page> print(Gc::Ref<Dom::Document> dom, Print::Settings
auto media = Style::Media::forPrint(settings);

Style::Computer computer{
media, *dom->styleSheets, *dom->fontDatabase
media,
dom->registeredPropertySet,
*dom->styleSheets,
*dom->fontDatabase,
};
computer.build();
computer.styleDocument(*dom);
Expand Down
8 changes: 7 additions & 1 deletion src/vaev-engine/driver/render.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,13 @@ export struct RenderResult {
};

export RenderResult render(Gc::Ref<Dom::Document> dom, Style::Media const& media, Layout::Viewport viewport) {
Style::Computer computer{media, *dom->styleSheets, *dom->fontDatabase};
Style::Computer computer{
media,
dom->registeredPropertySet,
*dom->styleSheets,
*dom->fontDatabase,
};

computer.build();
computer.styleDocument(*dom);

Expand Down
20 changes: 10 additions & 10 deletions src/vaev-engine/loader/loader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ export Async::Task<Gc::Ref<Dom::Document>> viewSourceAsync(Gc::Heap& heap, Http:
co_return Ok(dom);
}

Async::Task<Style::StyleSheet> _fetchStylesheetAsync(Http::Client& client, Ref::Url url, Style::Origin origin) {
Async::Task<Style::StyleSheet> _fetchStylesheetAsync(Style::PropertyRegistry& registry, Http::Client& client, Ref::Url url, Style::Origin origin) {
auto resp = co_trya$(client.getAsync(url));
if (not resp->body)
co_return Error::notFound("could not load stylesheet");
Expand All @@ -109,7 +109,7 @@ Async::Task<Style::StyleSheet> _fetchStylesheetAsync(Http::Client& client, Ref::
auto buf = co_trya$(Aio::readAllUtf8Async(*respBody));

Io::SScan s{buf};
co_return Ok(Style::StyleSheet::parse(s, url, origin));
co_return Ok(Style::StyleSheet::parse(registry, s, url, origin));
}

Async::Task<Rc<Scene::Node>> _fetchImageContentAsync(Http::Client& client, Ref::Url url);
Expand All @@ -119,7 +119,7 @@ Rc<Scene::Node> _missingImagePlaceholder() {
return makeRc<Scene::Image>(placeholder->bound().cast<f64>(), placeholder);
}

Async::Task<> _fetchResourcesAsync(Http::Client& client, Gc::Ref<Dom::Node> node, Style::StyleSheetList& sb) {
Async::Task<> _fetchResourcesAsync(Style::PropertyRegistry& registry, Http::Client& client, Gc::Ref<Dom::Node> node, Style::StyleSheetList& sb) {
auto el = node->is<Dom::Element>();
if (el and el->qualifiedName == Html::IMG_TAG) {
auto src = el->getAttribute(Html::SRC_ATTR);
Expand All @@ -141,7 +141,7 @@ Async::Task<> _fetchResourcesAsync(Http::Client& client, Gc::Ref<Dom::Node> node
} else if (el and el->qualifiedName == Html::STYLE_TAG) {
auto text = el->textContent();
Io::SScan textScan{text};
auto sheet = Style::StyleSheet::parse(textScan, node->baseURI());
auto sheet = Style::StyleSheet::parse(registry, textScan, node->baseURI());
sb.add(std::move(sheet));
} else if (el and el->qualifiedName == Html::LINK_TAG) {
auto rel = el->getAttribute(Html::REL_ATTR);
Expand All @@ -153,7 +153,7 @@ Async::Task<> _fetchResourcesAsync(Http::Client& client, Gc::Ref<Dom::Node> node
}

auto url = Ref::Url::parse(*href, node->baseURI());
auto sheet = co_await _fetchStylesheetAsync(client, url, Style::Origin::AUTHOR);
auto sheet = co_await _fetchStylesheetAsync(registry, client, url, Style::Origin::AUTHOR);

if (not sheet) {
logWarn("failed to fetch stylesheet from {}: {}", url, sheet);
Expand All @@ -164,7 +164,7 @@ Async::Task<> _fetchResourcesAsync(Http::Client& client, Gc::Ref<Dom::Node> node
}
} else {
for (auto child = node->firstChild(); child; child = child->nextSibling())
(void)co_await _fetchResourcesAsync(client, *child, sb);
(void)co_await _fetchResourcesAsync(registry, client, *child, sb);
}

co_return Ok();
Expand All @@ -191,16 +191,16 @@ export Async::Task<Gc::Ref<Dom::Document>> fetchDocumentAsync(Gc::Heap& heap, Ht
auto dom = co_trya$(_loadDocumentAsync(heap, url, resp));
auto stylesheets = heap.alloc<Style::StyleSheetList>();

stylesheets->add((co_await _fetchStylesheetAsync(client, "bundle://vaev-engine/html.css"_url, Style::Origin::USER_AGENT))
stylesheets->add((co_await _fetchStylesheetAsync(dom->registeredPropertySet, client, "bundle://vaev-engine/html.css"_url, Style::Origin::USER_AGENT))
.take("user agent stylesheet not available"));

stylesheets->add((co_await _fetchStylesheetAsync(client, "bundle://vaev-engine/print.css"_url, Style::Origin::USER_AGENT))
stylesheets->add((co_await _fetchStylesheetAsync(dom->registeredPropertySet, client, "bundle://vaev-engine/print.css"_url, Style::Origin::USER_AGENT))
.take("user agent stylesheet not available"));

stylesheets->add((co_await _fetchStylesheetAsync(client, "bundle://vaev-engine/svg.css"_url, Style::Origin::USER_AGENT))
stylesheets->add((co_await _fetchStylesheetAsync(dom->registeredPropertySet, client, "bundle://vaev-engine/svg.css"_url, Style::Origin::USER_AGENT))
.take("user agent stylesheet not available"));

(void)co_await _fetchResourcesAsync(client, *dom, *stylesheets);
(void)co_await _fetchResourcesAsync(dom->registeredPropertySet, client, *dom, *stylesheets);
dom->styleSheets = stylesheets;
dom->fontDatabase = co_await _loadFontfacesAsync(client, *stylesheets);

Expand Down
1 change: 1 addition & 0 deletions src/vaev-engine/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"layout/base",
"layout/builder",
"loader",
"props",
"style",
"values",
"xml"
Expand Down
Loading
Loading