0025982: Wrong result obtained by General Fuse operator.
[occt.git] / src / Font / Font_FontMgr.cxx
... / ...
CommitLineData
1// Created on: 2008-01-20
2// Created by: Alexander A. BORODIN
3// Copyright (c) 2008-2014 OPEN CASCADE SAS
4//
5// This file is part of Open CASCADE Technology software library.
6//
7// This library is free software; you can redistribute it and/or modify it under
8// the terms of the GNU Lesser General Public License version 2.1 as published
9// by the Free Software Foundation, with special exception defined in the file
10// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11// distribution for complete text of the license and disclaimer of any warranty.
12//
13// Alternatively, this file may be used under the terms of Open CASCADE
14// commercial license or contractual agreement.
15
16#include <Font_FontMgr.ixx>
17
18#include <Font_FTLibrary.hxx>
19#include <OSD_Environment.hxx>
20#include <NCollection_List.hxx>
21#include <NCollection_Map.hxx>
22#include <Standard_Stream.hxx>
23#include <TCollection_HAsciiString.hxx>
24
25#include <ft2build.h>
26#include FT_FREETYPE_H
27
28struct Font_FontMgr_FontAliasMapNode
29{
30 const char * EnumName;
31 const char * FontName;
32 Font_FontAspect FontAspect;
33};
34
35static const Font_FontMgr_FontAliasMapNode Font_FontMgr_MapOfFontsAliases[] =
36{
37
38#ifdef WNT
39
40 { "Courier" , "Courier New" , Font_FA_Regular },
41 { "Times-Roman" , "Times New Roman", Font_FA_Regular },
42 { "Times-Bold" , "Times New Roman", Font_FA_Bold },
43 { "Times-Italic" , "Times New Roman", Font_FA_Italic },
44 { "Times-BoldItalic" , "Times New Roman", Font_FA_BoldItalic },
45 { "ZapfChancery-MediumItalic", "Script" , Font_FA_Regular },
46 { "Symbol" , "Symbol" , Font_FA_Regular },
47 { "ZapfDingbats" , "WingDings" , Font_FA_Regular },
48 { "Rock" , "Arial" , Font_FA_Regular },
49 { "Iris" , "Lucida Console" , Font_FA_Regular }
50
51#else //X11
52
53 { "Courier" , "Courier" , Font_FA_Regular },
54 { "Times-Roman" , "Times" , Font_FA_Regular },
55 { "Times-Bold" , "Times" , Font_FA_Bold },
56 { "Times-Italic" , "Times" , Font_FA_Italic },
57 { "Times-BoldItalic" , "Times" , Font_FA_BoldItalic },
58 { "Arial" , "Helvetica" , Font_FA_Regular },
59 { "ZapfChancery-MediumItalic", "-adobe-itc zapf chancery-medium-i-normal--*-*-*-*-*-*-iso8859-1" , Font_FA_Regular },
60 { "Symbol" , "-adobe-symbol-medium-r-normal--*-*-*-*-*-*-adobe-fontspecific" , Font_FA_Regular },
61 { "ZapfDingbats" , "-adobe-itc zapf dingbats-medium-r-normal--*-*-*-*-*-*-adobe-fontspecific" , Font_FA_Regular },
62 { "Rock" , "-sgi-rock-medium-r-normal--*-*-*-*-p-*-iso8859-1" , Font_FA_Regular },
63 { "Iris" , "--iris-medium-r-normal--*-*-*-*-m-*-iso8859-1" , Font_FA_Regular }
64#endif
65
66};
67
68#define NUM_FONT_ENTRIES (int)(sizeof(Font_FontMgr_MapOfFontsAliases)/sizeof(Font_FontMgr_FontAliasMapNode))
69
70#if (defined(_WIN32) || defined(__WIN32__))
71
72 #include <windows.h>
73 #include <stdlib.h>
74
75 #ifdef _MSC_VER
76 #pragma comment (lib, "freetype.lib")
77 #endif
78
79 namespace
80 {
81
82 // list of supported extensions
83 static Standard_CString Font_FontMgr_Extensions[] =
84 {
85 "ttf",
86 "otf",
87 "ttc",
88 NULL
89 };
90
91 };
92
93#else
94
95 #include <OSD_DirectoryIterator.hxx>
96 #include <OSD_Path.hxx>
97 #include <OSD_File.hxx>
98 #include <OSD_OpenMode.hxx>
99 #include <OSD_Protection.hxx>
100
101 namespace
102 {
103
104 // list of supported extensions
105 static Standard_CString Font_FontMgr_Extensions[] =
106 {
107 "ttf",
108 "otf",
109 "ttc",
110 "pfa",
111 "pfb",
112 NULL
113 };
114
115 // X11 configuration file in plain text format (obsolete - doesn't exists in modern distributives)
116 static Standard_CString myFontServiceConf[] = {"/etc/X11/fs/config",
117 "/usr/X11R6/lib/X11/fs/config",
118 "/usr/X11/lib/X11/fs/config",
119 NULL
120 };
121
122 #ifdef __APPLE__
123 // default fonts paths in Mac OS X
124 static Standard_CString myDefaultFontsDirs[] = {"/System/Library/Fonts",
125 "/Library/Fonts",
126 NULL
127 };
128 #else
129 // default fonts paths in most Unix systems (Linux and others)
130 static Standard_CString myDefaultFontsDirs[] = {"/usr/share/fonts",
131 "/usr/local/share/fonts",
132 NULL
133 };
134 #endif
135
136 static void addDirsRecursively (const OSD_Path& thePath,
137 NCollection_Map<TCollection_AsciiString>& theDirsMap)
138 {
139 TCollection_AsciiString aDirName;
140 thePath.SystemName (aDirName);
141 if (!theDirsMap.Add (aDirName))
142 {
143 return;
144 }
145
146 for (OSD_DirectoryIterator aDirIterator (thePath, "*"); aDirIterator.More(); aDirIterator.Next())
147 {
148 OSD_Path aChildDirPath;
149 aDirIterator.Values().Path (aChildDirPath);
150
151 TCollection_AsciiString aChildDirName;
152 aChildDirPath.SystemName (aChildDirName);
153 if (!aChildDirName.IsEqual (".") && !aChildDirName.IsEqual (".."))
154 {
155 aChildDirName = aDirName + "/" + aChildDirName;
156 OSD_Path aPath (aChildDirName);
157 addDirsRecursively (aPath, theDirsMap);
158 }
159 }
160 }
161
162 };
163
164#endif
165
166// =======================================================================
167// function : checkFont
168// purpose :
169// =======================================================================
170static Handle(Font_SystemFont) checkFont (const Handle(Font_FTLibrary)& theFTLib,
171 const Standard_CString theFontPath)
172{
173 FT_Face aFontFace;
174 FT_Error aFaceError = FT_New_Face (theFTLib->Instance(), theFontPath, 0, &aFontFace);
175 if (aFaceError != FT_Err_Ok)
176 {
177 return NULL;
178 }
179
180 Font_FontAspect anAspect = Font_FA_Regular;
181 if (aFontFace->style_flags == (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD))
182 {
183 anAspect = Font_FA_BoldItalic;
184 }
185 else if (aFontFace->style_flags == FT_STYLE_FLAG_ITALIC)
186 {
187 anAspect = Font_FA_Italic;
188 }
189 else if (aFontFace->style_flags == FT_STYLE_FLAG_BOLD)
190 {
191 anAspect = Font_FA_Bold;
192 }
193
194 Handle(TCollection_HAsciiString) aFontName = new TCollection_HAsciiString (aFontFace->family_name);
195 Handle(TCollection_HAsciiString) aFontPath = new TCollection_HAsciiString (theFontPath);
196 Handle(Font_SystemFont) aResult = new Font_SystemFont (aFontName, anAspect, aFontPath);
197
198 FT_Done_Face (aFontFace);
199
200 return aResult;
201}
202
203// =======================================================================
204// function : GetInstance
205// purpose :
206// =======================================================================
207Handle(Font_FontMgr) Font_FontMgr::GetInstance()
208{
209 static Handle(Font_FontMgr) _mgr;
210 if (_mgr.IsNull())
211 {
212 _mgr = new Font_FontMgr();
213 }
214
215 return _mgr;
216}
217
218// =======================================================================
219// function : Font_FontMgr
220// purpose :
221// =======================================================================
222Font_FontMgr::Font_FontMgr()
223{
224 InitFontDataBase();
225}
226
227// =======================================================================
228// function : CheckFont
229// purpose :
230// =======================================================================
231Handle(Font_SystemFont) Font_FontMgr::CheckFont (Standard_CString theFontPath) const
232{
233 Handle(Font_FTLibrary) aFtLibrary = new Font_FTLibrary();
234 return checkFont (aFtLibrary, theFontPath);
235}
236
237// =======================================================================
238// function : RegisterFont
239// purpose :
240// =======================================================================
241Standard_Boolean Font_FontMgr::RegisterFont (const Handle(Font_SystemFont)& theFont,
242 const Standard_Boolean theToOverride)
243{
244 if (theFont.IsNull())
245 {
246 return Standard_False;
247 }
248
249 for (Font_NListOfSystemFont::Iterator aFontIter (myListOfFonts);
250 aFontIter.More(); aFontIter.Next())
251 {
252 if (!aFontIter.Value()->FontName()->IsSameString (theFont->FontName(), Standard_False))
253 {
254 continue;
255 }
256
257 if (theFont->FontAspect() != Font_FA_Undefined
258 && aFontIter.Value()->FontAspect() != theFont->FontAspect())
259 {
260 continue;
261 }
262
263 if (theFont->FontHeight() == -1 || aFontIter.Value()->FontHeight() == -1
264 || theFont->FontHeight() == aFontIter.Value()->FontHeight())
265 {
266 if (theFont->FontPath()->String() == aFontIter.Value()->FontPath()->String())
267 {
268 return Standard_True;
269 }
270 else if (theToOverride)
271 {
272 myListOfFonts.Remove (aFontIter);
273 }
274 else
275 {
276 return Standard_False;
277 }
278 }
279 }
280
281 myListOfFonts.Append (theFont);
282 return Standard_True;
283}
284
285// =======================================================================
286// function : InitFontDataBase
287// purpose :
288// =======================================================================
289void Font_FontMgr::InitFontDataBase()
290{
291 myListOfFonts.Clear();
292 Handle(Font_FTLibrary) aFtLibrary;
293
294#if defined(_WIN32)
295
296 // font directory is placed in "C:\Windows\Fonts\"
297 UINT aStrLength = GetSystemWindowsDirectoryA (NULL, 0);
298 if (aStrLength == 0)
299 {
300 return;
301 }
302
303 char* aWinDir = new char[aStrLength];
304 GetSystemWindowsDirectoryA (aWinDir, aStrLength);
305 Handle(TCollection_HAsciiString) aFontsDir = new TCollection_HAsciiString (aWinDir);
306 aFontsDir->AssignCat ("\\Fonts\\");
307 delete[] aWinDir;
308
309 // read fonts list from registry
310 HKEY aFontsKey;
311 if (RegOpenKeyExA (HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts",
312 0, KEY_READ, &aFontsKey) != ERROR_SUCCESS)
313 {
314 return;
315 }
316
317 NCollection_Map<TCollection_AsciiString> aSupportedExtensions;
318 for (Standard_Integer anIter = 0; Font_FontMgr_Extensions[anIter] != NULL; ++anIter)
319 {
320 Standard_CString anExt = Font_FontMgr_Extensions[anIter];
321 aSupportedExtensions.Add (TCollection_AsciiString (anExt));
322 }
323
324 aFtLibrary = new Font_FTLibrary();
325 static const DWORD aBufferSize = 256;
326 char aNameBuff[aBufferSize];
327 char aPathBuff[aBufferSize];
328 DWORD aNameSize = aBufferSize;
329 DWORD aPathSize = aBufferSize;
330 for (DWORD anIter = 0;
331 RegEnumValueA (aFontsKey, anIter,
332 aNameBuff, &aNameSize, NULL, NULL,
333 (LPBYTE )aPathBuff, &aPathSize) != ERROR_NO_MORE_ITEMS;
334 ++anIter, aNameSize = aBufferSize, aPathSize = aBufferSize)
335 {
336 aPathBuff[(aPathSize < aBufferSize) ? aPathSize : (aBufferSize - 1)] = '\0'; // ensure string is NULL-terminated
337
338 Handle(TCollection_HAsciiString) aFontName = new TCollection_HAsciiString (aNameBuff);
339 Handle(TCollection_HAsciiString) aFontPath = new TCollection_HAsciiString (aPathBuff);
340 if (aFontPath->Search ("\\") == -1)
341 {
342 aFontPath->Insert (1, aFontsDir); // make absolute path
343 }
344
345 // check file extension is in list of supported
346 const Standard_Integer anExtensionPosition = aFontPath->SearchFromEnd (".") + 1;
347 if (anExtensionPosition > 0 && anExtensionPosition < aFontPath->Length())
348 {
349 Handle(TCollection_HAsciiString) aFontExtension = aFontPath->SubString (anExtensionPosition, aFontPath->Length());
350 aFontExtension->LowerCase();
351 if (aSupportedExtensions.Contains (aFontExtension->String()))
352 {
353 Handle(Font_SystemFont) aNewFont = checkFont (aFtLibrary, aFontPath->ToCString());
354 if (!aNewFont.IsNull())
355 {
356 myListOfFonts.Append (aNewFont);
357 }
358 }
359 }
360 }
361
362 // close registry key
363 RegCloseKey (aFontsKey);
364
365#else
366
367 NCollection_Map<TCollection_AsciiString> aMapOfFontsDirs;
368 const OSD_Protection aProtectRead (OSD_R, OSD_R, OSD_R, OSD_R);
369
370 // read fonts directories from font service config file (obsolete)
371 for (Standard_Integer anIter = 0; myFontServiceConf[anIter] != NULL; ++anIter)
372 {
373 const TCollection_AsciiString aFileOfFontsPath (myFontServiceConf[anIter]);
374 OSD_File aFile (aFileOfFontsPath);
375 if (!aFile.Exists())
376 {
377 continue;
378 }
379
380 aFile.Open (OSD_ReadOnly, aProtectRead);
381 if (!aFile.IsOpen())
382 {
383 continue;
384 }
385
386 Standard_Integer aNByte = 256;
387 Standard_Integer aNbyteRead;
388 TCollection_AsciiString aStr; // read string with information
389 while (!aFile.IsAtEnd())
390 {
391 Standard_Integer aLocation = -1;
392 Standard_Integer aPathLocation = -1;
393
394 aFile.ReadLine (aStr, aNByte, aNbyteRead); // reading 1 line (256 bytes)
395 aLocation = aStr.Search ("catalogue=");
396 if (aLocation < 0)
397 {
398 aLocation = aStr.Search ("catalogue =");
399 }
400
401 aPathLocation = aStr.Search ("/");
402 if (aLocation > 0 && aPathLocation > 0)
403 {
404 aStr = aStr.Split (aPathLocation - 1);
405 TCollection_AsciiString aFontPath;
406 Standard_Integer aPathNumber = 1;
407 do
408 {
409 // Getting directory paths, which can be splitted by "," or ":"
410 aFontPath = aStr.Token (":,", aPathNumber);
411 aFontPath.RightAdjust();
412 if (!aFontPath.IsEmpty())
413 {
414 OSD_Path aPath(aFontPath);
415 addDirsRecursively (aPath, aMapOfFontsDirs);
416 }
417 aPathNumber++;
418 }
419 while (!aFontPath.IsEmpty());
420 }
421 }
422 aFile.Close();
423 }
424
425 // append default directories
426 for (Standard_Integer anIter = 0; myDefaultFontsDirs[anIter] != NULL; ++anIter)
427 {
428 Standard_CString anItem = myDefaultFontsDirs[anIter];
429 TCollection_AsciiString aPathStr (anItem);
430 OSD_Path aPath (aPathStr);
431 addDirsRecursively (aPath, aMapOfFontsDirs);
432 }
433
434 NCollection_Map<TCollection_AsciiString> aSupportedExtensions;
435 for (Standard_Integer anIter = 0; Font_FontMgr_Extensions[anIter] != NULL; ++anIter)
436 {
437 Standard_CString anExt = Font_FontMgr_Extensions[anIter];
438 aSupportedExtensions.Add (TCollection_AsciiString (anExt));
439 }
440
441 aFtLibrary = new Font_FTLibrary();
442 for (NCollection_Map<TCollection_AsciiString>::Iterator anIter (aMapOfFontsDirs);
443 anIter.More(); anIter.Next())
444 {
445 OSD_File aReadFile (anIter.Value() + "/fonts.dir");
446 if (!aReadFile.Exists())
447 {
448 continue; // invalid fonts directory
449 }
450
451 aReadFile.Open (OSD_ReadOnly, aProtectRead);
452 if (!aReadFile.IsOpen())
453 {
454 continue; // invalid fonts directory
455 }
456
457 Standard_Integer aNbyteRead, aNByte = 256;
458 TCollection_AsciiString aLine (aNByte);
459 Standard_Boolean isFirstLine = Standard_True;
460 const TCollection_AsciiString anEncoding ("iso8859-1\n");
461 while (!aReadFile.IsAtEnd())
462 {
463 aReadFile.ReadLine (aLine, aNByte, aNbyteRead);
464 if (isFirstLine)
465 {
466 // first line contains the number of fonts in this file
467 // just ignoring it...
468 isFirstLine = Standard_False;
469 continue;
470 }
471
472 Standard_Integer anExtensionPosition = aLine.Search (".") + 1;
473 if (anExtensionPosition == 0)
474 {
475 continue; // can't find extension position in the font description
476 }
477
478 Standard_Integer anEndOfFileName = aLine.Location (" ", anExtensionPosition, aLine.Length()) - 1;
479 if (anEndOfFileName < 0 || anEndOfFileName < anExtensionPosition)
480 {
481 continue; // font description have empty extension
482 }
483
484 TCollection_AsciiString aFontExtension = aLine.SubString (anExtensionPosition, anEndOfFileName);
485 aFontExtension.LowerCase();
486 if (aSupportedExtensions.Contains (aFontExtension) && (aLine.Search (anEncoding) > 0))
487 {
488 // In current implementation use fonts with ISO-8859-1 coding page.
489 // OCCT not give to manage coding page by means of programm interface.
490 // TODO: make high level interface for choosing necessary coding page.
491 Handle(TCollection_HAsciiString) aXLFD =
492 new TCollection_HAsciiString (aLine.SubString (anEndOfFileName + 2, aLine.Length()));
493 Handle(TCollection_HAsciiString) aFontPath =
494 new TCollection_HAsciiString (anIter.Value().ToCString());
495 if (aFontPath->SearchFromEnd ("/") != aFontPath->Length())
496 {
497 aFontPath->AssignCat ("/");
498 }
499 Handle(TCollection_HAsciiString) aFontFileName =
500 new TCollection_HAsciiString (aLine.SubString (1, anEndOfFileName));
501 aFontPath->AssignCat (aFontFileName);
502
503 Handle(Font_SystemFont) aNewFontFromXLFD = new Font_SystemFont (aXLFD, aFontPath);
504 Handle(Font_SystemFont) aNewFont = checkFont (aFtLibrary, aFontPath->ToCString());
505
506 if (aNewFontFromXLFD->IsValid() && !aNewFont.IsNull() &&
507 !aNewFont->IsEqual (aNewFontFromXLFD))
508 {
509 myListOfFonts.Append (aNewFont);
510 myListOfFonts.Append (aNewFontFromXLFD);
511 }
512 else if (!aNewFont.IsNull())
513 {
514 myListOfFonts.Append (aNewFont);
515 }
516 else if (aNewFontFromXLFD->IsValid())
517 {
518 myListOfFonts.Append (aNewFontFromXLFD);
519 }
520
521 }
522 }
523 aReadFile.Close();
524 }
525#endif
526}
527
528// =======================================================================
529// function : GetAvailableFonts
530// purpose :
531// =======================================================================
532const Font_NListOfSystemFont& Font_FontMgr::GetAvailableFonts() const
533{
534 return myListOfFonts;
535}
536
537// =======================================================================
538// function : GetAvailableFontsNames
539// purpose :
540// =======================================================================
541void Font_FontMgr::GetAvailableFontsNames (TColStd_SequenceOfHAsciiString& theFontsNames) const
542{
543 theFontsNames.Clear();
544 for (Font_NListOfSystemFont::Iterator anIter(myListOfFonts); anIter.More(); anIter.Next())
545 {
546 theFontsNames.Append (anIter.Value()->FontName());
547 }
548}
549
550// =======================================================================
551// function : GetFont
552// purpose :
553// =======================================================================
554Handle(Font_SystemFont) Font_FontMgr::GetFont (const Handle(TCollection_HAsciiString)& theFontName,
555 const Font_FontAspect theFontAspect,
556 const Standard_Integer theFontSize) const
557{
558 if ( (theFontSize < 2 && theFontSize != -1) || theFontName.IsNull())
559 {
560 return NULL;
561 }
562
563 for (Font_NListOfSystemFont::Iterator aFontsIterator (myListOfFonts);
564 aFontsIterator.More(); aFontsIterator.Next())
565 {
566 if (!theFontName->IsEmpty() && !aFontsIterator.Value()->FontName()->IsSameString (theFontName, Standard_False))
567 {
568 continue;
569 }
570
571 if (theFontAspect != Font_FA_Undefined && aFontsIterator.Value()->FontAspect() != theFontAspect)
572 {
573 continue;
574 }
575
576 if (theFontSize == -1 || aFontsIterator.Value()->FontHeight() == -1 ||
577 theFontSize == aFontsIterator.Value()->FontHeight())
578 {
579 return aFontsIterator.Value();
580 }
581 }
582
583 return NULL;
584}
585
586// =======================================================================
587// function : FindFont
588// purpose :
589// =======================================================================
590Handle(Font_SystemFont) Font_FontMgr::FindFont (const Handle(TCollection_HAsciiString)& theFontName,
591 const Font_FontAspect theFontAspect,
592 const Standard_Integer theFontSize) const
593{
594 Handle(TCollection_HAsciiString) aFontName = theFontName;
595 Font_FontAspect aFontAspect = theFontAspect;
596 Standard_Integer aFontSize = theFontSize;
597
598 Handle(Font_SystemFont) aFont = GetFont (aFontName, aFontAspect, aFontSize);
599 if (!aFont.IsNull())
600 {
601 return aFont;
602 }
603
604 // Trying to use font names mapping
605 for (Standard_Integer anIter = 0; anIter < NUM_FONT_ENTRIES; ++anIter)
606 {
607 Handle(TCollection_HAsciiString) aFontAlias =
608 new TCollection_HAsciiString (Font_FontMgr_MapOfFontsAliases[anIter].EnumName);
609
610 if (aFontAlias->IsSameString (aFontName, Standard_False))
611 {
612 aFontName = new TCollection_HAsciiString (Font_FontMgr_MapOfFontsAliases[anIter].FontName);
613 aFontAspect = Font_FontMgr_MapOfFontsAliases[anIter].FontAspect;
614 break;
615 }
616 }
617
618 // check font family alias with specified font aspect
619 if (theFontAspect != Font_FA_Undefined
620 && theFontAspect != Font_FA_Regular
621 && theFontAspect != aFontAspect)
622 {
623 aFont = GetFont (aFontName, theFontAspect, aFontSize);
624 if (!aFont.IsNull())
625 {
626 return aFont;
627 }
628 }
629
630 // check font alias with aspect in the name
631 aFont = GetFont (aFontName, aFontAspect, aFontSize);
632 if (!aFont.IsNull())
633 {
634 return aFont;
635 }
636
637 // Requested family name not found -> search for any font family with given aspect and height
638 aFontName = new TCollection_HAsciiString ("");
639 aFont = GetFont (aFontName, aFontAspect, aFontSize);
640 if (!aFont.IsNull())
641 {
642 return aFont;
643 }
644
645 // The last resort: trying to use ANY font available in the system
646 aFontAspect = Font_FA_Undefined;
647 aFontSize = -1;
648 aFont = GetFont (aFontName, aFontAspect, aFontSize);
649 if (!aFont.IsNull())
650 {
651 return aFont;
652 }
653
654 return NULL; // Fonts are not found in the system.
655}