The Battle for Wesnoth  1.19.7+dev
font_config.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2016 - 2024
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 
25 #include "serialization/parser.hpp"
27 
28 #include <sstream>
29 
30 
31 #include <fontconfig/fontconfig.h>
32 
33 static lg::log_domain log_font("font");
34 #define DBG_FT LOG_STREAM(debug, log_font)
35 #define LOG_FT LOG_STREAM(info, log_font)
36 #define WRN_FT LOG_STREAM(warn, log_font)
37 #define ERR_FT LOG_STREAM(err, log_font)
38 
39 namespace font {
40 
41 
42 namespace
43 {
44 
45 // Current font family for sanserif and monospace fonts in the game
46 
47 t_string family_order_sans;
48 t_string family_order_mono;
49 t_string family_order_light;
50 t_string family_order_script;
51 
52 } // end anon namespace
53 
54 /***
55  * Public interface
56  */
57 
59 {
60  config cfg;
61  try {
62  const auto cfg_path = filesystem::get_wml_location("hardwired/fonts.cfg");
63  if(!cfg_path) {
64  ERR_FT << "could not resolve path to fonts.cfg, file not found";
65  return false;
66  }
67 
68  filesystem::scoped_istream stream = preprocess_file(cfg_path.value());
69  read(cfg, *stream);
70  } catch(const config::error &e) {
71  ERR_FT << "could not read fonts.cfg:\n" << e.message;
72  return false;
73  }
74 
75  auto fonts_config = cfg.optional_child("fonts");
76  if (!fonts_config)
77  return false;
78 
79  family_order_sans = fonts_config["family_order"];
80  family_order_mono = fonts_config["family_order_monospace"];
81  family_order_light = fonts_config["family_order_light"];
82  family_order_script = fonts_config["family_order_script"];
83 
84  if(family_order_mono.empty()) {
85  ERR_FT << "No monospace font family order defined, falling back to sans serif order";
86  family_order_mono = family_order_sans;
87  }
88 
89  if(family_order_light.empty()) {
90  ERR_FT << "No light font family order defined, falling back to sans serif order";
91  family_order_light = family_order_sans;
92  }
93 
94  if(family_order_script.empty()) {
95  ERR_FT << "No script font family order defined, falling back to sans serif order";
96  family_order_script = family_order_sans;
97  }
98 
99  return true;
100 }
101 
103 {
104  switch(fclass) {
105  case FONT_MONOSPACE:
106  return family_order_mono;
107  case FONT_LIGHT:
108  return family_order_light;
109  case FONT_SCRIPT:
110  return family_order_script;
111  default:
112  return family_order_sans;
113  }
114 }
115 
116 /***
117  * Manager member functions
118  */
119 
121 {
122  std::string font_path = game_config::path + "/fonts";
123  if (!FcConfigAppFontAddDir(FcConfigGetCurrent(),
124  reinterpret_cast<const FcChar8 *>(font_path.c_str())))
125  {
126  ERR_FT << "Could not load the true type fonts";
127  throw font::error("font config lib failed to add the font path: '" + font_path + "'");
128  }
129 
130  std::string font_file = font_path + "/fonts.conf";
131  std::string font_file_contents = filesystem::read_file(font_file);
132 
133 // msys2 crosscompiling for windows for whatever reason makes the cache directory prefer using drives other than C:
134 // ie - D:\a\msys64\var\cache\fontconfig
135 // fontconfig also does not seem to provide a way to set the cachedir for a specific platform
136 // so load the fonts.conf file into memory and only for windows insert the cachedir configuration
137 #ifdef _WIN32
138  font_file_contents.insert(font_file_contents.find("</fontconfig>"), "<cachedir>"+filesystem::get_cache_dir()+"</cachedir>\n");
139 #endif
140 
141  if(!FcConfigParseAndLoadFromMemory(FcConfigGetCurrent(),
142  reinterpret_cast<const FcChar8*>(font_file_contents.c_str()),
143  FcFalse))
144  {
145  ERR_FT << "Could not load local font configuration";
146  throw font::error("font config lib failed to find font.conf: '" + font_file + "'");
147  }
148  else
149  {
150  LOG_FT << "Local font configuration loaded";
151  }
152 }
153 
155 {
156  FcConfigAppFontClear(FcConfigGetCurrent());
157 }
158 
159 } // end namespace font
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:172
optional_config_impl< config > optional_child(config_key_type key, int n=0)
Equivalent to mandatory_child, but returns an empty optional if the nth child was not found.
Definition: config.cpp:384
Definitions for the interface to Wesnoth Markup Language (WML).
Declarations for File-IO.
#define LOG_FT
Definition: font_config.cpp:35
static lg::log_domain log_font("font")
#define ERR_FT
Definition: font_config.cpp:37
Standard logging facilities (interface).
std::string get_cache_dir()
Definition: filesystem.cpp:838
utils::optional< std::string > get_wml_location(const std::string &path, const utils::optional< std::string > &current_dir)
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.
std::unique_ptr< std::istream > scoped_istream
Definition: filesystem.hpp:53
Graphical text output.
family_class
Font classes for get_font_families().
@ FONT_MONOSPACE
@ FONT_LIGHT
@ FONT_SCRIPT
const t_string & get_font_families(family_class fclass)
Returns the currently defined fonts.
bool load_font_config()
Definition: font_config.cpp:58
std::string path
Definition: filesystem.cpp:91
filesystem::scoped_istream preprocess_file(const std::string &fname, preproc_map *defines)
Function to use the WML preprocessor on a file.
void read(config &cfg, std::istream &in, abstract_validator *validator)
Definition: parser.cpp:629
#define e