Increment OCCT version up to 7.4.0
[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 };
c9983ee8 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>
264abd72 95 #endif
aff395a3 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)
65360da3 105 static Standard_CString myDefaultFontsDirs[] = {"/system/fonts", // Android
106 "/usr/share/fonts",
aff395a3 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)
7fd59977 114 {
aff395a3 115 TCollection_AsciiString aDirName;
116 thePath.SystemName (aDirName);
117 if (!theDirsMap.Add (aDirName))
118 {
119 return;
7fd59977 120 }
7fd59977 121
aff395a3 122 for (OSD_DirectoryIterator aDirIterator (thePath, "*"); aDirIterator.More(); aDirIterator.Next())
7fd59977 123 {
aff395a3 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 }
7fd59977 135 }
7fd59977 136 }
aff395a3 137
68858c7d 138 } // anonymous namespace
aff395a3 139
140#endif
141
142// =======================================================================
143// function : checkFont
144// purpose :
145// =======================================================================
725ef85e 146static Handle(Font_SystemFont) checkFont (const Handle(Font_FTLibrary)& theFTLib,
147 const Standard_CString theFontPath)
aff395a3 148{
149 FT_Face aFontFace;
725ef85e 150 FT_Error aFaceError = FT_New_Face (theFTLib->Instance(), theFontPath, 0, &aFontFace);
aff395a3 151 if (aFaceError != FT_Err_Ok)
152 {
153 return NULL;
7fd59977 154 }
7fd59977 155
aff395a3 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
508643cf 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 {
5b377041 174 aResult = new Font_SystemFont (aFontFace->family_name);
175 aResult->SetFontPath (anAspect, theFontPath);
e4f0cc46 176 // automatically identify some known single-line fonts
5b377041 177 aResult->SetSingleStrokeFont (aResult->FontKey().StartsWith ("olf "));
508643cf 178 }
7fd59977 179
aff395a3 180 FT_Done_Face (aFontFace);
7fd59977 181
aff395a3 182 return aResult;
183}
7fd59977 184
aff395a3 185// =======================================================================
186// function : GetInstance
187// purpose :
188// =======================================================================
189Handle(Font_FontMgr) Font_FontMgr::GetInstance()
190{
eeaaaefb 191 static Handle(Font_FontMgr) _mgr;
aff395a3 192 if (_mgr.IsNull())
193 {
eeaaaefb 194 _mgr = new Font_FontMgr();
aff395a3 195 }
7fd59977 196
197 return _mgr;
7fd59977 198}
199
aff395a3 200// =======================================================================
912761ea 201// function : ToUseUnicodeSubsetFallback
202// purpose :
203// =======================================================================
204Standard_Boolean& Font_FontMgr::ToUseUnicodeSubsetFallback()
205{
206 static Standard_Boolean TheToUseUnicodeSubsetFallback = true;
207 return TheToUseUnicodeSubsetFallback;
208}
209
210// =======================================================================
5b377041 211// function : addFontAlias
212// purpose :
213// =======================================================================
214void 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// =======================================================================
aff395a3 241// function : Font_FontMgr
242// purpose :
243// =======================================================================
244Font_FontMgr::Font_FontMgr()
5b377041 245: myToTraceAliases (Standard_False)
aff395a3 246{
5b377041 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();
912761ea 256 Handle(Font_FontAliasSequence) anArab = new Font_FontAliasSequence();
5b377041 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
912761ea 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
5b377041 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);
912761ea 335 addFontAlias ("arabic", anArab); // Font_NOF_ARABIC
5b377041 336 addFontAlias (Font_NOF_SYMBOL_MONO, aWinDin);
337 addFontAlias (Font_NOF_ASCII_SCRIPT_SIMPLEX, aScript);
338
339 myFallbackAlias = aSans;
340
7fd59977 341 InitFontDataBase();
7fd59977 342}
343
aff395a3 344// =======================================================================
725ef85e 345// function : CheckFont
346// purpose :
347// =======================================================================
348Handle(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// =======================================================================
358Standard_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
5b377041 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)
725ef85e 375 {
5b377041 376 if (anOldFont->FontPath ((Font_FontAspect )anAspectIter).IsEqual (theFont->FontPath ((Font_FontAspect )anAspectIter)))
725ef85e 377 {
378 continue;
379 }
5b377041 380 else if (theToOverride
381 || !anOldFont->HasFontAspect ((Font_FontAspect )anAspectIter))
725ef85e 382 {
5b377041 383 anOldFont->SetFontPath ((Font_FontAspect )anAspectIter, theFont->FontPath ((Font_FontAspect )anAspectIter));
725ef85e 384 }
5b377041 385 else if (theFont->HasFontAspect ((Font_FontAspect )anAspectIter))
725ef85e 386 {
5b377041 387 return Standard_False;
725ef85e 388 }
389 }
725ef85e 390 return Standard_True;
391}
392
393// =======================================================================
aff395a3 394// function : InitFontDataBase
395// purpose :
396// =======================================================================
397void Font_FontMgr::InitFontDataBase()
398{
5b377041 399 myFontMap.Clear();
c9983ee8 400 Handle(Font_FTLibrary) aFtLibrary = new Font_FTLibrary();
7fd59977 401
1ce0716b 402#if defined(OCCT_UWP)
403 // system font files are not accessible
404 (void )aFtLibrary;
405#elif defined(_WIN32)
7fd59977 406
aff395a3 407 // font directory is placed in "C:\Windows\Fonts\"
408 UINT aStrLength = GetSystemWindowsDirectoryA (NULL, 0);
409 if (aStrLength == 0)
a6535b1d 410 {
aff395a3 411 return;
a6535b1d 412 }
aff395a3 413
414 char* aWinDir = new char[aStrLength];
415 GetSystemWindowsDirectoryA (aWinDir, aStrLength);
5b377041 416 TCollection_AsciiString aFontsDir (aWinDir);
417 aFontsDir.AssignCat ("\\Fonts\\");
aff395a3 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)
7fd59977 424 {
425 return;
7fd59977 426 }
7fd59977 427
aff395a3 428 NCollection_Map<TCollection_AsciiString> aSupportedExtensions;
429 for (Standard_Integer anIter = 0; Font_FontMgr_Extensions[anIter] != NULL; ++anIter)
7fd59977 430 {
aff395a3 431 Standard_CString anExt = Font_FontMgr_Extensions[anIter];
432 aSupportedExtensions.Add (TCollection_AsciiString (anExt));
7fd59977 433 }
434
aff395a3 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
7fd59977 447
5b377041 448 TCollection_AsciiString aFontName (aNameBuff), aFontPath (aPathBuff);
449 if (aFontPath.Search ("\\") == -1)
aff395a3 450 {
5b377041 451 aFontPath.Insert (1, aFontsDir); // make absolute path
7fd59977 452 }
aff395a3 453
454 // check file extension is in list of supported
5b377041 455 const Standard_Integer anExtensionPosition = aFontPath.SearchFromEnd (".") + 1;
456 if (anExtensionPosition > 0 && anExtensionPosition < aFontPath.Length())
7fd59977 457 {
5b377041 458 TCollection_AsciiString aFontExtension = aFontPath.SubString (anExtensionPosition, aFontPath.Length());
459 aFontExtension.LowerCase();
460 if (aSupportedExtensions.Contains (aFontExtension))
aff395a3 461 {
5b377041 462 if (Handle(Font_SystemFont) aNewFont = checkFont (aFtLibrary, aFontPath.ToCString()))
aff395a3 463 {
5b377041 464 RegisterFont (aNewFont, false);
aff395a3 465 }
466 }
7fd59977 467 }
468 }
7fd59977 469
aff395a3 470 // close registry key
471 RegCloseKey (aFontsKey);
472
473#else
7fd59977 474
aff395a3 475 NCollection_Map<TCollection_AsciiString> aMapOfFontsDirs;
264abd72 476#if !defined(__ANDROID__) && !defined(__APPLE__)
c9983ee8 477 if (FcConfig* aFcCfg = FcInitLoadConfig())
7fd59977 478 {
c9983ee8 479 if (FcStrList* aFcFontDir = FcConfigGetFontDirs (aFcCfg))
aff395a3 480 {
c9983ee8 481 for (;;)
482 {
483 FcChar8* aFcFolder = FcStrListNext (aFcFontDir);
484 if (aFcFolder == NULL)
485 {
486 break;
487 }
7fd59977 488
c9983ee8 489 TCollection_AsciiString aPathStr ((const char* )aFcFolder);
490 OSD_Path aPath (aPathStr);
491 addDirsRecursively (aPath, aMapOfFontsDirs);
492 }
493 FcStrListDone (aFcFontDir);
aff395a3 494 }
c9983ee8 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);
aff395a3 502
c9983ee8 503 // read fonts directories from font service config file (obsolete)
504 for (Standard_Integer anIter = 0; myFontServiceConf[anIter] != NULL; ++anIter)
7fd59977 505 {
c9983ee8 506 const TCollection_AsciiString aFileOfFontsPath (myFontServiceConf[anIter]);
507 OSD_File aFile (aFileOfFontsPath);
508 if (!aFile.Exists())
509 {
510 continue;
511 }
aff395a3 512
c9983ee8 513 aFile.Open (OSD_ReadOnly, aProtectRead);
514 if (!aFile.IsOpen())
aff395a3 515 {
c9983ee8 516 continue;
aff395a3 517 }
518
c9983ee8 519 Standard_Integer aNByte = 256;
520 Standard_Integer aNbyteRead;
521 TCollection_AsciiString aStr; // read string with information
522 while (!aFile.IsAtEnd())
7fd59977 523 {
c9983ee8 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)
7fd59977 536 {
c9983ee8 537 aStr = aStr.Split (aPathLocation - 1);
538 TCollection_AsciiString aFontPath;
539 Standard_Integer aPathNumber = 1;
540 do
7fd59977 541 {
c9983ee8 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++;
7fd59977 551 }
c9983ee8 552 while (!aFontPath.IsEmpty());
aff395a3 553 }
7fd59977 554 }
c9983ee8 555 aFile.Close();
7fd59977 556 }
557 }
264abd72 558#endif
7fd59977 559
aff395a3 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
aff395a3 576 for (NCollection_Map<TCollection_AsciiString>::Iterator anIter (aMapOfFontsDirs);
577 anIter.More(); anIter.Next())
578 {
5b377041 579 #if !defined(__ANDROID__) && !defined(__APPLE__)
580 OSD_File aReadFile (anIter.Value() + "/fonts.dir");
581 if (!aReadFile.Exists())
65360da3 582 {
5b377041 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);
65360da3 589
5b377041 590 TCollection_AsciiString aFontFileName;
591 aFontFilePath.SystemName (aFontFileName);
592 aFontFileName = anIter.Value() + "/" + aFontFileName;
65360da3 593
5b377041 594 if (Handle(Font_SystemFont) aNewFont = checkFont (aFtLibrary, aFontFileName.ToCString()))
595 {
596 RegisterFont (aNewFont, false);
597 }
65360da3 598 }
5b377041 599
600 #if !defined(__ANDROID__) && !defined(__APPLE__)
601 continue;
aff395a3 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 }
7fd59977 624
aff395a3 625 Standard_Integer anExtensionPosition = aLine.Search (".") + 1;
626 if (anExtensionPosition == 0)
627 {
628 continue; // can't find extension position in the font description
629 }
7fd59977 630
aff395a3 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 }
7fd59977 636
aff395a3 637 TCollection_AsciiString aFontExtension = aLine.SubString (anExtensionPosition, anEndOfFileName);
638 aFontExtension.LowerCase();
639 if (aSupportedExtensions.Contains (aFontExtension) && (aLine.Search (anEncoding) > 0))
7fd59977 640 {
aff395a3 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.
5b377041 644 TCollection_AsciiString aXLFD (aLine.SubString (anEndOfFileName + 2, aLine.Length()));
645 TCollection_AsciiString aFontPath (anIter.Value().ToCString());
646 if (aFontPath.SearchFromEnd ("/") != aFontPath.Length())
aff395a3 647 {
5b377041 648 aFontPath.AssignCat ("/");
aff395a3 649 }
5b377041 650 TCollection_AsciiString aFontFileName (aLine.SubString (1, anEndOfFileName));
651 aFontPath.AssignCat (aFontFileName);
652 if (Handle(Font_SystemFont) aNewFont = checkFont (aFtLibrary, aFontPath.ToCString()))
aff395a3 653 {
5b377041 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 }
aff395a3 683 }
aff395a3 684 }
7fd59977 685 }
aff395a3 686 aReadFile.Close();
65360da3 687 #endif
7fd59977 688 }
689#endif
aff395a3 690}
691
692// =======================================================================
b514beda 693// function : GetAvailableFontsNames
694// purpose :
695// =======================================================================
aff395a3 696void Font_FontMgr::GetAvailableFontsNames (TColStd_SequenceOfHAsciiString& theFontsNames) const
697{
698 theFontsNames.Clear();
5b377041 699 for (NCollection_IndexedMap<Handle(Font_SystemFont), Font_SystemFont>::Iterator aFontIter (myFontMap);
700 aFontIter.More(); aFontIter.Next())
aff395a3 701 {
5b377041 702 const Handle(Font_SystemFont)& aFont = aFontIter.Value();
703 theFontsNames.Append (new TCollection_HAsciiString(aFont->FontName()));
aff395a3 704 }
7fd59977 705}
706
b514beda 707// =======================================================================
708// function : GetFont
709// purpose :
710// =======================================================================
aff395a3 711Handle(Font_SystemFont) Font_FontMgr::GetFont (const Handle(TCollection_HAsciiString)& theFontName,
b514beda 712 const Font_FontAspect theFontAspect,
aff395a3 713 const Standard_Integer theFontSize) const
7fd59977 714{
5b377041 715 if ((theFontSize < 2 && theFontSize != -1) || theFontName.IsNull())
aff395a3 716 {
5b377041 717 return Handle(Font_SystemFont)();
aff395a3 718 }
719
5b377041 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}
aff395a3 727
5b377041 728// =======================================================================
729// function : GetFont
730// purpose :
731// =======================================================================
732Handle(Font_SystemFont) Font_FontMgr::GetFont (const TCollection_AsciiString& theFontName) const
733{
734 return myFontMap.Find (theFontName);
7fd59977 735}
736
b514beda 737// =======================================================================
912761ea 738// function : FindFallbackFont
739// purpose :
740// =======================================================================
741Handle(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// =======================================================================
b514beda 756// function : FindFont
757// purpose :
758// =======================================================================
5b377041 759Handle(Font_SystemFont) Font_FontMgr::FindFont (const TCollection_AsciiString& theFontName,
1bbd7c79 760 Font_StrictLevel theStrictLevel,
5b377041 761 Font_FontAspect& theFontAspect) const
aff395a3 762{
5b377041 763 TCollection_AsciiString aFontName (theFontName);
764 aFontName.LowerCase();
765 Handle(Font_SystemFont) aFont = myFontMap.Find (aFontName);
1bbd7c79 766 if (!aFont.IsNull()
767 || theStrictLevel == Font_StrictLevel_Strict)
aff395a3 768 {
769 return aFont;
770 }
771
772 // Trying to use font names mapping
976627e6 773 for (int aPass = 0; aPass < 2; ++aPass)
aff395a3 774 {
976627e6 775 Handle(Font_FontAliasSequence) anAliases;
776 if (aPass == 0)
777 {
778 myFontAliases.Find (aFontName, anAliases);
779 }
1bbd7c79 780 else if (theStrictLevel == Font_StrictLevel_Any)
976627e6 781 {
782 anAliases = myFallbackAlias;
783 }
aff395a3 784
976627e6 785 if (anAliases.IsNull()
786 || anAliases->IsEmpty())
787 {
788 continue;
789 }
790
791 bool isAliasUsed = false, isBestAlias = false;
5b377041 792 for (Font_FontAliasSequence::Iterator anAliasIter (*anAliases); anAliasIter.More(); anAliasIter.Next())
b514beda 793 {
5b377041 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
976627e6 813 || aFont2->HasFontAspect (theFontAspect)))
5b377041 814 {
815 isBestAlias = true;
816 break;
817 }
818 }
819 }
976627e6 820
821 if (aPass == 0)
5b377041 822 {
823 if (isAliasUsed && myToTraceAliases)
824 {
825 Message::DefaultMessenger()->Send (TCollection_AsciiString("Font_FontMgr, using font alias '") + aFont->FontName() + "'"
976627e6 826 " instead of requested '" + theFontName +"'", Message_Trace);
5b377041 827 }
828 if (isBestAlias)
829 {
830 return aFont;
831 }
976627e6 832 else if (!aFont.IsNull())
833 {
834 break;
835 }
b514beda 836 }
837 }
aff395a3 838
912761ea 839 if (aFont.IsNull()
840 && theStrictLevel == Font_StrictLevel_Any)
aff395a3 841 {
5b377041 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)();
aff395a3 849 }
850
5b377041 851 if ((theFontAspect != Font_FA_Undefined
852 && !aFont->HasFontAspect (theFontAspect))
853 || (!aFontName.IsEmpty()
854 && !aFontName.IsEqual (aFont->FontKey())))
aff395a3 855 {
5b377041 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");
aff395a3 860 }
5b377041 861 return aFont;
862}
aff395a3 863
5b377041 864// =======================================================================
865// function : Font_FontMap::Find
866// purpose :
867// =======================================================================
868Handle(Font_SystemFont) Font_FontMgr::Font_FontMap::Find (const TCollection_AsciiString& theFontName) const
869{
870 if (IsEmpty())
aff395a3 871 {
5b377041 872 return Handle(Font_SystemFont)();
873 }
874 else if (theFontName.IsEmpty())
875 {
876 return FindKey (1); // return any font
aff395a3 877 }
878
5b377041 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)();
aff395a3 891}