The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
font_config.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2016 - 2025
3 by Chris Beck<render787@gmail.com>
4 Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY.
12
13 See the COPYING file for more details.
14*/
15
16#include "font/font_config.hpp"
17#include "font/error.hpp"
18
19#include "config.hpp"
20#include "log.hpp"
21#include "tstring.hpp"
22
23#include "filesystem.hpp"
24
27
28#include <sstream>
29
30
31#include <fontconfig/fontconfig.h>
32#ifdef _WIN32
33#include <pango/pangocairo.h>
34#endif
35
36static lg::log_domain log_font("font");
37#define DBG_FT LOG_STREAM(debug, log_font)
38#define LOG_FT LOG_STREAM(info, log_font)
39#define WRN_FT LOG_STREAM(warn, log_font)
40#define ERR_FT LOG_STREAM(err, log_font)
41
42namespace font
43{
44namespace
45{
46
47/** Records the game's families for sans serif, script, and monospace fonts */
48struct font_families
49{
50 font_families() = default;
51
52 explicit font_families(const config& cfg)
53 : sans(cfg["family_order"].t_str())
54 , mono(cfg["family_order_monospace"].t_str())
55 , script(cfg["family_order_script"].t_str())
56 {
57 if(mono.empty()) {
58 ERR_FT << "No monospace font family defined, falling back to sans serif";
59 mono = sans;
60 }
61
62 if(script.empty()) {
63 ERR_FT << "No script font family defined, falling back to sans serif";
64 script = sans;
65 }
66 }
67
71};
72
73font_families families;
74
75} //namespace
76
77/***
78 * Public interface
79 */
80
82try {
83 auto stream = preprocess_file(filesystem::get_wml_location("hardwired/fonts.cfg").value());
84 families = font_families{ io::read(*stream).mandatory_child("fonts") };
85 return true;
86
87} catch(const utils::bad_optional_access&) {
88 ERR_FT << "could not resolve path to fonts.cfg, file not found";
89 return false;
90
91} catch(const config::error& e) {
92 ERR_FT << "could not read fonts.cfg:\n" << e.message;
93 return false;
94}
95
97{
98 switch(fclass) {
100 return families.mono;
102 return families.script;
103 default:
104 return families.sans;
105 }
106}
107
108/***
109 * Manager member functions
110 */
111
113{
114 std::string font_path = game_config::path + "/fonts";
115 if (!FcConfigAppFontAddDir(FcConfigGetCurrent(),
116 reinterpret_cast<const FcChar8 *>(font_path.c_str())))
117 {
118 ERR_FT << "Could not load the true type fonts";
119 throw font::error("font config lib failed to add the font path: '" + font_path + "'");
120 }
121
122 std::string font_file = font_path + "/fonts.conf";
123 std::string font_file_contents = filesystem::read_file(font_file);
124
125// msys2 crosscompiling for windows for whatever reason makes the cache directory prefer using drives other than C:
126// ie - D:\a\msys64\var\cache\fontconfig
127// fontconfig also does not seem to provide a way to set the cachedir for a specific platform
128// so load the fonts.conf file into memory and only for windows insert the cachedir configuration
129#ifdef _WIN32
130 font_file_contents.insert(font_file_contents.find("</fontconfig>"), "<cachedir>"+filesystem::get_cache_dir()+"</cachedir>\n");
131#endif
132
133 if(!FcConfigParseAndLoadFromMemory(FcConfigGetCurrent(),
134 reinterpret_cast<const FcChar8*>(font_file_contents.c_str()),
135 FcFalse))
136 {
137 ERR_FT << "Could not load local font configuration";
138 throw font::error("font config lib failed to find font.conf: '" + font_file + "'");
139 }
140 else
141 {
142 LOG_FT << "Local font configuration loaded";
143 }
144
145#ifdef _WIN32
146 // Pango's default Windows back-end is the native win32/GDI one, which never
147 // consults fontconfig and thus never sees the custom fonts registered above.
148 // Setting PANGOCAIRO_BACKEND=fontconfig in main() is meant to prevent this,
149 // but on some Windows builds it has not reliably taken effect (since the
150 // SDL3 migration) before Pango's default font map is first created, so force
151 // it explicitly here instead of relying on that environment variable being
152 // seen in time.
153 PangoFontMap* fc_font_map = pango_cairo_font_map_new_for_font_type(CAIRO_FONT_TYPE_FT);
154 if(fc_font_map) {
155 pango_cairo_font_map_set_default(PANGO_CAIRO_FONT_MAP(fc_font_map));
156 g_object_unref(fc_font_map);
157 } else {
158 ERR_FT << "Could not create a fontconfig-backed Pango font map";
159 }
160#endif
161}
162
164{
165 FcConfigAppFontClear(FcConfigGetCurrent());
166}
167
168} // end namespace font
A config object defines a single node in a WML file, with access to child nodes.
Definition config.hpp:157
config & mandatory_child(std::string_view key, int n=0)
Returns the nth child with the given key, or throws an error if there is none.
Definition config.cpp:362
bool empty() const
Definition tstring.hpp:200
Definitions for the interface to Wesnoth Markup Language (WML).
const config * cfg
Declarations for File-IO.
#define LOG_FT
#define ERR_FT
t_string mono
t_string script
static lg::log_domain log_font("font")
t_string sans
Standard logging facilities (interface).
std::string get_cache_dir()
utils::optional< std::string > get_wml_location(const std::string &path, const utils::optional< std::string > &current_dir=utils::nullopt)
Returns a translated path to the actual file or directory, if it exists.
std::string read_file(const std::string &fname)
Basic disk I/O - read file.
Graphical text output.
const t_string & get_font_families(family_class fclass)
Returns the currently defined fonts.
bool load_font_config()
std::string path
config read(std::istream &in, abstract_validator *validator)
Definition parser.cpp:610
filesystem::scoped_istream preprocess_file(const std::string &fname, preproc_map &defines)
Function to use the WML preprocessor on a file.
std::unique_ptr< MIX_Audio, decltype(&MIX_DestroyAudio)> value
Definition sound.cpp:139
#define e