4fad2f6d7609be7a48b3149b11e521d4ba8b9405
[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__)
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
307 #if defined(_WIN32)
308   anArab->Append (Font_FontAlias ("times new roman"));
309 #elif defined(__APPLE__)
310   anArab->Append (Font_FontAlias ("decotype naskh"));
311 #elif defined(__ANDROID__)
312   anArab->Append (Font_FontAlias ("droid arabic naskh"));
313   anArab->Append (Font_FontAlias ("noto naskh arabic"));
314 #endif
315
316   addFontAlias ("mono",              aMono);
317   addFontAlias ("courier",           aMono);                      // Font_NOF_ASCII_MONO
318   addFontAlias ("monospace",         aMono);                      // Font_NOF_MONOSPACE
319   addFontAlias ("rock",              aSans);                      // Font_NOF_CARTOGRAPHIC_SIMPLEX
320   addFontAlias ("sansserif",         aSans);                      // Font_NOF_SANS_SERIF
321   addFontAlias ("sans-serif",        aSans);
322   addFontAlias ("sans",              aSans);
323   addFontAlias ("arial",             aSans);
324   addFontAlias ("times",             aSerif);
325   addFontAlias ("serif",             aSerif);                     // Font_NOF_SERIF
326   addFontAlias ("times-roman",       aSerif);                     // Font_NOF_ASCII_SIMPLEX
327   addFontAlias ("times-bold",        aSerif, Font_FA_Bold);       // Font_NOF_ASCII_DUPLEX
328   addFontAlias ("times-italic",      aSerif, Font_FA_Italic);     // Font_NOF_ASCII_ITALIC_COMPLEX
329   addFontAlias ("times-bolditalic",  aSerif, Font_FA_BoldItalic); // Font_NOF_ASCII_ITALIC_TRIPLEX
330   addFontAlias ("symbol",            aSymbol);                    // Font_NOF_GREEK_MONO
331   addFontAlias ("iris",              anIris);                     // Font_NOF_KANJI_MONO
332   addFontAlias ("korean",            aKorean);                    // Font_NOF_KOREAN
333   addFontAlias ("cjk",               aCJK);                       // Font_NOF_CJK
334   addFontAlias ("nsimsun",           aCJK);
335   addFontAlias ("arabic",            anArab);                     // Font_NOF_ARABIC
336   addFontAlias (Font_NOF_SYMBOL_MONO,          aWinDin);
337   addFontAlias (Font_NOF_ASCII_SCRIPT_SIMPLEX, aScript);
338
339   myFallbackAlias = aSans;
340
341   InitFontDataBase();
342 }
343
344 // =======================================================================
345 // function : CheckFont
346 // purpose  :
347 // =======================================================================
348 Handle(Font_SystemFont) Font_FontMgr::CheckFont (Standard_CString theFontPath) const
349 {
350   Handle(Font_FTLibrary) aFtLibrary = new Font_FTLibrary();
351   return checkFont (aFtLibrary, theFontPath);
352 }
353
354 // =======================================================================
355 // function : RegisterFont
356 // purpose  :
357 // =======================================================================
358 Standard_Boolean Font_FontMgr::RegisterFont (const Handle(Font_SystemFont)& theFont,
359                                              const Standard_Boolean         theToOverride)
360 {
361   if (theFont.IsNull())
362   {
363     return Standard_False;
364   }
365
366   const Standard_Integer anOldIndex = myFontMap.FindIndex (theFont);
367   if (anOldIndex == 0)
368   {
369     myFontMap.Add (theFont);
370     return Standard_True;
371   }
372
373   Handle(Font_SystemFont) anOldFont = myFontMap.FindKey (anOldIndex);
374   for (int anAspectIter = 0; anAspectIter < Font_FontAspect_NB; ++anAspectIter)
375   {
376     if (anOldFont->FontPath ((Font_FontAspect )anAspectIter).IsEqual (theFont->FontPath ((Font_FontAspect )anAspectIter)))
377     {
378       continue;
379     }
380     else if (theToOverride
381          || !anOldFont->HasFontAspect ((Font_FontAspect )anAspectIter))
382     {
383       anOldFont->SetFontPath ((Font_FontAspect )anAspectIter, theFont->FontPath ((Font_FontAspect )anAspectIter));
384     }
385     else if (theFont->HasFontAspect ((Font_FontAspect )anAspectIter))
386     {
387       return Standard_False;
388     }
389   }
390   return Standard_True;
391 }
392
393 // =======================================================================
394 // function : InitFontDataBase
395 // purpose  :
396 // =======================================================================
397 void Font_FontMgr::InitFontDataBase()
398 {
399   myFontMap.Clear();
400   Handle(Font_FTLibrary) aFtLibrary = new Font_FTLibrary();
401
402 #if defined(OCCT_UWP)
403   // system font files are not accessible
404   (void )aFtLibrary;
405 #elif defined(_WIN32)
406
407   // font directory is placed in "C:\Windows\Fonts\"
408   UINT aStrLength = GetSystemWindowsDirectoryA (NULL, 0);
409   if (aStrLength == 0)
410   {
411     return;
412   }
413
414   char* aWinDir = new char[aStrLength];
415   GetSystemWindowsDirectoryA (aWinDir, aStrLength);
416   TCollection_AsciiString aFontsDir (aWinDir);
417   aFontsDir.AssignCat ("\\Fonts\\");
418   delete[] aWinDir;
419
420   // read fonts list from registry
421   HKEY aFontsKey;
422   if (RegOpenKeyExA (HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts",
423                      0, KEY_READ, &aFontsKey) != ERROR_SUCCESS)
424   {
425     return;
426   }
427
428   NCollection_Map<TCollection_AsciiString> aSupportedExtensions;
429   for (Standard_Integer anIter = 0; Font_FontMgr_Extensions[anIter] != NULL; ++anIter)
430   {
431     Standard_CString anExt = Font_FontMgr_Extensions[anIter];
432     aSupportedExtensions.Add (TCollection_AsciiString (anExt));
433   }
434
435   static const DWORD aBufferSize = 256;
436   char aNameBuff[aBufferSize];
437   char aPathBuff[aBufferSize];
438   DWORD aNameSize = aBufferSize;
439   DWORD aPathSize = aBufferSize;
440   for (DWORD anIter = 0;
441        RegEnumValueA (aFontsKey, anIter,
442                       aNameBuff, &aNameSize, NULL, NULL,
443                       (LPBYTE )aPathBuff, &aPathSize) != ERROR_NO_MORE_ITEMS;
444       ++anIter, aNameSize = aBufferSize, aPathSize = aBufferSize)
445   {
446     aPathBuff[(aPathSize < aBufferSize) ? aPathSize : (aBufferSize - 1)] = '\0'; // ensure string is NULL-terminated
447
448     TCollection_AsciiString aFontName (aNameBuff), aFontPath (aPathBuff);
449     if (aFontPath.Search ("\\") == -1)
450     {
451       aFontPath.Insert (1, aFontsDir); // make absolute path
452     }
453
454     // check file extension is in list of supported
455     const Standard_Integer anExtensionPosition = aFontPath.SearchFromEnd (".") + 1;
456     if (anExtensionPosition > 0 && anExtensionPosition < aFontPath.Length())
457     {
458       TCollection_AsciiString aFontExtension = aFontPath.SubString (anExtensionPosition, aFontPath.Length());
459       aFontExtension.LowerCase();
460       if (aSupportedExtensions.Contains (aFontExtension))
461       {
462         if (Handle(Font_SystemFont) aNewFont = checkFont (aFtLibrary, aFontPath.ToCString()))
463         {
464           RegisterFont (aNewFont, false);
465         }
466       }
467     }
468   }
469
470   // close registry key
471   RegCloseKey (aFontsKey);
472
473 #else
474
475   NCollection_Map<TCollection_AsciiString> aMapOfFontsDirs;
476 #if !defined(__ANDROID__) && !defined(__APPLE__)
477   if (FcConfig* aFcCfg = FcInitLoadConfig())
478   {
479     if (FcStrList* aFcFontDir = FcConfigGetFontDirs (aFcCfg))
480     {
481       for (;;)
482       {
483         FcChar8* aFcFolder = FcStrListNext (aFcFontDir);
484         if (aFcFolder == NULL)
485         {
486           break;
487         }
488
489         TCollection_AsciiString aPathStr ((const char* )aFcFolder);
490         OSD_Path aPath (aPathStr);
491         addDirsRecursively (aPath, aMapOfFontsDirs);
492       }
493       FcStrListDone (aFcFontDir);
494     }
495     FcConfigDestroy (aFcCfg);
496   }
497
498   const OSD_Protection aProtectRead (OSD_R, OSD_R, OSD_R, OSD_R);
499   if (aMapOfFontsDirs.IsEmpty())
500   {
501     Message::DefaultMessenger()->Send ("Font_FontMgr, fontconfig library returns an empty folder list", Message_Alarm);
502
503     // read fonts directories from font service config file (obsolete)
504     for (Standard_Integer anIter = 0; myFontServiceConf[anIter] != NULL; ++anIter)
505     {
506       const TCollection_AsciiString aFileOfFontsPath (myFontServiceConf[anIter]);
507       OSD_File aFile (aFileOfFontsPath);
508       if (!aFile.Exists())
509       {
510         continue;
511       }
512
513       aFile.Open (OSD_ReadOnly, aProtectRead);
514       if (!aFile.IsOpen())
515       {
516         continue;
517       }
518
519       Standard_Integer aNByte = 256;
520       Standard_Integer aNbyteRead;
521       TCollection_AsciiString aStr; // read string with information
522       while (!aFile.IsAtEnd())
523       {
524         Standard_Integer aLocation = -1;
525         Standard_Integer aPathLocation = -1;
526
527         aFile.ReadLine (aStr, aNByte, aNbyteRead); // reading 1 line (256 bytes)
528         aLocation = aStr.Search ("catalogue=");
529         if (aLocation < 0)
530         {
531           aLocation = aStr.Search ("catalogue =");
532         }
533
534         aPathLocation = aStr.Search ("/");
535         if (aLocation > 0 && aPathLocation > 0)
536         {
537           aStr = aStr.Split (aPathLocation - 1);
538           TCollection_AsciiString aFontPath;
539           Standard_Integer aPathNumber = 1;
540           do
541           {
542             // Getting directory paths, which can be splitted by "," or ":"
543             aFontPath = aStr.Token (":,", aPathNumber);
544             aFontPath.RightAdjust();
545             if (!aFontPath.IsEmpty())
546             {
547               OSD_Path aPath(aFontPath);
548               addDirsRecursively (aPath, aMapOfFontsDirs);
549             }
550             aPathNumber++;
551           }
552           while (!aFontPath.IsEmpty());
553         }
554       }
555       aFile.Close();
556     }
557   }
558 #endif
559
560   // append default directories
561   for (Standard_Integer anIter = 0; myDefaultFontsDirs[anIter] != NULL; ++anIter)
562   {
563     Standard_CString anItem = myDefaultFontsDirs[anIter];
564     TCollection_AsciiString aPathStr (anItem);
565     OSD_Path aPath (aPathStr);
566     addDirsRecursively (aPath, aMapOfFontsDirs);
567   }
568
569   NCollection_Map<TCollection_AsciiString> aSupportedExtensions;
570   for (Standard_Integer anIter = 0; Font_FontMgr_Extensions[anIter] != NULL; ++anIter)
571   {
572     Standard_CString anExt = Font_FontMgr_Extensions[anIter];
573     aSupportedExtensions.Add (TCollection_AsciiString (anExt));
574   }
575
576   for (NCollection_Map<TCollection_AsciiString>::Iterator anIter (aMapOfFontsDirs);
577        anIter.More(); anIter.Next())
578   {
579   #if !defined(__ANDROID__) && !defined(__APPLE__)
580     OSD_File aReadFile (anIter.Value() + "/fonts.dir");
581     if (!aReadFile.Exists())
582     {
583   #endif
584       OSD_Path aFolderPath (anIter.Value());
585       for (OSD_FileIterator aFileIter (aFolderPath, "*"); aFileIter.More(); aFileIter.Next())
586       {
587         OSD_Path aFontFilePath;
588         aFileIter.Values().Path (aFontFilePath);
589
590         TCollection_AsciiString aFontFileName;
591         aFontFilePath.SystemName (aFontFileName);
592         aFontFileName = anIter.Value() + "/" + aFontFileName;
593
594         if (Handle(Font_SystemFont) aNewFont = checkFont (aFtLibrary, aFontFileName.ToCString()))
595         {
596           RegisterFont (aNewFont, false);
597         }
598       }
599
600   #if !defined(__ANDROID__) && !defined(__APPLE__)
601       continue;
602     }
603
604     aReadFile.Open (OSD_ReadOnly, aProtectRead);
605     if (!aReadFile.IsOpen())
606     {
607       continue; // invalid fonts directory
608     }
609
610     Standard_Integer aNbyteRead, aNByte = 256;
611     TCollection_AsciiString aLine (aNByte);
612     Standard_Boolean isFirstLine = Standard_True;
613     const TCollection_AsciiString anEncoding ("iso8859-1\n");
614     while (!aReadFile.IsAtEnd())
615     {
616       aReadFile.ReadLine (aLine, aNByte, aNbyteRead);
617       if (isFirstLine)
618       {
619         // first line contains the number of fonts in this file
620         // just ignoring it...
621         isFirstLine = Standard_False;
622         continue;
623       }
624
625       Standard_Integer anExtensionPosition = aLine.Search (".") + 1;
626       if (anExtensionPosition == 0)
627       {
628         continue; // can't find extension position in the font description
629       }
630
631       Standard_Integer anEndOfFileName = aLine.Location (" ", anExtensionPosition, aLine.Length()) - 1;
632       if (anEndOfFileName < 0 || anEndOfFileName < anExtensionPosition)
633       {
634         continue; // font description have empty extension
635       }
636
637       TCollection_AsciiString aFontExtension = aLine.SubString (anExtensionPosition, anEndOfFileName);
638       aFontExtension.LowerCase();
639       if (aSupportedExtensions.Contains (aFontExtension) && (aLine.Search (anEncoding) > 0))
640       {
641         // In current implementation use fonts with ISO-8859-1 coding page.
642         // OCCT not give to manage coding page by means of programm interface.
643         // TODO: make high level interface for choosing necessary coding page.
644         TCollection_AsciiString aXLFD (aLine.SubString (anEndOfFileName + 2, aLine.Length()));
645         TCollection_AsciiString aFontPath (anIter.Value().ToCString());
646         if (aFontPath.SearchFromEnd ("/") != aFontPath.Length())
647         {
648           aFontPath.AssignCat ("/");
649         }
650         TCollection_AsciiString aFontFileName (aLine.SubString (1, anEndOfFileName));
651         aFontPath.AssignCat (aFontFileName);
652         if (Handle(Font_SystemFont) aNewFont = checkFont (aFtLibrary, aFontPath.ToCString()))
653         {
654           RegisterFont (aNewFont, false);
655           if (!aXLFD.IsEmpty()
656             && aXLFD.Search ("-0-0-0-0-") != -1) // ignore non-resizable fonts
657           {
658             const TCollection_AsciiString anXName = aXLFD.Token ("-", 2);
659             Font_FontAspect anXAspect = Font_FA_Regular;
660             if (aXLFD.Token ("-", 3).IsEqual ("bold")
661              && (aXLFD.Token ("-", 4).IsEqual ("i")
662               || aXLFD.Token ("-", 4).IsEqual ("o")))
663             {
664               anXAspect = Font_FA_BoldItalic;
665             }
666             else if (aXLFD.Token ("-", 3).IsEqual ("bold"))
667             {
668               anXAspect = Font_FA_Bold;
669             }
670             else if (aXLFD.Token ("-", 4).IsEqual ("i")
671                   || aXLFD.Token ("-", 4).IsEqual ("o"))
672             {
673               anXAspect = Font_FA_Italic;
674             }
675
676             Handle(Font_SystemFont) aNewFontFromXLFD = new Font_SystemFont (anXName);
677             aNewFontFromXLFD->SetFontPath (anXAspect, aFontPath);
678             if (!aNewFont->IsEqual (aNewFontFromXLFD))
679             {
680               RegisterFont (aNewFontFromXLFD, false);
681             }
682           }
683         }
684       }
685     }
686     aReadFile.Close();
687   #endif
688   }
689 #endif
690 }
691
692 // =======================================================================
693 // function : GetAvailableFontsNames
694 // purpose  :
695 // =======================================================================
696 void Font_FontMgr::GetAvailableFontsNames (TColStd_SequenceOfHAsciiString& theFontsNames) const
697 {
698   theFontsNames.Clear();
699   for (NCollection_IndexedMap<Handle(Font_SystemFont), Font_SystemFont>::Iterator aFontIter (myFontMap);
700        aFontIter.More(); aFontIter.Next())
701   {
702     const Handle(Font_SystemFont)& aFont = aFontIter.Value();
703     theFontsNames.Append (new TCollection_HAsciiString(aFont->FontName()));
704   }
705 }
706
707 // =======================================================================
708 // function : GetFont
709 // purpose  :
710 // =======================================================================
711 Handle(Font_SystemFont) Font_FontMgr::GetFont (const Handle(TCollection_HAsciiString)& theFontName,
712                                                const Font_FontAspect  theFontAspect,
713                                                const Standard_Integer theFontSize) const
714 {
715   if ((theFontSize < 2 && theFontSize != -1) || theFontName.IsNull())
716   {
717     return Handle(Font_SystemFont)();
718   }
719
720   Handle(Font_SystemFont) aFont = myFontMap.Find (theFontName->String());
721   return (aFont.IsNull()
722        || theFontAspect == Font_FontAspect_UNDEFINED
723        || aFont->HasFontAspect (theFontAspect))
724        ? aFont
725        : Handle(Font_SystemFont)();
726 }
727
728 // =======================================================================
729 // function : GetFont
730 // purpose  :
731 // =======================================================================
732 Handle(Font_SystemFont) Font_FontMgr::GetFont (const TCollection_AsciiString& theFontName) const
733 {
734   return myFontMap.Find (theFontName);
735 }
736
737 // =======================================================================
738 // function : FindFallbackFont
739 // purpose  :
740 // =======================================================================
741 Handle(Font_SystemFont) Font_FontMgr::FindFallbackFont (Font_UnicodeSubset theSubset,
742                                                         Font_FontAspect theFontAspect) const
743 {
744   Font_FontAspect aFontAspect = theFontAspect;
745   switch (theSubset)
746   {
747     case Font_UnicodeSubset_Western: return FindFont (Font_NOF_SANS_SERIF, Font_StrictLevel_Aliases, aFontAspect);
748     case Font_UnicodeSubset_Korean:  return FindFont (Font_NOF_KOREAN,     Font_StrictLevel_Aliases, aFontAspect);
749     case Font_UnicodeSubset_CJK:     return FindFont (Font_NOF_CJK,        Font_StrictLevel_Aliases, aFontAspect);
750     case Font_UnicodeSubset_Arabic:  return FindFont (Font_NOF_ARABIC,     Font_StrictLevel_Aliases, aFontAspect);
751   }
752   return Handle(Font_SystemFont)();
753 }
754
755 // =======================================================================
756 // function : FindFont
757 // purpose  :
758 // =======================================================================
759 Handle(Font_SystemFont) Font_FontMgr::FindFont (const TCollection_AsciiString& theFontName,
760                                                 Font_StrictLevel theStrictLevel,
761                                                 Font_FontAspect& theFontAspect) const
762 {
763   TCollection_AsciiString aFontName (theFontName);
764   aFontName.LowerCase();
765   Handle(Font_SystemFont) aFont = myFontMap.Find (aFontName);
766   if (!aFont.IsNull()
767     || theStrictLevel == Font_StrictLevel_Strict)
768   {
769     return aFont;
770   }
771
772   // Trying to use font names mapping
773   for (int aPass = 0; aPass < 2; ++aPass)
774   {
775     Handle(Font_FontAliasSequence) anAliases;
776     if (aPass == 0)
777     {
778       myFontAliases.Find (aFontName, anAliases);
779     }
780     else if (theStrictLevel == Font_StrictLevel_Any)
781     {
782       anAliases = myFallbackAlias;
783     }
784
785     if (anAliases.IsNull()
786      || anAliases->IsEmpty())
787     {
788       continue;
789     }
790
791     bool isAliasUsed = false, isBestAlias = false;
792     for (Font_FontAliasSequence::Iterator anAliasIter (*anAliases); anAliasIter.More(); anAliasIter.Next())
793     {
794       const Font_FontAlias& anAlias = anAliasIter.Value();
795       if (Handle(Font_SystemFont) aFont2 = myFontMap.Find (anAlias.FontName))
796       {
797         if (aFont.IsNull())
798         {
799           aFont = aFont2;
800           isAliasUsed = true;
801         }
802
803         if ((anAlias.FontAspect != Font_FontAspect_UNDEFINED
804           && aFont2->HasFontAspect (anAlias.FontAspect)))
805         {
806           // special case - alias refers to styled font (e.g. "times-bold")
807           isBestAlias = true;
808           theFontAspect = anAlias.FontAspect;
809           break;
810         }
811         else if (anAlias.FontAspect == Font_FontAspect_UNDEFINED
812               && (theFontAspect == Font_FontAspect_UNDEFINED
813                 || aFont2->HasFontAspect (theFontAspect)))
814         {
815           isBestAlias = true;
816           break;
817         }
818       }
819     }
820
821     if (aPass == 0)
822     {
823       if (isAliasUsed && myToTraceAliases)
824       {
825         Message::DefaultMessenger()->Send (TCollection_AsciiString("Font_FontMgr, using font alias '") + aFont->FontName() + "'"
826                                             " instead of requested '" + theFontName +"'", Message_Trace);
827       }
828       if (isBestAlias)
829       {
830         return aFont;
831       }
832       else if (!aFont.IsNull())
833       {
834         break;
835       }
836     }
837   }
838
839   if (aFont.IsNull()
840    && theStrictLevel == Font_StrictLevel_Any)
841   {
842     // try finding ANY font in case if even default fallback alias myFallbackAlias cannot be found
843     aFont = myFontMap.Find (TCollection_AsciiString());
844   }
845   if (aFont.IsNull())
846   {
847     Message::DefaultMessenger()->Send (TCollection_AsciiString("Font_FontMgr, error: unable to find any font!", Message_Fail));
848     return Handle(Font_SystemFont)();
849   }
850
851   if ((theFontAspect != Font_FA_Undefined
852     && !aFont->HasFontAspect (theFontAspect))
853    || (!aFontName.IsEmpty()
854     && !aFontName.IsEqual (aFont->FontKey())))
855   {
856     TCollection_AsciiString aDesc = TCollection_AsciiString() + "'" + theFontName + "'"
857                                   + TCollection_AsciiString() + " [" + Font_FontMgr::FontAspectToString (theFontAspect) + "]";
858     Message::DefaultMessenger()->Send (TCollection_AsciiString("Font_FontMgr, warning: unable to find font ")
859                                      + aDesc + "; " + aFont->ToString() + " is used instead");
860   }
861   return aFont;
862 }
863
864 // =======================================================================
865 // function : Font_FontMap::Find
866 // purpose  :
867 // =======================================================================
868 Handle(Font_SystemFont) Font_FontMgr::Font_FontMap::Find (const TCollection_AsciiString& theFontName) const
869 {
870   if (IsEmpty())
871   {
872     return Handle(Font_SystemFont)();
873   }
874   else if (theFontName.IsEmpty())
875   {
876     return FindKey (1); // return any font
877   }
878
879   TCollection_AsciiString aFontName (theFontName);
880   aFontName.LowerCase();
881   for (IndexedMapNode* aNodeIter = (IndexedMapNode* )myData1[::HashCode (aFontName, NbBuckets())];
882        aNodeIter != NULL; aNodeIter = (IndexedMapNode* )aNodeIter->Next())
883   {
884     const Handle(Font_SystemFont)& aKey = aNodeIter->Key1();
885     if (aKey->FontKey().IsEqual (aFontName))
886     {
887       return aKey;
888     }
889   }
890   return Handle(Font_SystemFont)();
891 }