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