KiCad PCB EDA Suite
fontconfig.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2021 Ola Rinta-Koski
5 * Copyright (C) 2021-2022 KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software: you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#include <fontconfig/fontconfig.h>
22
23#include <font/fontconfig.h>
24#include <pgm_base.h>
25#include <wx/log.h>
26#include <trace_helpers.h>
27
28using namespace fontconfig;
29
30static FONTCONFIG* g_config = nullptr;
31
32
33inline static FcChar8* wxStringToFcChar8( const wxString& str )
34{
35 wxScopedCharBuffer const fcBuffer = str.ToUTF8();
36 return (FcChar8*) fcBuffer.data();
37}
38
39
40wxString FONTCONFIG::Version()
41{
42 return wxString::Format( "%d.%d.%d", FC_MAJOR, FC_MINOR, FC_REVISION );
43}
44
45
47{
48 (void) FcInitLoadConfigAndFonts();
49};
50
51
53{
54 if( !g_config )
55 {
56 FcInit();
57 g_config = new FONTCONFIG();
58 }
59
60 return g_config;
61}
62
63
64bool FONTCONFIG::FindFont( const wxString& aFontName, wxString& aFontFile )
65{
66 FcPattern* pat = FcNameParse( wxStringToFcChar8( aFontName ) );
67 FcConfigSubstitute( nullptr, pat, FcMatchPattern );
68 FcDefaultSubstitute( pat );
69
70 FcResult r = FcResultNoMatch;
71 FcPattern* font = FcFontMatch( nullptr, pat, &r );
72
73 wxString fontName;
74 bool ok = false;
75 bool substituted = false;
76
77 if( font )
78 {
79 FcChar8* file = nullptr;
80
81 if( FcPatternGetString( font, FC_FILE, 0, &file ) == FcResultMatch )
82 {
83 aFontFile = wxString::FromUTF8( (char*) file );
84
85 FcChar8* family = nullptr;
86 FcChar8* style = nullptr;
87
88 if( FcPatternGetString( font, FC_FAMILY, 0, &family ) == FcResultMatch )
89 {
90 fontName = wxString::FromUTF8( (char*) family );
91
92 if( FcPatternGetString( font, FC_STYLE, 0, &style ) == FcResultMatch )
93 {
94 wxString styleStr = wxString::FromUTF8( (char*) style );
95
96 if( !styleStr.IsEmpty() )
97 {
98 styleStr.Replace( " ", ":" );
99 fontName += ":" + styleStr;
100 }
101 }
102
103 // TODO: report Regular vs Book, Italic vs Oblique, etc. or filter them out?
104
105 if( aFontName.Contains( ":" ) )
106 substituted = aFontName.CmpNoCase( fontName ) != 0;
107 else
108 substituted = !fontName.StartsWith( aFontName );
109 }
110
111 ok = true;
112 }
113
114 FcPatternDestroy( font );
115 }
116
117 if( !ok )
118 wxLogWarning( _( "Error loading font '%s'." ), aFontName );
119 else if( substituted )
120 wxLogWarning( _( "Font '%s' not found; substituting '%s'." ), aFontName, fontName );
121
122 FcPatternDestroy( pat );
123 return ok;
124}
125
126
127void FONTCONFIG::ListFonts( std::vector<std::string>& aFonts )
128{
129 if( m_fonts.empty() )
130 {
131 FcPattern* pat = FcPatternCreate();
132 FcObjectSet* os = FcObjectSetBuild( FC_FAMILY, FC_STYLE, FC_LANG, FC_FILE, FC_OUTLINE,
133 nullptr );
134 FcFontSet* fs = FcFontList( nullptr, pat, os );
135
136 for( int i = 0; fs && i < fs->nfont; ++i )
137 {
138 FcPattern* font = fs->fonts[i];
139 FcChar8* file;
140 FcChar8* style;
141 FcChar8* family;
142 FcLangSet* langSet;
143 FcBool outline;
144
145 if( FcPatternGetString( font, FC_FILE, 0, &file ) == FcResultMatch
146 && FcPatternGetString( font, FC_FAMILY, 0, &family ) == FcResultMatch
147 && FcPatternGetString( font, FC_STYLE, 0, &style ) == FcResultMatch
148 && FcPatternGetLangSet( font, FC_LANG, 0, &langSet ) == FcResultMatch
149 && FcPatternGetBool( font, FC_OUTLINE, 0, &outline ) == FcResultMatch )
150 {
151 if( !outline )
152 continue;
153
154 std::string theFamily( reinterpret_cast<char *>( family ) );
155
156#ifdef __WXMAC__
157 // On Mac (at least) some of the font names are in their own language. If
158 // the OS doesn't support this language then we get a bunch of garbage names
159 // in the font menu.
160 //
161 // GTK, on the other hand, doesn't appear to support wxLocale::IsAvailable(),
162 // so we can't run these checks.
163
164 FcStrSet* langStrSet = FcLangSetGetLangs( langSet );
165 FcStrList* langStrList = FcStrListCreate( langStrSet );
166 FcChar8* langStr = FcStrListNext( langStrList );
167 bool langSupported = false;
168
169 if( !langStr )
170 {
171 // Symbol fonts (Wingdings, etc.) have no language
172 langSupported = true;
173 }
174 else while( langStr )
175 {
176 wxString langWxStr( reinterpret_cast<char *>( langStr ) );
177 const wxLanguageInfo* langInfo = wxLocale::FindLanguageInfo( langWxStr );
178
179 if( langInfo && wxLocale::IsAvailable( langInfo->Language ) )
180 {
181 langSupported = true;
182 break;
183 }
184 else
185 {
186 wxLogTrace( traceFonts, "Font '%s' language '%s' not supported by OS.",
187 theFamily, langWxStr );
188 }
189
190 langStr = FcStrListNext( langStrList );
191 }
192
193 FcStrListDone( langStrList );
194 FcStrSetDestroy( langStrSet );
195
196 if( !langSupported )
197 continue;
198#endif
199
200 std::string theFile( reinterpret_cast<char *>( file ) );
201 std::string theStyle( reinterpret_cast<char *>( style ) );
202 FONTINFO fontInfo( theFile, theStyle, theFamily );
203
204 if( theFamily.length() > 0 && theFamily.front() == '.' )
205 continue;
206
207 std::map<std::string, FONTINFO>::iterator it = m_fonts.find( theFamily );
208
209 if( it == m_fonts.end() )
210 m_fonts.emplace( theFamily, fontInfo );
211 else
212 it->second.Children().push_back( fontInfo );
213 }
214 }
215
216 if( fs )
217 FcFontSetDestroy( fs );
218 }
219
220 for( const std::pair<const std::string, FONTINFO>& entry : m_fonts )
221 aFonts.push_back( entry.second.Family() );
222}
bool FindFont(const wxString &aFontName, wxString &aFontFile)
Given a fully-qualified font name ("Times:Bold:Italic") find the closest matching font and return its...
Definition: fontconfig.cpp:64
std::map< std::string, FONTINFO > m_fonts
Definition: fontconfig.h:53
void ListFonts(std::vector< std::string > &aFonts)
List the current available font families.
Definition: fontconfig.cpp:127
#define _(s)
E_SERIE r
Definition: eserie.cpp:41
static FONTCONFIG * g_config
Definition: fontconfig.cpp:30
FONTCONFIG * Fontconfig()
Definition: fontconfig.cpp:52
static FcChar8 * wxStringToFcChar8(const wxString &str)
Definition: fontconfig.cpp:33
const wxChar *const traceFonts
Flag to enable locale debug output.
see class PGM_BASE
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
wxLogTrace helper definitions.