0031007: Coding - eliminate warnings issued while compiling with -pedantic flag
[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     // list of supported extensions
46     static Standard_CString Font_FontMgr_Extensions[] =
47     {
48       "ttf",
49       "otf",
50       "ttc",
51       NULL
52     };
53   }
54
55 #else
56
57   #include <OSD_DirectoryIterator.hxx>
58   #include <OSD_FileIterator.hxx>
59   #include <OSD_Path.hxx>
60   #include <OSD_File.hxx>
61   #include <OSD_OpenMode.hxx>
62   #include <OSD_Protection.hxx>
63
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",
75     #ifdef __APPLE__
76       // Datafork TrueType (OS X), obsolete
77       //"dfont",
78     #endif
79       NULL
80     };
81
82   #if !defined(__ANDROID__) && !defined(__APPLE__) && !defined(__EMSCRIPTEN__)
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                                                   };
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>
93   #endif
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)
103     static Standard_CString myDefaultFontsDirs[] = {"/system/fonts",         // Android
104                                                     "/usr/share/fonts",
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)
112     {
113       TCollection_AsciiString aDirName;
114       thePath.SystemName (aDirName);
115       if (!theDirsMap.Add (aDirName))
116       {
117         return;
118       }
119
120       for (OSD_DirectoryIterator aDirIterator (thePath, "*"); aDirIterator.More(); aDirIterator.Next())
121       {
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         }
133       }
134     }
135
136   } // anonymous namespace
137
138 #endif
139
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
146 static bool checkFont (NCollection_Sequence<Handle(Font_SystemFont)>& theFonts,
147                        const Handle(Font_FTLibrary)& theFTLib,
148                        const TCollection_AsciiString& theFontPath,
149                        FT_Long theFaceId = -1)
150 {
151   const FT_Long aFaceId = theFaceId != -1 ? theFaceId : 0;
152   FT_Face aFontFace;
153   FT_Error aFaceError = FT_New_Face (theFTLib->Instance(), theFontPath.ToCString(), aFaceId, &aFontFace);
154   if (aFaceError != FT_Err_Ok)
155   {
156     return false;
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);
162     return false;
163   }
164
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 : "");
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;
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     }
195   }
196   else if (aFontFace->style_flags == FT_STYLE_FLAG_ITALIC)
197   {
198     anAspect = Font_FA_Italic;
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     }
213   }
214   else if (aFontFace->style_flags == FT_STYLE_FLAG_BOLD)
215   {
216     anAspect = Font_FA_Bold;
217     const Standard_Integer aRemoveBold = aStyle.Search ("Bold");
218     if (aRemoveBold != -1)
219     {
220       aStyle.Remove (aRemoveBold, 4);
221     }
222   }
223
224   const Standard_Integer aRemoveReg = aStyle.Search ("Regular");
225   if (aRemoveReg != -1)
226   {
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     }
237   }
238
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   }
257
258   Handle(Font_SystemFont) aResult = new Font_SystemFont (aFamily);
259   aResult->SetFontPath (anAspect, theFontPath, (Standard_Integer )aFaceId);
260   // automatically identify some known single-line fonts
261   aResult->SetSingleStrokeFont (aResult->FontKey().StartsWith ("olf "));
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   }
280
281   FT_Done_Face (aFontFace);
282   return true;
283 }
284
285 // =======================================================================
286 // function : GetInstance
287 // purpose  :
288 // =======================================================================
289 Handle(Font_FontMgr) Font_FontMgr::GetInstance()
290 {
291   static Handle(Font_FontMgr) _mgr;
292   if (_mgr.IsNull())
293   {
294     _mgr = new Font_FontMgr();
295   }
296
297   return _mgr;
298 }
299
300 // =======================================================================
301 // function : ToUseUnicodeSubsetFallback
302 // purpose  :
303 // =======================================================================
304 Standard_Boolean& Font_FontMgr::ToUseUnicodeSubsetFallback()
305 {
306   static Standard_Boolean TheToUseUnicodeSubsetFallback = true;
307   return TheToUseUnicodeSubsetFallback;
308 }
309
310 // =======================================================================
311 // function : addFontAlias
312 // purpose  :
313 // =======================================================================
314 void 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
340 // =======================================================================
341 // function : Font_FontMgr
342 // purpose  :
343 // =======================================================================
344 Font_FontMgr::Font_FontMgr()
345 : myToTraceAliases (Standard_False)
346 {
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();
356   Handle(Font_FontAliasSequence) anArab  = new Font_FontAliasSequence();
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
406   aKorean->Append (Font_FontAlias ("droid sans fallback")); // Linux
407
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
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);
436   addFontAlias ("arabic",            anArab);                     // Font_NOF_ARABIC
437   addFontAlias (Font_NOF_SYMBOL_MONO,          aWinDin);
438   addFontAlias (Font_NOF_ASCII_SCRIPT_SIMPLEX, aScript);
439
440   myFallbackAlias = aSans;
441
442   InitFontDataBase();
443 }
444
445 // =======================================================================
446 // function : CheckFont
447 // purpose  :
448 // =======================================================================
449 Standard_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
456 // =======================================================================
457 // function : CheckFont
458 // purpose  :
459 // =======================================================================
460 Handle(Font_SystemFont) Font_FontMgr::CheckFont (Standard_CString theFontPath) const
461 {
462   Handle(Font_FTLibrary) aFtLibrary = new Font_FTLibrary();
463   NCollection_Sequence<Handle(Font_SystemFont)> aFonts;
464   return checkFont (aFonts, aFtLibrary, theFontPath, 0)
465        ? aFonts.First()
466        : Handle(Font_SystemFont)();
467 }
468
469 // =======================================================================
470 // function : RegisterFont
471 // purpose  :
472 // =======================================================================
473 Standard_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
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)
490   {
491     if (anOldFont->FontPath ((Font_FontAspect )anAspectIter).IsEqual (theFont->FontPath ((Font_FontAspect )anAspectIter))
492      && anOldFont->FontFaceId ((Font_FontAspect )anAspectIter) == theFont->FontFaceId ((Font_FontAspect )anAspectIter))
493     {
494       continue;
495     }
496     else if (theToOverride
497          || !anOldFont->HasFontAspect ((Font_FontAspect )anAspectIter))
498     {
499       anOldFont->SetFontPath ((Font_FontAspect )anAspectIter,
500                               theFont->FontPath ((Font_FontAspect )anAspectIter),
501                               theFont->FontFaceId ((Font_FontAspect )anAspectIter));
502     }
503     else if (theFont->HasFontAspect ((Font_FontAspect )anAspectIter))
504     {
505       return Standard_False;
506     }
507   }
508   return Standard_True;
509 }
510
511 // =======================================================================
512 // function : ClearFontDataBase()
513 // purpose  :
514 // =======================================================================
515 void Font_FontMgr::ClearFontDataBase()
516 {
517   myFontMap.Clear();
518 }
519
520 // =======================================================================
521 // function : InitFontDataBase
522 // purpose  :
523 // =======================================================================
524 void Font_FontMgr::InitFontDataBase()
525 {
526   myFontMap.Clear();
527   Handle(Font_FTLibrary) aFtLibrary = new Font_FTLibrary();
528   NCollection_Sequence<Handle(Font_SystemFont)> aFonts;
529
530 #if defined(OCCT_UWP)
531   // system font files are not accessible
532   (void )aFtLibrary;
533 #elif defined(_WIN32)
534
535   // font directory is placed in "C:\Windows\Fonts\"
536   UINT aStrLength = GetSystemWindowsDirectoryA (NULL, 0);
537   if (aStrLength == 0)
538   {
539     return;
540   }
541
542   char* aWinDir = new char[aStrLength];
543   GetSystemWindowsDirectoryA (aWinDir, aStrLength);
544   TCollection_AsciiString aFontsDir (aWinDir);
545   aFontsDir.AssignCat ("\\Fonts\\");
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)
552   {
553     return;
554   }
555
556   NCollection_Map<TCollection_AsciiString> aSupportedExtensions;
557   for (Standard_Integer anIter = 0; Font_FontMgr_Extensions[anIter] != NULL; ++anIter)
558   {
559     Standard_CString anExt = Font_FontMgr_Extensions[anIter];
560     aSupportedExtensions.Add (TCollection_AsciiString (anExt));
561   }
562
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
575
576     TCollection_AsciiString aFontName (aNameBuff), aFontPath (aPathBuff);
577     if (aFontPath.Search ("\\") == -1)
578     {
579       aFontPath.Insert (1, aFontsDir); // make absolute path
580     }
581
582     // check file extension is in list of supported
583     const Standard_Integer anExtensionPosition = aFontPath.SearchFromEnd (".") + 1;
584     if (anExtensionPosition > 0 && anExtensionPosition < aFontPath.Length())
585     {
586       TCollection_AsciiString aFontExtension = aFontPath.SubString (anExtensionPosition, aFontPath.Length());
587       aFontExtension.LowerCase();
588       if (aSupportedExtensions.Contains (aFontExtension))
589       {
590         aFonts.Clear();
591         checkFont (aFonts, aFtLibrary, aFontPath.ToCString());
592         RegisterFonts (aFonts, false);
593       }
594     }
595   }
596
597   // close registry key
598   RegCloseKey (aFontsKey);
599
600 #else
601
602   NCollection_Map<TCollection_AsciiString> aMapOfFontsDirs;
603 #if !defined(__ANDROID__) && !defined(__APPLE__) && !defined(__EMSCRIPTEN__)
604   if (FcConfig* aFcCfg = FcInitLoadConfig())
605   {
606     if (FcStrList* aFcFontDir = FcConfigGetFontDirs (aFcCfg))
607     {
608       for (;;)
609       {
610         FcChar8* aFcFolder = FcStrListNext (aFcFontDir);
611         if (aFcFolder == NULL)
612         {
613           break;
614         }
615
616         TCollection_AsciiString aPathStr ((const char* )aFcFolder);
617         OSD_Path aPath (aPathStr);
618         addDirsRecursively (aPath, aMapOfFontsDirs);
619       }
620       FcStrListDone (aFcFontDir);
621     }
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);
629
630     // read fonts directories from font service config file (obsolete)
631     for (Standard_Integer anIter = 0; myFontServiceConf[anIter] != NULL; ++anIter)
632     {
633       const TCollection_AsciiString aFileOfFontsPath (myFontServiceConf[anIter]);
634       OSD_File aFile (aFileOfFontsPath);
635       if (!aFile.Exists())
636       {
637         continue;
638       }
639
640       aFile.Open (OSD_ReadOnly, aProtectRead);
641       if (!aFile.IsOpen())
642       {
643         continue;
644       }
645
646       Standard_Integer aNByte = 256;
647       Standard_Integer aNbyteRead;
648       TCollection_AsciiString aStr; // read string with information
649       while (!aFile.IsAtEnd())
650       {
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)
663         {
664           aStr = aStr.Split (aPathLocation - 1);
665           TCollection_AsciiString aFontPath;
666           Standard_Integer aPathNumber = 1;
667           do
668           {
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++;
678           }
679           while (!aFontPath.IsEmpty());
680         }
681       }
682       aFile.Close();
683     }
684   }
685 #endif
686
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
703   for (NCollection_Map<TCollection_AsciiString>::Iterator anIter (aMapOfFontsDirs);
704        anIter.More(); anIter.Next())
705   {
706   #if !defined(__ANDROID__) && !defined(__APPLE__) && !defined(__EMSCRIPTEN__)
707     OSD_File aReadFile (anIter.Value() + "/fonts.dir");
708     if (!aReadFile.Exists())
709     {
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);
716
717         TCollection_AsciiString aFontFileName;
718         aFontFilePath.SystemName (aFontFileName);
719         aFontFileName = anIter.Value() + "/" + aFontFileName;
720
721         aFonts.Clear();
722         checkFont (aFonts, aFtLibrary, aFontFileName);
723         RegisterFonts (aFonts, false);
724       }
725
726   #if !defined(__ANDROID__) && !defined(__APPLE__) && !defined(__EMSCRIPTEN__)
727       continue;
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       }
750
751       Standard_Integer anExtensionPosition = aLine.Search (".") + 1;
752       if (anExtensionPosition == 0)
753       {
754         continue; // can't find extension position in the font description
755       }
756
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       }
762
763       TCollection_AsciiString aFontExtension = aLine.SubString (anExtensionPosition, anEndOfFileName);
764       aFontExtension.LowerCase();
765       if (aSupportedExtensions.Contains (aFontExtension) && (aLine.Search (anEncoding) > 0))
766       {
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.
770         TCollection_AsciiString aXLFD (aLine.SubString (anEndOfFileName + 2, aLine.Length()));
771         TCollection_AsciiString aFontPath (anIter.Value().ToCString());
772         if (aFontPath.SearchFromEnd ("/") != aFontPath.Length())
773         {
774           aFontPath.AssignCat ("/");
775         }
776         TCollection_AsciiString aFontFileName (aLine.SubString (1, anEndOfFileName));
777         aFontPath.AssignCat (aFontFileName);
778
779         aFonts.Clear();
780         if (checkFont (aFonts, aFtLibrary, aFontPath))
781         {
782           RegisterFonts (aFonts, false);
783           const Handle(Font_SystemFont)& aNewFont = aFonts.First();
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);
806             aNewFontFromXLFD->SetFontPath (anXAspect, aFontPath, 0);
807             if (!aNewFont->IsEqual (aNewFontFromXLFD))
808             {
809               RegisterFont (aNewFontFromXLFD, false);
810             }
811           }
812         }
813       }
814     }
815     aReadFile.Close();
816   #endif
817   }
818 #endif
819 }
820
821 // =======================================================================
822 // function : GetAvailableFontsNames
823 // purpose  :
824 // =======================================================================
825 void Font_FontMgr::GetAvailableFontsNames (TColStd_SequenceOfHAsciiString& theFontsNames) const
826 {
827   theFontsNames.Clear();
828   for (NCollection_IndexedMap<Handle(Font_SystemFont), Font_SystemFont>::Iterator aFontIter (myFontMap);
829        aFontIter.More(); aFontIter.Next())
830   {
831     const Handle(Font_SystemFont)& aFont = aFontIter.Value();
832     theFontsNames.Append (new TCollection_HAsciiString(aFont->FontName()));
833   }
834 }
835
836 // =======================================================================
837 // function : GetFont
838 // purpose  :
839 // =======================================================================
840 Handle(Font_SystemFont) Font_FontMgr::GetFont (const Handle(TCollection_HAsciiString)& theFontName,
841                                                const Font_FontAspect  theFontAspect,
842                                                const Standard_Integer theFontSize) const
843 {
844   if ((theFontSize < 2 && theFontSize != -1) || theFontName.IsNull())
845   {
846     return Handle(Font_SystemFont)();
847   }
848
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 }
856
857 // =======================================================================
858 // function : GetFont
859 // purpose  :
860 // =======================================================================
861 Handle(Font_SystemFont) Font_FontMgr::GetFont (const TCollection_AsciiString& theFontName) const
862 {
863   return myFontMap.Find (theFontName);
864 }
865
866 // =======================================================================
867 // function : FindFallbackFont
868 // purpose  :
869 // =======================================================================
870 Handle(Font_SystemFont) Font_FontMgr::FindFallbackFont (Font_UnicodeSubset theSubset,
871                                                         Font_FontAspect theFontAspect) const
872 {
873   Font_FontAspect aFontAspect = theFontAspect;
874   Handle(Font_SystemFont) aFont;
875   switch (theSubset)
876   {
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;
881   }
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;
895 }
896
897 // =======================================================================
898 // function : FindFont
899 // purpose  :
900 // =======================================================================
901 Handle(Font_SystemFont) Font_FontMgr::FindFont (const TCollection_AsciiString& theFontName,
902                                                 Font_StrictLevel theStrictLevel,
903                                                 Font_FontAspect& theFontAspect,
904                                                 Standard_Boolean theDoFailMsg) const
905 {
906   TCollection_AsciiString aFontName (theFontName);
907   aFontName.LowerCase();
908   Handle(Font_SystemFont) aFont = myFontMap.Find (aFontName);
909   if (!aFont.IsNull()
910     || theStrictLevel == Font_StrictLevel_Strict)
911   {
912     return aFont;
913   }
914
915   // Trying to use font names mapping
916   for (int aPass = 0; aPass < 2; ++aPass)
917   {
918     Handle(Font_FontAliasSequence) anAliases;
919     if (aPass == 0)
920     {
921       myFontAliases.Find (aFontName, anAliases);
922     }
923     else if (theStrictLevel == Font_StrictLevel_Any)
924     {
925       anAliases = myFallbackAlias;
926     }
927
928     if (anAliases.IsNull()
929      || anAliases->IsEmpty())
930     {
931       continue;
932     }
933
934     bool isAliasUsed = false, isBestAlias = false;
935     for (Font_FontAliasSequence::Iterator anAliasIter (*anAliases); anAliasIter.More(); anAliasIter.Next())
936     {
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
956                 || aFont2->HasFontAspect (theFontAspect)))
957         {
958           isBestAlias = true;
959           break;
960         }
961       }
962     }
963
964     if (aPass == 0)
965     {
966       if (isAliasUsed && myToTraceAliases)
967       {
968         Message::DefaultMessenger()->Send (TCollection_AsciiString("Font_FontMgr, using font alias '") + aFont->FontName() + "'"
969                                             " instead of requested '" + theFontName +"'", Message_Trace);
970       }
971       if (isBestAlias)
972       {
973         return aFont;
974       }
975       else if (!aFont.IsNull())
976       {
977         break;
978       }
979     }
980   }
981
982   if (aFont.IsNull()
983    && theStrictLevel == Font_StrictLevel_Any)
984   {
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   {
990     if (theDoFailMsg)
991     {
992       Message::DefaultMessenger()->Send (TCollection_AsciiString("Font_FontMgr, error: unable to find any font!"), Message_Fail);
993     }
994     return Handle(Font_SystemFont)();
995   }
996
997   if ((theFontAspect != Font_FA_Undefined
998     && !aFont->HasFontAspect (theFontAspect))
999    || (!aFontName.IsEmpty()
1000     && !aFontName.IsEqual (aFont->FontKey())))
1001   {
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");
1006   }
1007   return aFont;
1008 }
1009
1010 // =======================================================================
1011 // function : Font_FontMap::Find
1012 // purpose  :
1013 // =======================================================================
1014 Handle(Font_SystemFont) Font_FontMgr::Font_FontMap::Find (const TCollection_AsciiString& theFontName) const
1015 {
1016   if (IsEmpty())
1017   {
1018     return Handle(Font_SystemFont)();
1019   }
1020   else if (theFontName.IsEmpty())
1021   {
1022     return FindKey (1); // return any font
1023   }
1024
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)();
1037 }