srctree

Robin Linden parent c7ad03fb 408529dd
gfx/sfml: Use type/sfml for font-handling

The fallback-handling remains in gfx/sfml for now.

inlinesplit
browser/gui/app.cpp added: 50, removed: 95, total 0
@@ -649,7 +649,7 @@ void App::switch_canvas() {
reset_scroll();
if (selected_canvas_ == Canvas::OpenGL) {
selected_canvas_ = Canvas::Sfml;
canvas_ = std::make_unique<gfx::SfmlCanvas>(window_);
canvas_ = std::make_unique<gfx::SfmlCanvas>(window_, static_cast<type::SfmlType &>(engine_.font_system()));
} else {
selected_canvas_ = Canvas::OpenGL;
canvas_ = std::make_unique<gfx::OpenGLCanvas>();
 
browser/gui/app.h added: 50, removed: 95, total 0
@@ -58,7 +58,8 @@ private:
};
 
Canvas selected_canvas_{Canvas::Sfml};
std::unique_ptr<gfx::ICanvas> canvas_{std::make_unique<gfx::SfmlCanvas>(window_)};
std::unique_ptr<gfx::ICanvas> canvas_{
std::make_unique<gfx::SfmlCanvas>(window_, static_cast<type::SfmlType &>(engine_.font_system()))};
 
// The scroll offset is the opposite of the current translation of the web page.
// When we scroll "down", the web page is translated "up".
 
gfx/BUILD added: 50, removed: 95, total 0
@@ -71,7 +71,7 @@ cc_library(
deps = [
":gfx",
"//os:xdg",
"//util:string",
"//type:sfml",
"@sfml//:graphics",
"@spdlog",
],
@@ -96,6 +96,7 @@ cc_binary(
":gfx",
":opengl",
":sfml",
"//type:sfml",
"@sfml//:graphics",
"@sfml//:window",
],
 
gfx/gfx_example.cpp added: 50, removed: 95, total 0
@@ -5,6 +5,7 @@
#include "gfx/color.h"
#include "gfx/opengl_canvas.h"
#include "gfx/sfml_canvas.h"
#include "type/sfml.h"
 
#include <SFML/Graphics/RenderWindow.hpp>
#include <SFML/Window/Event.hpp>
@@ -22,9 +23,11 @@ int main(int argc, char **argv) {
window.setVerticalSyncEnabled(true);
window.setActive(true);
 
type::SfmlType type;
 
auto canvas = [&]() -> std::unique_ptr<gfx::ICanvas> {
if (argc == 2 && argv[1] == "--sf"sv) {
return std::make_unique<gfx::SfmlCanvas>(window);
return std::make_unique<gfx::SfmlCanvas>(window, type);
}
return std::make_unique<gfx::OpenGLCanvas>();
}();
 
gfx/sfml_canvas.cpp added: 50, removed: 95, total 0
@@ -6,7 +6,6 @@
#include "gfx/sfml_canvas.h"
 
#include "os/xdg.h"
#include "util/string.h"
 
#include <SFML/Graphics/RectangleShape.hpp>
#include <SFML/Graphics/RenderTarget.hpp>
@@ -15,8 +14,8 @@
#include <SFML/Graphics/View.hpp>
#include <spdlog/spdlog.h>
 
#include <algorithm>
#include <cassert>
#include <exception>
#include <filesystem>
#include <optional>
#include <string>
@@ -40,13 +39,13 @@ std::filesystem::recursive_directory_iterator get_font_dir_iterator(std::filesys
return {};
}
 
std::optional<std::shared_ptr<sf::Font>> load_fallback_font() {
auto font = std::make_shared<sf::Font>();
sf::Font load_fallback_font() {
sf::Font font;
for (auto const &path : os::font_paths()) {
for (auto const &entry : get_font_dir_iterator(path)) {
if (std::filesystem::is_regular_file(entry) && entry.path().filename().string().ends_with(".ttf")) {
spdlog::info("Trying fallback {}", entry.path().string());
if (font->loadFromFile(entry.path().string())) {
if (font.loadFromFile(entry.path().string())) {
spdlog::info("Using fallback {}", entry.path().string());
return font;
}
@@ -54,25 +53,23 @@ std::optional<std::shared_ptr<sf::Font>> load_fallback_font() {
}
}
 
return std::nullopt;
spdlog::critical("Not a single usable font found");
std::terminate();
}
 
// TODO(robinlinden): We should be looking at font names rather than filenames.
std::optional<std::string> find_path_to_font(std::string_view font_filename) {
for (auto const &path : os::font_paths()) {
for (auto const &entry : get_font_dir_iterator(path)) {
auto name = entry.path().filename().string();
// TODO(robinlinden): std::ranges once Clang supports it. Last tested w/ 15.
if (std::search(begin(name), end(name), begin(font_filename), end(font_filename), [](char a, char b) {
return util::lowercased(a) == util::lowercased(b);
}) != end(name)) {
spdlog::info("Found font {} for {}", entry.path().string(), font_filename);
return std::make_optional(entry.path().string());
}
std::shared_ptr<type::SfmlFont const> find_font(type::SfmlType &type, std::span<gfx::Font const> font_families) {
for (auto const &family : font_families) {
if (auto font = type.font(family.font)) {
return std::static_pointer_cast<type::SfmlFont const>(*std::move(font));
}
}
 
return std::nullopt;
auto fallback = std::make_shared<type::SfmlFont>(load_fallback_font());
if (!font_families.empty()) {
type.set_font(std::string{font_families[0].font}, fallback);
}
 
return fallback;
}
 
sf::Glsl::Vec2 to_vec2(int x, int y) {
@@ -103,7 +100,7 @@ sf::Text::Style to_sfml(FontStyle style) {
 
} // namespace
 
SfmlCanvas::SfmlCanvas(sf::RenderTarget &target) : target_{target} {
SfmlCanvas::SfmlCanvas(sf::RenderTarget &target, type::SfmlType &type) : target_{target}, type_{type} {
border_shader_.loadFromMemory(
std::string{reinterpret_cast<char const *>(gfx_basic_shader_vert), gfx_basic_shader_vert_len},
std::string{reinterpret_cast<char const *>(gfx_rect_shader_frag), gfx_rect_shader_frag_len});
@@ -172,67 +169,12 @@ void SfmlCanvas::draw_text(geom::Position p,
FontSize size,
FontStyle style,
Color color) {
// Try to find a cached font.
for (auto const &font : font_options) {
if (auto it = font_cache_.find(font.font); it != font_cache_.end()) {
draw_text(p, text, font, size, style, color);
return;
}
}
 
// Try to load one of the options provided.
for (auto const &font : font_options) {
auto font_path = find_path_to_font(font.font);
auto entry = std::make_shared<sf::Font>();
if (!font_path || !entry->loadFromFile(*font_path)) {
continue;
}
 
font_cache_[std::string{font.font}] = std::move(entry);
draw_text(p, text, font, size, style, color);
return;
}
 
// Let the normal draw_text deal with loading a fallback.
if (!font_options.empty()) {
draw_text(p, text, font_options.front(), size, style, color);
}
}
 
// TODO(robinlinden): Fonts are never evicted from the cache.
void SfmlCanvas::draw_text(
geom::Position p, std::string_view text, Font font, FontSize size, FontStyle style, Color color) {
p = p.translated(tx_, ty_).scaled(scale_);
 
auto const *sf_font = [&]() -> sf::Font const * {
if (auto it = font_cache_.find(font.font); it != font_cache_.end()) {
return &*it->second;
}
 
auto font_path = find_path_to_font(font.font);
auto entry = std::make_shared<sf::Font>();
if (!font_path || !entry->loadFromFile(*font_path)) {
spdlog::warn("Unable to load font {}, looking for literally any font", font.font);
if (auto fallback = load_fallback_font()) {
entry = *std::move(fallback);
}
}
 
if (!entry) {
return nullptr;
}
 
font_cache_[std::string{font.font}] = std::move(entry);
return &*font_cache_.find(font.font)->second;
}();
 
if (!sf_font) {
spdlog::error("Unable to find font, not drawing text");
return;
}
auto font = find_font(type_, font_options);
assert(font != nullptr);
 
sf::Text drawable;
drawable.setFont(*sf_font);
drawable.setFont(font->sf_font());
drawable.setString(sf::String::fromUtf8(cbegin(text), cend(text)));
drawable.setFillColor(sf::Color(color.as_rgba_u32()));
drawable.setCharacterSize(size.px * scale_);
@@ -241,6 +183,11 @@ void SfmlCanvas::draw_text(
target_.draw(drawable);
}
 
void SfmlCanvas::draw_text(
geom::Position p, std::string_view text, Font font, FontSize size, FontStyle style, Color color) {
draw_text(p, text, std::span<gfx::Font const>{{font}}, size, style, color);
}
 
void SfmlCanvas::draw_pixels(geom::Rect const &rect, std::span<std::uint8_t const> rgba_data) {
assert(rgba_data.size() == static_cast<std::size_t>(rect.width * rect.height * 4));
sf::Image img;
 
gfx/sfml_canvas.h added: 50, removed: 95, total 0
@@ -7,11 +7,11 @@
 
#include "gfx/icanvas.h"
 
#include "type/sfml.h"
 
#include <SFML/Graphics/Shader.hpp>
#include <SFML/Graphics/Texture.hpp>
 
#include <map>
#include <memory>
#include <vector>
 
namespace sf {
@@ -23,7 +23,7 @@ namespace gfx {
 
class SfmlCanvas : public ICanvas {
public:
explicit SfmlCanvas(sf::RenderTarget &target);
explicit SfmlCanvas(sf::RenderTarget &target, type::SfmlType &);
 
void set_viewport_size(int width, int height) override;
constexpr void set_scale(int scale) override { scale_ = scale; }
@@ -42,8 +42,8 @@ public:
 
private:
sf::RenderTarget &target_;
type::SfmlType &type_;
sf::Shader border_shader_{};
std::map<std::string, std::shared_ptr<sf::Font>, std::less<>> font_cache_;
std::vector<sf::Texture> textures_;
 
int scale_{1};
 
img/BUILD added: 50, removed: 95, total 0
@@ -76,6 +76,7 @@ cc_binary(
":qoi",
"//gfx",
"//gfx:sfml",
"//type:sfml",
"@sfml//:graphics",
"@sfml//:window",
],
 
img/img_example.cpp added: 50, removed: 95, total 0
@@ -8,6 +8,7 @@
 
#include "gfx/color.h"
#include "gfx/sfml_canvas.h"
#include "type/sfml.h"
 
#include <SFML/Graphics/RenderWindow.hpp>
#include <SFML/Window/Event.hpp>
@@ -112,7 +113,8 @@ int main(int argc, char **argv) {
window.setVerticalSyncEnabled(true);
window.setActive(true);
 
gfx::SfmlCanvas canvas{window};
type::SfmlType type;
gfx::SfmlCanvas canvas{window, type};
 
bool running = true;
while (running) {