Merge OCC22105 and OCC22360
[occt.git] / src / OSD / OSD_FontMgr.cxx
1 // Copyright:     OpenCASCADE
2
3 // File:          OSD_FontMgr.cxx
4 // Created:       20.01.2008
5 // Author:        Alexander A. BORODIN
6 // Updated:
7
8 #include <OSD_FontMgr.ixx>
9 #ifdef WNT
10 # include <windows.h>
11 # include <stdlib.h>
12 #else  //WNT
13 # include <dirent.h>
14 # include <X11/Xlib.h>
15 #endif //WNT
16
17 #include <NCollection_List.hxx>
18 #include <TCollection_HAsciiString.hxx>  
19 #include <Standard_Stream.hxx>
20
21
22 #ifndef WNT
23 #include <TCollection_AsciiString.hxx>
24
25 #include <NCollection_DefineList.hxx>
26 #include <NCollection_List.hxx>
27
28 #include <OSD_Path.hxx>
29 #include <OSD_FileIterator.hxx>
30 #include <OSD_DirectoryIterator.hxx>
31 #include <OSD_File.hxx>
32 #include <OSD_FileNode.hxx>
33 #include <OSD_OpenMode.hxx>
34 #include <OSD_Protection.hxx>
35 #include <OSD_NListOfSystemFont.hxx>
36
37 const  Standard_Integer font_service_conf_size = 3;
38 static Standard_Character font_service_conf[font_service_conf_size][64] = { {"/etc/X11/fs/config"},
39                                                                             {"/usr/X11R6/lib/X11/fs/config"},
40                                                                             {"/usr/X11/lib/X11/fs/config"}
41                                                                            };
42
43 DEFINE_LIST( StringList, NCollection_List, TCollection_HAsciiString );
44
45 void find_path_with_font_dir( const TCollection_AsciiString& dir,StringList& dirs )
46 {  
47   if( !dir.IsEmpty() )
48   {
49     TCollection_AsciiString PathName( dir );
50
51     Standard_Integer rem = PathName.Length();
52
53     if ( PathName.SearchFromEnd("/") == rem )
54       PathName.Remove( rem, 1 );
55
56     Standard_Boolean need_to_append = Standard_True;
57        
58     StringList::Iterator it( dirs );
59     for( ; it.More(); it.Next() )
60     {
61       if ( PathName.IsEqual(it.Value().ToCString()) ) {
62         need_to_append = Standard_False;
63         break;
64       }
65     }
66     if ( need_to_append )
67       dirs.Append( PathName );
68
69     OSD_DirectoryIterator osd_dir(PathName,"*");
70     while(osd_dir.More())
71     {
72       OSD_Path path_file;
73       osd_dir.Values().Path( path_file );
74       if( path_file.Name().Length() < 1 )
75       {
76         osd_dir.Next();
77         continue;
78       }
79       
80       TCollection_AsciiString full_path_name = PathName + "/" + path_file.Name();
81       rem = full_path_name.Length();
82       if ( full_path_name.SearchFromEnd("/") == rem )
83         full_path_name.Remove( rem, 1 );
84       find_path_with_font_dir( full_path_name, dirs );
85       osd_dir.Next();
86     }
87   }
88 }
89
90 #endif //WNT
91
92
93 Handle(OSD_FontMgr) OSD_FontMgr::GetInstance() {
94
95   static Handle(OSD_FontMgr) _mgr;
96   if ( _mgr.IsNull() )
97     _mgr = new OSD_FontMgr();
98
99   return _mgr;
100
101 }
102
103 OSD_FontMgr::OSD_FontMgr() {
104
105   InitFontDataBase();
106
107 }
108
109
110 void OSD_FontMgr::InitFontDataBase() {
111
112   MyListOfFonts.Clear();
113
114 #ifdef WNT
115   //detect font directory
116
117   Standard_Character* windir_var;
118   Standard_Size req_size;   
119   req_size = strlen( getenv("windir") );
120
121   windir_var = new Standard_Character[req_size + 1];
122
123   strcpy( windir_var, getenv("windir") );
124
125   Standard_Character *font_dir = new Standard_Character[ req_size + strlen("\\Fonts\\") + 1 ]  ;  
126
127   if( !strcpy( font_dir, windir_var ) )
128     return  ;   
129   if( !strcat( font_dir, "\\Fonts\\" ) )
130     return ;  
131
132   Handle(TCollection_HAsciiString) HFontDir = new TCollection_HAsciiString(font_dir);
133
134 #ifdef TRACE
135   cout << "System font directory: " << font_dir << "\n";
136 #endif TRACE
137
138   //read registry
139   HKEY fonts_hkey;
140   if( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
141       TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"),
142       0,
143       KEY_READ,
144       &fonts_hkey )
145       != ERROR_SUCCESS ) 
146   {
147     return;
148   }           
149   Standard_Integer           id = 0;
150   Standard_Character         buf_name[100];
151   Standard_Byte buf_data[100];
152   DWORD size_name = 100,
153         size_data = 100;
154
155   while ( true )
156   {
157     //detect file name    
158     DWORD type;
159     size_name = 100,
160       size_data = 100;
161     OSD_FontAspect aspect;
162     if( RegEnumValue( fonts_hkey,
163                       id,
164                       buf_name,
165                       &size_name,
166                       NULL,
167                       &type,
168                       buf_data,
169                       &size_data) == ERROR_NO_MORE_ITEMS ) {
170         break;
171       }
172       Handle(TCollection_HAsciiString) fname = 
173         new TCollection_HAsciiString(buf_name);
174       fname->RightAdjust();
175       fname->LeftAdjust();
176       //remove construction like (TrueType....
177       Standard_Integer anIndexTT = fname->SearchFromEnd( new TCollection_HAsciiString( " (" ) );
178       Standard_Boolean aTruncate = Standard_False;
179       if ( anIndexTT > 1 )
180         fname->Trunc( anIndexTT );
181       Standard_Integer anIndex = 0;
182       fname->RightAdjust();
183       if ( ( anIndex = fname->SearchFromEnd( new TCollection_HAsciiString("Bold Italic") ) ) > 0 ) {
184         aTruncate = ( anIndex > 1 ) && ( fname->Value(anIndex - 1 ) == ' ' );
185         aspect = OSD_FA_BoldItalic;
186       } else if ( ( anIndex = fname->SearchFromEnd( new TCollection_HAsciiString("Bold") ) ) > 0 ) {
187         aTruncate = ( anIndex > 1 ) && ( fname->Value(anIndex - 1 ) == ' ' );
188         aspect = OSD_FA_Bold;
189       } else if ( ( anIndex = fname->SearchFromEnd( new TCollection_HAsciiString("Italic") ) ) > 0 ) {
190         aTruncate = ( anIndex > 1 ) && ( fname->Value(anIndex - 1 ) == ' ' );
191         aspect = OSD_FA_Italic;
192       } else {
193         aspect = OSD_FA_Regular;
194       }
195       if( aTruncate )
196         fname->Trunc( anIndex - 1 );
197       fname->RightAdjust();
198       Handle(TCollection_HAsciiString) file_path =
199       new TCollection_HAsciiString( (Standard_Character*)buf_data );
200       if ( strchr( (Standard_Character*)buf_data, '\\' ) == NULL ) {
201         file_path->Insert( 1, HFontDir );
202       }
203       Handle(TCollection_HAsciiString) HFontDir = new TCollection_HAsciiString(font_dir);
204
205       if( ( ( file_path->Search(".ttf") > 0 ) || ( file_path->Search(".TTF") > 0 ) ||
206             ( file_path->Search(".otf") > 0 ) || ( file_path->Search(".OTF") > 0 ) ||
207             ( file_path->Search(".ttc") > 0 ) || ( file_path->Search(".TTC") > 0 ) ) ){
208         MyListOfFonts.Append( new OSD_SystemFont( fname, aspect, file_path ) );
209 #ifdef TRACE
210         cout  << "Adding font...\n"
211               << "  font name: " << fname->ToCString() << "\n"
212               << "  font file: " << file_path->ToCString() << "\n"
213               << "  font aspect: ";
214         switch( aspect ) {
215         case OSD_FA_Bold:
216           cout << "OSD_FA_Bold\n";
217           break;
218         case OSD_FA_BoldItalic:
219           cout << "OSD_FA_BoldItalic\n";
220           break;
221         case OSD_FA_Italic:
222           cout << "OSD_FA_Italic\n";
223           break;
224         default:
225           cout << "OSD_FA_Regular\n";
226           break;
227         }
228 #endif
229       }
230   id++; 
231   }
232   //close registry
233   RegCloseKey( fonts_hkey );
234 #endif //WNT
235
236 #ifndef WNT
237   StringList dirs;
238   Handle(TCollection_HAsciiString) str = new TCollection_HAsciiString;
239   Display * disp = XOpenDisplay("localhost:0.0");
240
241   if (!disp) 
242   {
243     // let the X server find the available connection
244     disp = XOpenDisplay(":0.0");
245     if (!disp)
246     {
247       cout << "Display is NULL!" << endl;
248       return ;
249     }
250   }
251
252   Standard_Integer npaths = 0;
253
254   Standard_Character** fontpath = XGetFontPath(disp, &npaths);
255 #ifdef TRACE
256   cout << "NPATHS = " << npaths << endl ;
257 #endif
258   for (Standard_Integer i = 0; i < npaths; i++  ) 
259   {  
260 #ifdef TRACE         
261     cout << "Font Path: " << fontpath[i] << endl;
262 #endif
263     if ( fontpath[i][0] == '/' ) {
264       TCollection_AsciiString aFontPath( fontpath[i] );
265       find_path_with_font_dir( aFontPath, dirs );
266     }
267     else
268     {
269       TCollection_AsciiString aFontPath( fontpath[i] );
270       TCollection_AsciiString aCutFontPath;        
271       Standard_Integer location = -1 ;
272        location = aFontPath.Location( "/",1,aFontPath.Length() );
273       if( location > 0 )
274         aCutFontPath.AssignCat( aFontPath.SubString(location, aFontPath.Length() ) );
275       find_path_with_font_dir( aCutFontPath, dirs ); 
276     }
277   }
278   XFreeFontPath(fontpath);
279
280
281   OSD_OpenMode aMode =  OSD_ReadOnly;
282   OSD_Protection  aProtect( OSD_R, OSD_R, OSD_R, OSD_R );
283
284   for( Standard_Integer j = 0 ; j < font_service_conf_size; j++ )
285   {
286     TCollection_AsciiString fileOfFontServiceName( font_service_conf[j] );
287     OSD_File aFile( fileOfFontServiceName );
288
289     if( aFile.Exists() ) 
290       aFile.Open( aMode, aProtect );
291   
292     if( aFile.IsOpen() )//font service
293     {
294       Standard_Integer aNByte = 256;
295       Standard_Integer aNbyteRead;
296       TCollection_AsciiString aStr( aNByte );//read string with information
297       TCollection_AsciiString aStrCut( aNByte );//cut of string
298       TCollection_AsciiString endStr;//cutting string
299
300       Standard_Boolean read_dirs = Standard_False;
301       Standard_Integer location =- 1; //disposition of necessary literals
302       Standard_Integer begin =- 1; //first left entry in string
303       Standard_Integer end =- 1; //first right entry in string
304       while( !aFile.IsAtEnd() )
305       {
306         aFile.ReadLine( aStr, aNByte, aNbyteRead );//reading 1 lines(256 bytes) 
307         location = aStr.Location( "catalogue = ", 1, aStr.Length() );
308         if(location == 0)
309           location = aStr.Location( "catalogue=", 1, aStr.Length() );
310         if(location == 0)
311           location = aStr.Location( "catalogue= ", 1, aStr.Length() );
312         if(location == 0)
313           location = aStr.Location( "catalogue = ", 1, aStr.Length() );
314         if( location > 0 )  
315         {
316 #ifdef TRACE
317           cout << " Font config find!!" << endl;
318 #endif
319           read_dirs = Standard_True;
320         }
321   
322         if( read_dirs )
323         {  
324           begin = aStr.Location( "/", 1, aStr.Length() );//begin of path name
325           end = aStr.Location( ":", 1, aStr.Length() );//end of path name
326           if( end < 1 )
327             end = aStr.Location( ",", 1, aStr.Length() );//also end of path name
328           end -= 1;
329           if( begin > 0 && end > 0 )
330           {
331             if( ( end - begin ) > 0 )
332               endStr.AssignCat( aStr.SubString ( begin, end ) );//cutting necessary literals for string
333             dirs.Append( TCollection_HAsciiString ( endStr ) );
334             endStr.Clear();
335           }
336           else 
337             if( begin > 0 && end == -1 )
338             { 
339               //if end of string don't have "," or ":"
340               //it is possible last sentence in block of word
341               endStr.AssignCat( aStr.SubString( begin, aStr.Length() - 1 ) );
342               dirs.Append( TCollection_HAsciiString( endStr ) );   
343               endStr.Clear();
344             }
345         } 
346  
347       }
348       aFile.Close();
349     }
350   }
351
352   if( dirs.Size() > 0 )
353   {   
354     //if dirs list contains elements
355     OSD_OpenMode aModeRead =  OSD_ReadOnly;
356     OSD_Protection  aProtectRead( OSD_R, OSD_R , OSD_R , OSD_R );
357
358     TCollection_AsciiString fileFontsDir;
359     StringList::Iterator it( dirs ); 
360     for( ; it.More(); it.Next() ) 
361     {     
362       fileFontsDir.AssignCat( it.Value().ToCString() );   
363       fileFontsDir.AssignCat( "/fonts.dir" );//append file name in path way
364
365       OSD_File readFile( fileFontsDir );  
366       readFile.Open( aModeRead, aProtectRead );
367
368       Standard_Integer aNbyteRead, aNByte = 256;
369       if( readFile.IsOpen ( ) )
370       {
371         TCollection_AsciiString aLine( aNByte );
372         Standard_Integer countOfString = 0 ;
373         while( ! readFile.IsAtEnd() )//return true if EOF
374         {
375           if( countOfString > 1 )
376           {
377             readFile.ReadLine( aLine , aNByte , aNbyteRead );
378             if( ( ( aLine.Search(".pfa") > 0 ) || ( aLine.Search(".PFA") > 0 ) ||
379                   ( aLine.Search(".pfb") > 0 ) || ( aLine.Search(".PFB") > 0 ) ||
380                   ( aLine.Search(".ttf") > 0 ) || ( aLine.Search(".TTF") > 0 ) ||
381                   ( aLine.Search(".otf") > 0 ) || ( aLine.Search(".OTF") > 0 ) ||
382                   ( aLine.Search(".ttc") > 0 ) || ( aLine.Search(".TTC") > 0 ) )
383                   && ( aLine.Search( "iso8859-1\n" ) > 0 ) )    
384             { 
385
386               // In current implementation use fonts with ISO-8859-1 coding page.
387               // OCCT not give to manage coding page by means of programm interface. 
388               // TODO: make high level interface for 
389               // choosing necessary coding page.  
390               TCollection_AsciiString aXLFD;
391               Standard_Integer leftXLFD = aLine.SearchFromEnd(" ");
392               Standard_Integer rightXLFD = aLine.Length();
393               if( leftXLFD && rightXLFD )
394                 aXLFD.AssignCat(aLine.SubString( leftXLFD + 1, rightXLFD ) );
395
396               TCollection_AsciiString aPath;
397               TCollection_AsciiString aTemp( it.Value().ToCString() );
398               if ( aTemp.SearchFromEnd("/") == aTemp.Length() )
399               {
400                 //this branch intend to SUN
401                 aPath.AssignCat( aTemp.ToCString() );
402                 aPath.AssignCat( aLine.Token( " ", 1 ) );
403               }
404               else {
405                 //this branch intend to Linux       
406                 aPath.AssignCat( aTemp.ToCString( ) );
407                 aPath.AssignCat( "/" );
408                 aPath.AssignCat( aLine.Token( " ", 1 ) );
409               }
410               MyListOfFonts.Append( new OSD_SystemFont( new TCollection_HAsciiString( aXLFD ),
411                 new TCollection_HAsciiString( aPath ) ) );
412             }
413             
414           }
415           else
416             readFile.ReadLine( aLine, aNByte, aNbyteRead ); 
417           countOfString++;
418         }
419         readFile.Close();
420       } 
421       fileFontsDir.Clear(); 
422     }
423   }
424 #endif
425 }
426
427 OSD_NListOfSystemFont OSD_FontMgr::GetAvalableFonts() const
428 {
429   return MyListOfFonts;
430 }
431
432