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