srctree

Robin Lindén parent 65e14f37 750784e5
type: Don't require fonts to only deal w/ one specific font size

inlinesplit
layout/layout.cpp added: 44, removed: 60, total 0
@@ -288,9 +288,9 @@ void calculate_border(LayoutBox &box, int const font_size, int const root_font_s
}
 
std::optional<std::shared_ptr<type::IFont const>> find_font(
type::IType const &type, std::span<std::string_view const> font_families, type::Px font_size) {
type::IType const &type, std::span<std::string_view const> font_families) {
for (auto const &family : font_families) {
if (auto font = type.font(family, font_size)) {
if (auto font = type.font(family)) {
return font;
}
}
@@ -307,13 +307,12 @@ void layout(LayoutBox &box, geom::Rect const &bounds, int const root_font_size,
 
auto font_families = box.get_property<css::PropertyId::FontFamily>();
if (auto text = box.text()) {
auto font = find_font(type, font_families, type::Px{font_size});
auto font = find_font(type, font_families);
if (font) {
box.dimensions.content.width = (*font)->measure(*text).width;
box.dimensions.content.width = (*font)->measure(*text, type::Px{font_size}).width;
} else {
spdlog::warn("No font found for font-families: {}", fmt::join(font_families, ", "));
type::NaiveFont fallback{type::Px{font_size}};
box.dimensions.content.width = fallback.measure(*text).width;
box.dimensions.content.width = type::NaiveFont{}.measure(*text, type::Px{font_size}).width;
}
}
 
@@ -352,21 +351,22 @@ void layout(LayoutBox &box, geom::Rect const &bounds, int const root_font_size,
calculate_position(box, bounds);
int last_child_end{};
int current_line{};
auto font_size = !box.children.empty() ? box.children[0].get_property<css::PropertyId::FontSize>() : 0;
auto font_size =
type::Px{!box.children.empty() ? box.children[0].get_property<css::PropertyId::FontSize>() : 0};
auto font_families = !box.children.empty() ? box.children[0].get_property<css::PropertyId::FontFamily>()
: std::vector<std::string_view>{};
 
auto maybe_font = find_font(type, font_families, type::Px{font_size});
auto maybe_font = find_font(type, font_families);
if (!maybe_font) {
spdlog::warn("No font found for font-families: {}", fmt::join(font_families, ", "));
maybe_font = std::make_shared<type::NaiveFont>(type::Px{font_size});
maybe_font = std::make_shared<type::NaiveFont>();
}
auto font = *maybe_font;
 
for (std::size_t i = 0; i < box.children.size(); ++i) {
auto *child = &box.children[i];
layout(*child,
box.dimensions.content.translated(last_child_end, current_line * font_size),
box.dimensions.content.translated(last_child_end, current_line * font_size.v),
root_font_size,
type);
// TODO(robinlinden): Handle cases where the text isn't a direct child of the anonymous block.
@@ -376,7 +376,8 @@ void layout(LayoutBox &box, geom::Rect const &bounds, int const root_font_size,
std::size_t best_split_point = std::string_view::npos;
for (auto split_point = text->find(' '); split_point != std::string_view::npos;
split_point = text->find(' ', split_point + 1)) {
if (last_child_end + font->measure(text->substr(0, split_point)).width > bounds.width) {
if (last_child_end + font->measure(text->substr(0, split_point), font_size).width
> bounds.width) {
break;
}
 
@@ -384,7 +385,8 @@ void layout(LayoutBox &box, geom::Rect const &bounds, int const root_font_size,
}
 
if (best_split_point != std::string_view::npos) {
child->dimensions.content.width = font->measure(text->substr(0, best_split_point)).width;
child->dimensions.content.width =
font->measure(text->substr(0, best_split_point), font_size).width;
auto bonus_child = *child;
bonus_child.layout_text = std::string{text->substr(best_split_point + 1)};
box.children.insert(box.children.begin() + i + 1, std::move(bonus_child));
@@ -395,7 +397,7 @@ void layout(LayoutBox &box, geom::Rect const &bounds, int const root_font_size,
child = &box.children[i];
child->layout_text = std::string{text->substr(0, best_split_point)};
} else {
child->dimensions.content.width = font->measure(*text).width;
child->dimensions.content.width = font->measure(*text, font_size).width;
last_child_end += child->dimensions.margin_box().width;
}
}
 
layout/layout_test.cpp added: 44, removed: 60, total 0
@@ -24,9 +24,7 @@ namespace {
 
class NoType : public type::IType {
public:
std::optional<std::shared_ptr<type::IFont const>> font(std::string_view, type::Px) const override {
return std::nullopt;
}
std::optional<std::shared_ptr<type::IFont const>> font(std::string_view) const override { return std::nullopt; }
};
 
// Until we have a nicer tree-creation abstraction for the tests, this needs to
 
type/naive.h added: 44, removed: 60, total 0
@@ -7,38 +7,25 @@
 
#include "type/type.h"
 
#include <map>
#include <memory>
#include <optional>
#include <string_view>
#include <utility>
 
namespace type {
 
class NaiveFont : public IFont {
public:
explicit NaiveFont(Px font_size) : font_size_{font_size} {}
 
Size measure(std::string_view text) const override {
return Size{static_cast<int>(text.size()) * font_size_.v / 2, font_size_.v};
Size measure(std::string_view text, Px font_size) const override {
return Size{static_cast<int>(text.size()) * font_size.v / 2, font_size.v};
}
 
private:
Px font_size_{};
};
 
class NaiveType : public IType {
public:
std::optional<std::shared_ptr<IFont const>> font(std::string_view, Px size) const override {
if (auto font = font_cache_.find(size.v); font != font_cache_.end()) {
return font->second;
}
 
return font_cache_.insert(std::pair{size.v, std::make_shared<NaiveFont>(size)}).first->second;
}
std::optional<std::shared_ptr<IFont const>> font(std::string_view) const override { return font_; }
 
private:
mutable std::map<int, std::shared_ptr<NaiveFont>> font_cache_;
std::shared_ptr<NaiveFont> font_{std::make_shared<NaiveFont>()};
};
 
} // namespace type
 
type/naive_test.cpp added: 44, removed: 60, total 0
@@ -12,20 +12,20 @@ int main() {
s.add_test("NaiveFont::measure", [](etest::IActions &a) {
type::NaiveType type{};
 
auto font10px = type.font("a", type::Px{10}).value();
a.expect_eq(font10px->measure("a"), type::Size{5, 10});
a.expect_eq(font10px->measure("hello"), type::Size{25, 10});
auto font10px = type.font("a").value();
a.expect_eq(font10px->measure("a", type::Px{10}), type::Size{5, 10});
a.expect_eq(font10px->measure("hello", type::Px{10}), type::Size{25, 10});
 
auto font20px = type.font("a", type::Px{20}).value();
a.expect_eq(font20px->measure("a"), type::Size{10, 20});
a.expect_eq(font20px->measure("hello"), type::Size{50, 20});
auto font20px = type.font("a").value();
a.expect_eq(font20px->measure("a", type::Px{20}), type::Size{10, 20});
a.expect_eq(font20px->measure("hello", type::Px{20}), type::Size{50, 20});
});
 
s.add_test("NaiveType::font_cache", [](etest::IActions &a) {
type::NaiveType type{};
 
auto font0 = type.font("a", type::Px{10}).value();
auto font1 = type.font("a", type::Px{10}).value();
auto font0 = type.font("a").value();
auto font1 = type.font("a").value();
a.expect_eq(font0.get(), font1.get());
});
 
 
type/sfml.cpp added: 44, removed: 60, total 0
@@ -48,16 +48,15 @@ std::optional<std::string> find_path_to_font(std::string_view font_filename) {
 
} // namespace
 
Size SfmlFont::measure(std::string_view text) const {
Size SfmlFont::measure(std::string_view text, Px font_size) const {
sf::Text sf_text{
sf::String::fromUtf8(text.data(), text.data() + text.size()), font_, static_cast<unsigned>(font_size_.v)};
sf::String::fromUtf8(text.data(), text.data() + text.size()), font_, static_cast<unsigned>(font_size.v)};
auto bounds = sf_text.getLocalBounds();
return Size{static_cast<int>(bounds.width), static_cast<int>(bounds.height)};
}
 
std::optional<std::shared_ptr<IFont const>> SfmlType::font(std::string_view name, Px size) const {
std::optional<std::shared_ptr<IFont const>> SfmlType::font(std::string_view name) const {
if (auto font = font_cache_.find(name); font != font_cache_.end()) {
font->second->set_font_size(size);
return font->second;
}
 
@@ -66,7 +65,7 @@ std::optional<std::shared_ptr<IFont const>> SfmlType::font(std::string_view name
return std::nullopt;
}
 
return font_cache_.insert(std::pair{std::string{name}, std::make_shared<SfmlFont>(font, size)}).first->second;
return font_cache_.insert(std::pair{std::string{name}, std::make_shared<SfmlFont>(font)}).first->second;
}
 
} // namespace type
 
type/sfml.h added: 44, removed: 60, total 0
@@ -19,19 +19,17 @@ namespace type {
 
class SfmlFont : public IFont {
public:
SfmlFont(sf::Font const &font, Px font_size) : font_{font}, font_size_{font_size} {}
explicit SfmlFont(sf::Font const &font) : font_{font} {}
 
Size measure(std::string_view text) const override;
void set_font_size(Px size) { font_size_ = size; }
Size measure(std::string_view text, Px font_size) const override;
 
private:
sf::Font font_{};
Px font_size_{};
};
 
class SfmlType : public IType {
public:
std::optional<std::shared_ptr<IFont const>> font(std::string_view name, Px size) const override;
std::optional<std::shared_ptr<IFont const>> font(std::string_view name) const override;
 
private:
mutable std::map<std::string, std::shared_ptr<SfmlFont>, std::less<>> font_cache_;
 
type/type.h added: 44, removed: 60, total 0
@@ -25,13 +25,13 @@ struct Px {
class IFont {
public:
virtual ~IFont() = default;
[[nodiscard]] virtual Size measure(std::string_view) const = 0;
[[nodiscard]] virtual Size measure(std::string_view, Px font_size) const = 0;
};
 
class IType {
public:
virtual ~IType() = default;
[[nodiscard]] virtual std::optional<std::shared_ptr<IFont const>> font(std::string_view name, Px size) const = 0;
[[nodiscard]] virtual std::optional<std::shared_ptr<IFont const>> font(std::string_view name) const = 0;
};
 
} // namespace type