0030439: Visualization - extend fonts search within Font_FontMgr::FindFont() on Linux
[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   #endif
92
93   #ifdef __APPLE__
94     // default fonts paths in Mac OS X
95     static Standard_CString myDefaultFontsDirs[] = {"/System/Library/Fonts",
96                                                     "/Library/Fonts",
97                                                     NULL
98                                                    };
99   #else
100     // default fonts paths in most Unix systems (Linux and others)
101     static Standard_CString myDefaultFontsDirs[] = {"/system/fonts",         // Android
102                                                     "/usr/share/fonts",
103                                                     "/usr/local/share/fonts",
104                                                     NULL
105                                                    };
106   #endif
107
108     static void addDirsRecursively (const OSD_Path&                           thePath,
109                                     NCollection_Map<TCollection_AsciiString>& theDirsMap)
110     {
111       TCollection_AsciiString aDirName;
112       thePath.SystemName (aDirName);
113       if (!theDirsMap.Add (aDirName))
114       {
115         return;
116       }
117
118       for (OSD_DirectoryIterator aDirIterator (thePath, "*"); aDirIterator.More(); aDirIterator.Next())
119       {
120         OSD_Path aChildDirPath;
121         aDirIterator.Values().Path (aChildDirPath);
122
123         TCollection_AsciiString aChildDirName;
124         aChildDirPath.SystemName (aChildDirName);
125         if (!aChildDirName.IsEqual (".") && !aChildDirName.IsEqual (".."))
126         {
127           aChildDirName = aDirName + "/" + aChildDirName;
128           OSD_Path aPath (aChildDirName);
129           addDirsRecursively (aPath, theDirsMap);
130         }
131       }
132     }
133
134   } // anonymous namespace
135
136 #endif
137
138 // =======================================================================
139 // function : checkFont
140 // purpose  :
141 // =======================================================================
142 static Handle(Font_SystemFont) checkFont (const Handle(Font_FTLibrary)& theFTLib,
143                                           const Standard_CString        theFontPath)
144 {
145   FT_Face aFontFace;
146   FT_Error aFaceError = FT_New_Face (theFTLib->Instance(), theFontPath, 0, &aFontFace);
147   if (aFaceError != FT_Err_Ok)
148   {
149     return NULL;
150   }
151
152   Font_FontAspect anAspect = Font_FA_Regular;
153   if (aFontFace->style_flags == (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD))
154   {
155     anAspect = Font_FA_BoldItalic;
156   }
157   else if (aFontFace->style_flags == FT_STYLE_FLAG_ITALIC)
158   {
159     anAspect = Font_FA_Italic;
160   }
161   else if (aFontFace->style_flags == FT_STYLE_FLAG_BOLD)
162   {
163     anAspect = Font_FA_Bold;
164   }
165
166   Handle(Font_SystemFont) aResult;
167   if (aFontFace->family_name != NULL                           // skip broken fonts (error in FreeType?)
168    && FT_Select_Charmap (aFontFace, ft_encoding_unicode) == 0) // Font_FTFont supports only UNICODE fonts
169   {
170     aResult = new Font_SystemFont (aFontFace->family_name);
171     aResult->SetFontPath (anAspect, theFontPath);
172     // automatically identify some known single-line fonts
173     aResult->SetSingleStrokeFont (aResult->FontKey().StartsWith ("olf "));
174   }
175
176   FT_Done_Face (aFontFace);
177
178   return aResult;
179 }
180
181 // =======================================================================
182 // function : GetInstance
183 // purpose  :
184 // =======================================================================
185 Handle(Font_FontMgr) Font_FontMgr::GetInstance()
186 {
187   static Handle(Font_FontMgr) _mgr;
188   if (_mgr.IsNull())
189   {
190     _mgr = new Font_FontMgr();
191   }
192
193   return _mgr;
194 }
195
196 // =======================================================================
197 // function : addFontAlias
198 // purpose  :
199 // =======================================================================
200 void Font_FontMgr::addFontAlias (const TCollection_AsciiString& theAliasName,
201                                  const Handle(Font_FontAliasSequence)& theAliases,
202                                  Font_FontAspect theAspect)
203 {
204   if (theAliases.IsNull()
205    || theAliases->IsEmpty())
206   {
207     return;
208   }
209
210   Handle(Font_FontAliasSequence) anAliases = theAliases;
211   if (theAspect != Font_FA_Undefined)
212   {
213     anAliases = new Font_FontAliasSequence();
214     for (Font_FontAliasSequence::Iterator anAliasIter (*theAliases); anAliasIter.More(); anAliasIter.Next())
215     {
216       const TCollection_AsciiString& aName = anAliasIter.Value().FontName;
217       anAliases->Append (Font_FontAlias (aName, theAspect));
218     }
219   }
220
221   TCollection_AsciiString anAliasName (theAliasName);
222   anAliasName.LowerCase();
223   myFontAliases.Bind (anAliasName, anAliases);
224 }
225
226 // =======================================================================
227 // function : Font_FontMgr
228 // purpose  :
229 // =======================================================================
230 Font_FontMgr::Font_FontMgr()
231 : myToTraceAliases (Standard_False)
232 {
233   Handle(Font_FontAliasSequence) aMono   = new Font_FontAliasSequence();
234   Handle(Font_FontAliasSequence) aSerif  = new Font_FontAliasSequence();
235   Handle(Font_FontAliasSequence) aSans   = new Font_FontAliasSequence();
236   Handle(Font_FontAliasSequence) aSymbol = new Font_FontAliasSequence();
237   Handle(Font_FontAliasSequence) aScript = new Font_FontAliasSequence();
238   Handle(Font_FontAliasSequence) aWinDin = new Font_FontAliasSequence();
239   Handle(Font_FontAliasSequence) anIris  = new Font_FontAliasSequence();
240   Handle(Font_FontAliasSequence) aCJK    = new Font_FontAliasSequence();
241   Handle(Font_FontAliasSequence) aKorean = new Font_FontAliasSequence();
242
243   // best matches - pre-installed on Windows, some of them are pre-installed on macOS,
244   // and sometimes them can be found installed on other systems (by user)
245   aMono  ->Append (Font_FontAlias ("courier new"));
246   aSerif ->Append (Font_FontAlias ("times new roman"));
247   aSans  ->Append (Font_FontAlias ("arial"));
248   aSymbol->Append (Font_FontAlias ("symbol"));
249   aScript->Append (Font_FontAlias ("script"));
250   aWinDin->Append (Font_FontAlias ("wingdings"));
251   anIris ->Append (Font_FontAlias ("lucida console"));
252
253 #if defined(__ANDROID__)
254   // Noto font family is usually installed on Android 6+ devices
255   aMono  ->Append (Font_FontAlias ("noto mono"));
256   aSerif ->Append (Font_FontAlias ("noto serif"));
257   // Droid font family is usually installed on Android 4+ devices
258   aMono  ->Append (Font_FontAlias ("droid sans mono"));
259   aSerif ->Append (Font_FontAlias ("droid serif"));
260   aSans  ->Append (Font_FontAlias ("roboto")); // actually DroidSans.ttf
261 #elif !defined(_WIN32) && !defined(__APPLE__) //X11
262   aSerif ->Append (Font_FontAlias ("times"));
263   aSans  ->Append (Font_FontAlias ("helvetica"));
264   // GNU FreeFonts family is usually installed on Linux
265   aMono  ->Append (Font_FontAlias ("freemono"));
266   aSerif ->Append (Font_FontAlias ("freeserif"));
267   aSans  ->Append (Font_FontAlias ("freesans"));
268   // DejaVu font family is usually installed on Linux
269   aMono  ->Append (Font_FontAlias ("dejavu sans mono"));
270   aSerif ->Append (Font_FontAlias ("dejavu serif"));
271   aSans  ->Append (Font_FontAlias ("dejavu sans"));
272 #endif
273
274   // default CJK (Chinese/Japanese/Korean) fonts
275   aCJK   ->Append (Font_FontAlias ("simsun"));        // Windows
276   aCJK   ->Append (Font_FontAlias ("droid sans fallback")); // Android, Linux
277   aCJK   ->Append (Font_FontAlias ("noto sans sc"));  // Android
278
279 #if defined(_WIN32)
280   aKorean->Append (Font_FontAlias ("malgun gothic")); // introduced since Vista
281   aKorean->Append (Font_FontAlias ("gulim"));         // used on older systems (Windows XP)
282 #elif defined(__APPLE__)
283   aKorean->Append (Font_FontAlias ("applegothic"));
284   aKorean->Append (Font_FontAlias ("stfangsong"));
285 #endif
286   aKorean->Append (Font_FontAlias ("nanumgothic"));   // Android, Linux
287   aKorean->Append (Font_FontAlias ("noto sans kr"));  // Android
288   aKorean->Append (Font_FontAlias ("nanummyeongjo")); // Linux
289   aKorean->Append (Font_FontAlias ("noto serif cjk jp")); // Linux
290   aKorean->Append (Font_FontAlias ("noto sans cjk jp")); // Linux
291
292   addFontAlias ("mono",              aMono);
293   addFontAlias ("courier",           aMono);                      // Font_NOF_ASCII_MONO
294   addFontAlias ("monospace",         aMono);                      // Font_NOF_MONOSPACE
295   addFontAlias ("rock",              aSans);                      // Font_NOF_CARTOGRAPHIC_SIMPLEX
296   addFontAlias ("sansserif",         aSans);                      // Font_NOF_SANS_SERIF
297   addFontAlias ("sans-serif",        aSans);
298   addFontAlias ("sans",              aSans);
299   addFontAlias ("arial",             aSans);
300   addFontAlias ("times",             aSerif);
301   addFontAlias ("serif",             aSerif);                     // Font_NOF_SERIF
302   addFontAlias ("times-roman",       aSerif);                     // Font_NOF_ASCII_SIMPLEX
303   addFontAlias ("times-bold",        aSerif, Font_FA_Bold);       // Font_NOF_ASCII_DUPLEX
304   addFontAlias ("times-italic",      aSerif, Font_FA_Italic);     // Font_NOF_ASCII_ITALIC_COMPLEX
305   addFontAlias ("times-bolditalic",  aSerif, Font_FA_BoldItalic); // Font_NOF_ASCII_ITALIC_TRIPLEX
306   addFontAlias ("symbol",            aSymbol);                    // Font_NOF_GREEK_MONO
307   addFontAlias ("iris",              anIris);                     // Font_NOF_KANJI_MONO
308   addFontAlias ("korean",            aKorean);                    // Font_NOF_KOREAN
309   addFontAlias ("cjk",               aCJK);                       // Font_NOF_CJK
310   addFontAlias ("nsimsun",           aCJK);
311   addFontAlias (Font_NOF_SYMBOL_MONO,          aWinDin);
312   addFontAlias (Font_NOF_ASCII_SCRIPT_SIMPLEX, aScript);
313
314   myFallbackAlias = aSans;
315
316   InitFontDataBase();
317 }
318
319 // =======================================================================
320 // function : CheckFont
321 // purpose  :
322 // =======================================================================
323 Handle(Font_SystemFont) Font_FontMgr::CheckFont (Standard_CString theFontPath) const
324 {
325   Handle(Font_FTLibrary) aFtLibrary = new Font_FTLibrary();
326   return checkFont (aFtLibrary, theFontPath);
327 }
328
329 // =======================================================================
330 // function : RegisterFont
331 // purpose  :
332 // =======================================================================
333 Standard_Boolean Font_FontMgr::RegisterFont (const Handle(Font_SystemFont)& theFont,
334                                              const Standard_Boolean         theToOverride)
335 {
336   if (theFont.IsNull())
337   {
338     return Standard_False;
339   }
340
341   const Standard_Integer anOldIndex = myFontMap.FindIndex (theFont);
342   if (anOldIndex == 0)
343   {
344     myFontMap.Add (theFont);
345     return Standard_True;
346   }
347
348   Handle(Font_SystemFont) anOldFont = myFontMap.FindKey (anOldIndex);
349   for (int anAspectIter = 0; anAspectIter < Font_FontAspect_NB; ++anAspectIter)
350   {
351     if (anOldFont->FontPath ((Font_FontAspect )anAspectIter).IsEqual (theFont->FontPath ((Font_FontAspect )anAspectIter)))
352     {
353       continue;
354     }
355     else if (theToOverride
356          || !anOldFont->HasFontAspect ((Font_FontAspect )anAspectIter))
357     {
358       anOldFont->SetFontPath ((Font_FontAspect )anAspectIter, theFont->FontPath ((Font_FontAspect )anAspectIter));
359     }
360     else if (theFont->HasFontAspect ((Font_FontAspect )anAspectIter))
361     {
362       return Standard_False;
363     }
364   }
365   return Standard_True;
366 }
367
368 // =======================================================================
369 // function : InitFontDataBase
370 // purpose  :
371 // =======================================================================
372 void Font_FontMgr::InitFontDataBase()
373 {
374   myFontMap.Clear();
375   Handle(Font_FTLibrary) aFtLibrary;
376
377 #if defined(OCCT_UWP)
378   // system font files are not accessible
379   (void )aFtLibrary;
380 #elif defined(_WIN32)
381
382   // font directory is placed in "C:\Windows\Fonts\"
383   UINT aStrLength = GetSystemWindowsDirectoryA (NULL, 0);
384   if (aStrLength == 0)
385   {
386     return;
387   }
388
389   char* aWinDir = new char[aStrLength];
390   GetSystemWindowsDirectoryA (aWinDir, aStrLength);
391   TCollection_AsciiString aFontsDir (aWinDir);
392   aFontsDir.AssignCat ("\\Fonts\\");
393   delete[] aWinDir;
394
395   // read fonts list from registry
396   HKEY aFontsKey;
397   if (RegOpenKeyExA (HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts",
398                      0, KEY_READ, &aFontsKey) != ERROR_SUCCESS)
399   {
400     return;
401   }
402
403   NCollection_Map<TCollection_AsciiString> aSupportedExtensions;
404   for (Standard_Integer anIter = 0; Font_FontMgr_Extensions[anIter] != NULL; ++anIter)
405   {
406     Standard_CString anExt = Font_FontMgr_Extensions[anIter];
407     aSupportedExtensions.Add (TCollection_AsciiString (anExt));
408   }
409
410   aFtLibrary = new Font_FTLibrary();
411   static const DWORD aBufferSize = 256;
412   char aNameBuff[aBufferSize];
413   char aPathBuff[aBufferSize];
414   DWORD aNameSize = aBufferSize;
415   DWORD aPathSize = aBufferSize;
416   for (DWORD anIter = 0;
417        RegEnumValueA (aFontsKey, anIter,
418                       aNameBuff, &aNameSize, NULL, NULL,
419                       (LPBYTE )aPathBuff, &aPathSize) != ERROR_NO_MORE_ITEMS;
420       ++anIter, aNameSize = aBufferSize, aPathSize = aBufferSize)
421   {
422     aPathBuff[(aPathSize < aBufferSize) ? aPathSize : (aBufferSize - 1)] = '\0'; // ensure string is NULL-terminated
423
424     TCollection_AsciiString aFontName (aNameBuff), aFontPath (aPathBuff);
425     if (aFontPath.Search ("\\") == -1)
426     {
427       aFontPath.Insert (1, aFontsDir); // make absolute path
428     }
429
430     // check file extension is in list of supported
431     const Standard_Integer anExtensionPosition = aFontPath.SearchFromEnd (".") + 1;
432     if (anExtensionPosition > 0 && anExtensionPosition < aFontPath.Length())
433     {
434       TCollection_AsciiString aFontExtension = aFontPath.SubString (anExtensionPosition, aFontPath.Length());
435       aFontExtension.LowerCase();
436       if (aSupportedExtensions.Contains (aFontExtension))
437       {
438         if (Handle(Font_SystemFont) aNewFont = checkFont (aFtLibrary, aFontPath.ToCString()))
439         {
440           RegisterFont (aNewFont, false);
441         }
442       }
443     }
444   }
445
446   // close registry key
447   RegCloseKey (aFontsKey);
448
449 #else
450
451   NCollection_Map<TCollection_AsciiString> aMapOfFontsDirs;
452 #if !defined(__ANDROID__) && !defined(__APPLE__)
453   const OSD_Protection aProtectRead (OSD_R, OSD_R, OSD_R, OSD_R);
454
455   // read fonts directories from font service config file (obsolete)
456   for (Standard_Integer anIter = 0; myFontServiceConf[anIter] != NULL; ++anIter)
457   {
458     const TCollection_AsciiString aFileOfFontsPath (myFontServiceConf[anIter]);
459     OSD_File aFile (aFileOfFontsPath);
460     if (!aFile.Exists())
461     {
462       continue;
463     }
464
465     aFile.Open (OSD_ReadOnly, aProtectRead);
466     if (!aFile.IsOpen())
467     {
468       continue;
469     }
470
471     Standard_Integer aNByte = 256;
472     Standard_Integer aNbyteRead;
473     TCollection_AsciiString aStr; // read string with information
474     while (!aFile.IsAtEnd())
475     {
476       Standard_Integer aLocation = -1;
477       Standard_Integer aPathLocation = -1;
478
479       aFile.ReadLine (aStr, aNByte, aNbyteRead); // reading 1 line (256 bytes)
480       aLocation = aStr.Search ("catalogue=");
481       if (aLocation < 0)
482       {
483         aLocation = aStr.Search ("catalogue =");
484       }
485
486       aPathLocation = aStr.Search ("/");
487       if (aLocation > 0 && aPathLocation > 0)
488       {
489         aStr = aStr.Split (aPathLocation - 1);
490         TCollection_AsciiString aFontPath;
491         Standard_Integer aPathNumber = 1;
492         do
493         {
494           // Getting directory paths, which can be splitted by "," or ":"
495           aFontPath = aStr.Token (":,", aPathNumber);
496           aFontPath.RightAdjust();
497           if (!aFontPath.IsEmpty())
498           {
499             OSD_Path aPath(aFontPath);
500             addDirsRecursively (aPath, aMapOfFontsDirs);
501           }
502           aPathNumber++;
503         }
504         while (!aFontPath.IsEmpty());
505       }
506     }
507     aFile.Close();
508   }
509 #endif
510
511   // append default directories
512   for (Standard_Integer anIter = 0; myDefaultFontsDirs[anIter] != NULL; ++anIter)
513   {
514     Standard_CString anItem = myDefaultFontsDirs[anIter];
515     TCollection_AsciiString aPathStr (anItem);
516     OSD_Path aPath (aPathStr);
517     addDirsRecursively (aPath, aMapOfFontsDirs);
518   }
519
520   NCollection_Map<TCollection_AsciiString> aSupportedExtensions;
521   for (Standard_Integer anIter = 0; Font_FontMgr_Extensions[anIter] != NULL; ++anIter)
522   {
523     Standard_CString anExt = Font_FontMgr_Extensions[anIter];
524     aSupportedExtensions.Add (TCollection_AsciiString (anExt));
525   }
526
527   aFtLibrary = new Font_FTLibrary();
528   for (NCollection_Map<TCollection_AsciiString>::Iterator anIter (aMapOfFontsDirs);
529        anIter.More(); anIter.Next())
530   {
531   #if !defined(__ANDROID__) && !defined(__APPLE__)
532     OSD_File aReadFile (anIter.Value() + "/fonts.dir");
533     if (!aReadFile.Exists())
534     {
535   #endif
536       OSD_Path aFolderPath (anIter.Value());
537       for (OSD_FileIterator aFileIter (aFolderPath, "*"); aFileIter.More(); aFileIter.Next())
538       {
539         OSD_Path aFontFilePath;
540         aFileIter.Values().Path (aFontFilePath);
541
542         TCollection_AsciiString aFontFileName;
543         aFontFilePath.SystemName (aFontFileName);
544         aFontFileName = anIter.Value() + "/" + aFontFileName;
545
546         if (Handle(Font_SystemFont) aNewFont = checkFont (aFtLibrary, aFontFileName.ToCString()))
547         {
548           RegisterFont (aNewFont, false);
549         }
550       }
551
552   #if !defined(__ANDROID__) && !defined(__APPLE__)
553       continue;
554     }
555
556     aReadFile.Open (OSD_ReadOnly, aProtectRead);
557     if (!aReadFile.IsOpen())
558     {
559       continue; // invalid fonts directory
560     }
561
562     Standard_Integer aNbyteRead, aNByte = 256;
563     TCollection_AsciiString aLine (aNByte);
564     Standard_Boolean isFirstLine = Standard_True;
565     const TCollection_AsciiString anEncoding ("iso8859-1\n");
566     while (!aReadFile.IsAtEnd())
567     {
568       aReadFile.ReadLine (aLine, aNByte, aNbyteRead);
569       if (isFirstLine)
570       {
571         // first line contains the number of fonts in this file
572         // just ignoring it...
573         isFirstLine = Standard_False;
574         continue;
575       }
576
577       Standard_Integer anExtensionPosition = aLine.Search (".") + 1;
578       if (anExtensionPosition == 0)
579       {
580         continue; // can't find extension position in the font description
581       }
582
583       Standard_Integer anEndOfFileName = aLine.Location (" ", anExtensionPosition, aLine.Length()) - 1;
584       if (anEndOfFileName < 0 || anEndOfFileName < anExtensionPosition)
585       {
586         continue; // font description have empty extension
587       }
588
589       TCollection_AsciiString aFontExtension = aLine.SubString (anExtensionPosition, anEndOfFileName);
590       aFontExtension.LowerCase();
591       if (aSupportedExtensions.Contains (aFontExtension) && (aLine.Search (anEncoding) > 0))
592       {
593         // In current implementation use fonts with ISO-8859-1 coding page.
594         // OCCT not give to manage coding page by means of programm interface.
595         // TODO: make high level interface for choosing necessary coding page.
596         TCollection_AsciiString aXLFD (aLine.SubString (anEndOfFileName + 2, aLine.Length()));
597         TCollection_AsciiString aFontPath (anIter.Value().ToCString());
598         if (aFontPath.SearchFromEnd ("/") != aFontPath.Length())
599         {
600           aFontPath.AssignCat ("/");
601         }
602         TCollection_AsciiString aFontFileName (aLine.SubString (1, anEndOfFileName));
603         aFontPath.AssignCat (aFontFileName);
604         if (Handle(Font_SystemFont) aNewFont = checkFont (aFtLibrary, aFontPath.ToCString()))
605         {
606           RegisterFont (aNewFont, false);
607           if (!aXLFD.IsEmpty()
608             && aXLFD.Search ("-0-0-0-0-") != -1) // ignore non-resizable fonts
609           {
610             const TCollection_AsciiString anXName = aXLFD.Token ("-", 2);
611             Font_FontAspect anXAspect = Font_FA_Regular;
612             if (aXLFD.Token ("-", 3).IsEqual ("bold")
613              && (aXLFD.Token ("-", 4).IsEqual ("i")
614               || aXLFD.Token ("-", 4).IsEqual ("o")))
615             {
616               anXAspect = Font_FA_BoldItalic;
617             }
618             else if (aXLFD.Token ("-", 3).IsEqual ("bold"))
619             {
620               anXAspect = Font_FA_Bold;
621             }
622             else if (aXLFD.Token ("-", 4).IsEqual ("i")
623                   || aXLFD.Token ("-", 4).IsEqual ("o"))
624             {
625               anXAspect = Font_FA_Italic;
626             }
627
628             Handle(Font_SystemFont) aNewFontFromXLFD = new Font_SystemFont (anXName);
629             aNewFontFromXLFD->SetFontPath (anXAspect, aFontPath);
630             if (!aNewFont->IsEqual (aNewFontFromXLFD))
631             {
632               RegisterFont (aNewFontFromXLFD, false);
633             }
634           }
635         }
636       }
637     }
638     aReadFile.Close();
639   #endif
640   }
641 #endif
642 }
643
644 // =======================================================================
645 // function : GetAvailableFontsNames
646 // purpose  :
647 // =======================================================================
648 void Font_FontMgr::GetAvailableFontsNames (TColStd_SequenceOfHAsciiString& theFontsNames) const
649 {
650   theFontsNames.Clear();
651   for (NCollection_IndexedMap<Handle(Font_SystemFont), Font_SystemFont>::Iterator aFontIter (myFontMap);
652        aFontIter.More(); aFontIter.Next())
653   {
654     const Handle(Font_SystemFont)& aFont = aFontIter.Value();
655     theFontsNames.Append (new TCollection_HAsciiString(aFont->FontName()));
656   }
657 }
658
659 // =======================================================================
660 // function : GetFont
661 // purpose  :
662 // =======================================================================
663 Handle(Font_SystemFont) Font_FontMgr::GetFont (const Handle(TCollection_HAsciiString)& theFontName,
664                                                const Font_FontAspect  theFontAspect,
665                                                const Standard_Integer theFontSize) const
666 {
667   if ((theFontSize < 2 && theFontSize != -1) || theFontName.IsNull())
668   {
669     return Handle(Font_SystemFont)();
670   }
671
672   Handle(Font_SystemFont) aFont = myFontMap.Find (theFontName->String());
673   return (aFont.IsNull()
674        || theFontAspect == Font_FontAspect_UNDEFINED
675        || aFont->HasFontAspect (theFontAspect))
676        ? aFont
677        : Handle(Font_SystemFont)();
678 }
679
680 // =======================================================================
681 // function : GetFont
682 // purpose  :
683 // =======================================================================
684 Handle(Font_SystemFont) Font_FontMgr::GetFont (const TCollection_AsciiString& theFontName) const
685 {
686   return myFontMap.Find (theFontName);
687 }
688
689 // =======================================================================
690 // function : FindFont
691 // purpose  :
692 // =======================================================================
693 Handle(Font_SystemFont) Font_FontMgr::FindFont (const TCollection_AsciiString& theFontName,
694                                                 Font_FontAspect& theFontAspect) const
695 {
696   TCollection_AsciiString aFontName (theFontName);
697   aFontName.LowerCase();
698   Handle(Font_SystemFont) aFont = myFontMap.Find (aFontName);
699   if (!aFont.IsNull())
700   {
701     return aFont;
702   }
703
704   // Trying to use font names mapping
705   Handle(Font_FontAliasSequence) anAliases;
706   const Standard_Boolean hasAliases  = myFontAliases.Find (aFontName, anAliases)
707                                    && !anAliases.IsNull()
708                                    && !anAliases->IsEmpty();
709   if (!hasAliases
710     && aFont.IsNull())
711   {
712     anAliases = myFallbackAlias;
713   }
714
715   bool isAliasUsed = false, isBestAlias = false;
716   if (!anAliases.IsNull()
717    && !anAliases->IsEmpty())
718   {
719     for (Font_FontAliasSequence::Iterator anAliasIter (*anAliases); anAliasIter.More(); anAliasIter.Next())
720     {
721       const Font_FontAlias& anAlias = anAliasIter.Value();
722       if (Handle(Font_SystemFont) aFont2 = myFontMap.Find (anAlias.FontName))
723       {
724         if (aFont.IsNull())
725         {
726           aFont = aFont2;
727           isAliasUsed = true;
728         }
729
730         if ((anAlias.FontAspect != Font_FontAspect_UNDEFINED
731           && aFont2->HasFontAspect (anAlias.FontAspect)))
732         {
733           // special case - alias refers to styled font (e.g. "times-bold")
734           isBestAlias = true;
735           theFontAspect = anAlias.FontAspect;
736           break;
737         }
738         else if (anAlias.FontAspect == Font_FontAspect_UNDEFINED
739               && (theFontAspect == Font_FontAspect_UNDEFINED
740                || aFont2->HasFontAspect (theFontAspect)))
741         {
742           isBestAlias = true;
743           break;
744         }
745       }
746     }
747     if (hasAliases)
748     {
749       if (isAliasUsed && myToTraceAliases)
750       {
751         Message::DefaultMessenger()->Send (TCollection_AsciiString("Font_FontMgr, using font alias '") + aFont->FontName() + "'"
752                                            " instead of requested '" + theFontName +"'", Message_Trace);
753       }
754       if (isBestAlias)
755       {
756         return aFont;
757       }
758     }
759   }
760
761   if (aFont.IsNull())
762   {
763     // try finding ANY font in case if even default fallback alias myFallbackAlias cannot be found
764     aFont = myFontMap.Find (TCollection_AsciiString());
765   }
766   if (aFont.IsNull())
767   {
768     Message::DefaultMessenger()->Send (TCollection_AsciiString("Font_FontMgr, error: unable to find any font!", Message_Fail));
769     return Handle(Font_SystemFont)();
770   }
771
772   if ((theFontAspect != Font_FA_Undefined
773     && !aFont->HasFontAspect (theFontAspect))
774    || (!aFontName.IsEmpty()
775     && !aFontName.IsEqual (aFont->FontKey())))
776   {
777     TCollection_AsciiString aDesc = TCollection_AsciiString() + "'" + theFontName + "'"
778                                   + TCollection_AsciiString() + " [" + Font_FontMgr::FontAspectToString (theFontAspect) + "]";
779     Message::DefaultMessenger()->Send (TCollection_AsciiString("Font_FontMgr, warning: unable to find font ")
780                                      + aDesc + "; " + aFont->ToString() + " is used instead");
781   }
782   return aFont;
783 }
784
785 // =======================================================================
786 // function : Font_FontMap::Find
787 // purpose  :
788 // =======================================================================
789 Handle(Font_SystemFont) Font_FontMgr::Font_FontMap::Find (const TCollection_AsciiString& theFontName) const
790 {
791   if (IsEmpty())
792   {
793     return Handle(Font_SystemFont)();
794   }
795   else if (theFontName.IsEmpty())
796   {
797     return FindKey (1); // return any font
798   }
799
800   TCollection_AsciiString aFontName (theFontName);
801   aFontName.LowerCase();
802   for (IndexedMapNode* aNodeIter = (IndexedMapNode* )myData1[::HashCode (aFontName, NbBuckets())];
803        aNodeIter != NULL; aNodeIter = (IndexedMapNode* )aNodeIter->Next())
804   {
805     const Handle(Font_SystemFont)& aKey = aNodeIter->Key1();
806     if (aKey->FontKey().IsEqual (aFontName))
807     {
808       return aKey;
809     }
810   }
811   return Handle(Font_SystemFont)();
812 }