1 // Created on: 2008-01-20
2 // Created by: Alexander A. BORODIN
3 // Copyright (c) 2008-2014 OPEN CASCADE SAS
5 // This file is part of Open CASCADE Technology software library.
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.
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
17 #include <Font_FontMgr.hxx>
18 #include <Font_FTLibrary.hxx>
19 #include <Font_SystemFont.hxx>
20 #include <NCollection_List.hxx>
21 #include <NCollection_Map.hxx>
22 #include <OSD_Environment.hxx>
23 #include <Standard_Stream.hxx>
24 #include <Standard_Type.hxx>
25 #include <TCollection_HAsciiString.hxx>
28 #include FT_FREETYPE_H
29 struct Font_FontMgr_FontAliasMapNode
31 const char * EnumName;
32 const char * FontName;
33 Font_FontAspect FontAspect;
36 static const Font_FontMgr_FontAliasMapNode Font_FontMgr_MapOfFontsAliases[] =
41 { "Courier" , "Courier New" , Font_FA_Regular },
42 { "Times-Roman" , "Times New Roman", Font_FA_Regular },
43 { "Times-Bold" , "Times New Roman", Font_FA_Bold },
44 { "Times-Italic" , "Times New Roman", Font_FA_Italic },
45 { "Times-BoldItalic" , "Times New Roman", Font_FA_BoldItalic },
46 { "ZapfChancery-MediumItalic", "Script" , Font_FA_Regular },
47 { "Symbol" , "Symbol" , Font_FA_Regular },
48 { "ZapfDingbats" , "WingDings" , Font_FA_Regular },
49 { "Rock" , "Arial" , Font_FA_Regular },
50 { "Iris" , "Lucida Console" , Font_FA_Regular }
52 #elif defined(__ANDROID__)
54 { "Courier" , "Droid Sans Mono", Font_FA_Regular },
55 { "Times-Roman" , "Droid Serif" , Font_FA_Regular },
56 { "Times-Bold" , "Droid Serif" , Font_FA_Bold },
57 { "Times-Italic" , "Droid Serif" , Font_FA_Italic },
58 { "Times-BoldItalic" , "Droid Serif" , Font_FA_BoldItalic },
59 { "Arial" , "Roboto" , Font_FA_Regular },
63 { "Courier" , "Courier" , Font_FA_Regular },
64 { "Times-Roman" , "Times" , Font_FA_Regular },
65 { "Times-Bold" , "Times" , Font_FA_Bold },
66 { "Times-Italic" , "Times" , Font_FA_Italic },
67 { "Times-BoldItalic" , "Times" , Font_FA_BoldItalic },
68 { "Arial" , "Helvetica" , Font_FA_Regular },
69 { "ZapfChancery-MediumItalic", "-adobe-itc zapf chancery-medium-i-normal--*-*-*-*-*-*-iso8859-1" , Font_FA_Regular },
70 { "Symbol" , "-adobe-symbol-medium-r-normal--*-*-*-*-*-*-adobe-fontspecific" , Font_FA_Regular },
71 { "ZapfDingbats" , "-adobe-itc zapf dingbats-medium-r-normal--*-*-*-*-*-*-adobe-fontspecific" , Font_FA_Regular },
72 { "Rock" , "-sgi-rock-medium-r-normal--*-*-*-*-p-*-iso8859-1" , Font_FA_Regular },
73 { "Iris" , "--iris-medium-r-normal--*-*-*-*-m-*-iso8859-1" , Font_FA_Regular }
78 #define NUM_FONT_ENTRIES (int)(sizeof(Font_FontMgr_MapOfFontsAliases)/sizeof(Font_FontMgr_FontAliasMapNode))
86 #pragma comment (lib, "freetype.lib")
92 // list of supported extensions
93 static Standard_CString Font_FontMgr_Extensions[] =
105 #include <OSD_DirectoryIterator.hxx>
106 #include <OSD_FileIterator.hxx>
107 #include <OSD_Path.hxx>
108 #include <OSD_File.hxx>
109 #include <OSD_OpenMode.hxx>
110 #include <OSD_Protection.hxx>
115 // list of supported extensions
116 static Standard_CString Font_FontMgr_Extensions[] =
126 // X11 configuration file in plain text format (obsolete - doesn't exists in modern distributives)
127 static Standard_CString myFontServiceConf[] = {"/etc/X11/fs/config",
128 "/usr/X11R6/lib/X11/fs/config",
129 "/usr/X11/lib/X11/fs/config",
134 // default fonts paths in Mac OS X
135 static Standard_CString myDefaultFontsDirs[] = {"/System/Library/Fonts",
140 // default fonts paths in most Unix systems (Linux and others)
141 static Standard_CString myDefaultFontsDirs[] = {"/system/fonts", // Android
143 "/usr/local/share/fonts",
148 static void addDirsRecursively (const OSD_Path& thePath,
149 NCollection_Map<TCollection_AsciiString>& theDirsMap)
151 TCollection_AsciiString aDirName;
152 thePath.SystemName (aDirName);
153 if (!theDirsMap.Add (aDirName))
158 for (OSD_DirectoryIterator aDirIterator (thePath, "*"); aDirIterator.More(); aDirIterator.Next())
160 OSD_Path aChildDirPath;
161 aDirIterator.Values().Path (aChildDirPath);
163 TCollection_AsciiString aChildDirName;
164 aChildDirPath.SystemName (aChildDirName);
165 if (!aChildDirName.IsEqual (".") && !aChildDirName.IsEqual (".."))
167 aChildDirName = aDirName + "/" + aChildDirName;
168 OSD_Path aPath (aChildDirName);
169 addDirsRecursively (aPath, theDirsMap);
178 // =======================================================================
179 // function : checkFont
181 // =======================================================================
182 static Handle(Font_SystemFont) checkFont (const Handle(Font_FTLibrary)& theFTLib,
183 const Standard_CString theFontPath)
186 FT_Error aFaceError = FT_New_Face (theFTLib->Instance(), theFontPath, 0, &aFontFace);
187 if (aFaceError != FT_Err_Ok)
192 Font_FontAspect anAspect = Font_FA_Regular;
193 if (aFontFace->style_flags == (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD))
195 anAspect = Font_FA_BoldItalic;
197 else if (aFontFace->style_flags == FT_STYLE_FLAG_ITALIC)
199 anAspect = Font_FA_Italic;
201 else if (aFontFace->style_flags == FT_STYLE_FLAG_BOLD)
203 anAspect = Font_FA_Bold;
206 Handle(Font_SystemFont) aResult;
207 if (aFontFace->family_name != NULL // skip broken fonts (error in FreeType?)
208 && FT_Select_Charmap (aFontFace, ft_encoding_unicode) == 0) // Font_FTFont supports only UNICODE fonts
210 Handle(TCollection_HAsciiString) aFontName = new TCollection_HAsciiString (aFontFace->family_name);
211 Handle(TCollection_HAsciiString) aFontPath = new TCollection_HAsciiString (theFontPath);
212 aResult = new Font_SystemFont (aFontName, anAspect, aFontPath);
215 FT_Done_Face (aFontFace);
220 // =======================================================================
221 // function : GetInstance
223 // =======================================================================
224 Handle(Font_FontMgr) Font_FontMgr::GetInstance()
226 static Handle(Font_FontMgr) _mgr;
229 _mgr = new Font_FontMgr();
235 // =======================================================================
236 // function : Font_FontMgr
238 // =======================================================================
239 Font_FontMgr::Font_FontMgr()
244 // =======================================================================
245 // function : CheckFont
247 // =======================================================================
248 Handle(Font_SystemFont) Font_FontMgr::CheckFont (Standard_CString theFontPath) const
250 Handle(Font_FTLibrary) aFtLibrary = new Font_FTLibrary();
251 return checkFont (aFtLibrary, theFontPath);
254 // =======================================================================
255 // function : RegisterFont
257 // =======================================================================
258 Standard_Boolean Font_FontMgr::RegisterFont (const Handle(Font_SystemFont)& theFont,
259 const Standard_Boolean theToOverride)
261 if (theFont.IsNull())
263 return Standard_False;
266 for (Font_NListOfSystemFont::Iterator aFontIter (myListOfFonts);
267 aFontIter.More(); aFontIter.Next())
269 if (!aFontIter.Value()->FontName()->IsSameString (theFont->FontName(), Standard_False))
274 if (theFont->FontAspect() != Font_FA_Undefined
275 && aFontIter.Value()->FontAspect() != theFont->FontAspect())
280 if (theFont->FontHeight() == -1 || aFontIter.Value()->FontHeight() == -1
281 || theFont->FontHeight() == aFontIter.Value()->FontHeight())
283 if (theFont->FontPath()->String() == aFontIter.Value()->FontPath()->String())
285 return Standard_True;
287 else if (theToOverride)
289 myListOfFonts.Remove (aFontIter);
293 return Standard_False;
298 myListOfFonts.Append (theFont);
299 return Standard_True;
302 // =======================================================================
303 // function : InitFontDataBase
305 // =======================================================================
306 void Font_FontMgr::InitFontDataBase()
308 myListOfFonts.Clear();
309 Handle(Font_FTLibrary) aFtLibrary;
313 // font directory is placed in "C:\Windows\Fonts\"
314 UINT aStrLength = GetSystemWindowsDirectoryA (NULL, 0);
320 char* aWinDir = new char[aStrLength];
321 GetSystemWindowsDirectoryA (aWinDir, aStrLength);
322 Handle(TCollection_HAsciiString) aFontsDir = new TCollection_HAsciiString (aWinDir);
323 aFontsDir->AssignCat ("\\Fonts\\");
326 // read fonts list from registry
328 if (RegOpenKeyExA (HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts",
329 0, KEY_READ, &aFontsKey) != ERROR_SUCCESS)
334 NCollection_Map<TCollection_AsciiString> aSupportedExtensions;
335 for (Standard_Integer anIter = 0; Font_FontMgr_Extensions[anIter] != NULL; ++anIter)
337 Standard_CString anExt = Font_FontMgr_Extensions[anIter];
338 aSupportedExtensions.Add (TCollection_AsciiString (anExt));
341 aFtLibrary = new Font_FTLibrary();
342 static const DWORD aBufferSize = 256;
343 char aNameBuff[aBufferSize];
344 char aPathBuff[aBufferSize];
345 DWORD aNameSize = aBufferSize;
346 DWORD aPathSize = aBufferSize;
347 for (DWORD anIter = 0;
348 RegEnumValueA (aFontsKey, anIter,
349 aNameBuff, &aNameSize, NULL, NULL,
350 (LPBYTE )aPathBuff, &aPathSize) != ERROR_NO_MORE_ITEMS;
351 ++anIter, aNameSize = aBufferSize, aPathSize = aBufferSize)
353 aPathBuff[(aPathSize < aBufferSize) ? aPathSize : (aBufferSize - 1)] = '\0'; // ensure string is NULL-terminated
355 Handle(TCollection_HAsciiString) aFontName = new TCollection_HAsciiString (aNameBuff);
356 Handle(TCollection_HAsciiString) aFontPath = new TCollection_HAsciiString (aPathBuff);
357 if (aFontPath->Search ("\\") == -1)
359 aFontPath->Insert (1, aFontsDir); // make absolute path
362 // check file extension is in list of supported
363 const Standard_Integer anExtensionPosition = aFontPath->SearchFromEnd (".") + 1;
364 if (anExtensionPosition > 0 && anExtensionPosition < aFontPath->Length())
366 Handle(TCollection_HAsciiString) aFontExtension = aFontPath->SubString (anExtensionPosition, aFontPath->Length());
367 aFontExtension->LowerCase();
368 if (aSupportedExtensions.Contains (aFontExtension->String()))
370 Handle(Font_SystemFont) aNewFont = checkFont (aFtLibrary, aFontPath->ToCString());
371 if (!aNewFont.IsNull())
373 myListOfFonts.Append (aNewFont);
379 // close registry key
380 RegCloseKey (aFontsKey);
384 NCollection_Map<TCollection_AsciiString> aMapOfFontsDirs;
385 const OSD_Protection aProtectRead (OSD_R, OSD_R, OSD_R, OSD_R);
387 // read fonts directories from font service config file (obsolete)
388 for (Standard_Integer anIter = 0; myFontServiceConf[anIter] != NULL; ++anIter)
390 const TCollection_AsciiString aFileOfFontsPath (myFontServiceConf[anIter]);
391 OSD_File aFile (aFileOfFontsPath);
397 aFile.Open (OSD_ReadOnly, aProtectRead);
403 Standard_Integer aNByte = 256;
404 Standard_Integer aNbyteRead;
405 TCollection_AsciiString aStr; // read string with information
406 while (!aFile.IsAtEnd())
408 Standard_Integer aLocation = -1;
409 Standard_Integer aPathLocation = -1;
411 aFile.ReadLine (aStr, aNByte, aNbyteRead); // reading 1 line (256 bytes)
412 aLocation = aStr.Search ("catalogue=");
415 aLocation = aStr.Search ("catalogue =");
418 aPathLocation = aStr.Search ("/");
419 if (aLocation > 0 && aPathLocation > 0)
421 aStr = aStr.Split (aPathLocation - 1);
422 TCollection_AsciiString aFontPath;
423 Standard_Integer aPathNumber = 1;
426 // Getting directory paths, which can be splitted by "," or ":"
427 aFontPath = aStr.Token (":,", aPathNumber);
428 aFontPath.RightAdjust();
429 if (!aFontPath.IsEmpty())
431 OSD_Path aPath(aFontPath);
432 addDirsRecursively (aPath, aMapOfFontsDirs);
436 while (!aFontPath.IsEmpty());
442 // append default directories
443 for (Standard_Integer anIter = 0; myDefaultFontsDirs[anIter] != NULL; ++anIter)
445 Standard_CString anItem = myDefaultFontsDirs[anIter];
446 TCollection_AsciiString aPathStr (anItem);
447 OSD_Path aPath (aPathStr);
448 addDirsRecursively (aPath, aMapOfFontsDirs);
451 NCollection_Map<TCollection_AsciiString> aSupportedExtensions;
452 for (Standard_Integer anIter = 0; Font_FontMgr_Extensions[anIter] != NULL; ++anIter)
454 Standard_CString anExt = Font_FontMgr_Extensions[anIter];
455 aSupportedExtensions.Add (TCollection_AsciiString (anExt));
458 aFtLibrary = new Font_FTLibrary();
459 for (NCollection_Map<TCollection_AsciiString>::Iterator anIter (aMapOfFontsDirs);
460 anIter.More(); anIter.Next())
463 OSD_Path aFolderPath (anIter.Value());
464 for (OSD_FileIterator aFileIter (aFolderPath, "*"); aFileIter.More(); aFileIter.Next())
466 OSD_Path aFontFilePath;
467 aFileIter.Values().Path (aFontFilePath);
469 TCollection_AsciiString aFontFileName;
470 aFontFilePath.SystemName (aFontFileName);
471 aFontFileName = anIter.Value() + "/" + aFontFileName;
473 Handle(Font_SystemFont) aNewFont = checkFont (aFtLibrary, aFontFileName.ToCString());
474 if (!aNewFont.IsNull())
476 myListOfFonts.Append (aNewFont);
480 OSD_File aReadFile (anIter.Value() + "/fonts.dir");
481 if (!aReadFile.Exists())
483 continue; // invalid fonts directory
486 aReadFile.Open (OSD_ReadOnly, aProtectRead);
487 if (!aReadFile.IsOpen())
489 continue; // invalid fonts directory
492 Standard_Integer aNbyteRead, aNByte = 256;
493 TCollection_AsciiString aLine (aNByte);
494 Standard_Boolean isFirstLine = Standard_True;
495 const TCollection_AsciiString anEncoding ("iso8859-1\n");
496 while (!aReadFile.IsAtEnd())
498 aReadFile.ReadLine (aLine, aNByte, aNbyteRead);
501 // first line contains the number of fonts in this file
502 // just ignoring it...
503 isFirstLine = Standard_False;
507 Standard_Integer anExtensionPosition = aLine.Search (".") + 1;
508 if (anExtensionPosition == 0)
510 continue; // can't find extension position in the font description
513 Standard_Integer anEndOfFileName = aLine.Location (" ", anExtensionPosition, aLine.Length()) - 1;
514 if (anEndOfFileName < 0 || anEndOfFileName < anExtensionPosition)
516 continue; // font description have empty extension
519 TCollection_AsciiString aFontExtension = aLine.SubString (anExtensionPosition, anEndOfFileName);
520 aFontExtension.LowerCase();
521 if (aSupportedExtensions.Contains (aFontExtension) && (aLine.Search (anEncoding) > 0))
523 // In current implementation use fonts with ISO-8859-1 coding page.
524 // OCCT not give to manage coding page by means of programm interface.
525 // TODO: make high level interface for choosing necessary coding page.
526 Handle(TCollection_HAsciiString) aXLFD =
527 new TCollection_HAsciiString (aLine.SubString (anEndOfFileName + 2, aLine.Length()));
528 Handle(TCollection_HAsciiString) aFontPath =
529 new TCollection_HAsciiString (anIter.Value().ToCString());
530 if (aFontPath->SearchFromEnd ("/") != aFontPath->Length())
532 aFontPath->AssignCat ("/");
534 Handle(TCollection_HAsciiString) aFontFileName =
535 new TCollection_HAsciiString (aLine.SubString (1, anEndOfFileName));
536 aFontPath->AssignCat (aFontFileName);
538 Handle(Font_SystemFont) aNewFontFromXLFD = new Font_SystemFont (aXLFD, aFontPath);
539 Handle(Font_SystemFont) aNewFont = checkFont (aFtLibrary, aFontPath->ToCString());
541 if (aNewFontFromXLFD->IsValid() && !aNewFont.IsNull() &&
542 !aNewFont->IsEqual (aNewFontFromXLFD))
544 myListOfFonts.Append (aNewFont);
545 myListOfFonts.Append (aNewFontFromXLFD);
547 else if (!aNewFont.IsNull())
549 myListOfFonts.Append (aNewFont);
551 else if (aNewFontFromXLFD->IsValid())
553 myListOfFonts.Append (aNewFontFromXLFD);
563 // =======================================================================
564 // function : GetAvailableFonts
566 // =======================================================================
567 const Font_NListOfSystemFont& Font_FontMgr::GetAvailableFonts() const
569 return myListOfFonts;
572 // =======================================================================
573 // function : GetAvailableFontsNames
575 // =======================================================================
576 void Font_FontMgr::GetAvailableFontsNames (TColStd_SequenceOfHAsciiString& theFontsNames) const
578 theFontsNames.Clear();
579 for (Font_NListOfSystemFont::Iterator anIter(myListOfFonts); anIter.More(); anIter.Next())
581 theFontsNames.Append (anIter.Value()->FontName());
585 // =======================================================================
586 // function : GetFont
588 // =======================================================================
589 Handle(Font_SystemFont) Font_FontMgr::GetFont (const Handle(TCollection_HAsciiString)& theFontName,
590 const Font_FontAspect theFontAspect,
591 const Standard_Integer theFontSize) const
593 if ( (theFontSize < 2 && theFontSize != -1) || theFontName.IsNull())
598 for (Font_NListOfSystemFont::Iterator aFontsIterator (myListOfFonts);
599 aFontsIterator.More(); aFontsIterator.Next())
601 if (!theFontName->IsEmpty() && !aFontsIterator.Value()->FontName()->IsSameString (theFontName, Standard_False))
606 if (theFontAspect != Font_FA_Undefined && aFontsIterator.Value()->FontAspect() != theFontAspect)
611 if (theFontSize == -1 || aFontsIterator.Value()->FontHeight() == -1 ||
612 theFontSize == aFontsIterator.Value()->FontHeight())
614 return aFontsIterator.Value();
621 // =======================================================================
622 // function : FindFont
624 // =======================================================================
625 Handle(Font_SystemFont) Font_FontMgr::FindFont (const Handle(TCollection_HAsciiString)& theFontName,
626 const Font_FontAspect theFontAspect,
627 const Standard_Integer theFontSize) const
629 Handle(TCollection_HAsciiString) aFontName = theFontName;
630 Font_FontAspect aFontAspect = theFontAspect;
631 Standard_Integer aFontSize = theFontSize;
633 Handle(Font_SystemFont) aFont = GetFont (aFontName, aFontAspect, aFontSize);
639 // Trying to use font names mapping
640 for (Standard_Integer anIter = 0; anIter < NUM_FONT_ENTRIES; ++anIter)
642 Handle(TCollection_HAsciiString) aFontAlias =
643 new TCollection_HAsciiString (Font_FontMgr_MapOfFontsAliases[anIter].EnumName);
645 if (aFontAlias->IsSameString (aFontName, Standard_False))
647 aFontName = new TCollection_HAsciiString (Font_FontMgr_MapOfFontsAliases[anIter].FontName);
648 aFontAspect = Font_FontMgr_MapOfFontsAliases[anIter].FontAspect;
653 // check font family alias with specified font aspect
654 if (theFontAspect != Font_FA_Undefined
655 && theFontAspect != Font_FA_Regular
656 && theFontAspect != aFontAspect)
658 aFont = GetFont (aFontName, theFontAspect, aFontSize);
665 // check font alias with aspect in the name
666 aFont = GetFont (aFontName, aFontAspect, aFontSize);
672 // Requested family name not found -> search for any font family with given aspect and height
673 aFontName = new TCollection_HAsciiString ("");
674 aFont = GetFont (aFontName, aFontAspect, aFontSize);
680 // The last resort: trying to use ANY font available in the system
681 aFontAspect = Font_FA_Undefined;
683 aFont = GetFont (aFontName, aFontAspect, aFontSize);
689 return NULL; // Fonts are not found in the system.