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