1 // Created on: 2008-01-20
2 // Created by: Alexander A. BORODIN
3 // Copyright (c) 2008-2012 OPEN CASCADE SAS
5 // The content of this file is subject to the Open CASCADE Technology Public
6 // License Version 6.5 (the "License"). You may not use the content of this file
7 // except in compliance with the License. Please obtain a copy of the License
8 // at http://www.opencascade.org and read it completely before using this file.
10 // The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
11 // main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
13 // The Original Code and all software distributed under the License is
14 // distributed on an "AS IS" basis, without warranty of any kind, and the
15 // Initial Developer hereby disclaims all such warranties, including without
16 // limitation, any warranties of merchantability, fitness for a particular
17 // purpose or non-infringement. Please see the License for the specific terms
18 // and conditions governing the rights and limitations under the License.
20 #include <Font_FontMgr.ixx>
22 #include <OSD_Environment.hxx>
23 #include <NCollection_List.hxx>
24 #include <NCollection_Map.hxx>
25 #include <Standard_Stream.hxx>
26 #include <TCollection_HAsciiString.hxx>
29 #include FT_FREETYPE_H
31 struct Font_FontMgr_FontAliasMapNode
33 const char * EnumName;
34 const char * FontName;
35 Font_FontAspect FontAspect;
38 static const Font_FontMgr_FontAliasMapNode Font_FontMgr_MapOfFontsAliases[] =
43 { "Courier" , "Courier New" , Font_FA_Regular },
44 { "Times-Roman" , "Times New Roman", Font_FA_Regular },
45 { "Times-Bold" , "Times New Roman", Font_FA_Bold },
46 { "Times-Italic" , "Times New Roman", Font_FA_Italic },
47 { "Times-BoldItalic" , "Times New Roman", Font_FA_BoldItalic },
48 { "ZapfChancery-MediumItalic", "Script" , Font_FA_Regular },
49 { "Symbol" , "Symbol" , Font_FA_Regular },
50 { "ZapfDingbats" , "WingDings" , Font_FA_Regular },
51 { "Rock" , "Arial" , Font_FA_Regular },
52 { "Iris" , "Lucida Console" , Font_FA_Regular }
56 { "Courier" , "Courier" , Font_FA_Regular },
57 { "Times-Roman" , "Times" , Font_FA_Regular },
58 { "Times-Bold" , "Times" , Font_FA_Bold },
59 { "Times-Italic" , "Times" , Font_FA_Italic },
60 { "Times-BoldItalic" , "Times" , Font_FA_BoldItalic },
61 { "Arial" , "Helvetica" , Font_FA_Regular },
62 { "ZapfChancery-MediumItalic", "-adobe-itc zapf chancery-medium-i-normal--*-*-*-*-*-*-iso8859-1" , Font_FA_Regular },
63 { "Symbol" , "-adobe-symbol-medium-r-normal--*-*-*-*-*-*-adobe-fontspecific" , Font_FA_Regular },
64 { "ZapfDingbats" , "-adobe-itc zapf dingbats-medium-r-normal--*-*-*-*-*-*-adobe-fontspecific" , Font_FA_Regular },
65 { "Rock" , "-sgi-rock-medium-r-normal--*-*-*-*-p-*-iso8859-1" , Font_FA_Regular },
66 { "Iris" , "--iris-medium-r-normal--*-*-*-*-m-*-iso8859-1" , Font_FA_Regular }
71 #define NUM_FONT_ENTRIES (sizeof(Font_FontMgr_MapOfFontsAliases)/sizeof(Font_FontMgr_FontAliasMapNode))
73 #if (defined(_WIN32) || defined(__WIN32__))
79 #pragma comment (lib, "freetype.lib")
85 // list of supported extensions
86 static Standard_CString Font_FontMgr_Extensions[] =
98 #include <OSD_DirectoryIterator.hxx>
99 #include <OSD_Path.hxx>
100 #include <OSD_File.hxx>
101 #include <OSD_OpenMode.hxx>
102 #include <OSD_Protection.hxx>
107 // list of supported extensions
108 static Standard_CString Font_FontMgr_Extensions[] =
118 // X11 configuration file in plain text format (obsolete - doesn't exists in modern distributives)
119 static Standard_CString myFontServiceConf[] = {"/etc/X11/fs/config",
120 "/usr/X11R6/lib/X11/fs/config",
121 "/usr/X11/lib/X11/fs/config",
126 // default fonts paths in Mac OS X
127 static Standard_CString myDefaultFontsDirs[] = {"/System/Library/Fonts",
132 // default fonts paths in most Unix systems (Linux and others)
133 static Standard_CString myDefaultFontsDirs[] = {"/usr/share/fonts",
134 "/usr/local/share/fonts",
139 static void addDirsRecursively (const OSD_Path& thePath,
140 NCollection_Map<TCollection_AsciiString>& theDirsMap)
142 TCollection_AsciiString aDirName;
143 thePath.SystemName (aDirName);
144 if (!theDirsMap.Add (aDirName))
149 for (OSD_DirectoryIterator aDirIterator (thePath, "*"); aDirIterator.More(); aDirIterator.Next())
151 OSD_Path aChildDirPath;
152 aDirIterator.Values().Path (aChildDirPath);
154 TCollection_AsciiString aChildDirName;
155 aChildDirPath.SystemName (aChildDirName);
156 if (!aChildDirName.IsEqual (".") && !aChildDirName.IsEqual (".."))
158 aChildDirName = aDirName + "/" + aChildDirName;
159 OSD_Path aPath (aChildDirName);
160 addDirsRecursively (aPath, theDirsMap);
169 // =======================================================================
170 // function : checkFont
172 // =======================================================================
173 static Handle(Font_SystemFont) checkFont (FT_Library theFTLib,
174 const Standard_CString theFontPath)
177 FT_Error aFaceError = FT_New_Face (theFTLib, theFontPath, 0, &aFontFace);
178 if (aFaceError != FT_Err_Ok)
183 Font_FontAspect anAspect = Font_FA_Regular;
184 if (aFontFace->style_flags == (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD))
186 anAspect = Font_FA_BoldItalic;
188 else if (aFontFace->style_flags == FT_STYLE_FLAG_ITALIC)
190 anAspect = Font_FA_Italic;
192 else if (aFontFace->style_flags == FT_STYLE_FLAG_BOLD)
194 anAspect = Font_FA_Bold;
197 Handle(TCollection_HAsciiString) aFontName = new TCollection_HAsciiString (aFontFace->family_name);
198 Handle(TCollection_HAsciiString) aFontPath = new TCollection_HAsciiString (theFontPath);
199 Handle(Font_SystemFont) aResult = new Font_SystemFont (aFontName, anAspect, aFontPath);
201 FT_Done_Face (aFontFace);
206 // =======================================================================
207 // function : GetInstance
209 // =======================================================================
210 Handle(Font_FontMgr) Font_FontMgr::GetInstance()
212 static Handle(Font_FontMgr) _mgr;
215 _mgr = new Font_FontMgr();
221 // =======================================================================
222 // function : Font_FontMgr
224 // =======================================================================
225 Font_FontMgr::Font_FontMgr()
230 // =======================================================================
231 // function : InitFontDataBase
233 // =======================================================================
234 void Font_FontMgr::InitFontDataBase()
236 myListOfFonts.Clear();
237 FT_Library aFtLibrary = NULL;
239 #if (defined(_WIN32) || defined(__WIN32__))
241 // font directory is placed in "C:\Windows\Fonts\"
242 UINT aStrLength = GetSystemWindowsDirectoryA (NULL, 0);
248 char* aWinDir = new char[aStrLength];
249 GetSystemWindowsDirectoryA (aWinDir, aStrLength);
250 Handle(TCollection_HAsciiString) aFontsDir = new TCollection_HAsciiString (aWinDir);
251 aFontsDir->AssignCat ("\\Fonts\\");
254 // read fonts list from registry
256 if (RegOpenKeyExA (HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts",
257 0, KEY_READ, &aFontsKey) != ERROR_SUCCESS)
262 NCollection_Map<TCollection_AsciiString> aSupportedExtensions;
263 for (Standard_Integer anIter = 0; Font_FontMgr_Extensions[anIter] != NULL; ++anIter)
265 Standard_CString anExt = Font_FontMgr_Extensions[anIter];
266 aSupportedExtensions.Add (TCollection_AsciiString (anExt));
269 FT_Init_FreeType (&aFtLibrary);
270 static const DWORD aBufferSize = 256;
271 char aNameBuff[aBufferSize];
272 char aPathBuff[aBufferSize];
273 DWORD aNameSize = aBufferSize;
274 DWORD aPathSize = aBufferSize;
275 for (DWORD anIter = 0;
276 RegEnumValueA (aFontsKey, anIter,
277 aNameBuff, &aNameSize, NULL, NULL,
278 (LPBYTE )aPathBuff, &aPathSize) != ERROR_NO_MORE_ITEMS;
279 ++anIter, aNameSize = aBufferSize, aPathSize = aBufferSize)
281 aPathBuff[(aPathSize < aBufferSize) ? aPathSize : (aBufferSize - 1)] = '\0'; // ensure string is NULL-terminated
283 Handle(TCollection_HAsciiString) aFontName = new TCollection_HAsciiString (aNameBuff);
284 Handle(TCollection_HAsciiString) aFontPath = new TCollection_HAsciiString (aPathBuff);
285 if (aFontPath->Search ("\\") == -1)
287 aFontPath->Insert (1, aFontsDir); // make absolute path
290 // check file extension is in list of supported
291 const Standard_Integer anExtensionPosition = aFontPath->SearchFromEnd (".") + 1;
292 if (anExtensionPosition > 0 && anExtensionPosition < aFontPath->Length())
294 Handle(TCollection_HAsciiString) aFontExtension = aFontPath->SubString (anExtensionPosition, aFontPath->Length());
295 aFontExtension->LowerCase();
296 if (aSupportedExtensions.Contains (aFontExtension->String()))
298 Handle(Font_SystemFont) aNewFont = checkFont (aFtLibrary, aFontPath->ToCString());
299 if (!aNewFont.IsNull())
301 myListOfFonts.Append (aNewFont);
307 // close registry key
308 RegCloseKey (aFontsKey);
312 NCollection_Map<TCollection_AsciiString> aMapOfFontsDirs;
313 const OSD_Protection aProtectRead (OSD_R, OSD_R, OSD_R, OSD_R);
315 // read fonts directories from font service config file (obsolete)
316 for (Standard_Integer anIter = 0; myFontServiceConf[anIter] != NULL; ++anIter)
318 const TCollection_AsciiString aFileOfFontsPath (myFontServiceConf[anIter]);
319 OSD_File aFile (aFileOfFontsPath);
325 aFile.Open (OSD_ReadOnly, aProtectRead);
331 Standard_Integer aNByte = 256;
332 Standard_Integer aNbyteRead;
333 TCollection_AsciiString aStr; // read string with information
334 while (!aFile.IsAtEnd())
336 Standard_Integer aLocation = -1;
337 Standard_Integer aPathLocation = -1;
339 aFile.ReadLine (aStr, aNByte, aNbyteRead); // reading 1 line (256 bytes)
340 aLocation = aStr.Search ("catalogue=");
343 aLocation = aStr.Search ("catalogue =");
346 aPathLocation = aStr.Search ("/");
347 if (aLocation > 0 && aPathLocation > 0)
349 aStr = aStr.Split (aPathLocation - 1);
350 TCollection_AsciiString aFontPath;
351 Standard_Integer aPathNumber = 1;
354 // Getting directory paths, which can be splitted by "," or ":"
355 aFontPath = aStr.Token (":,", aPathNumber);
356 aFontPath.RightAdjust();
357 if (!aFontPath.IsEmpty())
359 OSD_Path aPath(aFontPath);
360 addDirsRecursively (aPath, aMapOfFontsDirs);
364 while (!aFontPath.IsEmpty());
370 // append default directories
371 for (Standard_Integer anIter = 0; myDefaultFontsDirs[anIter] != NULL; ++anIter)
373 Standard_CString anItem = myDefaultFontsDirs[anIter];
374 TCollection_AsciiString aPathStr (anItem);
375 OSD_Path aPath (aPathStr);
376 addDirsRecursively (aPath, aMapOfFontsDirs);
379 NCollection_Map<TCollection_AsciiString> aSupportedExtensions;
380 for (Standard_Integer anIter = 0; Font_FontMgr_Extensions[anIter] != NULL; ++anIter)
382 Standard_CString anExt = Font_FontMgr_Extensions[anIter];
383 aSupportedExtensions.Add (TCollection_AsciiString (anExt));
386 FT_Init_FreeType (&aFtLibrary);
387 for (NCollection_Map<TCollection_AsciiString>::Iterator anIter (aMapOfFontsDirs);
388 anIter.More(); anIter.Next())
390 OSD_File aReadFile (anIter.Value() + "/fonts.dir");
391 if (!aReadFile.Exists())
393 continue; // invalid fonts directory
396 aReadFile.Open (OSD_ReadOnly, aProtectRead);
397 if (!aReadFile.IsOpen())
399 continue; // invalid fonts directory
402 Standard_Integer aNbyteRead, aNByte = 256;
403 TCollection_AsciiString aLine (aNByte);
404 Standard_Boolean isFirstLine = Standard_True;
405 const TCollection_AsciiString anEncoding ("iso8859-1\n");
406 while (!aReadFile.IsAtEnd())
408 aReadFile.ReadLine (aLine, aNByte, aNbyteRead);
411 // first line contains the number of fonts in this file
412 // just ignoring it...
413 isFirstLine = Standard_False;
417 Standard_Integer anExtensionPosition = aLine.Search (".") + 1;
418 if (anExtensionPosition == 0)
420 continue; // can't find extension position in the font description
423 Standard_Integer anEndOfFileName = aLine.Location (" ", anExtensionPosition, aLine.Length()) - 1;
424 if (anEndOfFileName < 0 || anEndOfFileName < anExtensionPosition)
426 continue; // font description have empty extension
429 TCollection_AsciiString aFontExtension = aLine.SubString (anExtensionPosition, anEndOfFileName);
430 aFontExtension.LowerCase();
431 if (aSupportedExtensions.Contains (aFontExtension) && (aLine.Search (anEncoding) > 0))
433 // In current implementation use fonts with ISO-8859-1 coding page.
434 // OCCT not give to manage coding page by means of programm interface.
435 // TODO: make high level interface for choosing necessary coding page.
436 Handle(TCollection_HAsciiString) aXLFD =
437 new TCollection_HAsciiString (aLine.SubString (anEndOfFileName + 2, aLine.Length()));
438 Handle(TCollection_HAsciiString) aFontPath =
439 new TCollection_HAsciiString (anIter.Value().ToCString());
440 if (aFontPath->SearchFromEnd ("/") != aFontPath->Length())
442 aFontPath->AssignCat ("/");
444 Handle(TCollection_HAsciiString) aFontFileName =
445 new TCollection_HAsciiString (aLine.SubString (1, anEndOfFileName));
446 aFontPath->AssignCat (aFontFileName);
448 Handle(Font_SystemFont) aNewFontFromXLFD = new Font_SystemFont (aXLFD, aFontPath);
449 Handle(Font_SystemFont) aNewFont = checkFont (aFtLibrary, aFontPath->ToCString());
451 if (aNewFontFromXLFD->IsValid() && !aNewFont.IsNull() &&
452 !aNewFont->IsEqual (aNewFontFromXLFD))
454 myListOfFonts.Append (aNewFont);
455 myListOfFonts.Append (aNewFontFromXLFD);
457 else if (!aNewFont.IsNull())
459 myListOfFonts.Append (aNewFont);
461 else if (aNewFontFromXLFD->IsValid())
463 myListOfFonts.Append (aNewFontFromXLFD);
471 FT_Done_FreeType (aFtLibrary);
474 // =======================================================================
475 // function : GetAvailableFonts
477 // =======================================================================
478 const Font_NListOfSystemFont& Font_FontMgr::GetAvailableFonts() const
480 return myListOfFonts;
483 void Font_FontMgr::GetAvailableFontsNames (TColStd_SequenceOfHAsciiString& theFontsNames) const
485 theFontsNames.Clear();
486 for (Font_NListOfSystemFont::Iterator anIter(myListOfFonts); anIter.More(); anIter.Next())
488 theFontsNames.Append (anIter.Value()->FontName());
492 Handle(Font_SystemFont) Font_FontMgr::GetFont (const Handle(TCollection_HAsciiString)& theFontName,
493 const Font_FontAspect theFontAspect,
494 const Standard_Integer theFontSize) const
496 if ( (theFontSize < 2 && theFontSize != -1) || theFontName.IsNull())
501 Font_NListOfSystemFont::Iterator aFontsIterator (myListOfFonts);
503 for (; aFontsIterator.More(); aFontsIterator.Next())
505 if (!theFontName->IsEmpty() && !aFontsIterator.Value()->FontName()->IsSameString (theFontName, Standard_False))
510 if (theFontAspect != Font_FA_Undefined && aFontsIterator.Value()->FontAspect() != theFontAspect)
515 if (theFontSize == -1 || aFontsIterator.Value()->FontHeight() == -1 ||
516 theFontSize == aFontsIterator.Value()->FontHeight())
518 return aFontsIterator.Value();
525 Handle(Font_SystemFont) Font_FontMgr::FindFont (const Handle(TCollection_HAsciiString)& theFontName,
526 const Font_FontAspect theFontAspect,
527 const Standard_Integer theFontSize) const
529 Handle(TCollection_HAsciiString) aFontName = theFontName;
530 Font_FontAspect aFontAspect = theFontAspect;
531 Standard_Integer aFontSize = theFontSize;
533 Handle(Font_SystemFont) aFont = GetFont (aFontName, aFontAspect, aFontSize);
540 // Trying to use font names mapping
541 for (Standard_Integer anIter = 0; anIter < NUM_FONT_ENTRIES; ++anIter)
543 Handle(TCollection_HAsciiString) aFontAlias =
544 new TCollection_HAsciiString (Font_FontMgr_MapOfFontsAliases[anIter].EnumName);
546 if (aFontAlias->IsSameString (aFontName, Standard_False))
548 aFontName = new TCollection_HAsciiString (Font_FontMgr_MapOfFontsAliases[anIter].FontName);
549 aFontAspect = Font_FontMgr_MapOfFontsAliases[anIter].FontAspect;
554 aFont = GetFont (aFontName, aFontAspect, aFontSize);
561 // Requested family name not found -> search for any font family with given aspect and height
562 aFontName = new TCollection_HAsciiString ("");
563 aFont = GetFont (aFontName, aFontAspect, aFontSize);
570 // The last resort: trying to use ANY font available in the system
571 aFontAspect = Font_FA_Undefined;
573 aFont = GetFont (aFontName, aFontAspect, aFontSize);
580 return NULL; // Fonts are not found in the system.