0031007: Coding - eliminate warnings issued while compiling with -pedantic flag
[occt.git] / src / Font / Font_FontMgr.cxx
CommitLineData
b311480e 1// Created on: 2008-01-20
2// Created by: Alexander A. BORODIN
973c2be1 3// Copyright (c) 2008-2014 OPEN CASCADE SAS
b311480e 4//
973c2be1 5// This file is part of Open CASCADE Technology software library.
b311480e 6//
d5f74e42 7// This library is free software; you can redistribute it and/or modify it under
8// the terms of the GNU Lesser General Public License version 2.1 as published
973c2be1 9// by the Free Software Foundation, with special exception defined in the file
10// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11// distribution for complete text of the license and disclaimer of any warranty.
b311480e 12//
973c2be1 13// Alternatively, this file may be used under the terms of Open CASCADE
14// commercial license or contractual agreement.
b311480e 15
42cf5bc1 16#include <Font_FontMgr.hxx>
5b377041 17
18#include <Font_NameOfFont.hxx>
725ef85e 19#include <Font_FTLibrary.hxx>
42cf5bc1 20#include <Font_SystemFont.hxx>
5b377041 21#include <Message.hxx>
22#include <Message_Messenger.hxx>
7fd59977 23#include <NCollection_List.hxx>
aff395a3 24#include <NCollection_Map.hxx>
42cf5bc1 25#include <OSD_Environment.hxx>
7fd59977 26#include <Standard_Stream.hxx>
42cf5bc1 27#include <Standard_Type.hxx>
aff395a3 28#include <TCollection_HAsciiString.hxx>
7fd59977 29
aff395a3 30#include <ft2build.h>
31#include FT_FREETYPE_H
25e59720 32IMPLEMENT_STANDARD_RTTIEXT(Font_FontMgr,Standard_Transient)
92efcf78 33
65360da3 34#if defined(_WIN32)
7fd59977 35
aff395a3 36 #include <windows.h>
37 #include <stdlib.h>
38
39 #ifdef _MSC_VER
40 #pragma comment (lib, "freetype.lib")
41 #endif
42
43 namespace
7fd59977 44 {
aff395a3 45 // list of supported extensions
46 static Standard_CString Font_FontMgr_Extensions[] =
47 {
48 "ttf",
49 "otf",
50 "ttc",
51 NULL
52 };
8c2d3314 53 }
aff395a3 54
55#else
7fd59977 56
aff395a3 57 #include <OSD_DirectoryIterator.hxx>
65360da3 58 #include <OSD_FileIterator.hxx>
aff395a3 59 #include <OSD_Path.hxx>
60 #include <OSD_File.hxx>
61 #include <OSD_OpenMode.hxx>
62 #include <OSD_Protection.hxx>
7fd59977 63
aff395a3 64 namespace
65 {
66
67 // list of supported extensions
68 static Standard_CString Font_FontMgr_Extensions[] =
69 {
70 "ttf",
71 "otf",
72 "ttc",
73 "pfa",
74 "pfb",
264abd72 75 #ifdef __APPLE__
76 // Datafork TrueType (OS X), obsolete
77 //"dfont",
78 #endif
aff395a3 79 NULL
80 };
81
565baee6 82 #if !defined(__ANDROID__) && !defined(__APPLE__) && !defined(__EMSCRIPTEN__)
aff395a3 83 // X11 configuration file in plain text format (obsolete - doesn't exists in modern distributives)
84 static Standard_CString myFontServiceConf[] = {"/etc/X11/fs/config",
85 "/usr/X11R6/lib/X11/fs/config",
86 "/usr/X11/lib/X11/fs/config",
87 NULL
88 };
c9983ee8 89
90 // Although fontconfig library can be built for various platforms,
91 // practically it is useful only on desktop Linux distributions, where it is always packaged.
92 #include <fontconfig/fontconfig.h>
264abd72 93 #endif
aff395a3 94
95 #ifdef __APPLE__
96 // default fonts paths in Mac OS X
97 static Standard_CString myDefaultFontsDirs[] = {"/System/Library/Fonts",
98 "/Library/Fonts",
99 NULL
100 };
101 #else
102 // default fonts paths in most Unix systems (Linux and others)
65360da3 103 static Standard_CString myDefaultFontsDirs[] = {"/system/fonts", // Android
104 "/usr/share/fonts",
aff395a3 105 "/usr/local/share/fonts",
106 NULL
107 };
108 #endif
109
110 static void addDirsRecursively (const OSD_Path& thePath,
111 NCollection_Map<TCollection_AsciiString>& theDirsMap)
7fd59977 112 {
aff395a3 113 TCollection_AsciiString aDirName;
114 thePath.SystemName (aDirName);
115 if (!theDirsMap.Add (aDirName))
116 {
117 return;
7fd59977 118 }
7fd59977 119
aff395a3 120 for (OSD_DirectoryIterator aDirIterator (thePath, "*"); aDirIterator.More(); aDirIterator.Next())
7fd59977 121 {
aff395a3 122 OSD_Path aChildDirPath;
123 aDirIterator.Values().Path (aChildDirPath);
124
125 TCollection_AsciiString aChildDirName;
126 aChildDirPath.SystemName (aChildDirName);
127 if (!aChildDirName.IsEqual (".") && !aChildDirName.IsEqual (".."))
128 {
129 aChildDirName = aDirName + "/" + aChildDirName;
130 OSD_Path aPath (aChildDirName);
131 addDirsRecursively (aPath, theDirsMap);
132 }
7fd59977 133 }
7fd59977 134 }
aff395a3 135
68858c7d 136 } // anonymous namespace
aff395a3 137
138#endif
139
9a90a452 140//! Retrieve font information.
141//! @param theFonts [out] list of validated fonts
142//! @param theFTLib [in] font library
143//! @param theFontPath [in] path to the file
144//! @param theFaceId [in] face id, or -1 to load all faces within the file
145//! @return TRUE if at least one font face has been detected
146static bool checkFont (NCollection_Sequence<Handle(Font_SystemFont)>& theFonts,
147 const Handle(Font_FTLibrary)& theFTLib,
148 const TCollection_AsciiString& theFontPath,
149 FT_Long theFaceId = -1)
aff395a3 150{
9a90a452 151 const FT_Long aFaceId = theFaceId != -1 ? theFaceId : 0;
aff395a3 152 FT_Face aFontFace;
9a90a452 153 FT_Error aFaceError = FT_New_Face (theFTLib->Instance(), theFontPath.ToCString(), aFaceId, &aFontFace);
aff395a3 154 if (aFaceError != FT_Err_Ok)
155 {
9a90a452 156 return false;
15e4e6a2 157 }
158 if (aFontFace->family_name == NULL // skip broken fonts (error in FreeType?)
159 || FT_Select_Charmap (aFontFace, ft_encoding_unicode) != 0) // Font_FTFont supports only UNICODE fonts
160 {
161 FT_Done_Face (aFontFace);
9a90a452 162 return false;
7fd59977 163 }
7fd59977 164
15e4e6a2 165 // FreeType decomposes font definition into Family Name and Style Name,
166 // so that fonts within the same Family and different Styles can be identified.
167 // OCCT Font Manager natively handles 4 basic styles: Regular, Bold, Italic and Bold+Italic.
168 // To include other non-standard Styles, their names can be appended to Family Name; for this, names of normal Styles should be removed.
169 TCollection_AsciiString aFamily (aFontFace->family_name);
170 TCollection_AsciiString aStyle (aFontFace->style_name != NULL ? aFontFace->style_name : "");
aff395a3 171 Font_FontAspect anAspect = Font_FA_Regular;
172 if (aFontFace->style_flags == (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD))
173 {
174 anAspect = Font_FA_BoldItalic;
15e4e6a2 175 const Standard_Integer aRemoveItalic = aStyle.Search ("Italic");
176 if (aRemoveItalic != -1)
177 {
178 aStyle.Remove (aRemoveItalic, 6);
179 }
180 else
181 {
182 // synonym
183 const Standard_Integer aRemoveOblique = aStyle.Search ("Oblique");
184 if (aRemoveOblique != -1)
185 {
186 aStyle.Remove (aRemoveOblique, 7);
187 }
188 }
189
190 const Standard_Integer aRemoveBold = aStyle.Search ("Bold");
191 if (aRemoveBold != -1)
192 {
193 aStyle.Remove (aRemoveBold, 4);
194 }
aff395a3 195 }
196 else if (aFontFace->style_flags == FT_STYLE_FLAG_ITALIC)
197 {
198 anAspect = Font_FA_Italic;
15e4e6a2 199 const Standard_Integer aRemoveItalic = aStyle.Search ("Italic");
200 if (aRemoveItalic != -1)
201 {
202 aStyle.Remove (aRemoveItalic, 6);
203 }
204 else
205 {
206 // synonym
207 const Standard_Integer aRemoveOblique = aStyle.Search ("Oblique");
208 if (aRemoveOblique != -1)
209 {
210 aStyle.Remove (aRemoveOblique, 7);
211 }
212 }
aff395a3 213 }
214 else if (aFontFace->style_flags == FT_STYLE_FLAG_BOLD)
215 {
216 anAspect = Font_FA_Bold;
15e4e6a2 217 const Standard_Integer aRemoveBold = aStyle.Search ("Bold");
218 if (aRemoveBold != -1)
219 {
220 aStyle.Remove (aRemoveBold, 4);
221 }
aff395a3 222 }
223
15e4e6a2 224 const Standard_Integer aRemoveReg = aStyle.Search ("Regular");
225 if (aRemoveReg != -1)
508643cf 226 {
15e4e6a2 227 aStyle.Remove (aRemoveReg, 7);
228 }
229 else
230 {
231 // synonym
232 const Standard_Integer aRemoveBook = aStyle.Search ("Book");
233 if (aRemoveBook != -1)
234 {
235 aStyle.Remove (aRemoveBook, 4);
236 }
508643cf 237 }
7fd59977 238
15e4e6a2 239 aStyle.LeftAdjust();
240 aStyle.RightAdjust();
241 for (;;)
242 {
243 // remove double spaces after removal of several keywords in-between, like "Condensed Bold Italic Oblique"
244 const Standard_Integer aRemoveSpace = aStyle.Search (" ");
245 if (aRemoveSpace == -1)
246 {
247 break;
248 }
249
250 aStyle.Remove (aRemoveSpace, 1);
251 }
252
253 if (!aStyle.IsEmpty())
254 {
255 aFamily = aFamily + " " + aStyle;
256 }
7fd59977 257
15e4e6a2 258 Handle(Font_SystemFont) aResult = new Font_SystemFont (aFamily);
9a90a452 259 aResult->SetFontPath (anAspect, theFontPath, (Standard_Integer )aFaceId);
15e4e6a2 260 // automatically identify some known single-line fonts
261 aResult->SetSingleStrokeFont (aResult->FontKey().StartsWith ("olf "));
9a90a452 262 theFonts.Append (aResult);
263
264 if (theFaceId < aFontFace->num_faces)
265 {
266 const FT_Long aNbInstances = aFontFace->style_flags >> 16;
267 for (FT_Long anInstIter = 1; anInstIter < aNbInstances; ++anInstIter)
268 {
269 const FT_Long aSubFaceId = aFaceId + (anInstIter << 16);
270 checkFont (theFonts, theFTLib, theFontPath, aSubFaceId);
271 }
272 }
273 if (theFaceId == -1)
274 {
275 for (FT_Long aFaceIter = 1; aFaceIter < aFontFace->num_faces; ++aFaceIter)
276 {
277 checkFont (theFonts, theFTLib, theFontPath, aFaceIter);
278 }
279 }
15e4e6a2 280
281 FT_Done_Face (aFontFace);
9a90a452 282 return true;
aff395a3 283}
7fd59977 284
aff395a3 285// =======================================================================
286// function : GetInstance
287// purpose :
288// =======================================================================
289Handle(Font_FontMgr) Font_FontMgr::GetInstance()
290{
eeaaaefb 291 static Handle(Font_FontMgr) _mgr;
aff395a3 292 if (_mgr.IsNull())
293 {
eeaaaefb 294 _mgr = new Font_FontMgr();
aff395a3 295 }
7fd59977 296
297 return _mgr;
7fd59977 298}
299
912761ea 300// =======================================================================
301// function : ToUseUnicodeSubsetFallback
302// purpose :
303// =======================================================================
304Standard_Boolean& Font_FontMgr::ToUseUnicodeSubsetFallback()
305{
306 static Standard_Boolean TheToUseUnicodeSubsetFallback = true;
307 return TheToUseUnicodeSubsetFallback;
308}
309
5b377041 310// =======================================================================
311// function : addFontAlias
312// purpose :
313// =======================================================================
314void Font_FontMgr::addFontAlias (const TCollection_AsciiString& theAliasName,
315 const Handle(Font_FontAliasSequence)& theAliases,
316 Font_FontAspect theAspect)
317{
318 if (theAliases.IsNull()
319 || theAliases->IsEmpty())
320 {
321 return;
322 }
323
324 Handle(Font_FontAliasSequence) anAliases = theAliases;
325 if (theAspect != Font_FA_Undefined)
326 {
327 anAliases = new Font_FontAliasSequence();
328 for (Font_FontAliasSequence::Iterator anAliasIter (*theAliases); anAliasIter.More(); anAliasIter.Next())
329 {
330 const TCollection_AsciiString& aName = anAliasIter.Value().FontName;
331 anAliases->Append (Font_FontAlias (aName, theAspect));
332 }
333 }
334
335 TCollection_AsciiString anAliasName (theAliasName);
336 anAliasName.LowerCase();
337 myFontAliases.Bind (anAliasName, anAliases);
338}
339
aff395a3 340// =======================================================================
341// function : Font_FontMgr
342// purpose :
343// =======================================================================
344Font_FontMgr::Font_FontMgr()
5b377041 345: myToTraceAliases (Standard_False)
aff395a3 346{
5b377041 347 Handle(Font_FontAliasSequence) aMono = new Font_FontAliasSequence();
348 Handle(Font_FontAliasSequence) aSerif = new Font_FontAliasSequence();
349 Handle(Font_FontAliasSequence) aSans = new Font_FontAliasSequence();
350 Handle(Font_FontAliasSequence) aSymbol = new Font_FontAliasSequence();
351 Handle(Font_FontAliasSequence) aScript = new Font_FontAliasSequence();
352 Handle(Font_FontAliasSequence) aWinDin = new Font_FontAliasSequence();
353 Handle(Font_FontAliasSequence) anIris = new Font_FontAliasSequence();
354 Handle(Font_FontAliasSequence) aCJK = new Font_FontAliasSequence();
355 Handle(Font_FontAliasSequence) aKorean = new Font_FontAliasSequence();
912761ea 356 Handle(Font_FontAliasSequence) anArab = new Font_FontAliasSequence();
5b377041 357
358 // best matches - pre-installed on Windows, some of them are pre-installed on macOS,
359 // and sometimes them can be found installed on other systems (by user)
360 aMono ->Append (Font_FontAlias ("courier new"));
361 aSerif ->Append (Font_FontAlias ("times new roman"));
362 aSans ->Append (Font_FontAlias ("arial"));
363 aSymbol->Append (Font_FontAlias ("symbol"));
364 aScript->Append (Font_FontAlias ("script"));
365 aWinDin->Append (Font_FontAlias ("wingdings"));
366 anIris ->Append (Font_FontAlias ("lucida console"));
367
368#if defined(__ANDROID__)
369 // Noto font family is usually installed on Android 6+ devices
370 aMono ->Append (Font_FontAlias ("noto mono"));
371 aSerif ->Append (Font_FontAlias ("noto serif"));
372 // Droid font family is usually installed on Android 4+ devices
373 aMono ->Append (Font_FontAlias ("droid sans mono"));
374 aSerif ->Append (Font_FontAlias ("droid serif"));
375 aSans ->Append (Font_FontAlias ("roboto")); // actually DroidSans.ttf
376#elif !defined(_WIN32) && !defined(__APPLE__) //X11
377 aSerif ->Append (Font_FontAlias ("times"));
378 aSans ->Append (Font_FontAlias ("helvetica"));
379 // GNU FreeFonts family is usually installed on Linux
380 aMono ->Append (Font_FontAlias ("freemono"));
381 aSerif ->Append (Font_FontAlias ("freeserif"));
382 aSans ->Append (Font_FontAlias ("freesans"));
383 // DejaVu font family is usually installed on Linux
384 aMono ->Append (Font_FontAlias ("dejavu sans mono"));
385 aSerif ->Append (Font_FontAlias ("dejavu serif"));
386 aSans ->Append (Font_FontAlias ("dejavu sans"));
387#endif
388
389 // default CJK (Chinese/Japanese/Korean) fonts
390 aCJK ->Append (Font_FontAlias ("simsun")); // Windows
391 aCJK ->Append (Font_FontAlias ("droid sans fallback")); // Android, Linux
392 aCJK ->Append (Font_FontAlias ("noto sans sc")); // Android
393
394#if defined(_WIN32)
395 aKorean->Append (Font_FontAlias ("malgun gothic")); // introduced since Vista
396 aKorean->Append (Font_FontAlias ("gulim")); // used on older systems (Windows XP)
397#elif defined(__APPLE__)
398 aKorean->Append (Font_FontAlias ("applegothic"));
399 aKorean->Append (Font_FontAlias ("stfangsong"));
400#endif
401 aKorean->Append (Font_FontAlias ("nanumgothic")); // Android, Linux
402 aKorean->Append (Font_FontAlias ("noto sans kr")); // Android
403 aKorean->Append (Font_FontAlias ("nanummyeongjo")); // Linux
404 aKorean->Append (Font_FontAlias ("noto serif cjk jp")); // Linux
405 aKorean->Append (Font_FontAlias ("noto sans cjk jp")); // Linux
36e28f96 406 aKorean->Append (Font_FontAlias ("droid sans fallback")); // Linux
5b377041 407
912761ea 408#if defined(_WIN32)
409 anArab->Append (Font_FontAlias ("times new roman"));
410#elif defined(__APPLE__)
411 anArab->Append (Font_FontAlias ("decotype naskh"));
412#elif defined(__ANDROID__)
413 anArab->Append (Font_FontAlias ("droid arabic naskh"));
414 anArab->Append (Font_FontAlias ("noto naskh arabic"));
415#endif
416
5b377041 417 addFontAlias ("mono", aMono);
418 addFontAlias ("courier", aMono); // Font_NOF_ASCII_MONO
419 addFontAlias ("monospace", aMono); // Font_NOF_MONOSPACE
420 addFontAlias ("rock", aSans); // Font_NOF_CARTOGRAPHIC_SIMPLEX
421 addFontAlias ("sansserif", aSans); // Font_NOF_SANS_SERIF
422 addFontAlias ("sans-serif", aSans);
423 addFontAlias ("sans", aSans);
424 addFontAlias ("arial", aSans);
425 addFontAlias ("times", aSerif);
426 addFontAlias ("serif", aSerif); // Font_NOF_SERIF
427 addFontAlias ("times-roman", aSerif); // Font_NOF_ASCII_SIMPLEX
428 addFontAlias ("times-bold", aSerif, Font_FA_Bold); // Font_NOF_ASCII_DUPLEX
429 addFontAlias ("times-italic", aSerif, Font_FA_Italic); // Font_NOF_ASCII_ITALIC_COMPLEX
430 addFontAlias ("times-bolditalic", aSerif, Font_FA_BoldItalic); // Font_NOF_ASCII_ITALIC_TRIPLEX
431 addFontAlias ("symbol", aSymbol); // Font_NOF_GREEK_MONO
432 addFontAlias ("iris", anIris); // Font_NOF_KANJI_MONO
433 addFontAlias ("korean", aKorean); // Font_NOF_KOREAN
434 addFontAlias ("cjk", aCJK); // Font_NOF_CJK
435 addFontAlias ("nsimsun", aCJK);
912761ea 436 addFontAlias ("arabic", anArab); // Font_NOF_ARABIC
5b377041 437 addFontAlias (Font_NOF_SYMBOL_MONO, aWinDin);
438 addFontAlias (Font_NOF_ASCII_SCRIPT_SIMPLEX, aScript);
439
440 myFallbackAlias = aSans;
441
7fd59977 442 InitFontDataBase();
7fd59977 443}
444
9a90a452 445// =======================================================================
446// function : CheckFont
447// purpose :
448// =======================================================================
449Standard_Boolean Font_FontMgr::CheckFont (NCollection_Sequence<Handle(Font_SystemFont)>& theFonts,
450 const TCollection_AsciiString& theFontPath) const
451{
452 Handle(Font_FTLibrary) aFtLibrary = new Font_FTLibrary();
453 return checkFont (theFonts, aFtLibrary, theFontPath, 0);
454}
455
725ef85e 456// =======================================================================
457// function : CheckFont
458// purpose :
459// =======================================================================
460Handle(Font_SystemFont) Font_FontMgr::CheckFont (Standard_CString theFontPath) const
461{
462 Handle(Font_FTLibrary) aFtLibrary = new Font_FTLibrary();
9a90a452 463 NCollection_Sequence<Handle(Font_SystemFont)> aFonts;
464 return checkFont (aFonts, aFtLibrary, theFontPath, 0)
465 ? aFonts.First()
466 : Handle(Font_SystemFont)();
725ef85e 467}
468
469// =======================================================================
470// function : RegisterFont
471// purpose :
472// =======================================================================
473Standard_Boolean Font_FontMgr::RegisterFont (const Handle(Font_SystemFont)& theFont,
474 const Standard_Boolean theToOverride)
475{
476 if (theFont.IsNull())
477 {
478 return Standard_False;
479 }
480
5b377041 481 const Standard_Integer anOldIndex = myFontMap.FindIndex (theFont);
482 if (anOldIndex == 0)
483 {
484 myFontMap.Add (theFont);
485 return Standard_True;
486 }
487
488 Handle(Font_SystemFont) anOldFont = myFontMap.FindKey (anOldIndex);
489 for (int anAspectIter = 0; anAspectIter < Font_FontAspect_NB; ++anAspectIter)
725ef85e 490 {
9a90a452 491 if (anOldFont->FontPath ((Font_FontAspect )anAspectIter).IsEqual (theFont->FontPath ((Font_FontAspect )anAspectIter))
492 && anOldFont->FontFaceId ((Font_FontAspect )anAspectIter) == theFont->FontFaceId ((Font_FontAspect )anAspectIter))
725ef85e 493 {
494 continue;
495 }
5b377041 496 else if (theToOverride
497 || !anOldFont->HasFontAspect ((Font_FontAspect )anAspectIter))
725ef85e 498 {
9a90a452 499 anOldFont->SetFontPath ((Font_FontAspect )anAspectIter,
500 theFont->FontPath ((Font_FontAspect )anAspectIter),
501 theFont->FontFaceId ((Font_FontAspect )anAspectIter));
725ef85e 502 }
5b377041 503 else if (theFont->HasFontAspect ((Font_FontAspect )anAspectIter))
725ef85e 504 {
5b377041 505 return Standard_False;
725ef85e 506 }
507 }
725ef85e 508 return Standard_True;
509}
510
36e28f96 511// =======================================================================
512// function : ClearFontDataBase()
513// purpose :
514// =======================================================================
515void Font_FontMgr::ClearFontDataBase()
516{
517 myFontMap.Clear();
518}
519
aff395a3 520// =======================================================================
521// function : InitFontDataBase
522// purpose :
523// =======================================================================
524void Font_FontMgr::InitFontDataBase()
525{
5b377041 526 myFontMap.Clear();
c9983ee8 527 Handle(Font_FTLibrary) aFtLibrary = new Font_FTLibrary();
9a90a452 528 NCollection_Sequence<Handle(Font_SystemFont)> aFonts;
7fd59977 529
1ce0716b 530#if defined(OCCT_UWP)
531 // system font files are not accessible
532 (void )aFtLibrary;
533#elif defined(_WIN32)
7fd59977 534
aff395a3 535 // font directory is placed in "C:\Windows\Fonts\"
536 UINT aStrLength = GetSystemWindowsDirectoryA (NULL, 0);
537 if (aStrLength == 0)
a6535b1d 538 {
aff395a3 539 return;
a6535b1d 540 }
aff395a3 541
542 char* aWinDir = new char[aStrLength];
543 GetSystemWindowsDirectoryA (aWinDir, aStrLength);
5b377041 544 TCollection_AsciiString aFontsDir (aWinDir);
545 aFontsDir.AssignCat ("\\Fonts\\");
aff395a3 546 delete[] aWinDir;
547
548 // read fonts list from registry
549 HKEY aFontsKey;
550 if (RegOpenKeyExA (HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts",
551 0, KEY_READ, &aFontsKey) != ERROR_SUCCESS)
7fd59977 552 {
553 return;
7fd59977 554 }
7fd59977 555
aff395a3 556 NCollection_Map<TCollection_AsciiString> aSupportedExtensions;
557 for (Standard_Integer anIter = 0; Font_FontMgr_Extensions[anIter] != NULL; ++anIter)
7fd59977 558 {
aff395a3 559 Standard_CString anExt = Font_FontMgr_Extensions[anIter];
560 aSupportedExtensions.Add (TCollection_AsciiString (anExt));
7fd59977 561 }
562
aff395a3 563 static const DWORD aBufferSize = 256;
564 char aNameBuff[aBufferSize];
565 char aPathBuff[aBufferSize];
566 DWORD aNameSize = aBufferSize;
567 DWORD aPathSize = aBufferSize;
568 for (DWORD anIter = 0;
569 RegEnumValueA (aFontsKey, anIter,
570 aNameBuff, &aNameSize, NULL, NULL,
571 (LPBYTE )aPathBuff, &aPathSize) != ERROR_NO_MORE_ITEMS;
572 ++anIter, aNameSize = aBufferSize, aPathSize = aBufferSize)
573 {
574 aPathBuff[(aPathSize < aBufferSize) ? aPathSize : (aBufferSize - 1)] = '\0'; // ensure string is NULL-terminated
7fd59977 575
5b377041 576 TCollection_AsciiString aFontName (aNameBuff), aFontPath (aPathBuff);
577 if (aFontPath.Search ("\\") == -1)
aff395a3 578 {
5b377041 579 aFontPath.Insert (1, aFontsDir); // make absolute path
7fd59977 580 }
aff395a3 581
582 // check file extension is in list of supported
5b377041 583 const Standard_Integer anExtensionPosition = aFontPath.SearchFromEnd (".") + 1;
584 if (anExtensionPosition > 0 && anExtensionPosition < aFontPath.Length())
7fd59977 585 {
5b377041 586 TCollection_AsciiString aFontExtension = aFontPath.SubString (anExtensionPosition, aFontPath.Length());
587 aFontExtension.LowerCase();
588 if (aSupportedExtensions.Contains (aFontExtension))
aff395a3 589 {
9a90a452 590 aFonts.Clear();
591 checkFont (aFonts, aFtLibrary, aFontPath.ToCString());
592 RegisterFonts (aFonts, false);
aff395a3 593 }
7fd59977 594 }
595 }
7fd59977 596
aff395a3 597 // close registry key
598 RegCloseKey (aFontsKey);
599
600#else
7fd59977 601
aff395a3 602 NCollection_Map<TCollection_AsciiString> aMapOfFontsDirs;
565baee6 603#if !defined(__ANDROID__) && !defined(__APPLE__) && !defined(__EMSCRIPTEN__)
c9983ee8 604 if (FcConfig* aFcCfg = FcInitLoadConfig())
7fd59977 605 {
c9983ee8 606 if (FcStrList* aFcFontDir = FcConfigGetFontDirs (aFcCfg))
aff395a3 607 {
c9983ee8 608 for (;;)
609 {
610 FcChar8* aFcFolder = FcStrListNext (aFcFontDir);
611 if (aFcFolder == NULL)
612 {
613 break;
614 }
7fd59977 615
c9983ee8 616 TCollection_AsciiString aPathStr ((const char* )aFcFolder);
617 OSD_Path aPath (aPathStr);
618 addDirsRecursively (aPath, aMapOfFontsDirs);
619 }
620 FcStrListDone (aFcFontDir);
aff395a3 621 }
c9983ee8 622 FcConfigDestroy (aFcCfg);
623 }
624
625 const OSD_Protection aProtectRead (OSD_R, OSD_R, OSD_R, OSD_R);
626 if (aMapOfFontsDirs.IsEmpty())
627 {
628 Message::DefaultMessenger()->Send ("Font_FontMgr, fontconfig library returns an empty folder list", Message_Alarm);
aff395a3 629
c9983ee8 630 // read fonts directories from font service config file (obsolete)
631 for (Standard_Integer anIter = 0; myFontServiceConf[anIter] != NULL; ++anIter)
7fd59977 632 {
c9983ee8 633 const TCollection_AsciiString aFileOfFontsPath (myFontServiceConf[anIter]);
634 OSD_File aFile (aFileOfFontsPath);
635 if (!aFile.Exists())
636 {
637 continue;
638 }
aff395a3 639
c9983ee8 640 aFile.Open (OSD_ReadOnly, aProtectRead);
641 if (!aFile.IsOpen())
aff395a3 642 {
c9983ee8 643 continue;
aff395a3 644 }
645
c9983ee8 646 Standard_Integer aNByte = 256;
647 Standard_Integer aNbyteRead;
648 TCollection_AsciiString aStr; // read string with information
649 while (!aFile.IsAtEnd())
7fd59977 650 {
c9983ee8 651 Standard_Integer aLocation = -1;
652 Standard_Integer aPathLocation = -1;
653
654 aFile.ReadLine (aStr, aNByte, aNbyteRead); // reading 1 line (256 bytes)
655 aLocation = aStr.Search ("catalogue=");
656 if (aLocation < 0)
657 {
658 aLocation = aStr.Search ("catalogue =");
659 }
660
661 aPathLocation = aStr.Search ("/");
662 if (aLocation > 0 && aPathLocation > 0)
7fd59977 663 {
c9983ee8 664 aStr = aStr.Split (aPathLocation - 1);
665 TCollection_AsciiString aFontPath;
666 Standard_Integer aPathNumber = 1;
667 do
7fd59977 668 {
c9983ee8 669 // Getting directory paths, which can be splitted by "," or ":"
670 aFontPath = aStr.Token (":,", aPathNumber);
671 aFontPath.RightAdjust();
672 if (!aFontPath.IsEmpty())
673 {
674 OSD_Path aPath(aFontPath);
675 addDirsRecursively (aPath, aMapOfFontsDirs);
676 }
677 aPathNumber++;
7fd59977 678 }
c9983ee8 679 while (!aFontPath.IsEmpty());
aff395a3 680 }
7fd59977 681 }
c9983ee8 682 aFile.Close();
7fd59977 683 }
684 }
264abd72 685#endif
7fd59977 686
aff395a3 687 // append default directories
688 for (Standard_Integer anIter = 0; myDefaultFontsDirs[anIter] != NULL; ++anIter)
689 {
690 Standard_CString anItem = myDefaultFontsDirs[anIter];
691 TCollection_AsciiString aPathStr (anItem);
692 OSD_Path aPath (aPathStr);
693 addDirsRecursively (aPath, aMapOfFontsDirs);
694 }
695
696 NCollection_Map<TCollection_AsciiString> aSupportedExtensions;
697 for (Standard_Integer anIter = 0; Font_FontMgr_Extensions[anIter] != NULL; ++anIter)
698 {
699 Standard_CString anExt = Font_FontMgr_Extensions[anIter];
700 aSupportedExtensions.Add (TCollection_AsciiString (anExt));
701 }
702
aff395a3 703 for (NCollection_Map<TCollection_AsciiString>::Iterator anIter (aMapOfFontsDirs);
704 anIter.More(); anIter.Next())
705 {
565baee6 706 #if !defined(__ANDROID__) && !defined(__APPLE__) && !defined(__EMSCRIPTEN__)
5b377041 707 OSD_File aReadFile (anIter.Value() + "/fonts.dir");
708 if (!aReadFile.Exists())
65360da3 709 {
5b377041 710 #endif
711 OSD_Path aFolderPath (anIter.Value());
712 for (OSD_FileIterator aFileIter (aFolderPath, "*"); aFileIter.More(); aFileIter.Next())
713 {
714 OSD_Path aFontFilePath;
715 aFileIter.Values().Path (aFontFilePath);
65360da3 716
5b377041 717 TCollection_AsciiString aFontFileName;
718 aFontFilePath.SystemName (aFontFileName);
719 aFontFileName = anIter.Value() + "/" + aFontFileName;
65360da3 720
9a90a452 721 aFonts.Clear();
722 checkFont (aFonts, aFtLibrary, aFontFileName);
723 RegisterFonts (aFonts, false);
65360da3 724 }
5b377041 725
565baee6 726 #if !defined(__ANDROID__) && !defined(__APPLE__) && !defined(__EMSCRIPTEN__)
5b377041 727 continue;
aff395a3 728 }
729
730 aReadFile.Open (OSD_ReadOnly, aProtectRead);
731 if (!aReadFile.IsOpen())
732 {
733 continue; // invalid fonts directory
734 }
735
736 Standard_Integer aNbyteRead, aNByte = 256;
737 TCollection_AsciiString aLine (aNByte);
738 Standard_Boolean isFirstLine = Standard_True;
739 const TCollection_AsciiString anEncoding ("iso8859-1\n");
740 while (!aReadFile.IsAtEnd())
741 {
742 aReadFile.ReadLine (aLine, aNByte, aNbyteRead);
743 if (isFirstLine)
744 {
745 // first line contains the number of fonts in this file
746 // just ignoring it...
747 isFirstLine = Standard_False;
748 continue;
749 }
7fd59977 750
aff395a3 751 Standard_Integer anExtensionPosition = aLine.Search (".") + 1;
752 if (anExtensionPosition == 0)
753 {
754 continue; // can't find extension position in the font description
755 }
7fd59977 756
aff395a3 757 Standard_Integer anEndOfFileName = aLine.Location (" ", anExtensionPosition, aLine.Length()) - 1;
758 if (anEndOfFileName < 0 || anEndOfFileName < anExtensionPosition)
759 {
760 continue; // font description have empty extension
761 }
7fd59977 762
aff395a3 763 TCollection_AsciiString aFontExtension = aLine.SubString (anExtensionPosition, anEndOfFileName);
764 aFontExtension.LowerCase();
765 if (aSupportedExtensions.Contains (aFontExtension) && (aLine.Search (anEncoding) > 0))
7fd59977 766 {
aff395a3 767 // In current implementation use fonts with ISO-8859-1 coding page.
768 // OCCT not give to manage coding page by means of programm interface.
769 // TODO: make high level interface for choosing necessary coding page.
5b377041 770 TCollection_AsciiString aXLFD (aLine.SubString (anEndOfFileName + 2, aLine.Length()));
771 TCollection_AsciiString aFontPath (anIter.Value().ToCString());
772 if (aFontPath.SearchFromEnd ("/") != aFontPath.Length())
aff395a3 773 {
5b377041 774 aFontPath.AssignCat ("/");
aff395a3 775 }
5b377041 776 TCollection_AsciiString aFontFileName (aLine.SubString (1, anEndOfFileName));
777 aFontPath.AssignCat (aFontFileName);
9a90a452 778
779 aFonts.Clear();
780 if (checkFont (aFonts, aFtLibrary, aFontPath))
aff395a3 781 {
9a90a452 782 RegisterFonts (aFonts, false);
783 const Handle(Font_SystemFont)& aNewFont = aFonts.First();
5b377041 784 if (!aXLFD.IsEmpty()
785 && aXLFD.Search ("-0-0-0-0-") != -1) // ignore non-resizable fonts
786 {
787 const TCollection_AsciiString anXName = aXLFD.Token ("-", 2);
788 Font_FontAspect anXAspect = Font_FA_Regular;
789 if (aXLFD.Token ("-", 3).IsEqual ("bold")
790 && (aXLFD.Token ("-", 4).IsEqual ("i")
791 || aXLFD.Token ("-", 4).IsEqual ("o")))
792 {
793 anXAspect = Font_FA_BoldItalic;
794 }
795 else if (aXLFD.Token ("-", 3).IsEqual ("bold"))
796 {
797 anXAspect = Font_FA_Bold;
798 }
799 else if (aXLFD.Token ("-", 4).IsEqual ("i")
800 || aXLFD.Token ("-", 4).IsEqual ("o"))
801 {
802 anXAspect = Font_FA_Italic;
803 }
804
805 Handle(Font_SystemFont) aNewFontFromXLFD = new Font_SystemFont (anXName);
9a90a452 806 aNewFontFromXLFD->SetFontPath (anXAspect, aFontPath, 0);
5b377041 807 if (!aNewFont->IsEqual (aNewFontFromXLFD))
808 {
809 RegisterFont (aNewFontFromXLFD, false);
810 }
811 }
aff395a3 812 }
aff395a3 813 }
7fd59977 814 }
aff395a3 815 aReadFile.Close();
65360da3 816 #endif
7fd59977 817 }
818#endif
aff395a3 819}
820
b514beda 821// =======================================================================
822// function : GetAvailableFontsNames
823// purpose :
824// =======================================================================
aff395a3 825void Font_FontMgr::GetAvailableFontsNames (TColStd_SequenceOfHAsciiString& theFontsNames) const
826{
827 theFontsNames.Clear();
5b377041 828 for (NCollection_IndexedMap<Handle(Font_SystemFont), Font_SystemFont>::Iterator aFontIter (myFontMap);
829 aFontIter.More(); aFontIter.Next())
aff395a3 830 {
5b377041 831 const Handle(Font_SystemFont)& aFont = aFontIter.Value();
832 theFontsNames.Append (new TCollection_HAsciiString(aFont->FontName()));
aff395a3 833 }
7fd59977 834}
835
b514beda 836// =======================================================================
837// function : GetFont
838// purpose :
839// =======================================================================
aff395a3 840Handle(Font_SystemFont) Font_FontMgr::GetFont (const Handle(TCollection_HAsciiString)& theFontName,
b514beda 841 const Font_FontAspect theFontAspect,
aff395a3 842 const Standard_Integer theFontSize) const
7fd59977 843{
5b377041 844 if ((theFontSize < 2 && theFontSize != -1) || theFontName.IsNull())
aff395a3 845 {
5b377041 846 return Handle(Font_SystemFont)();
aff395a3 847 }
848
5b377041 849 Handle(Font_SystemFont) aFont = myFontMap.Find (theFontName->String());
850 return (aFont.IsNull()
851 || theFontAspect == Font_FontAspect_UNDEFINED
852 || aFont->HasFontAspect (theFontAspect))
853 ? aFont
854 : Handle(Font_SystemFont)();
855}
aff395a3 856
5b377041 857// =======================================================================
858// function : GetFont
859// purpose :
860// =======================================================================
861Handle(Font_SystemFont) Font_FontMgr::GetFont (const TCollection_AsciiString& theFontName) const
862{
863 return myFontMap.Find (theFontName);
7fd59977 864}
865
912761ea 866// =======================================================================
867// function : FindFallbackFont
868// purpose :
869// =======================================================================
870Handle(Font_SystemFont) Font_FontMgr::FindFallbackFont (Font_UnicodeSubset theSubset,
871 Font_FontAspect theFontAspect) const
872{
873 Font_FontAspect aFontAspect = theFontAspect;
36e28f96 874 Handle(Font_SystemFont) aFont;
912761ea 875 switch (theSubset)
876 {
36e28f96 877 case Font_UnicodeSubset_Western: aFont = FindFont (Font_NOF_SANS_SERIF, Font_StrictLevel_Aliases, aFontAspect, false); break;
878 case Font_UnicodeSubset_Korean: aFont = FindFont (Font_NOF_KOREAN, Font_StrictLevel_Aliases, aFontAspect, false); break;
879 case Font_UnicodeSubset_CJK: aFont = FindFont (Font_NOF_CJK, Font_StrictLevel_Aliases, aFontAspect, false); break;
880 case Font_UnicodeSubset_Arabic: aFont = FindFont (Font_NOF_ARABIC, Font_StrictLevel_Aliases, aFontAspect, false); break;
912761ea 881 }
36e28f96 882 if (aFont.IsNull())
883 {
884 const char* aRange = "";
885 switch (theSubset)
886 {
887 case Font_UnicodeSubset_Western: aRange = "Western"; break;
888 case Font_UnicodeSubset_Korean: aRange = "Korean"; break;
889 case Font_UnicodeSubset_CJK: aRange = "CJK"; break;
890 case Font_UnicodeSubset_Arabic: aRange = "Arabic"; break;
891 }
892 Message::DefaultMessenger()->Send (TCollection_AsciiString("Font_FontMgr, error: unable to find ") + aRange + " fallback font!", Message_Fail);
893 }
894 return aFont;
912761ea 895}
896
b514beda 897// =======================================================================
898// function : FindFont
899// purpose :
900// =======================================================================
5b377041 901Handle(Font_SystemFont) Font_FontMgr::FindFont (const TCollection_AsciiString& theFontName,
1bbd7c79 902 Font_StrictLevel theStrictLevel,
36e28f96 903 Font_FontAspect& theFontAspect,
904 Standard_Boolean theDoFailMsg) const
aff395a3 905{
5b377041 906 TCollection_AsciiString aFontName (theFontName);
907 aFontName.LowerCase();
908 Handle(Font_SystemFont) aFont = myFontMap.Find (aFontName);
1bbd7c79 909 if (!aFont.IsNull()
910 || theStrictLevel == Font_StrictLevel_Strict)
aff395a3 911 {
912 return aFont;
913 }
914
915 // Trying to use font names mapping
976627e6 916 for (int aPass = 0; aPass < 2; ++aPass)
aff395a3 917 {
976627e6 918 Handle(Font_FontAliasSequence) anAliases;
919 if (aPass == 0)
920 {
921 myFontAliases.Find (aFontName, anAliases);
922 }
1bbd7c79 923 else if (theStrictLevel == Font_StrictLevel_Any)
976627e6 924 {
925 anAliases = myFallbackAlias;
926 }
aff395a3 927
976627e6 928 if (anAliases.IsNull()
929 || anAliases->IsEmpty())
930 {
931 continue;
932 }
933
934 bool isAliasUsed = false, isBestAlias = false;
5b377041 935 for (Font_FontAliasSequence::Iterator anAliasIter (*anAliases); anAliasIter.More(); anAliasIter.Next())
b514beda 936 {
5b377041 937 const Font_FontAlias& anAlias = anAliasIter.Value();
938 if (Handle(Font_SystemFont) aFont2 = myFontMap.Find (anAlias.FontName))
939 {
940 if (aFont.IsNull())
941 {
942 aFont = aFont2;
943 isAliasUsed = true;
944 }
945
946 if ((anAlias.FontAspect != Font_FontAspect_UNDEFINED
947 && aFont2->HasFontAspect (anAlias.FontAspect)))
948 {
949 // special case - alias refers to styled font (e.g. "times-bold")
950 isBestAlias = true;
951 theFontAspect = anAlias.FontAspect;
952 break;
953 }
954 else if (anAlias.FontAspect == Font_FontAspect_UNDEFINED
955 && (theFontAspect == Font_FontAspect_UNDEFINED
976627e6 956 || aFont2->HasFontAspect (theFontAspect)))
5b377041 957 {
958 isBestAlias = true;
959 break;
960 }
961 }
962 }
976627e6 963
964 if (aPass == 0)
5b377041 965 {
966 if (isAliasUsed && myToTraceAliases)
967 {
968 Message::DefaultMessenger()->Send (TCollection_AsciiString("Font_FontMgr, using font alias '") + aFont->FontName() + "'"
976627e6 969 " instead of requested '" + theFontName +"'", Message_Trace);
5b377041 970 }
971 if (isBestAlias)
972 {
973 return aFont;
974 }
976627e6 975 else if (!aFont.IsNull())
976 {
977 break;
978 }
b514beda 979 }
980 }
aff395a3 981
912761ea 982 if (aFont.IsNull()
983 && theStrictLevel == Font_StrictLevel_Any)
aff395a3 984 {
5b377041 985 // try finding ANY font in case if even default fallback alias myFallbackAlias cannot be found
986 aFont = myFontMap.Find (TCollection_AsciiString());
987 }
988 if (aFont.IsNull())
989 {
36e28f96 990 if (theDoFailMsg)
991 {
992 Message::DefaultMessenger()->Send (TCollection_AsciiString("Font_FontMgr, error: unable to find any font!"), Message_Fail);
993 }
5b377041 994 return Handle(Font_SystemFont)();
aff395a3 995 }
996
5b377041 997 if ((theFontAspect != Font_FA_Undefined
998 && !aFont->HasFontAspect (theFontAspect))
999 || (!aFontName.IsEmpty()
1000 && !aFontName.IsEqual (aFont->FontKey())))
aff395a3 1001 {
5b377041 1002 TCollection_AsciiString aDesc = TCollection_AsciiString() + "'" + theFontName + "'"
1003 + TCollection_AsciiString() + " [" + Font_FontMgr::FontAspectToString (theFontAspect) + "]";
1004 Message::DefaultMessenger()->Send (TCollection_AsciiString("Font_FontMgr, warning: unable to find font ")
1005 + aDesc + "; " + aFont->ToString() + " is used instead");
aff395a3 1006 }
5b377041 1007 return aFont;
1008}
aff395a3 1009
5b377041 1010// =======================================================================
1011// function : Font_FontMap::Find
1012// purpose :
1013// =======================================================================
1014Handle(Font_SystemFont) Font_FontMgr::Font_FontMap::Find (const TCollection_AsciiString& theFontName) const
1015{
1016 if (IsEmpty())
aff395a3 1017 {
5b377041 1018 return Handle(Font_SystemFont)();
1019 }
1020 else if (theFontName.IsEmpty())
1021 {
1022 return FindKey (1); // return any font
aff395a3 1023 }
1024
5b377041 1025 TCollection_AsciiString aFontName (theFontName);
1026 aFontName.LowerCase();
1027 for (IndexedMapNode* aNodeIter = (IndexedMapNode* )myData1[::HashCode (aFontName, NbBuckets())];
1028 aNodeIter != NULL; aNodeIter = (IndexedMapNode* )aNodeIter->Next())
1029 {
1030 const Handle(Font_SystemFont)& aKey = aNodeIter->Key1();
1031 if (aKey->FontKey().IsEqual (aFontName))
1032 {
1033 return aKey;
1034 }
1035 }
1036 return Handle(Font_SystemFont)();
aff395a3 1037}