The Battle for Wesnoth  1.13.10+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
font_config.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2016 - 2017 by Chris Beck<render787@gmail.com>
3  Part of the Battle for Wesnoth Project http://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 #include "font/font_config.hpp"
17 #include "font/error.hpp"
18 #include "font/sdl_ttf.hpp"
19 
20 #include "config.hpp"
21 #include "log.hpp"
22 #include "tstring.hpp"
23 
24 #include "filesystem.hpp"
25 #include "game_config.hpp"
26 
27 #include "serialization/parser.hpp"
31 #include "preferences/general.hpp"
32 
33 #include <list>
34 #include <set>
35 #include <stack>
36 #include <sstream>
37 #include <vector>
38 
39 #include <cairo-features.h>
40 
41 #ifdef CAIRO_HAS_WIN32_FONT
42 #include <windows.h>
43 #undef CAIRO_HAS_FT_FONT
44 #endif
45 
46 #ifdef CAIRO_HAS_FT_FONT
47 #include <fontconfig/fontconfig.h>
48 #endif
49 
50 #if !defined(CAIRO_HAS_FT_FONT) && !defined(CAIRO_HAS_WIN32_FONT)
51 #error unable to find font loading tools.
52 #endif
53 
54 static lg::log_domain log_font("font");
55 #define DBG_FT LOG_STREAM(debug, log_font)
56 #define LOG_FT LOG_STREAM(info, log_font)
57 #define WRN_FT LOG_STREAM(warn, log_font)
58 #define ERR_FT LOG_STREAM(err, log_font)
59 
60 namespace font {
61 
62 
64  if(game_config::path.empty() == false) {
65  if(!filesystem::file_exists(game_config::path + "/fonts/" + name)) {
66  if(!filesystem::file_exists("fonts/" + name)) {
67  if(!filesystem::file_exists(name)) {
68  WRN_FT << "Failed opening font file '" << name << "': No such file or directory" << std::endl;
69  return false;
70  }
71  }
72  }
73  } else {
74  if(!filesystem::file_exists("fonts/" + name)) {
75  if(!filesystem::file_exists(name)) {
76  WRN_FT << "Failed opening font file '" << name << "': No such file or directory" << std::endl;
77  return false;
78  }
79  }
80  }
81  return true;
82 }
83 
84 static bool add_font_to_fontlist(const config &fonts_config,
85  std::vector<font::subset_descriptor>& fontlist, const std::string& name)
86 {
87  const config &font = fonts_config.find_child("font", "name", name);
88  if (!font) {
89  return false;
90  }
91  //DBG_FT << "Adding a font record: " << font.debug() << std::endl;
92 
93  fontlist.push_back(font::subset_descriptor(font));
94 
95  return true;
96 }
97 
98 // Current font family for sanserif and monospace fonts in the game
99 
102 
103 /***
104  * Public interface
105  */
106 
108 {
109  //read font config separately, so we do not have to re-read the whole
110  //config when changing languages
111  config cfg;
112  try {
113  const std::string& cfg_path = filesystem::get_wml_location("hardwired/fonts.cfg");
114  if(cfg_path.empty()) {
115  ERR_FT << "could not resolve path to fonts.cfg, file not found\n";
116  return false;
117  }
118 
119  filesystem::scoped_istream stream = preprocess_file(cfg_path);
120  read(cfg, *stream);
121  } catch(config::error &e) {
122  ERR_FT << "could not read fonts.cfg:\n"
123  << e.message << '\n';
124  return false;
125  }
126 
127  const config &fonts_config = cfg.child("fonts");
128  if (!fonts_config)
129  return false;
130 
131  std::set<std::string> known_fonts;
132  for (const config &font : fonts_config.child_range("font")) {
133  known_fonts.insert(font["name"]);
134  if (font.has_attribute("bold_name")) {
135  known_fonts.insert(font["bold_name"]);
136  }
137  if (font.has_attribute("italic_name")) {
138  known_fonts.insert(font["italic_name"]);
139  }
140  }
141 
142  family_order_sans = fonts_config["family_order"];
143  family_order_mono = fonts_config["family_order_monospace"];
144 
145  if(family_order_mono.empty()) {
146  ERR_FT << "No monospace font family order defined, falling back to sans serif order\n";
147  family_order_mono = family_order_sans;
148  }
149 
150  std::vector<font::subset_descriptor> fontlist;
151 
152  for(auto font : utils::split(fonts_config["order"])) {
153  add_font_to_fontlist(fonts_config, fontlist, font);
154  known_fonts.erase(font);
155  }
156 
157  for(auto kfont : known_fonts) {
158  add_font_to_fontlist(fonts_config, fontlist, kfont);
159  }
160 
161  if(fontlist.empty())
162  return false;
163 
164  sdl_ttf::set_font_list(fontlist);
165  return true;
166 }
167 
169 {
170  switch(fclass) {
171  case FONT_MONOSPACE:
172  return family_order_mono;
173  default:
174  return family_order_sans;
175  }
176 }
177 
178 /***
179  * Manager member functions
180  */
181 
183 {
184 #ifdef CAIRO_HAS_FT_FONT
185  std::string font_path = game_config::path + "/fonts";
186  if (!FcConfigAppFontAddDir(FcConfigGetCurrent(),
187  reinterpret_cast<const FcChar8 *>(font_path.c_str())))
188  {
189  ERR_FT << "Could not load the true type fonts" << std::endl;
190  throw font::error("font config lib failed to add the font path: '" + font_path + "'");
191  }
192 
193  std::string font_file = font_path + "/fonts.conf";
194  if(!FcConfigParseAndLoad(FcConfigGetCurrent(),
195  reinterpret_cast<const FcChar8*>(font_file.c_str()),
196  FcFalse))
197  {
198  ERR_FT << "Could not load local font configuration\n";
199  throw font::error("font config lib failed to find font.conf: '" + font_file + "'");
200  }
201  else
202  {
203  LOG_FT << "Local font configuration loaded\n";
204  }
205 #endif
206 
207 #if CAIRO_HAS_WIN32_FONT
208  for(const std::string& path : filesystem::get_binary_paths("fonts")) {
209  std::vector<std::string> files;
212  }
213  for(const std::string& file : files) {
214  if(file.substr(file.length() - 4) == ".ttf" || file.substr(file.length() - 4) == ".ttc")
215  {
216  const std::wstring wfile = unicode_cast<std::wstring>(file);
217  AddFontResourceExW(wfile.c_str(), FR_PRIVATE, nullptr);
218  }
219  }
220  }
221 #endif
222 }
223 
225 {
226 #ifdef CAIRO_HAS_FT_FONT
227  FcConfigAppFontClear(FcConfigGetCurrent());
228 #endif
229 
230 #if CAIRO_HAS_WIN32_FONT
231  for(const std::string& path : filesystem::get_binary_paths("fonts")) {
232  std::vector<std::string> files;
235  for(const std::string& file : files) {
236  if(file.substr(file.length() - 4) == ".ttf" || file.substr(file.length() - 4) == ".ttc")
237  {
238  const std::wstring wfile = unicode_cast<std::wstring>(file);
239  RemoveFontResourceExW(wfile.c_str(), FR_PRIVATE, nullptr);
240  }
241  }
242  }
243 #endif
244 }
245 
246 
247 } // end namespace font
config & child(config_key_type key, int n=0)
Returns the nth child with the given key, or a reference to an invalid config if there is none...
Definition: config.cpp:352
std::vector< char_t > string
family_class
Font classes for get_font_families().
bool check_font_file(std::string name)
Test if a font file exists.
Definition: font_config.cpp:63
Note: Specific to sdl_ttf.
config & find_child(config_key_type key, const std::string &name, const std::string &value)
Returns the first child of tag key with a name attribute containing value.
Definition: config.cpp:715
static l_noret error(LoadState *S, const char *why)
Definition: lundump.cpp:39
ucs4_convert_impl::enableif< TD, typename TS::value_type >::type unicode_cast(const TS &source)
child_itors child_range(config_key_type key)
Definition: config.cpp:295
#define WRN_FT
Definition: font_config.cpp:57
#define LOG_FT
Definition: font_config.cpp:56
Definitions for the interface to Wesnoth Markup Language (WML).
std::vector< std::string > split(const std::string &val, const char c, const int flags)
Splits a (comma-)separated string into a vector of pieces.
const t_string & get_font_families(family_class fclass)
Returns the currently defined fonts.
t_string family_order_sans
void read(config &cfg, std::istream &in, abstract_validator *validator)
Definition: parser.cpp:612
bool is_directory(const std::string &fname)
Returns true if the given file is a directory.
std::unique_ptr< std::istream > scoped_istream
Definition: filesystem.hpp:37
std::string path
Definition: game_config.cpp:56
static lg::log_domain log_font("font")
bool load_font_config()
const std::vector< std::string > & get_binary_paths(const std::string &type)
Returns a vector with all possible paths to a given type of binary, e.g.
void get_files_in_dir(const std::string &dir, std::vector< std::string > *files, std::vector< std::string > *dirs=nullptr, file_name_option mode=FILE_NAME_ONLY, file_filter_option filter=NO_FILTER, file_reorder_option reorder=DONT_REORDER, file_tree_checksum *checksum=nullptr)
Populates 'files' with all the files and 'dirs' with all the directories in dir.
std::string get_wml_location(const std::string &filename, const std::string &current_dir=std::string())
Returns a complete path to the actual WML file or directory or an empty string if the file isn't pres...
static void set_font_list(const std::vector< subset_descriptor > &fontlist)
Definition: sdl_ttf.cpp:515
Declarations for File-IO.
#define ERR_FT
Definition: font_config.cpp:58
Standard logging facilities (interface).
std::string message
Definition: exceptions.hpp:31
static const char * name(const std::vector< SDL_Joystick * > &joysticks, const size_t index)
Definition: joystick.cpp:48
t_string family_order_mono
static bool add_font_to_fontlist(const config &fonts_config, std::vector< font::subset_descriptor > &fontlist, const std::string &name)
Definition: font_config.cpp:84
#define e
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:93
filesystem::scoped_istream preprocess_file(const std::string &fname, preproc_map *defines)
bool file_exists(const std::string &name)
Returns true if a file or directory with such name already exists.
bool empty() const
Definition: tstring.hpp:172