0031118: Visualization - Font_FontMgr skips fonts with unknown styles like Narrow...
[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
565baee6 84 #if !defined(__ANDROID__) && !defined(__APPLE__) && !defined(__EMSCRIPTEN__)
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 {
15e4e6a2 153 return Handle(Font_SystemFont)();
154 }
155 if (aFontFace->family_name == NULL // skip broken fonts (error in FreeType?)
156 || FT_Select_Charmap (aFontFace, ft_encoding_unicode) != 0) // Font_FTFont supports only UNICODE fonts
157 {
158 FT_Done_Face (aFontFace);
159 return Handle(Font_SystemFont)();
7fd59977 160 }
7fd59977 161
15e4e6a2 162 // FreeType decomposes font definition into Family Name and Style Name,
163 // so that fonts within the same Family and different Styles can be identified.
164 // OCCT Font Manager natively handles 4 basic styles: Regular, Bold, Italic and Bold+Italic.
165 // To include other non-standard Styles, their names can be appended to Family Name; for this, names of normal Styles should be removed.
166 TCollection_AsciiString aFamily (aFontFace->family_name);
167 TCollection_AsciiString aStyle (aFontFace->style_name != NULL ? aFontFace->style_name : "");
aff395a3 168 Font_FontAspect anAspect = Font_FA_Regular;
169 if (aFontFace->style_flags == (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD))
170 {
171 anAspect = Font_FA_BoldItalic;
15e4e6a2 172 const Standard_Integer aRemoveItalic = aStyle.Search ("Italic");
173 if (aRemoveItalic != -1)
174 {
175 aStyle.Remove (aRemoveItalic, 6);
176 }
177 else
178 {
179 // synonym
180 const Standard_Integer aRemoveOblique = aStyle.Search ("Oblique");
181 if (aRemoveOblique != -1)
182 {
183 aStyle.Remove (aRemoveOblique, 7);
184 }
185 }
186
187 const Standard_Integer aRemoveBold = aStyle.Search ("Bold");
188 if (aRemoveBold != -1)
189 {
190 aStyle.Remove (aRemoveBold, 4);
191 }
aff395a3 192 }
193 else if (aFontFace->style_flags == FT_STYLE_FLAG_ITALIC)
194 {
195 anAspect = Font_FA_Italic;
15e4e6a2 196 const Standard_Integer aRemoveItalic = aStyle.Search ("Italic");
197 if (aRemoveItalic != -1)
198 {
199 aStyle.Remove (aRemoveItalic, 6);
200 }
201 else
202 {
203 // synonym
204 const Standard_Integer aRemoveOblique = aStyle.Search ("Oblique");
205 if (aRemoveOblique != -1)
206 {
207 aStyle.Remove (aRemoveOblique, 7);
208 }
209 }
aff395a3 210 }
211 else if (aFontFace->style_flags == FT_STYLE_FLAG_BOLD)
212 {
213 anAspect = Font_FA_Bold;
15e4e6a2 214 const Standard_Integer aRemoveBold = aStyle.Search ("Bold");
215 if (aRemoveBold != -1)
216 {
217 aStyle.Remove (aRemoveBold, 4);
218 }
aff395a3 219 }
220
15e4e6a2 221 const Standard_Integer aRemoveReg = aStyle.Search ("Regular");
222 if (aRemoveReg != -1)
508643cf 223 {
15e4e6a2 224 aStyle.Remove (aRemoveReg, 7);
225 }
226 else
227 {
228 // synonym
229 const Standard_Integer aRemoveBook = aStyle.Search ("Book");
230 if (aRemoveBook != -1)
231 {
232 aStyle.Remove (aRemoveBook, 4);
233 }
508643cf 234 }
7fd59977 235
15e4e6a2 236 aStyle.LeftAdjust();
237 aStyle.RightAdjust();
238 for (;;)
239 {
240 // remove double spaces after removal of several keywords in-between, like "Condensed Bold Italic Oblique"
241 const Standard_Integer aRemoveSpace = aStyle.Search (" ");
242 if (aRemoveSpace == -1)
243 {
244 break;
245 }
246
247 aStyle.Remove (aRemoveSpace, 1);
248 }
249
250 if (!aStyle.IsEmpty())
251 {
252 aFamily = aFamily + " " + aStyle;
253 }
7fd59977 254
15e4e6a2 255 Handle(Font_SystemFont) aResult = new Font_SystemFont (aFamily);
256 aResult->SetFontPath (anAspect, theFontPath);
257 // automatically identify some known single-line fonts
258 aResult->SetSingleStrokeFont (aResult->FontKey().StartsWith ("olf "));
259
260 FT_Done_Face (aFontFace);
aff395a3 261 return aResult;
262}
7fd59977 263
aff395a3 264// =======================================================================
265// function : GetInstance
266// purpose :
267// =======================================================================
268Handle(Font_FontMgr) Font_FontMgr::GetInstance()
269{
eeaaaefb 270 static Handle(Font_FontMgr) _mgr;
aff395a3 271 if (_mgr.IsNull())
272 {
eeaaaefb 273 _mgr = new Font_FontMgr();
aff395a3 274 }
7fd59977 275
276 return _mgr;
7fd59977 277}
278
912761ea 279// =======================================================================
280// function : ToUseUnicodeSubsetFallback
281// purpose :
282// =======================================================================
283Standard_Boolean& Font_FontMgr::ToUseUnicodeSubsetFallback()
284{
285 static Standard_Boolean TheToUseUnicodeSubsetFallback = true;
286 return TheToUseUnicodeSubsetFallback;
287}
288
5b377041 289// =======================================================================
290// function : addFontAlias
291// purpose :
292// =======================================================================
293void Font_FontMgr::addFontAlias (const TCollection_AsciiString& theAliasName,
294 const Handle(Font_FontAliasSequence)& theAliases,
295 Font_FontAspect theAspect)
296{
297 if (theAliases.IsNull()
298 || theAliases->IsEmpty())
299 {
300 return;
301 }
302
303 Handle(Font_FontAliasSequence) anAliases = theAliases;
304 if (theAspect != Font_FA_Undefined)
305 {
306 anAliases = new Font_FontAliasSequence();
307 for (Font_FontAliasSequence::Iterator anAliasIter (*theAliases); anAliasIter.More(); anAliasIter.Next())
308 {
309 const TCollection_AsciiString& aName = anAliasIter.Value().FontName;
310 anAliases->Append (Font_FontAlias (aName, theAspect));
311 }
312 }
313
314 TCollection_AsciiString anAliasName (theAliasName);
315 anAliasName.LowerCase();
316 myFontAliases.Bind (anAliasName, anAliases);
317}
318
aff395a3 319// =======================================================================
320// function : Font_FontMgr
321// purpose :
322// =======================================================================
323Font_FontMgr::Font_FontMgr()
5b377041 324: myToTraceAliases (Standard_False)
aff395a3 325{
5b377041 326 Handle(Font_FontAliasSequence) aMono = new Font_FontAliasSequence();
327 Handle(Font_FontAliasSequence) aSerif = new Font_FontAliasSequence();
328 Handle(Font_FontAliasSequence) aSans = new Font_FontAliasSequence();
329 Handle(Font_FontAliasSequence) aSymbol = new Font_FontAliasSequence();
330 Handle(Font_FontAliasSequence) aScript = new Font_FontAliasSequence();
331 Handle(Font_FontAliasSequence) aWinDin = new Font_FontAliasSequence();
332 Handle(Font_FontAliasSequence) anIris = new Font_FontAliasSequence();
333 Handle(Font_FontAliasSequence) aCJK = new Font_FontAliasSequence();
334 Handle(Font_FontAliasSequence) aKorean = new Font_FontAliasSequence();
912761ea 335 Handle(Font_FontAliasSequence) anArab = new Font_FontAliasSequence();
5b377041 336
337 // best matches - pre-installed on Windows, some of them are pre-installed on macOS,
338 // and sometimes them can be found installed on other systems (by user)
339 aMono ->Append (Font_FontAlias ("courier new"));
340 aSerif ->Append (Font_FontAlias ("times new roman"));
341 aSans ->Append (Font_FontAlias ("arial"));
342 aSymbol->Append (Font_FontAlias ("symbol"));
343 aScript->Append (Font_FontAlias ("script"));
344 aWinDin->Append (Font_FontAlias ("wingdings"));
345 anIris ->Append (Font_FontAlias ("lucida console"));
346
347#if defined(__ANDROID__)
348 // Noto font family is usually installed on Android 6+ devices
349 aMono ->Append (Font_FontAlias ("noto mono"));
350 aSerif ->Append (Font_FontAlias ("noto serif"));
351 // Droid font family is usually installed on Android 4+ devices
352 aMono ->Append (Font_FontAlias ("droid sans mono"));
353 aSerif ->Append (Font_FontAlias ("droid serif"));
354 aSans ->Append (Font_FontAlias ("roboto")); // actually DroidSans.ttf
355#elif !defined(_WIN32) && !defined(__APPLE__) //X11
356 aSerif ->Append (Font_FontAlias ("times"));
357 aSans ->Append (Font_FontAlias ("helvetica"));
358 // GNU FreeFonts family is usually installed on Linux
359 aMono ->Append (Font_FontAlias ("freemono"));
360 aSerif ->Append (Font_FontAlias ("freeserif"));
361 aSans ->Append (Font_FontAlias ("freesans"));
362 // DejaVu font family is usually installed on Linux
363 aMono ->Append (Font_FontAlias ("dejavu sans mono"));
364 aSerif ->Append (Font_FontAlias ("dejavu serif"));
365 aSans ->Append (Font_FontAlias ("dejavu sans"));
366#endif
367
368 // default CJK (Chinese/Japanese/Korean) fonts
369 aCJK ->Append (Font_FontAlias ("simsun")); // Windows
370 aCJK ->Append (Font_FontAlias ("droid sans fallback")); // Android, Linux
371 aCJK ->Append (Font_FontAlias ("noto sans sc")); // Android
372
373#if defined(_WIN32)
374 aKorean->Append (Font_FontAlias ("malgun gothic")); // introduced since Vista
375 aKorean->Append (Font_FontAlias ("gulim")); // used on older systems (Windows XP)
376#elif defined(__APPLE__)
377 aKorean->Append (Font_FontAlias ("applegothic"));
378 aKorean->Append (Font_FontAlias ("stfangsong"));
379#endif
380 aKorean->Append (Font_FontAlias ("nanumgothic")); // Android, Linux
381 aKorean->Append (Font_FontAlias ("noto sans kr")); // Android
382 aKorean->Append (Font_FontAlias ("nanummyeongjo")); // Linux
383 aKorean->Append (Font_FontAlias ("noto serif cjk jp")); // Linux
384 aKorean->Append (Font_FontAlias ("noto sans cjk jp")); // Linux
36e28f96 385 aKorean->Append (Font_FontAlias ("droid sans fallback")); // Linux
5b377041 386
912761ea 387#if defined(_WIN32)
388 anArab->Append (Font_FontAlias ("times new roman"));
389#elif defined(__APPLE__)
390 anArab->Append (Font_FontAlias ("decotype naskh"));
391#elif defined(__ANDROID__)
392 anArab->Append (Font_FontAlias ("droid arabic naskh"));
393 anArab->Append (Font_FontAlias ("noto naskh arabic"));
394#endif
395
5b377041 396 addFontAlias ("mono", aMono);
397 addFontAlias ("courier", aMono); // Font_NOF_ASCII_MONO
398 addFontAlias ("monospace", aMono); // Font_NOF_MONOSPACE
399 addFontAlias ("rock", aSans); // Font_NOF_CARTOGRAPHIC_SIMPLEX
400 addFontAlias ("sansserif", aSans); // Font_NOF_SANS_SERIF
401 addFontAlias ("sans-serif", aSans);
402 addFontAlias ("sans", aSans);
403 addFontAlias ("arial", aSans);
404 addFontAlias ("times", aSerif);
405 addFontAlias ("serif", aSerif); // Font_NOF_SERIF
406 addFontAlias ("times-roman", aSerif); // Font_NOF_ASCII_SIMPLEX
407 addFontAlias ("times-bold", aSerif, Font_FA_Bold); // Font_NOF_ASCII_DUPLEX
408 addFontAlias ("times-italic", aSerif, Font_FA_Italic); // Font_NOF_ASCII_ITALIC_COMPLEX
409 addFontAlias ("times-bolditalic", aSerif, Font_FA_BoldItalic); // Font_NOF_ASCII_ITALIC_TRIPLEX
410 addFontAlias ("symbol", aSymbol); // Font_NOF_GREEK_MONO
411 addFontAlias ("iris", anIris); // Font_NOF_KANJI_MONO
412 addFontAlias ("korean", aKorean); // Font_NOF_KOREAN
413 addFontAlias ("cjk", aCJK); // Font_NOF_CJK
414 addFontAlias ("nsimsun", aCJK);
912761ea 415 addFontAlias ("arabic", anArab); // Font_NOF_ARABIC
5b377041 416 addFontAlias (Font_NOF_SYMBOL_MONO, aWinDin);
417 addFontAlias (Font_NOF_ASCII_SCRIPT_SIMPLEX, aScript);
418
419 myFallbackAlias = aSans;
420
7fd59977 421 InitFontDataBase();
7fd59977 422}
423
725ef85e 424// =======================================================================
425// function : CheckFont
426// purpose :
427// =======================================================================
428Handle(Font_SystemFont) Font_FontMgr::CheckFont (Standard_CString theFontPath) const
429{
430 Handle(Font_FTLibrary) aFtLibrary = new Font_FTLibrary();
431 return checkFont (aFtLibrary, theFontPath);
432}
433
434// =======================================================================
435// function : RegisterFont
436// purpose :
437// =======================================================================
438Standard_Boolean Font_FontMgr::RegisterFont (const Handle(Font_SystemFont)& theFont,
439 const Standard_Boolean theToOverride)
440{
441 if (theFont.IsNull())
442 {
443 return Standard_False;
444 }
445
5b377041 446 const Standard_Integer anOldIndex = myFontMap.FindIndex (theFont);
447 if (anOldIndex == 0)
448 {
449 myFontMap.Add (theFont);
450 return Standard_True;
451 }
452
453 Handle(Font_SystemFont) anOldFont = myFontMap.FindKey (anOldIndex);
454 for (int anAspectIter = 0; anAspectIter < Font_FontAspect_NB; ++anAspectIter)
725ef85e 455 {
5b377041 456 if (anOldFont->FontPath ((Font_FontAspect )anAspectIter).IsEqual (theFont->FontPath ((Font_FontAspect )anAspectIter)))
725ef85e 457 {
458 continue;
459 }
5b377041 460 else if (theToOverride
461 || !anOldFont->HasFontAspect ((Font_FontAspect )anAspectIter))
725ef85e 462 {
5b377041 463 anOldFont->SetFontPath ((Font_FontAspect )anAspectIter, theFont->FontPath ((Font_FontAspect )anAspectIter));
725ef85e 464 }
5b377041 465 else if (theFont->HasFontAspect ((Font_FontAspect )anAspectIter))
725ef85e 466 {
5b377041 467 return Standard_False;
725ef85e 468 }
469 }
725ef85e 470 return Standard_True;
471}
472
36e28f96 473// =======================================================================
474// function : ClearFontDataBase()
475// purpose :
476// =======================================================================
477void Font_FontMgr::ClearFontDataBase()
478{
479 myFontMap.Clear();
480}
481
aff395a3 482// =======================================================================
483// function : InitFontDataBase
484// purpose :
485// =======================================================================
486void Font_FontMgr::InitFontDataBase()
487{
5b377041 488 myFontMap.Clear();
c9983ee8 489 Handle(Font_FTLibrary) aFtLibrary = new Font_FTLibrary();
7fd59977 490
1ce0716b 491#if defined(OCCT_UWP)
492 // system font files are not accessible
493 (void )aFtLibrary;
494#elif defined(_WIN32)
7fd59977 495
aff395a3 496 // font directory is placed in "C:\Windows\Fonts\"
497 UINT aStrLength = GetSystemWindowsDirectoryA (NULL, 0);
498 if (aStrLength == 0)
a6535b1d 499 {
aff395a3 500 return;
a6535b1d 501 }
aff395a3 502
503 char* aWinDir = new char[aStrLength];
504 GetSystemWindowsDirectoryA (aWinDir, aStrLength);
5b377041 505 TCollection_AsciiString aFontsDir (aWinDir);
506 aFontsDir.AssignCat ("\\Fonts\\");
aff395a3 507 delete[] aWinDir;
508
509 // read fonts list from registry
510 HKEY aFontsKey;
511 if (RegOpenKeyExA (HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts",
512 0, KEY_READ, &aFontsKey) != ERROR_SUCCESS)
7fd59977 513 {
514 return;
7fd59977 515 }
7fd59977 516
aff395a3 517 NCollection_Map<TCollection_AsciiString> aSupportedExtensions;
518 for (Standard_Integer anIter = 0; Font_FontMgr_Extensions[anIter] != NULL; ++anIter)
7fd59977 519 {
aff395a3 520 Standard_CString anExt = Font_FontMgr_Extensions[anIter];
521 aSupportedExtensions.Add (TCollection_AsciiString (anExt));
7fd59977 522 }
523
aff395a3 524 static const DWORD aBufferSize = 256;
525 char aNameBuff[aBufferSize];
526 char aPathBuff[aBufferSize];
527 DWORD aNameSize = aBufferSize;
528 DWORD aPathSize = aBufferSize;
529 for (DWORD anIter = 0;
530 RegEnumValueA (aFontsKey, anIter,
531 aNameBuff, &aNameSize, NULL, NULL,
532 (LPBYTE )aPathBuff, &aPathSize) != ERROR_NO_MORE_ITEMS;
533 ++anIter, aNameSize = aBufferSize, aPathSize = aBufferSize)
534 {
535 aPathBuff[(aPathSize < aBufferSize) ? aPathSize : (aBufferSize - 1)] = '\0'; // ensure string is NULL-terminated
7fd59977 536
5b377041 537 TCollection_AsciiString aFontName (aNameBuff), aFontPath (aPathBuff);
538 if (aFontPath.Search ("\\") == -1)
aff395a3 539 {
5b377041 540 aFontPath.Insert (1, aFontsDir); // make absolute path
7fd59977 541 }
aff395a3 542
543 // check file extension is in list of supported
5b377041 544 const Standard_Integer anExtensionPosition = aFontPath.SearchFromEnd (".") + 1;
545 if (anExtensionPosition > 0 && anExtensionPosition < aFontPath.Length())
7fd59977 546 {
5b377041 547 TCollection_AsciiString aFontExtension = aFontPath.SubString (anExtensionPosition, aFontPath.Length());
548 aFontExtension.LowerCase();
549 if (aSupportedExtensions.Contains (aFontExtension))
aff395a3 550 {
5b377041 551 if (Handle(Font_SystemFont) aNewFont = checkFont (aFtLibrary, aFontPath.ToCString()))
aff395a3 552 {
5b377041 553 RegisterFont (aNewFont, false);
aff395a3 554 }
555 }
7fd59977 556 }
557 }
7fd59977 558
aff395a3 559 // close registry key
560 RegCloseKey (aFontsKey);
561
562#else
7fd59977 563
aff395a3 564 NCollection_Map<TCollection_AsciiString> aMapOfFontsDirs;
565baee6 565#if !defined(__ANDROID__) && !defined(__APPLE__) && !defined(__EMSCRIPTEN__)
c9983ee8 566 if (FcConfig* aFcCfg = FcInitLoadConfig())
7fd59977 567 {
c9983ee8 568 if (FcStrList* aFcFontDir = FcConfigGetFontDirs (aFcCfg))
aff395a3 569 {
c9983ee8 570 for (;;)
571 {
572 FcChar8* aFcFolder = FcStrListNext (aFcFontDir);
573 if (aFcFolder == NULL)
574 {
575 break;
576 }
7fd59977 577
c9983ee8 578 TCollection_AsciiString aPathStr ((const char* )aFcFolder);
579 OSD_Path aPath (aPathStr);
580 addDirsRecursively (aPath, aMapOfFontsDirs);
581 }
582 FcStrListDone (aFcFontDir);
aff395a3 583 }
c9983ee8 584 FcConfigDestroy (aFcCfg);
585 }
586
587 const OSD_Protection aProtectRead (OSD_R, OSD_R, OSD_R, OSD_R);
588 if (aMapOfFontsDirs.IsEmpty())
589 {
590 Message::DefaultMessenger()->Send ("Font_FontMgr, fontconfig library returns an empty folder list", Message_Alarm);
aff395a3 591
c9983ee8 592 // read fonts directories from font service config file (obsolete)
593 for (Standard_Integer anIter = 0; myFontServiceConf[anIter] != NULL; ++anIter)
7fd59977 594 {
c9983ee8 595 const TCollection_AsciiString aFileOfFontsPath (myFontServiceConf[anIter]);
596 OSD_File aFile (aFileOfFontsPath);
597 if (!aFile.Exists())
598 {
599 continue;
600 }
aff395a3 601
c9983ee8 602 aFile.Open (OSD_ReadOnly, aProtectRead);
603 if (!aFile.IsOpen())
aff395a3 604 {
c9983ee8 605 continue;
aff395a3 606 }
607
c9983ee8 608 Standard_Integer aNByte = 256;
609 Standard_Integer aNbyteRead;
610 TCollection_AsciiString aStr; // read string with information
611 while (!aFile.IsAtEnd())
7fd59977 612 {
c9983ee8 613 Standard_Integer aLocation = -1;
614 Standard_Integer aPathLocation = -1;
615
616 aFile.ReadLine (aStr, aNByte, aNbyteRead); // reading 1 line (256 bytes)
617 aLocation = aStr.Search ("catalogue=");
618 if (aLocation < 0)
619 {
620 aLocation = aStr.Search ("catalogue =");
621 }
622
623 aPathLocation = aStr.Search ("/");
624 if (aLocation > 0 && aPathLocation > 0)
7fd59977 625 {
c9983ee8 626 aStr = aStr.Split (aPathLocation - 1);
627 TCollection_AsciiString aFontPath;
628 Standard_Integer aPathNumber = 1;
629 do
7fd59977 630 {
c9983ee8 631 // Getting directory paths, which can be splitted by "," or ":"
632 aFontPath = aStr.Token (":,", aPathNumber);
633 aFontPath.RightAdjust();
634 if (!aFontPath.IsEmpty())
635 {
636 OSD_Path aPath(aFontPath);
637 addDirsRecursively (aPath, aMapOfFontsDirs);
638 }
639 aPathNumber++;
7fd59977 640 }
c9983ee8 641 while (!aFontPath.IsEmpty());
aff395a3 642 }
7fd59977 643 }
c9983ee8 644 aFile.Close();
7fd59977 645 }
646 }
264abd72 647#endif
7fd59977 648
aff395a3 649 // append default directories
650 for (Standard_Integer anIter = 0; myDefaultFontsDirs[anIter] != NULL; ++anIter)
651 {
652 Standard_CString anItem = myDefaultFontsDirs[anIter];
653 TCollection_AsciiString aPathStr (anItem);
654 OSD_Path aPath (aPathStr);
655 addDirsRecursively (aPath, aMapOfFontsDirs);
656 }
657
658 NCollection_Map<TCollection_AsciiString> aSupportedExtensions;
659 for (Standard_Integer anIter = 0; Font_FontMgr_Extensions[anIter] != NULL; ++anIter)
660 {
661 Standard_CString anExt = Font_FontMgr_Extensions[anIter];
662 aSupportedExtensions.Add (TCollection_AsciiString (anExt));
663 }
664
aff395a3 665 for (NCollection_Map<TCollection_AsciiString>::Iterator anIter (aMapOfFontsDirs);
666 anIter.More(); anIter.Next())
667 {
565baee6 668 #if !defined(__ANDROID__) && !defined(__APPLE__) && !defined(__EMSCRIPTEN__)
5b377041 669 OSD_File aReadFile (anIter.Value() + "/fonts.dir");
670 if (!aReadFile.Exists())
65360da3 671 {
5b377041 672 #endif
673 OSD_Path aFolderPath (anIter.Value());
674 for (OSD_FileIterator aFileIter (aFolderPath, "*"); aFileIter.More(); aFileIter.Next())
675 {
676 OSD_Path aFontFilePath;
677 aFileIter.Values().Path (aFontFilePath);
65360da3 678
5b377041 679 TCollection_AsciiString aFontFileName;
680 aFontFilePath.SystemName (aFontFileName);
681 aFontFileName = anIter.Value() + "/" + aFontFileName;
65360da3 682
5b377041 683 if (Handle(Font_SystemFont) aNewFont = checkFont (aFtLibrary, aFontFileName.ToCString()))
684 {
685 RegisterFont (aNewFont, false);
686 }
65360da3 687 }
5b377041 688
565baee6 689 #if !defined(__ANDROID__) && !defined(__APPLE__) && !defined(__EMSCRIPTEN__)
5b377041 690 continue;
aff395a3 691 }
692
693 aReadFile.Open (OSD_ReadOnly, aProtectRead);
694 if (!aReadFile.IsOpen())
695 {
696 continue; // invalid fonts directory
697 }
698
699 Standard_Integer aNbyteRead, aNByte = 256;
700 TCollection_AsciiString aLine (aNByte);
701 Standard_Boolean isFirstLine = Standard_True;
702 const TCollection_AsciiString anEncoding ("iso8859-1\n");
703 while (!aReadFile.IsAtEnd())
704 {
705 aReadFile.ReadLine (aLine, aNByte, aNbyteRead);
706 if (isFirstLine)
707 {
708 // first line contains the number of fonts in this file
709 // just ignoring it...
710 isFirstLine = Standard_False;
711 continue;
712 }
7fd59977 713
aff395a3 714 Standard_Integer anExtensionPosition = aLine.Search (".") + 1;
715 if (anExtensionPosition == 0)
716 {
717 continue; // can't find extension position in the font description
718 }
7fd59977 719
aff395a3 720 Standard_Integer anEndOfFileName = aLine.Location (" ", anExtensionPosition, aLine.Length()) - 1;
721 if (anEndOfFileName < 0 || anEndOfFileName < anExtensionPosition)
722 {
723 continue; // font description have empty extension
724 }
7fd59977 725
aff395a3 726 TCollection_AsciiString aFontExtension = aLine.SubString (anExtensionPosition, anEndOfFileName);
727 aFontExtension.LowerCase();
728 if (aSupportedExtensions.Contains (aFontExtension) && (aLine.Search (anEncoding) > 0))
7fd59977 729 {
aff395a3 730 // In current implementation use fonts with ISO-8859-1 coding page.
731 // OCCT not give to manage coding page by means of programm interface.
732 // TODO: make high level interface for choosing necessary coding page.
5b377041 733 TCollection_AsciiString aXLFD (aLine.SubString (anEndOfFileName + 2, aLine.Length()));
734 TCollection_AsciiString aFontPath (anIter.Value().ToCString());
735 if (aFontPath.SearchFromEnd ("/") != aFontPath.Length())
aff395a3 736 {
5b377041 737 aFontPath.AssignCat ("/");
aff395a3 738 }
5b377041 739 TCollection_AsciiString aFontFileName (aLine.SubString (1, anEndOfFileName));
740 aFontPath.AssignCat (aFontFileName);
741 if (Handle(Font_SystemFont) aNewFont = checkFont (aFtLibrary, aFontPath.ToCString()))
aff395a3 742 {
5b377041 743 RegisterFont (aNewFont, false);
744 if (!aXLFD.IsEmpty()
745 && aXLFD.Search ("-0-0-0-0-") != -1) // ignore non-resizable fonts
746 {
747 const TCollection_AsciiString anXName = aXLFD.Token ("-", 2);
748 Font_FontAspect anXAspect = Font_FA_Regular;
749 if (aXLFD.Token ("-", 3).IsEqual ("bold")
750 && (aXLFD.Token ("-", 4).IsEqual ("i")
751 || aXLFD.Token ("-", 4).IsEqual ("o")))
752 {
753 anXAspect = Font_FA_BoldItalic;
754 }
755 else if (aXLFD.Token ("-", 3).IsEqual ("bold"))
756 {
757 anXAspect = Font_FA_Bold;
758 }
759 else if (aXLFD.Token ("-", 4).IsEqual ("i")
760 || aXLFD.Token ("-", 4).IsEqual ("o"))
761 {
762 anXAspect = Font_FA_Italic;
763 }
764
765 Handle(Font_SystemFont) aNewFontFromXLFD = new Font_SystemFont (anXName);
766 aNewFontFromXLFD->SetFontPath (anXAspect, aFontPath);
767 if (!aNewFont->IsEqual (aNewFontFromXLFD))
768 {
769 RegisterFont (aNewFontFromXLFD, false);
770 }
771 }
aff395a3 772 }
aff395a3 773 }
7fd59977 774 }
aff395a3 775 aReadFile.Close();
65360da3 776 #endif
7fd59977 777 }
778#endif
aff395a3 779}
780
b514beda 781// =======================================================================
782// function : GetAvailableFontsNames
783// purpose :
784// =======================================================================
aff395a3 785void Font_FontMgr::GetAvailableFontsNames (TColStd_SequenceOfHAsciiString& theFontsNames) const
786{
787 theFontsNames.Clear();
5b377041 788 for (NCollection_IndexedMap<Handle(Font_SystemFont), Font_SystemFont>::Iterator aFontIter (myFontMap);
789 aFontIter.More(); aFontIter.Next())
aff395a3 790 {
5b377041 791 const Handle(Font_SystemFont)& aFont = aFontIter.Value();
792 theFontsNames.Append (new TCollection_HAsciiString(aFont->FontName()));
aff395a3 793 }
7fd59977 794}
795
b514beda 796// =======================================================================
797// function : GetFont
798// purpose :
799// =======================================================================
aff395a3 800Handle(Font_SystemFont) Font_FontMgr::GetFont (const Handle(TCollection_HAsciiString)& theFontName,
b514beda 801 const Font_FontAspect theFontAspect,
aff395a3 802 const Standard_Integer theFontSize) const
7fd59977 803{
5b377041 804 if ((theFontSize < 2 && theFontSize != -1) || theFontName.IsNull())
aff395a3 805 {
5b377041 806 return Handle(Font_SystemFont)();
aff395a3 807 }
808
5b377041 809 Handle(Font_SystemFont) aFont = myFontMap.Find (theFontName->String());
810 return (aFont.IsNull()
811 || theFontAspect == Font_FontAspect_UNDEFINED
812 || aFont->HasFontAspect (theFontAspect))
813 ? aFont
814 : Handle(Font_SystemFont)();
815}
aff395a3 816
5b377041 817// =======================================================================
818// function : GetFont
819// purpose :
820// =======================================================================
821Handle(Font_SystemFont) Font_FontMgr::GetFont (const TCollection_AsciiString& theFontName) const
822{
823 return myFontMap.Find (theFontName);
7fd59977 824}
825
912761ea 826// =======================================================================
827// function : FindFallbackFont
828// purpose :
829// =======================================================================
830Handle(Font_SystemFont) Font_FontMgr::FindFallbackFont (Font_UnicodeSubset theSubset,
831 Font_FontAspect theFontAspect) const
832{
833 Font_FontAspect aFontAspect = theFontAspect;
36e28f96 834 Handle(Font_SystemFont) aFont;
912761ea 835 switch (theSubset)
836 {
36e28f96 837 case Font_UnicodeSubset_Western: aFont = FindFont (Font_NOF_SANS_SERIF, Font_StrictLevel_Aliases, aFontAspect, false); break;
838 case Font_UnicodeSubset_Korean: aFont = FindFont (Font_NOF_KOREAN, Font_StrictLevel_Aliases, aFontAspect, false); break;
839 case Font_UnicodeSubset_CJK: aFont = FindFont (Font_NOF_CJK, Font_StrictLevel_Aliases, aFontAspect, false); break;
840 case Font_UnicodeSubset_Arabic: aFont = FindFont (Font_NOF_ARABIC, Font_StrictLevel_Aliases, aFontAspect, false); break;
912761ea 841 }
36e28f96 842 if (aFont.IsNull())
843 {
844 const char* aRange = "";
845 switch (theSubset)
846 {
847 case Font_UnicodeSubset_Western: aRange = "Western"; break;
848 case Font_UnicodeSubset_Korean: aRange = "Korean"; break;
849 case Font_UnicodeSubset_CJK: aRange = "CJK"; break;
850 case Font_UnicodeSubset_Arabic: aRange = "Arabic"; break;
851 }
852 Message::DefaultMessenger()->Send (TCollection_AsciiString("Font_FontMgr, error: unable to find ") + aRange + " fallback font!", Message_Fail);
853 }
854 return aFont;
912761ea 855}
856
b514beda 857// =======================================================================
858// function : FindFont
859// purpose :
860// =======================================================================
5b377041 861Handle(Font_SystemFont) Font_FontMgr::FindFont (const TCollection_AsciiString& theFontName,
1bbd7c79 862 Font_StrictLevel theStrictLevel,
36e28f96 863 Font_FontAspect& theFontAspect,
864 Standard_Boolean theDoFailMsg) const
aff395a3 865{
5b377041 866 TCollection_AsciiString aFontName (theFontName);
867 aFontName.LowerCase();
868 Handle(Font_SystemFont) aFont = myFontMap.Find (aFontName);
1bbd7c79 869 if (!aFont.IsNull()
870 || theStrictLevel == Font_StrictLevel_Strict)
aff395a3 871 {
872 return aFont;
873 }
874
875 // Trying to use font names mapping
976627e6 876 for (int aPass = 0; aPass < 2; ++aPass)
aff395a3 877 {
976627e6 878 Handle(Font_FontAliasSequence) anAliases;
879 if (aPass == 0)
880 {
881 myFontAliases.Find (aFontName, anAliases);
882 }
1bbd7c79 883 else if (theStrictLevel == Font_StrictLevel_Any)
976627e6 884 {
885 anAliases = myFallbackAlias;
886 }
aff395a3 887
976627e6 888 if (anAliases.IsNull()
889 || anAliases->IsEmpty())
890 {
891 continue;
892 }
893
894 bool isAliasUsed = false, isBestAlias = false;
5b377041 895 for (Font_FontAliasSequence::Iterator anAliasIter (*anAliases); anAliasIter.More(); anAliasIter.Next())
b514beda 896 {
5b377041 897 const Font_FontAlias& anAlias = anAliasIter.Value();
898 if (Handle(Font_SystemFont) aFont2 = myFontMap.Find (anAlias.FontName))
899 {
900 if (aFont.IsNull())
901 {
902 aFont = aFont2;
903 isAliasUsed = true;
904 }
905
906 if ((anAlias.FontAspect != Font_FontAspect_UNDEFINED
907 && aFont2->HasFontAspect (anAlias.FontAspect)))
908 {
909 // special case - alias refers to styled font (e.g. "times-bold")
910 isBestAlias = true;
911 theFontAspect = anAlias.FontAspect;
912 break;
913 }
914 else if (anAlias.FontAspect == Font_FontAspect_UNDEFINED
915 && (theFontAspect == Font_FontAspect_UNDEFINED
976627e6 916 || aFont2->HasFontAspect (theFontAspect)))
5b377041 917 {
918 isBestAlias = true;
919 break;
920 }
921 }
922 }
976627e6 923
924 if (aPass == 0)
5b377041 925 {
926 if (isAliasUsed && myToTraceAliases)
927 {
928 Message::DefaultMessenger()->Send (TCollection_AsciiString("Font_FontMgr, using font alias '") + aFont->FontName() + "'"
976627e6 929 " instead of requested '" + theFontName +"'", Message_Trace);
5b377041 930 }
931 if (isBestAlias)
932 {
933 return aFont;
934 }
976627e6 935 else if (!aFont.IsNull())
936 {
937 break;
938 }
b514beda 939 }
940 }
aff395a3 941
912761ea 942 if (aFont.IsNull()
943 && theStrictLevel == Font_StrictLevel_Any)
aff395a3 944 {
5b377041 945 // try finding ANY font in case if even default fallback alias myFallbackAlias cannot be found
946 aFont = myFontMap.Find (TCollection_AsciiString());
947 }
948 if (aFont.IsNull())
949 {
36e28f96 950 if (theDoFailMsg)
951 {
952 Message::DefaultMessenger()->Send (TCollection_AsciiString("Font_FontMgr, error: unable to find any font!"), Message_Fail);
953 }
5b377041 954 return Handle(Font_SystemFont)();
aff395a3 955 }
956
5b377041 957 if ((theFontAspect != Font_FA_Undefined
958 && !aFont->HasFontAspect (theFontAspect))
959 || (!aFontName.IsEmpty()
960 && !aFontName.IsEqual (aFont->FontKey())))
aff395a3 961 {
5b377041 962 TCollection_AsciiString aDesc = TCollection_AsciiString() + "'" + theFontName + "'"
963 + TCollection_AsciiString() + " [" + Font_FontMgr::FontAspectToString (theFontAspect) + "]";
964 Message::DefaultMessenger()->Send (TCollection_AsciiString("Font_FontMgr, warning: unable to find font ")
965 + aDesc + "; " + aFont->ToString() + " is used instead");
aff395a3 966 }
5b377041 967 return aFont;
968}
aff395a3 969
5b377041 970// =======================================================================
971// function : Font_FontMap::Find
972// purpose :
973// =======================================================================
974Handle(Font_SystemFont) Font_FontMgr::Font_FontMap::Find (const TCollection_AsciiString& theFontName) const
975{
976 if (IsEmpty())
aff395a3 977 {
5b377041 978 return Handle(Font_SystemFont)();
979 }
980 else if (theFontName.IsEmpty())
981 {
982 return FindKey (1); // return any font
aff395a3 983 }
984
5b377041 985 TCollection_AsciiString aFontName (theFontName);
986 aFontName.LowerCase();
987 for (IndexedMapNode* aNodeIter = (IndexedMapNode* )myData1[::HashCode (aFontName, NbBuckets())];
988 aNodeIter != NULL; aNodeIter = (IndexedMapNode* )aNodeIter->Next())
989 {
990 const Handle(Font_SystemFont)& aKey = aNodeIter->Key1();
991 if (aKey->FontKey().IsEqual (aFontName))
992 {
993 return aKey;
994 }
995 }
996 return Handle(Font_SystemFont)();
aff395a3 997}