1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_vcl.hxx"
30 
31 #include <cstdlib>
32 #include <cstring>
33 
34 #include "fontcache.hxx"
35 
36 #include "osl/thread.h"
37 
38 #include "unotools/atom.hxx"
39 
40 #include "tools/stream.hxx"
41 
42 #include <unistd.h>
43 #include <sys/stat.h>
44 
45 #if OSL_DEBUG_LEVEL >1
46 #include <cstdio>
47 #endif
48 
49 #define FONTCACHEFILE "/user/psprint/pspfontcache"
50 #define CACHE_MAGIC "PspFontCacheFile format 4"
51 
52 using namespace std;
53 using namespace rtl;
54 using namespace psp;
55 using namespace utl;
56 
57 /*
58  *  static helpers
59  */
60 
61 /*
62  *  FontCache constructor
63  */
64 
65 FontCache::FontCache()
66 {
67     m_bDoFlush = false;
68     m_aCacheFile = getOfficePath( UserPath );
69     if( m_aCacheFile.Len() )
70     {
71         m_aCacheFile.AppendAscii( FONTCACHEFILE );
72         read();
73     }
74 }
75 
76 /*
77  *  FontCache destructor
78  */
79 
80 FontCache::~FontCache()
81 {
82     clearCache();
83 }
84 
85 /*
86  *  FontCache::clearCache
87  */
88 void FontCache::clearCache()
89 {
90     for( FontCacheData::iterator dir_it = m_aCache.begin(); dir_it != m_aCache.end(); ++dir_it )
91     {
92         for( FontDirMap::iterator entry_it = dir_it->second.m_aEntries.begin(); entry_it != dir_it->second.m_aEntries.end(); ++entry_it )
93         {
94             for( FontCacheEntry::iterator font_it = entry_it->second.m_aEntry.begin(); font_it != entry_it->second.m_aEntry.end(); ++font_it )
95                 delete *font_it;
96         }
97     }
98     m_aCache.clear();
99 }
100 
101 /*
102  *  FontCache::Commit
103  */
104 
105 void FontCache::flush()
106 {
107     if( ! m_bDoFlush || ! m_aCacheFile.Len() )
108         return;
109 
110     SvFileStream aStream;
111     aStream.Open( m_aCacheFile, STREAM_WRITE | STREAM_TRUNC );
112     if( ! (aStream.IsOpen() && aStream.IsWritable()) )
113     {
114 #if OSL_DEBUG_LEVEL > 1
115         fprintf( stderr, "FontCache::flush: opening cache file %s failed\n", ByteString( m_aCacheFile, osl_getThreadTextEncoding() ).GetBuffer() );
116 #endif
117         return;
118     }
119 
120     aStream.SetLineDelimiter( LINEEND_LF );
121     aStream.WriteLine( ByteString( CACHE_MAGIC ) );
122 
123     PrintFontManager& rManager( PrintFontManager::get() );
124     MultiAtomProvider* pAtoms = rManager.m_pAtoms;
125 
126     for( FontCacheData::const_iterator dir_it = m_aCache.begin(); dir_it != m_aCache.end(); ++ dir_it )
127     {
128         const FontDirMap& rDir( dir_it->second.m_aEntries );
129 
130         ByteString aDirectory( rManager.getDirectory( dir_it->first ) );
131         ByteString aLine( "FontCacheDirectory:" );
132         aLine.Append( ByteString::CreateFromInt64( dir_it->second.m_nTimestamp ) );
133         aLine.Append( ':' );
134         aLine.Append( aDirectory );
135         if( rDir.empty() && dir_it->second.m_bNoFiles )
136             aLine.Insert( "Empty", 0 );
137         aStream.WriteLine( aLine );
138 
139         for( FontDirMap::const_iterator entry_it = rDir.begin(); entry_it != rDir.end(); ++entry_it )
140         {
141             // insert cache entries
142             const FontCacheEntry& rEntry( entry_it->second.m_aEntry );
143             if( rEntry.begin() == rEntry.end() )
144                 continue;
145 
146             aLine = "File:";
147             aLine.Append( ByteString( entry_it->first ) );
148             aStream.WriteLine( aLine );
149 
150             int nEntrySize = entry_it->second.m_aEntry.size();
151             // write: type;nfonts
152             aLine = ByteString::CreateFromInt32( rEntry.front()->m_eType );
153             aLine.Append( ';' );
154             aLine.Append( ByteString::CreateFromInt32( nEntrySize ) );
155             aStream.WriteLine( aLine );
156 
157             sal_Int32 nSubEntry = 0;
158             for( FontCacheEntry::const_iterator it = rEntry.begin(); it != rEntry.end(); ++it, nSubEntry++ )
159             {
160                 /*
161                  *  for each font entry write:
162                  *  name[;name[;name]]
163                  *  fontnr;PSName;italic;weight;width;pitch;encoding;ascend;descend;leading;vsubst;gxw;gxh;gyw;gyh;useroverrride;embed;antialias[;{metricfile,typeflags}][;stylename]
164                  */
165                 if( nEntrySize > 1 )
166                     nSubEntry = static_cast<const PrintFontManager::TrueTypeFontFile*>(*it)->m_nCollectionEntry;
167                 else
168                     nSubEntry = -1;
169 
170                 aLine = OUStringToOString( pAtoms->getString( ATOM_FAMILYNAME, (*it)->m_nFamilyName ), RTL_TEXTENCODING_UTF8 );
171                 for( ::std::list< int >::const_iterator name_it = (*it)->m_aAliases.begin(); name_it != (*it)->m_aAliases.end(); ++name_it )
172                 {
173                     const OUString& rAdd( pAtoms->getString( ATOM_FAMILYNAME, *name_it ) );
174                     if( rAdd.getLength() )
175                     {
176                         aLine.Append( ';' );
177                         aLine.Append( ByteString( String( rAdd ), RTL_TEXTENCODING_UTF8 ) );
178                     }
179                 }
180                 aStream.WriteLine( aLine );
181 
182                 const OUString& rPSName( pAtoms->getString( ATOM_PSNAME, (*it)->m_nPSName ) );
183                 aLine = ByteString::CreateFromInt32( nSubEntry );
184                 aLine.Append( ';' );
185                 aLine.Append( ByteString( String( rPSName ), RTL_TEXTENCODING_UTF8 ) );
186                 aLine.Append( ';' );
187                 aLine.Append( ByteString::CreateFromInt32( (*it)->m_eItalic ) );
188                 aLine.Append( ';' );
189                 aLine.Append( ByteString::CreateFromInt32( (*it)->m_eWeight ) );
190                 aLine.Append( ';' );
191                 aLine.Append( ByteString::CreateFromInt32( (*it)->m_eWidth ) );
192                 aLine.Append( ';' );
193                 aLine.Append( ByteString::CreateFromInt32( (*it)->m_ePitch ) );
194                 aLine.Append( ';' );
195                 aLine.Append( ByteString::CreateFromInt32( (*it)->m_aEncoding ) );
196                 aLine.Append( ';' );
197                 aLine.Append( ByteString::CreateFromInt32( (*it)->m_nAscend ) );
198                 aLine.Append( ';' );
199                 aLine.Append( ByteString::CreateFromInt32( (*it)->m_nDescend ) );
200                 aLine.Append( ';' );
201                 aLine.Append( ByteString::CreateFromInt32( (*it)->m_nLeading ) );
202                 aLine.Append( ';' );
203                 aLine.Append( (*it)->m_bHaveVerticalSubstitutedGlyphs ? "1" : "0" );
204                 aLine.Append( ';' );
205                 aLine.Append( ByteString::CreateFromInt32( (*it)->m_aGlobalMetricX.width ) );
206                 aLine.Append( ';' );
207                 aLine.Append( ByteString::CreateFromInt32( (*it)->m_aGlobalMetricX.height ) );
208                 aLine.Append( ';' );
209                 aLine.Append( ByteString::CreateFromInt32( (*it)->m_aGlobalMetricY.width ) );
210                 aLine.Append( ';' );
211                 aLine.Append( ByteString::CreateFromInt32( (*it)->m_aGlobalMetricY.height ) );
212                 aLine.Append( ';' );
213                 aLine.Append( (*it)->m_bUserOverride ? "1" : "0" );
214                 aLine.Append( ';' );
215                 aLine.Append( ByteString::CreateFromInt32( 0 ) );
216                 aLine.Append( ';' );
217                 aLine.Append( ByteString::CreateFromInt32( 0 ) );
218 
219                 switch( (*it)->m_eType )
220                 {
221                     case fonttype::Type1:
222                         aLine.Append( ';' );
223                         aLine.Append( ByteString( static_cast<const PrintFontManager::Type1FontFile*>(*it)->m_aMetricFile ) );
224                         break;
225                     case fonttype::TrueType:
226                         aLine.Append( ';' );
227                         aLine.Append( ByteString::CreateFromInt32( static_cast<const PrintFontManager::TrueTypeFontFile*>(*it)->m_nTypeFlags ) );
228                         break;
229                     default: break;
230                 }
231                 if( (*it)->m_aStyleName.getLength() )
232                 {
233                     aLine.Append( ';' );
234                     aLine.Append( ByteString( String( (*it)->m_aStyleName ), RTL_TEXTENCODING_UTF8 ) );
235                 }
236                 aStream.WriteLine( aLine );
237             }
238             aStream.WriteLine( ByteString() );
239         }
240     }
241     m_bDoFlush = false;
242 }
243 
244 /*
245  * FontCache::read
246  */
247 
248 void FontCache::read()
249 {
250     PrintFontManager& rManager( PrintFontManager::get() );
251     MultiAtomProvider* pAtoms = rManager.m_pAtoms;
252 
253     SvFileStream aStream( m_aCacheFile, STREAM_READ );
254     if( ! aStream.IsOpen() )
255     {
256 #if OSL_DEBUG_LEVEL > 1
257         fprintf( stderr, "FontCache::read: opening cache file %s failed\n", ByteString( m_aCacheFile, osl_getThreadTextEncoding() ).GetBuffer() );
258 #endif
259         return;
260     }
261 
262 
263     ByteString aLine;
264     aStream.ReadLine( aLine );
265     if( !aLine.Equals( CACHE_MAGIC ) )
266     {
267         #if OSL_DEBUG_LEVEL >1
268         fprintf( stderr, "FontCache::read: cache file %s fails magic test\n", ByteString( m_aCacheFile, osl_getThreadTextEncoding() ).GetBuffer() );
269         #endif
270         return;
271     }
272 
273     int nDir = 0;
274     FontDirMap* pDir = NULL;
275     xub_StrLen nIndex;
276     bool bKeepOnlyUserOverridden = false;
277     do
278     {
279         aStream.ReadLine( aLine );
280         if( aLine.CompareTo( "FontCacheDirectory:", 19 ) == COMPARE_EQUAL ||
281             aLine.CompareTo( "EmptyFontCacheDirectory:", 24 ) == COMPARE_EQUAL )
282         {
283             bool bEmpty = (aLine.CompareTo( "Empty", 5 ) == COMPARE_EQUAL);
284             xub_StrLen nSearchIndex = bEmpty ? 24 : 19;
285 
286             OString aDir;
287             sal_Int64 nTimestamp = 0;
288             xub_StrLen nTEnd = aLine.Search( ':', nSearchIndex );
289             if( nTEnd != STRING_NOTFOUND )
290             {
291                 nTimestamp = aLine.Copy( nSearchIndex, nTEnd - nSearchIndex ).ToInt64();
292                 aDir = aLine.Copy( nTEnd+1 );
293             }
294             else
295             {
296                 // invalid format, remove
297                 pDir = NULL;
298                 nDir = 0;
299                 m_bDoFlush = true;
300                 continue;
301             }
302 
303             // is the directory modified ?
304             struct stat aStat;
305             if( stat( aDir.getStr(), &aStat )				||
306                 ! S_ISDIR(aStat.st_mode) )
307             {
308                 // remove outdated cache data
309                 pDir = NULL;
310                 nDir = 0;
311                 m_bDoFlush = true;
312                 continue;
313             }
314             else
315             {
316                 nDir = rManager.getDirectoryAtom( aDir, true );
317                 m_aCache[ nDir ].m_nTimestamp = (sal_Int64)aStat.st_mtime;
318                 m_aCache[ nDir ].m_bNoFiles = bEmpty;
319                 pDir = bEmpty ? NULL : &m_aCache[ nDir ].m_aEntries;
320                 bKeepOnlyUserOverridden = ((sal_Int64)aStat.st_mtime != nTimestamp);
321                 m_aCache[ nDir ].m_bUserOverrideOnly = bKeepOnlyUserOverridden;
322             }
323         }
324         else if( pDir && aLine.CompareTo( "File:", 5 ) == COMPARE_EQUAL )
325         {
326             OString aFile( aLine.Copy( 5 ) );
327             aStream.ReadLine( aLine );
328 
329             const char* pLine = aLine.GetBuffer();
330 
331             fonttype::type eType = (fonttype::type)atoi( pLine );
332             if( eType != fonttype::TrueType		&&
333                 eType != fonttype::Type1		&&
334                 eType != fonttype::Builtin
335                 )
336                 continue;
337             while( *pLine && *pLine != ';' )
338                 pLine++;
339             if( *pLine != ';' )
340                 continue;
341 
342             pLine++;
343             sal_Int32 nFonts = atoi( pLine );
344             for( int n = 0; n < nFonts; n++ )
345             {
346                 aStream.ReadLine( aLine );
347                 pLine = aLine.GetBuffer();
348                 int nLen = aLine.Len();
349 
350                 PrintFontManager::PrintFont* pFont = NULL;
351                 switch( eType )
352                 {
353                     case fonttype::TrueType:
354                         pFont = new PrintFontManager::TrueTypeFontFile();
355                         break;
356                     case fonttype::Type1:
357                         pFont = new PrintFontManager::Type1FontFile();
358                         break;
359                     case fonttype::Builtin:
360                         pFont = new PrintFontManager::BuiltinFont();
361                         break;
362                     default: break;
363                 }
364 
365                 for( nIndex = 0; nIndex < nLen && pLine[nIndex] != ';'; nIndex++ )
366                     ;
367 
368                 pFont->m_nFamilyName = pAtoms->getAtom( ATOM_FAMILYNAME,
369                                                         OUString( pLine, nIndex, RTL_TEXTENCODING_UTF8 ),
370                                                         sal_True );
371                 while( nIndex < nLen )
372                 {
373                     xub_StrLen nLastIndex = nIndex+1;
374                     for( nIndex = nLastIndex ; nIndex < nLen && pLine[nIndex] != ';'; nIndex++ )
375                         ;
376                     if( nIndex - nLastIndex )
377                     {
378                         OUString aAlias( pLine+nLastIndex, nIndex-nLastIndex, RTL_TEXTENCODING_UTF8 );
379                         pFont->m_aAliases.push_back( pAtoms->getAtom( ATOM_FAMILYNAME, aAlias, sal_True ) );
380                     }
381                 }
382                 aStream.ReadLine( aLine );
383                 pLine = aLine.GetBuffer();
384                 nLen = aLine.Len();
385 
386                 // get up to 20 token positions
387                 const int nMaxTokens = 20;
388                 int nTokenPos[nMaxTokens];
389                 nTokenPos[0] = 0;
390                 int nTokens = 1;
391                 for( int i = 0; i < nLen; i++ )
392                 {
393                     if( pLine[i] == ';' )
394                     {
395                         nTokenPos[nTokens++] = i+1;
396                         if( nTokens == nMaxTokens )
397                             break;
398                     }
399                 }
400                 if( nTokens < 18 )
401                 {
402                     delete pFont;
403                     continue;
404                 }
405                 int nCollEntry      = atoi( pLine );
406                 pFont->m_nPSName    = pAtoms->getAtom( ATOM_PSNAME, OUString( pLine + nTokenPos[1], nTokenPos[2]-nTokenPos[1]-1, RTL_TEXTENCODING_UTF8 ), sal_True );
407                 pFont->m_eItalic    = (italic::type)atoi( pLine+nTokenPos[2] );
408                 pFont->m_eWeight    = (weight::type)atoi( pLine+nTokenPos[3] );
409                 pFont->m_eWidth     = (width::type)atoi( pLine+nTokenPos[4] );
410                 pFont->m_ePitch     = (pitch::type)atoi( pLine+nTokenPos[5] );
411                 pFont->m_aEncoding  = (rtl_TextEncoding)atoi( pLine+nTokenPos[6] );
412                 pFont->m_nAscend    = atoi( pLine + nTokenPos[7] );
413                 pFont->m_nDescend   = atoi( pLine + nTokenPos[8] );
414                 pFont->m_nLeading   = atoi( pLine + nTokenPos[9] );
415                 pFont->m_bHaveVerticalSubstitutedGlyphs
416                                     = (atoi( pLine + nTokenPos[10] ) != 0);
417                 pFont->m_aGlobalMetricX.width
418                                     = atoi( pLine + nTokenPos[11] );
419                 pFont->m_aGlobalMetricX.height
420                                     = atoi( pLine + nTokenPos[12] );
421                 pFont->m_aGlobalMetricY.width
422                                     = atoi( pLine + nTokenPos[13] );
423                 pFont->m_aGlobalMetricY.height
424                                     = atoi( pLine + nTokenPos[14] );
425                 pFont->m_bUserOverride
426                                     = (atoi( pLine + nTokenPos[15] ) != 0);
427                 int nStyleTokenNr = 18;
428                 switch( eType )
429                 {
430                     case fonttype::TrueType:
431                         static_cast<PrintFontManager::TrueTypeFontFile*>(pFont)->m_nTypeFlags = atoi( pLine + nTokenPos[18] );
432                         static_cast<PrintFontManager::TrueTypeFontFile*>(pFont)->m_nCollectionEntry = nCollEntry;
433                         static_cast<PrintFontManager::TrueTypeFontFile*>(pFont)->m_nDirectory = nDir;
434                         static_cast<PrintFontManager::TrueTypeFontFile*>(pFont)->m_aFontFile = aFile;
435                         nStyleTokenNr++;
436                         break;
437                     case fonttype::Type1:
438                     {
439                         int nTokLen = (nTokens > 19 ) ? nTokenPos[19]-nTokenPos[18]-1 : nLen - nTokenPos[18];
440                         static_cast<PrintFontManager::Type1FontFile*>(pFont)->m_aMetricFile = OString( pLine + nTokenPos[18], nTokLen );
441                         static_cast<PrintFontManager::Type1FontFile*>(pFont)->m_nDirectory = nDir;
442                         static_cast<PrintFontManager::Type1FontFile*>(pFont)->m_aFontFile = aFile;
443                         nStyleTokenNr++;
444                     }
445                     break;
446                     case fonttype::Builtin:
447                         static_cast<PrintFontManager::BuiltinFont*>(pFont)->m_nDirectory = nDir;
448                         static_cast<PrintFontManager::BuiltinFont*>(pFont)->m_aMetricFile = aFile;
449                         break;
450                     default: break;
451                 }
452                 if( nTokens > nStyleTokenNr )
453                     pFont->m_aStyleName = OUString::intern( pLine + nTokenPos[nStyleTokenNr],
454                                                             nLen - nTokenPos[nStyleTokenNr],
455                                                             RTL_TEXTENCODING_UTF8 );
456 
457                 bool bObsolete = false;
458                 if( bKeepOnlyUserOverridden )
459                 {
460                     if( pFont->m_bUserOverride )
461                     {
462                         ByteString aFilePath = rManager.getDirectory( nDir );
463                         aFilePath.Append( '/' );
464                         aFilePath.Append( ByteString(aFile) );
465                         struct stat aStat;
466                         if( stat( aFilePath.GetBuffer(), &aStat )   ||
467                             ! S_ISREG( aStat.st_mode )              ||
468                             aStat.st_size < 16 )
469                         {
470                             bObsolete = true;
471                         }
472                         #if OSL_DEBUG_LEVEL > 2
473                         else
474                             fprintf( stderr, "keeping file %s in outdated cache entry due to user override\n",
475                                      aFilePath.GetBuffer() );
476                         #endif
477                     }
478                     else
479                         bObsolete = true;
480                 }
481                 if( bObsolete )
482                 {
483                     m_bDoFlush = true;
484 #if OSL_DEBUG_LEVEL > 2
485                     fprintf( stderr, "removing obsolete font %s\n", aFile.getStr() );
486 #endif
487                     delete pFont;
488                     continue;
489                 }
490 
491                 FontCacheEntry& rEntry = (*pDir)[aFile].m_aEntry;
492                 rEntry.push_back( pFont );
493             }
494         }
495     } while( ! aStream.IsEof() );
496 }
497 
498 /*
499  *  FontCache::updateDirTimestamp
500  */
501 void FontCache::updateDirTimestamp( int nDirID )
502 {
503     PrintFontManager& rManager( PrintFontManager::get() );
504     const OString& rDir = rManager.getDirectory( nDirID );
505 
506     struct stat aStat;
507     if( ! stat( rDir.getStr(), &aStat )	)
508         m_aCache[ nDirID ].m_nTimestamp = (sal_Int64)aStat.st_mtime;
509 }
510 
511 
512 /*
513  *  FontCache::copyPrintFont
514  */
515 void FontCache::copyPrintFont( const PrintFontManager::PrintFont* pFrom, PrintFontManager::PrintFont* pTo ) const
516 {
517     if( pFrom->m_eType != pTo->m_eType )
518         return;
519     switch( pFrom->m_eType )
520     {
521         case fonttype::TrueType:
522             static_cast<PrintFontManager::TrueTypeFontFile*>(pTo)->m_nDirectory = static_cast<const PrintFontManager::TrueTypeFontFile*>(pFrom)->m_nDirectory;
523             static_cast<PrintFontManager::TrueTypeFontFile*>(pTo)->m_aFontFile = static_cast<const PrintFontManager::TrueTypeFontFile*>(pFrom)->m_aFontFile;
524             static_cast<PrintFontManager::TrueTypeFontFile*>(pTo)->m_nCollectionEntry = static_cast<const PrintFontManager::TrueTypeFontFile*>(pFrom)->m_nCollectionEntry;
525             static_cast<PrintFontManager::TrueTypeFontFile*>(pTo)->m_nTypeFlags = static_cast<const PrintFontManager::TrueTypeFontFile*>(pFrom)->m_nTypeFlags;
526             break;
527         case fonttype::Type1:
528             static_cast<PrintFontManager::Type1FontFile*>(pTo)->m_nDirectory = static_cast<const PrintFontManager::Type1FontFile*>(pFrom)->m_nDirectory;
529             static_cast<PrintFontManager::Type1FontFile*>(pTo)->m_aFontFile = static_cast<const PrintFontManager::Type1FontFile*>(pFrom)->m_aFontFile;
530             static_cast<PrintFontManager::Type1FontFile*>(pTo)->m_aMetricFile = static_cast<const PrintFontManager::Type1FontFile*>(pFrom)->m_aMetricFile;
531             break;
532         case fonttype::Builtin:
533             static_cast<PrintFontManager::BuiltinFont*>(pTo)->m_nDirectory = static_cast<const PrintFontManager::BuiltinFont*>(pFrom)->m_nDirectory;
534             static_cast<PrintFontManager::BuiltinFont*>(pTo)->m_aMetricFile = static_cast<const PrintFontManager::BuiltinFont*>(pFrom)->m_aMetricFile;
535             break;
536         default: break;
537     }
538     pTo->m_nFamilyName		= pFrom->m_nFamilyName;
539     pTo->m_aStyleName       = pFrom->m_aStyleName;
540     pTo->m_aAliases			= pFrom->m_aAliases;
541     pTo->m_nPSName			= pFrom->m_nPSName;
542     pTo->m_eItalic			= pFrom->m_eItalic;
543     pTo->m_eWeight			= pFrom->m_eWeight;
544     pTo->m_eWidth			= pFrom->m_eWidth;
545     pTo->m_ePitch			= pFrom->m_ePitch;
546     pTo->m_aEncoding		= pFrom->m_aEncoding;
547     pTo->m_aGlobalMetricX	= pFrom->m_aGlobalMetricX;
548     pTo->m_aGlobalMetricY	= pFrom->m_aGlobalMetricY;
549     pTo->m_nAscend			= pFrom->m_nAscend;
550     pTo->m_nDescend			= pFrom->m_nDescend;
551     pTo->m_nLeading			= pFrom->m_nLeading;
552     pTo->m_nXMin			= pFrom->m_nXMin;
553     pTo->m_nYMin			= pFrom->m_nYMin;
554     pTo->m_nXMax			= pFrom->m_nXMax;
555     pTo->m_nYMax			= pFrom->m_nYMax;
556     pTo->m_bHaveVerticalSubstitutedGlyphs = pFrom->m_bHaveVerticalSubstitutedGlyphs;
557     pTo->m_bUserOverride    = pFrom->m_bUserOverride;
558 }
559 
560 /*
561  *  FontCache::equalsPrintFont
562  */
563 bool FontCache::equalsPrintFont( const PrintFontManager::PrintFont* pLeft, PrintFontManager::PrintFont* pRight ) const
564 {
565     if( pLeft->m_eType != pRight->m_eType )
566         return false;
567     switch( pLeft->m_eType )
568     {
569         case fonttype::TrueType:
570         {
571             const PrintFontManager::TrueTypeFontFile* pLT = static_cast<const PrintFontManager::TrueTypeFontFile*>(pLeft);
572             const PrintFontManager::TrueTypeFontFile* pRT = static_cast<const PrintFontManager::TrueTypeFontFile*>(pRight);
573             if( pRT->m_nDirectory		!= pLT->m_nDirectory		||
574                 pRT->m_aFontFile		!= pLT->m_aFontFile			||
575                 pRT->m_nCollectionEntry	!= pLT->m_nCollectionEntry	||
576                 pRT->m_nTypeFlags		!= pLT->m_nTypeFlags )
577                 return false;
578         }
579         break;
580         case fonttype::Type1:
581         {
582             const PrintFontManager::Type1FontFile* pLT = static_cast<const PrintFontManager::Type1FontFile*>(pLeft);
583             const PrintFontManager::Type1FontFile* pRT = static_cast<const PrintFontManager::Type1FontFile*>(pRight);
584             if( pRT->m_nDirectory		!= pLT->m_nDirectory		||
585                 pRT->m_aFontFile		!= pLT->m_aFontFile			||
586                 pRT->m_aMetricFile		!= pLT->m_aMetricFile )
587                 return false;
588         }
589         break;
590         case fonttype::Builtin:
591         {
592             const PrintFontManager::BuiltinFont* pLT = static_cast<const PrintFontManager::BuiltinFont*>(pLeft);
593             const PrintFontManager::BuiltinFont* pRT = static_cast<const PrintFontManager::BuiltinFont*>(pRight);
594             if( pRT->m_nDirectory		!= pLT->m_nDirectory		||
595                 pRT->m_aMetricFile		!= pLT->m_aMetricFile )
596                 return false;
597         }
598         break;
599         default: break;
600     }
601     if( pRight->m_nFamilyName		!= pLeft->m_nFamilyName		||
602         pRight->m_aStyleName        != pLeft->m_aStyleName      ||
603         pRight->m_nPSName			!= pLeft->m_nPSName			||
604         pRight->m_eItalic			!= pLeft->m_eItalic			||
605         pRight->m_eWeight			!= pLeft->m_eWeight			||
606         pRight->m_eWidth			!= pLeft->m_eWidth			||
607         pRight->m_ePitch			!= pLeft->m_ePitch			||
608         pRight->m_aEncoding			!= pLeft->m_aEncoding		||
609         pRight->m_aGlobalMetricX	!= pLeft->m_aGlobalMetricX	||
610         pRight->m_aGlobalMetricY	!= pLeft->m_aGlobalMetricY	||
611         pRight->m_nAscend			!= pLeft->m_nAscend			||
612         pRight->m_nDescend			!= pLeft->m_nDescend		||
613         pRight->m_nLeading			!= pLeft->m_nLeading		||
614         pRight->m_nXMin				!= pLeft->m_nXMin			||
615         pRight->m_nYMin				!= pLeft->m_nYMin			||
616         pRight->m_nXMax				!= pLeft->m_nXMax			||
617         pRight->m_nYMax				!= pLeft->m_nYMax			||
618         pRight->m_bHaveVerticalSubstitutedGlyphs != pLeft->m_bHaveVerticalSubstitutedGlyphs ||
619         pRight->m_bUserOverride     != pLeft->m_bUserOverride
620         )
621         return false;
622     std::list< int >::const_iterator lit, rit;
623     for( lit = pLeft->m_aAliases.begin(), rit = pRight->m_aAliases.begin();
624          lit != pLeft->m_aAliases.end() && rit != pRight->m_aAliases.end() && (*lit) == (*rit);
625          ++lit, ++rit )
626         ;
627     return lit == pLeft->m_aAliases.end() && rit == pRight->m_aAliases.end();
628 }
629 
630 /*
631  *  FontCache::clonePrintFont
632  */
633 PrintFontManager::PrintFont* FontCache::clonePrintFont( const PrintFontManager::PrintFont* pOldFont ) const
634 {
635     PrintFontManager::PrintFont* pFont = NULL;
636     switch( pOldFont->m_eType )
637     {
638         case fonttype::TrueType:
639             pFont = new PrintFontManager::TrueTypeFontFile();
640             break;
641         case fonttype::Type1:
642             pFont = new PrintFontManager::Type1FontFile();
643             break;
644         case fonttype::Builtin:
645             pFont = new PrintFontManager::BuiltinFont();
646             break;
647         default: break;
648     }
649     if( pFont )
650     {
651         copyPrintFont( pOldFont, pFont );
652     }
653     return pFont;
654  }
655 
656 /*
657  *  FontCache::getFontCacheFile
658  */
659 bool FontCache::getFontCacheFile( int nDirID, const OString& rFile, list< PrintFontManager::PrintFont* >& rNewFonts ) const
660 {
661     bool bSuccess = false;
662 
663     FontCacheData::const_iterator dir = m_aCache.find( nDirID );
664     if( dir != m_aCache.end() )
665     {
666         FontDirMap::const_iterator entry = dir->second.m_aEntries.find( rFile );
667         if( entry != dir->second.m_aEntries.end() )
668         {
669             for( FontCacheEntry::const_iterator font = entry->second.m_aEntry.begin(); font != entry->second.m_aEntry.end(); ++font )
670             {
671                 bSuccess = true;
672                 PrintFontManager::PrintFont* pFont = clonePrintFont( *font );
673                 rNewFonts.push_back( pFont );
674             }
675         }
676     }
677     return bSuccess;
678 }
679 
680 /*
681  *  FontCache::updateFontCacheEntry
682  */
683 void FontCache::updateFontCacheEntry( const PrintFontManager::PrintFont* pFont, bool bFlush )
684 {
685     PrintFontManager& rManager( PrintFontManager::get() );
686 
687     OString aFile;
688     int nDirID = 0;
689     switch( pFont->m_eType )
690     {
691         case fonttype::TrueType:
692             nDirID = static_cast<const PrintFontManager::TrueTypeFontFile*>(pFont)->m_nDirectory;
693             aFile = static_cast<const PrintFontManager::TrueTypeFontFile*>(pFont)->m_aFontFile;
694             break;
695         case fonttype::Type1:
696             nDirID = static_cast<const PrintFontManager::Type1FontFile*>(pFont)->m_nDirectory;
697             aFile = static_cast<const PrintFontManager::Type1FontFile*>(pFont)->m_aFontFile;
698             break;
699         case fonttype::Builtin:
700             nDirID = static_cast<const PrintFontManager::BuiltinFont*>(pFont)->m_nDirectory;
701             aFile = static_cast<const PrintFontManager::BuiltinFont*>(pFont)->m_aMetricFile;
702             break;
703         default:
704             return;
705     }
706     FontCacheData::const_iterator dir = m_aCache.find( nDirID );
707     FontDirMap::const_iterator entry;
708     FontCacheEntry::const_iterator font;
709     PrintFontManager::PrintFont* pCacheFont = NULL;
710 
711     if( dir != m_aCache.end() )
712     {
713         entry = dir->second.m_aEntries.find( aFile );
714         if( entry != dir->second.m_aEntries.end() )
715         {
716             for( font = entry->second.m_aEntry.begin(); font != entry->second.m_aEntry.end(); ++font )
717             {
718                 if( (*font)->m_eType == pFont->m_eType &&
719                     ( (*font)->m_eType != fonttype::TrueType ||
720                       static_cast<const PrintFontManager::TrueTypeFontFile*>(*font)->m_nCollectionEntry == static_cast<const PrintFontManager::TrueTypeFontFile*>(pFont)->m_nCollectionEntry
721                       ) )
722                     break;
723             }
724             if( font != entry->second.m_aEntry.end() )
725                 pCacheFont = *font;
726         }
727     }
728     else
729         createCacheDir( nDirID );
730 
731     if( pCacheFont )
732     {
733         if( ! equalsPrintFont( pFont, pCacheFont ) )
734         {
735             copyPrintFont( pFont, pCacheFont );
736             m_bDoFlush = true;
737         }
738     }
739     else
740     {
741         pCacheFont = clonePrintFont( pFont );
742         m_aCache[nDirID].m_aEntries[aFile].m_aEntry.push_back( pCacheFont );
743 
744         ByteString aPath = rManager.getDirectory( nDirID );
745         aPath.Append( '/' );
746         aPath.Append( ByteString( aFile ) );
747         m_bDoFlush = true;
748     }
749     if( bFlush )
750         flush();
751 }
752 
753 /*
754  *  FontCache::listDirectory
755  */
756 bool FontCache::listDirectory( const OString& rDir, std::list< PrintFontManager::PrintFont* >& rNewFonts ) const
757 {
758     PrintFontManager& rManager( PrintFontManager::get() );
759     int nDirID = rManager.getDirectoryAtom( rDir );
760     FontCacheData::const_iterator dir = m_aCache.find( nDirID );
761     bool bFound = (dir != m_aCache.end());
762 
763     if( bFound && !dir->second.m_bNoFiles )
764     {
765         for( FontDirMap::const_iterator file = dir->second.m_aEntries.begin(); file != dir->second.m_aEntries.end(); ++file )
766         {
767             for( FontCacheEntry::const_iterator font = file->second.m_aEntry.begin(); font != file->second.m_aEntry.end(); ++font )
768             {
769                 PrintFontManager::PrintFont* pFont = clonePrintFont( *font );
770                 rNewFonts.push_back( pFont );
771             }
772         }
773     }
774     return bFound;
775 }
776 
777 /*
778  *  FontCache::listDirectory
779  */
780 bool FontCache::scanAdditionalFiles( const OString& rDir )
781 {
782     PrintFontManager& rManager( PrintFontManager::get() );
783     int nDirID = rManager.getDirectoryAtom( rDir );
784     FontCacheData::const_iterator dir = m_aCache.find( nDirID );
785     bool bFound = (dir != m_aCache.end());
786 
787     return (bFound && dir->second.m_bUserOverrideOnly);
788 }
789 
790 /*
791  *  FontCache::createCacheDir
792  */
793 void FontCache::createCacheDir( int nDirID )
794 {
795     PrintFontManager& rManager( PrintFontManager::get() );
796 
797     const OString& rDir = rManager.getDirectory( nDirID );
798     struct stat aStat;
799     if( ! stat( rDir.getStr(), &aStat ) )
800         m_aCache[nDirID].m_nTimestamp = (sal_Int64)aStat.st_mtime;
801 }
802 
803 /*
804  *  FontCache::markEmptyDir
805  */
806 void FontCache::markEmptyDir( int nDirID, bool bNoFiles )
807 {
808     createCacheDir( nDirID );
809     m_aCache[nDirID].m_bNoFiles = bNoFiles;
810     m_bDoFlush = true;
811 }
812