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