srctree

Robin Linden parent 77e70324 c49d628c
css: Add a splice-helper for style sheets

css/style_sheet.h added: 44, removed: 17, total 27
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2023 Robin Lindén <dev@robinlinden.eu>
// SPDX-FileCopyrightText: 2021-2023 Robin Lindén <dev@robinlinden.eu>
//
// SPDX-License-Identifier: BSD-2-Clause
 
@@ -7,6 +7,7 @@
 
#include "css/rule.h"
 
#include <iterator>
#include <vector>
 
namespace css {
@@ -14,6 +15,12 @@ namespace css {
struct StyleSheet {
std::vector<Rule> rules;
[[nodiscard]] bool operator==(StyleSheet const &) const = default;
 
void splice(StyleSheet &&other) {
rules.reserve(rules.size() + other.rules.size());
rules.insert(
end(rules), std::make_move_iterator(begin(other.rules)), std::make_move_iterator(end(other.rules)));
}
};
 
} // namespace css
 
filename was Deleted added: 44, removed: 17, total 27
@@ -0,0 +1,28 @@
// SPDX-FileCopyrightText: 2023 Robin Lindén <dev@robinlinden.eu>
//
// SPDX-License-Identifier: BSD-2-Clause
 
#include "css/style_sheet.h"
 
#include "etest/etest2.h"
 
#include <utility>
#include <vector>
 
int main() {
etest::Suite s;
 
s.add_test("StyleSheet::splice", [](etest::IActions &a) {
css::StyleSheet a1;
a1.rules.push_back({.selectors = {"a"}});
a1.rules.push_back({.selectors = {"b"}});
css::StyleSheet a2;
a2.rules.push_back({.selectors = {"c"}});
a2.rules.push_back({.selectors = {"d"}});
 
a1.splice(std::move(a2));
a.expect_eq(a1.rules, std::vector<css::Rule>{{{"a"}}, {{"b"}}, {{"c"}}, {{"d"}}});
});
 
return s.run();
}
 
engine/engine.cpp added: 44, removed: 17, total 27
@@ -13,7 +13,6 @@
#include <spdlog/spdlog.h>
 
#include <future>
#include <iterator>
#include <utility>
 
using namespace std::literals;
@@ -84,11 +83,7 @@ void Engine::on_navigation_success() {
 
// Style can only contain text, and we enforce this in our HTML parser.
auto const &style_content = std::get<dom::Text>(style->children[0]);
auto new_rules = css::parse(style_content.text).rules;
stylesheet_.rules.reserve(stylesheet_.rules.size() + new_rules.size());
stylesheet_.rules.insert(end(stylesheet_.rules),
std::make_move_iterator(begin(new_rules)),
std::make_move_iterator(end(new_rules)));
stylesheet_.splice(css::parse(style_content.text));
}
 
auto head_links = dom::nodes_by_xpath(dom_.html(), "/html/head/link");
@@ -100,10 +95,10 @@ void Engine::on_navigation_success() {
 
// Start downloading all stylesheets.
spdlog::info("Loading {} stylesheets", head_links.size());
std::vector<std::future<std::vector<css::Rule>>> future_new_rules;
std::vector<std::future<css::StyleSheet>> future_new_rules;
future_new_rules.reserve(head_links.size());
for (auto const *link : head_links) {
future_new_rules.push_back(std::async(std::launch::async, [=, this]() -> std::vector<css::Rule> {
future_new_rules.push_back(std::async(std::launch::async, [=, this]() -> css::StyleSheet {
auto const &href = link->attributes.at("href");
auto stylesheet_url = uri::Uri::parse(href, uri_);
 
@@ -144,16 +139,13 @@ void Engine::on_navigation_success() {
return {};
}
 
return css::parse(style_data.body).rules;
return css::parse(style_data.body);
}));
}
 
// In order, wait for the download to finish and merge with the big stylesheet.
for (auto &future_rules : future_new_rules) {
auto rules = future_rules.get();
stylesheet_.rules.reserve(stylesheet_.rules.size() + rules.size());
stylesheet_.rules.insert(
end(stylesheet_.rules), std::make_move_iterator(begin(rules)), std::make_move_iterator(end(rules)));
stylesheet_.splice(future_rules.get());
}
 
spdlog::info("Styling dom w/ {} rules", stylesheet_.rules.size());