blob: 816ddc99baa945f29e1a8c99b4def6163f1ace56 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_vcl.hxx"
#include <unistd.h>
#include <sys/stat.h>
#include <dirent.h>
#include <stdlib.h>
#include <osl/thread.h>
#include "unotools/atom.hxx"
#include "fontcache.hxx"
#include "fontsubset.hxx"
#include "impfont.hxx"
#include "svdata.hxx"
#include "salinst.hxx"
#include "vcl/fontmanager.hxx"
#include "vcl/strhelper.hxx"
#include "vcl/ppdparser.hxx"
#include "tools/urlobj.hxx"
#include "tools/stream.hxx"
#include "tools/debug.hxx"
#include "tools/config.hxx"
#include "osl/file.hxx"
#include "osl/process.h"
#include "rtl/tencinfo.h"
#include "rtl/ustrbuf.hxx"
#include "rtl/strbuf.hxx"
#include "i18npool/mslangid.hxx"
#include "parseAFM.hxx"
#include "sft.hxx"
#if OSL_DEBUG_LEVEL > 1
#include <sys/times.h>
#include <stdio.h>
#endif
#include "sal/alloca.h"
#include <set>
#include <hash_set>
#include <algorithm>
#include "adobeenc.tab" // get encoding table for AFM metrics
#ifdef CALLGRIND_COMPILE
#include <valgrind/callgrind.h>
#endif
#include "comphelper/processfactory.hxx"
#include "com/sun/star/beans/XMaterialHolder.hpp"
#include "com/sun/star/beans/NamedValue.hpp"
#define PRINTER_METRICDIR "fontmetric"
namespace {
namespace css = com::sun::star;
}
using namespace vcl;
using namespace utl;
using namespace psp;
using namespace osl;
using namespace rtl;
using namespace com::sun::star::uno;
using namespace com::sun::star::beans;
using namespace com::sun::star::lang;
/*
* static helpers
*/
inline sal_uInt16 getUInt16BE( const sal_uInt8*& pBuffer )
{
sal_uInt16 nRet = (sal_uInt16)pBuffer[1] |
(((sal_uInt16)pBuffer[0]) << 8);
pBuffer+=2;
return nRet;
}
inline sal_uInt32 getUInt32BE( const sal_uInt8*& pBuffer )
{
sal_uInt32 nRet = (((sal_uInt32)pBuffer[0]) << 24) |
(((sal_uInt32)pBuffer[1]) << 16) |
(((sal_uInt32)pBuffer[2]) << 8) |
(((sal_uInt32)pBuffer[3]) );
pBuffer += 4;
return nRet;
}
static italic::type parseItalic( const ByteString& rItalic )
{
italic::type eItalic = italic::Unknown;
if( rItalic.EqualsIgnoreCaseAscii( "i" ) )
eItalic = italic::Italic;
else if( rItalic.EqualsIgnoreCaseAscii( "o" ) )
eItalic = italic::Oblique;
else
eItalic = italic::Upright;
return eItalic;
}
// -------------------------------------------------------------------------
static weight::type parseWeight( const ByteString& rWeight )
{
weight::type eWeight = weight::Unknown;
if( rWeight.Search( "bold" ) != STRING_NOTFOUND )
{
if( rWeight.Search( "emi" ) != STRING_NOTFOUND ) // semi, demi
eWeight = weight::SemiBold;
else if( rWeight.Search( "ultra" ) != STRING_NOTFOUND )
eWeight = weight::UltraBold;
else
eWeight = weight::Bold;
}
else if( rWeight.Search( "heavy" ) != STRING_NOTFOUND )
eWeight = weight::Bold;
else if( rWeight.Search( "light" ) != STRING_NOTFOUND )
{
if( rWeight.Search( "emi" ) != STRING_NOTFOUND ) // semi, demi
eWeight = weight::SemiLight;
else if( rWeight.Search( "ultra" ) != STRING_NOTFOUND )
eWeight = weight::UltraLight;
else
eWeight = weight::Light;
}
else if( rWeight.Search( "black" ) != STRING_NOTFOUND )
eWeight = weight::Black;
else if( rWeight.Equals( "demi" ) )
eWeight = weight::SemiBold;
else if( rWeight.Equals( "book" ) ||
rWeight.Equals( "semicondensed" ) )
eWeight = weight::Light;
else if( rWeight.Equals( "medium" ) || rWeight.Equals( "roman" ) )
eWeight = weight::Medium;
else
eWeight = weight::Normal;
return eWeight;
}
// -------------------------------------------------------------------------
static width::type parseWidth( const ByteString& rWidth )
{
width::type eWidth = width::Unknown;
if( rWidth.Equals( "bold" ) ||
rWidth.Equals( "semiexpanded" ) )
eWidth = width::SemiExpanded;
else if( rWidth.Equals( "condensed" ) ||
rWidth.Equals( "narrow" ) )
eWidth = width::Condensed;
else if( rWidth.Equals( "double wide" ) ||
rWidth.Equals( "extraexpanded" ) ||
rWidth.Equals( "ultraexpanded" ) )
eWidth = width::UltraExpanded;
else if( rWidth.Equals( "expanded" ) ||
rWidth.Equals( "wide" ) )
eWidth = width::Expanded;
else if( rWidth.Equals( "extracondensed" ) )
eWidth = width::ExtraCondensed;
else if( rWidth.Equals( "semicondensed" ) )
eWidth = width::SemiCondensed;
else if( rWidth.Equals( "ultracondensed" ) )
eWidth = width::UltraCondensed;
else
eWidth = width::Normal;
return eWidth;
}
// -------------------------------------------------------------------------
bool PrintFontManager::XLFDEntry::operator<(const PrintFontManager::XLFDEntry& rRight) const
{
sal_Int32 nCmp = 0;
if( (nMask & MaskFamily) && (rRight.nMask & MaskFamily) )
{
nCmp = rtl_str_compareIgnoreAsciiCase_WithLength( aFamily.pData->buffer,
aFamily.pData->length,
rRight.aFamily.pData->buffer,
rRight.aFamily.pData->length );
if( nCmp != 0 )
return nCmp < 0;
}
if( (nMask & MaskFoundry) && (rRight.nMask & MaskFoundry) )
{
nCmp = rtl_str_compareIgnoreAsciiCase_WithLength( aFoundry.pData->buffer,
aFoundry.pData->length,
rRight.aFoundry.pData->buffer,
rRight.aFoundry.pData->length );
if( nCmp != 0 )
return nCmp < 0;
}
if( (nMask & MaskItalic) && (rRight.nMask & MaskItalic) )
{
if( eItalic != rRight.eItalic )
return (int)eItalic < (int)rRight.eItalic;
}
if( (nMask & MaskWeight) && (rRight.nMask & MaskWeight) )
{
if( eWeight != rRight.eWeight )
return (int)eWeight < (int)rRight.eWeight;
}
if( (nMask & MaskWidth) && (rRight.nMask & MaskWidth) )
{
if( eWidth != rRight.eWidth )
return (int)eWidth < (int)rRight.eWidth;
}
if( (nMask & MaskPitch) && (rRight.nMask & MaskPitch) )
{
if( ePitch != rRight.ePitch )
return (int)ePitch < (int)rRight.ePitch;
}
if( (nMask & MaskAddStyle) && (rRight.nMask & MaskAddStyle) )
{
nCmp = rtl_str_compareIgnoreAsciiCase_WithLength( aAddStyle.pData->buffer,
aAddStyle.pData->length,
rRight.aAddStyle.pData->buffer,
rRight.aAddStyle.pData->length );
if( nCmp != 0 )
return nCmp < 0;
}
if( (nMask & MaskEncoding) && (rRight.nMask & MaskEncoding) )
{
if( aEncoding != rRight.aEncoding )
return aEncoding < rRight.aEncoding;
}
return false;
}
bool PrintFontManager::XLFDEntry::operator==(const PrintFontManager::XLFDEntry& rRight) const
{
sal_Int32 nCmp = 0;
if( (nMask & MaskFamily) && (rRight.nMask & MaskFamily) )
{
nCmp = rtl_str_compareIgnoreAsciiCase_WithLength( aFamily.pData->buffer,
aFamily.pData->length,
rRight.aFamily.pData->buffer,
rRight.aFamily.pData->length );
if( nCmp != 0 )
return false;
}
if( (nMask & MaskFoundry) && (rRight.nMask & MaskFoundry) )
{
nCmp = rtl_str_compareIgnoreAsciiCase_WithLength( aFoundry.pData->buffer,
aFoundry.pData->length,
rRight.aFoundry.pData->buffer,
rRight.aFoundry.pData->length );
if( nCmp != 0 )
return false;
}
if( (nMask & MaskItalic) && (rRight.nMask & MaskItalic) )
{
if( eItalic != rRight.eItalic )
return false;
}
if( (nMask & MaskWeight) && (rRight.nMask & MaskWeight) )
{
if( eWeight != rRight.eWeight )
return false;
}
if( (nMask & MaskWidth) && (rRight.nMask & MaskWidth) )
{
if( eWidth != rRight.eWidth )
return false;
}
if( (nMask & MaskPitch) && (rRight.nMask & MaskPitch) )
{
if( ePitch != rRight.ePitch )
return false;
}
if( (nMask & MaskAddStyle) && (rRight.nMask & MaskAddStyle) )
{
nCmp = rtl_str_compareIgnoreAsciiCase_WithLength( aAddStyle.pData->buffer,
aAddStyle.pData->length,
rRight.aAddStyle.pData->buffer,
rRight.aAddStyle.pData->length );
if( nCmp != 0 )
return false;
}
if( (nMask & MaskEncoding) && (rRight.nMask & MaskEncoding) )
{
if( aEncoding != rRight.aEncoding )
return false;
}
return true;
}
/*
* PrintFont implementations
*/
PrintFontManager::PrintFont::PrintFont( fonttype::type eType ) :
m_eType( eType ),
m_nFamilyName( 0 ),
m_nPSName( 0 ),
m_eItalic( italic::Unknown ),
m_eWidth( width::Unknown ),
m_eWeight( weight::Unknown ),
m_ePitch( pitch::Unknown ),
m_aEncoding( RTL_TEXTENCODING_DONTKNOW ),
m_bFontEncodingOnly( false ),
m_pMetrics( NULL ),
m_nAscend( 0 ),
m_nDescend( 0 ),
m_nLeading( 0 ),
m_nXMin( 0 ),
m_nYMin( 0 ),
m_nXMax( 0 ),
m_nYMax( 0 ),
m_bHaveVerticalSubstitutedGlyphs( false ),
m_bUserOverride( false )
{
}
// -------------------------------------------------------------------------
PrintFontManager::PrintFont::~PrintFont()
{
if( m_pMetrics )
delete m_pMetrics;
}
// -------------------------------------------------------------------------
PrintFontManager::Type1FontFile::~Type1FontFile()
{
}
// -------------------------------------------------------------------------
PrintFontManager::TrueTypeFontFile::TrueTypeFontFile()
: PrintFont( fonttype::TrueType )
, m_nDirectory( 0 )
, m_nCollectionEntry(-1)
, m_nTypeFlags( TYPEFLAG_INVALID )
{}
// -------------------------------------------------------------------------
PrintFontManager::TrueTypeFontFile::~TrueTypeFontFile()
{
}
// -------------------------------------------------------------------------
PrintFontManager::BuiltinFont::~BuiltinFont()
{
}
// -------------------------------------------------------------------------
bool PrintFontManager::Type1FontFile::queryMetricPage( int /*nPage*/, MultiAtomProvider* pProvider )
{
return readAfmMetrics( PrintFontManager::get().getAfmFile( this ), pProvider, false, false );
}
// -------------------------------------------------------------------------
bool PrintFontManager::BuiltinFont::queryMetricPage( int /*nPage*/, MultiAtomProvider* pProvider )
{
return readAfmMetrics( PrintFontManager::get().getAfmFile( this ), pProvider, false, false );
}
// -------------------------------------------------------------------------
bool PrintFontManager::TrueTypeFontFile::queryMetricPage( int nPage, MultiAtomProvider* pProvider )
{
bool bSuccess = false;
ByteString aFile( PrintFontManager::get().getFontFile( this ) );
TrueTypeFont* pTTFont = NULL;
if( OpenTTFontFile( aFile.GetBuffer(), m_nCollectionEntry < 0 ? 0 : m_nCollectionEntry, &pTTFont ) == SF_OK )
{
if( ! m_pMetrics )
{
m_pMetrics = new PrintFontMetrics;
memset (m_pMetrics->m_aPages, 0, sizeof(m_pMetrics->m_aPages));
}
m_pMetrics->m_aPages[ nPage/8 ] |= (1 << ( nPage & 7 ));
int i;
sal_uInt16 table[256], table_vert[256];
for( i = 0; i < 256; i++ )
table[ i ] = 256*nPage + i;
int nCharacters = nPage < 255 ? 256 : 254;
MapString( pTTFont, table, nCharacters, NULL, 0 );
TTSimpleGlyphMetrics* pMetrics = GetTTSimpleCharMetrics( pTTFont, nPage*256, nCharacters, 0 );
if( pMetrics )
{
for( i = 0; i < nCharacters; i++ )
{
if( table[i] )
{
CharacterMetric& rChar = m_pMetrics->m_aMetrics[ nPage*256 + i ];
rChar.width = pMetrics[ i ].adv;
rChar.height = m_aGlobalMetricX.height;
}
}
free( pMetrics );
}
for( i = 0; i < 256; i++ )
table_vert[ i ] = 256*nPage + i;
MapString( pTTFont, table_vert, nCharacters, NULL, 1 );
pMetrics = GetTTSimpleCharMetrics( pTTFont, nPage*256, nCharacters, 1 );
if( pMetrics )
{
for( i = 0; i < nCharacters; i++ )
{
if( table_vert[i] )
{
CharacterMetric& rChar = m_pMetrics->m_aMetrics[ nPage*256 + i + ( 1 << 16 ) ];
rChar.width = m_aGlobalMetricY.width;
rChar.height = pMetrics[ i ].adv;
if( table_vert[i] != table[i] )
m_pMetrics->m_bVerticalSubstitutions[ nPage*256 + i ] = 1;
}
}
free( pMetrics );
}
if( ! m_pMetrics->m_bKernPairsQueried )
{
m_pMetrics->m_bKernPairsQueried = true;
// this is really a hack
// in future MapString/KernGlyphs should be used
// but vcl is not in a state where that could be used
// so currently we get kernpairs by accessing the raw data
struct _TrueTypeFont* pImplTTFont = (struct _TrueTypeFont*)pTTFont;
//-----------------------------------------------------------------
// Kerning: KT_MICROSOFT
//-----------------------------------------------------------------
if( pImplTTFont->nkern && pImplTTFont->kerntype == KT_MICROSOFT )
{
// create a glyph -> character mapping
::std::hash_map< sal_uInt16, sal_Unicode > aGlyphMap;
::std::hash_map< sal_uInt16, sal_Unicode >::iterator left, right;
for( i = 21; i < 0xfffd; i++ )
{
sal_uInt16 nGlyph = MapChar( pTTFont, (sal_Unicode)i, 0 ); // kerning for horz only
if( nGlyph != 0 )
aGlyphMap[ nGlyph ] = (sal_Unicode)i;
}
KernPair aPair;
for( i = 0; i < (int)pImplTTFont->nkern; i++ )
{
const sal_uInt8* pTable = pImplTTFont->kerntables[i];
/*sal_uInt16 nVersion =*/ getUInt16BE( pTable );
/*sal_uInt16 nLength =*/ getUInt16BE( pTable );
sal_uInt16 nCoverage = getUInt16BE( pTable );
aPair.kern_x = 0;
aPair.kern_y = 0;
switch( nCoverage >> 8 )
{
case 0:
{
sal_uInt16 nPairs = getUInt16BE( pTable );
pTable += 6;
for( int n = 0; n < nPairs; n++ )
{
sal_uInt16 nLeftGlyph = getUInt16BE( pTable );
sal_uInt16 nRightGlyph = getUInt16BE( pTable );
sal_Int16 nKern = (sal_Int16)getUInt16BE( pTable );
left = aGlyphMap.find( nLeftGlyph );
right = aGlyphMap.find( nRightGlyph );
if( left != aGlyphMap.end() && right != aGlyphMap.end() )
{
aPair.first = left->second;
aPair.second = right->second;
switch( nCoverage & 1 )
{
case 1:
aPair.kern_x = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
m_pMetrics->m_aXKernPairs.push_back( aPair );
break;
case 0:
aPair.kern_y = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
m_pMetrics->m_aYKernPairs.push_back( aPair );
break;
}
}
}
}
break;
case 2:
{
const sal_uInt8* pSubTable = pTable;
/*sal_uInt16 nRowWidth =*/ getUInt16BE( pTable );
sal_uInt16 nOfLeft = getUInt16BE( pTable );
sal_uInt16 nOfRight = getUInt16BE( pTable );
/*sal_uInt16 nOfArray =*/ getUInt16BE( pTable );
const sal_uInt8* pTmp = pSubTable + nOfLeft;
sal_uInt16 nFirstLeft = getUInt16BE( pTmp );
sal_uInt16 nLastLeft = getUInt16BE( pTmp ) + nFirstLeft - 1;
pTmp = pSubTable + nOfRight;
sal_uInt16 nFirstRight = getUInt16BE( pTmp );
sal_uInt16 nLastRight = getUInt16BE( pTmp ) + nFirstRight -1;
// int nPairs = (int)(nLastLeft-nFirstLeft+1)*(int)(nLastRight-nFirstRight+1);
for( aPair.first = nFirstLeft; aPair.first < nLastLeft; aPair.first++ )
{
for( aPair.second = 0; aPair.second < nLastRight; aPair.second++ )
{
sal_Int16 nKern = (sal_Int16)getUInt16BE( pTmp );
switch( nCoverage & 1 )
{
case 1:
aPair.kern_x = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
m_pMetrics->m_aXKernPairs.push_back( aPair );
break;
case 0:
aPair.kern_y = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
m_pMetrics->m_aYKernPairs.push_back( aPair );
break;
}
}
}
}
break;
}
}
}
//-----------------------------------------------------------------
// Kerning: KT_APPLE_NEW
//-----------------------------------------------------------------
if( pImplTTFont->nkern && pImplTTFont->kerntype == KT_APPLE_NEW )
{
// create a glyph -> character mapping
::std::hash_map< sal_uInt16, sal_Unicode > aGlyphMap;
::std::hash_map< sal_uInt16, sal_Unicode >::iterator left, right;
for( i = 21; i < 0xfffd; i++ )
{
sal_uInt16 nGlyph = MapChar( pTTFont, (sal_Unicode)i, 0 ); // kerning for horz only
if( nGlyph != 0 )
aGlyphMap[ nGlyph ] = (sal_Unicode)i;
}
// Loop through each of the 'kern' subtables
KernPair aPair;
for( i = 0; (unsigned int)i < pImplTTFont->nkern; i++ )
{
const sal_uInt8* pTable = pImplTTFont->kerntables[i];
/*sal_uInt32 nLength =*/ getUInt32BE( pTable );
sal_uInt16 nCoverage = getUInt16BE( pTable );
/*sal_uInt16 nTupleIndex =*/ getUInt16BE( pTable );
// Get kerning type
// sal_Bool bKernVertical = nCoverage & 0x8000;
// sal_Bool bKernCrossStream = nCoverage & 0x4000;
// sal_Bool bKernVariation = nCoverage & 0x2000;
// Kerning sub-table format, 0 through 3
sal_uInt8 nSubTableFormat = nCoverage & 0x00FF;
aPair.kern_x = 0;
aPair.kern_y = 0;
switch( nSubTableFormat )
{
case 0:
{
// Grab the # of kern pairs but skip over the:
// searchRange
// entrySelector
// rangeShift
sal_uInt16 nPairs = getUInt16BE( pTable );
pTable += 6;
for( int n = 0; n < nPairs; n++ )
{
sal_uInt16 nLeftGlyph = getUInt16BE( pTable );
sal_uInt16 nRightGlyph = getUInt16BE( pTable );
sal_Int16 nKern = (sal_Int16)getUInt16BE( pTable );
left = aGlyphMap.find( nLeftGlyph );
right = aGlyphMap.find( nRightGlyph );
if( left != aGlyphMap.end() && right != aGlyphMap.end() )
{
aPair.first = left->second;
aPair.second = right->second;
// Only support horizontal kerning for now
aPair.kern_x = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
aPair.kern_y = 0;
m_pMetrics->m_aXKernPairs.push_back( aPair );
/* switch( nCoverage & 1 )
{
case 1:
aPair.kern_x = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
m_pMetrics->m_aXKernPairs.push_back( aPair );
break;
case 0:
aPair.kern_y = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
m_pMetrics->m_aYKernPairs.push_back( aPair );
break;
}
*/
}
}
}
break;
case 2:
{
const sal_uInt8* pSubTable = pTable;
/*sal_uInt16 nRowWidth =*/ getUInt16BE( pTable );
sal_uInt16 nOfLeft = getUInt16BE( pTable );
sal_uInt16 nOfRight = getUInt16BE( pTable );
/*sal_uInt16 nOfArray =*/ getUInt16BE( pTable );
const sal_uInt8* pTmp = pSubTable + nOfLeft;
sal_uInt16 nFirstLeft = getUInt16BE( pTmp );
sal_uInt16 nLastLeft = getUInt16BE( pTmp ) + nFirstLeft - 1;
pTmp = pSubTable + nOfRight;
sal_uInt16 nFirstRight = getUInt16BE( pTmp );
sal_uInt16 nLastRight = getUInt16BE( pTmp ) + nFirstRight -1;
for( aPair.first = nFirstLeft; aPair.first < nLastLeft; aPair.first++ )
{
for( aPair.second = 0; aPair.second < nLastRight; aPair.second++ )
{
sal_Int16 nKern = (sal_Int16)getUInt16BE( pTmp );
switch( nCoverage & 1 )
{
case 1:
aPair.kern_x = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
m_pMetrics->m_aXKernPairs.push_back( aPair );
break;
case 0:
aPair.kern_y = (int)nKern * 1000 / pImplTTFont->unitsPerEm;
m_pMetrics->m_aYKernPairs.push_back( aPair );
break;
}
}
}
}
break;
default:
fprintf( stderr, "Found unsupported Apple-style kern subtable type %d.\n", nSubTableFormat );
break;
}
}
}
#if OSL_DEBUG_LEVEL > 1
fprintf( stderr, "found %d/%d kern pairs for %s\n",
m_pMetrics->m_aXKernPairs.size(),
m_pMetrics->m_aYKernPairs.size(),
OUStringToOString( pProvider->getString( ATOM_FAMILYNAME, m_nFamilyName ), RTL_TEXTENCODING_MS_1252 ).getStr() );
#else
(void) pProvider; /* avoid warnings */
#endif
}
CloseTTFont( pTTFont );
bSuccess = true;
}
return bSuccess;
}
// -------------------------------------------------------------------------
/* #i73387# There seem to be fonts with a rather unwell chosen family name
* consider e.g. "Helvetica Narrow" which defines its family as "Helvetica"
* It can really only be distinguished by its PSName and FullName. Both of
* which are not user presentable in OOo. So replace it by something sensible.
*
* If other fonts feature this behaviour, insert them to the map.
*/
static bool familyNameOverride( const OUString& i_rPSname, OUString& o_rFamilyName )
{
static std::hash_map< OUString, OUString, OUStringHash > aPSNameToFamily( 16 );
if( aPSNameToFamily.empty() ) // initialization
{
aPSNameToFamily[ OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica-Narrow" ) ) ] =
OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica Narrow" ) );
aPSNameToFamily[ OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica-Narrow-Bold" ) ) ] =
OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica Narrow" ) );
aPSNameToFamily[ OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica-Narrow-BoldOblique" ) ) ] =
OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica Narrow" ) );
aPSNameToFamily[ OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica-Narrow-Oblique" ) ) ] =
OUString( RTL_CONSTASCII_USTRINGPARAM( "Helvetica Narrow" ) );
}
std::hash_map<OUString,OUString,OUStringHash>::const_iterator it =
aPSNameToFamily.find( i_rPSname );
bool bReplaced = (it != aPSNameToFamily.end() );
if( bReplaced )
o_rFamilyName = it->second;
return bReplaced;
};
bool PrintFontManager::PrintFont::readAfmMetrics( const OString& rFileName, MultiAtomProvider* pProvider, bool bFillEncodingvector, bool bOnlyGlobalAttributes )
{
PrintFontManager& rManager( PrintFontManager::get() );
int i;
FontInfo* pInfo = NULL;
parseFile( rFileName.getStr(), &pInfo, P_ALL );
if( ! pInfo || ! pInfo->numOfChars )
{
if( pInfo )
freeFontInfo( pInfo );
return false;
}
m_aEncodingVector.clear();
// fill in global info
// PSName
OUString aPSName( OStringToOUString( pInfo->gfi->fontName, RTL_TEXTENCODING_ISO_8859_1 ) );
m_nPSName = pProvider->getAtom( ATOM_PSNAME, aPSName, sal_True );
// family name (if not already set)
OUString aFamily;
if( ! m_nFamilyName )
{
aFamily = OStringToOUString( pInfo->gfi->familyName, RTL_TEXTENCODING_ISO_8859_1 );
if( ! aFamily.getLength() )
{
aFamily = OStringToOUString( pInfo->gfi->fontName, RTL_TEXTENCODING_ISO_8859_1 );
sal_Int32 nIndex = 0;
aFamily = aFamily.getToken( 0, '-', nIndex );
}
familyNameOverride( aPSName, aFamily );
m_nFamilyName = pProvider->getAtom( ATOM_FAMILYNAME, aFamily, sal_True );
}
else
aFamily = pProvider->getString( ATOM_FAMILYNAME, m_nFamilyName );
// style name: if fullname begins with family name
// interpret the rest of fullname as style
if( ! m_aStyleName.getLength() && pInfo->gfi->fullName && *pInfo->gfi->fullName )
{
OUString aFullName( OStringToOUString( pInfo->gfi->fullName, RTL_TEXTENCODING_ISO_8859_1 ) );
if( aFullName.indexOf( aFamily ) == 0 )
m_aStyleName = WhitespaceToSpace( aFullName.copy( aFamily.getLength() ) );
}
// italic
if( pInfo->gfi->italicAngle > 0 )
m_eItalic = italic::Oblique;
else if( pInfo->gfi->italicAngle < 0 )
m_eItalic = italic::Italic;
else
m_eItalic = italic::Upright;
// weight
ByteString aLowerWeight( pInfo->gfi->weight );
aLowerWeight.ToLowerAscii();
m_eWeight = parseWeight( aLowerWeight );
// pitch
m_ePitch = pInfo->gfi->isFixedPitch ? pitch::Fixed : pitch::Variable;
// encoding - only set if unknown
int nAdobeEncoding = 0;
if( pInfo->gfi->encodingScheme )
{
if( !strcmp( pInfo->gfi->encodingScheme, "AdobeStandardEncoding" ) )
nAdobeEncoding = 1;
else if( !strcmp( pInfo->gfi->encodingScheme, "ISO10646-1" ) )
{
nAdobeEncoding = 1;
m_aEncoding = RTL_TEXTENCODING_UNICODE;
}
else if( !strcmp( pInfo->gfi->encodingScheme, "Symbol") )
nAdobeEncoding = 2;
else if( !strcmp( pInfo->gfi->encodingScheme, "FontSpecific") )
nAdobeEncoding = 3;
if( m_aEncoding == RTL_TEXTENCODING_DONTKNOW )
m_aEncoding = nAdobeEncoding == 1 ?
RTL_TEXTENCODING_ADOBE_STANDARD : RTL_TEXTENCODING_SYMBOL;
}
else if( m_aEncoding == RTL_TEXTENCODING_DONTKNOW )
m_aEncoding = RTL_TEXTENCODING_ADOBE_STANDARD;
// try to parse the font name and decide wether it might be a
// japanese font. Who invented this PITA ?
OUString aPSNameLastToken( aPSName.copy( aPSName.lastIndexOf( '-' )+1 ) );
if( ! aPSNameLastToken.compareToAscii( "H" ) ||
! aPSNameLastToken.compareToAscii( "V" ) )
{
static const char* pEncs[] =
{
"EUC",
"RKSJ",
"SJ"
};
static const rtl_TextEncoding aEncs[] =
{
RTL_TEXTENCODING_EUC_JP,
RTL_TEXTENCODING_SHIFT_JIS,
RTL_TEXTENCODING_JIS_X_0208
};
for( unsigned int enc = 0; enc < sizeof( aEncs )/sizeof(aEncs[0]) && m_aEncoding == RTL_TEXTENCODING_DONTKNOW; enc++ )
{
sal_Int32 nIndex = 0, nOffset = 1;
do
{
OUString aToken( aPSName.getToken( nOffset, '-', nIndex ) );
if( nIndex == -1 )
break;
nOffset = 0;
if( ! aToken.compareToAscii( pEncs[enc] ) )
{
m_aEncoding = aEncs[ enc ];
m_bFontEncodingOnly = true;
}
} while( nIndex != -1 );
}
// default is jis
if( m_aEncoding == RTL_TEXTENCODING_DONTKNOW )
m_aEncoding = RTL_TEXTENCODING_JIS_X_0208;
#if OSL_DEBUG_LEVEL > 1
fprintf( stderr, "Encoding %d for %s\n", m_aEncoding, pInfo->gfi->fontName );
#endif
}
// hack for GB encoded builtin fonts posing as FontSpecific
if( m_eType == fonttype::Builtin && ( nAdobeEncoding == 3 || nAdobeEncoding == 0 ) )
{
int nLen = aFamily.getLength();
if( nLen > 2 &&
aFamily.getStr()[ nLen-2 ] == 'G' &&
aFamily.getStr()[ nLen-1 ] == 'B' &&
pInfo->numOfChars > 255 )
{
m_aEncoding = RTL_TEXTENCODING_GBK;
m_bFontEncodingOnly = true;
#if OSL_DEBUG_LEVEL > 1
fprintf( stderr, "found builtin font %s with GBK encoding\n", pInfo->gfi->fontName );
#endif
}
}
// #i37313# check if Fontspecific is not rather some character encoding
if( nAdobeEncoding == 3 && m_aEncoding == RTL_TEXTENCODING_SYMBOL )
{
bool bYFound = false;
bool bQFound = false;
CharMetricInfo* pChar = pInfo->cmi;
for( int j = 0; j < pInfo->numOfChars && ! (bYFound && bQFound); j++ )
{
if( pChar[j].name )
{
if( pChar[j].name[0] == 'Y' && pChar[j].name[1] == 0 )
bYFound = true;
else if( pChar[j].name[0] == 'Q' && pChar[j].name[1] == 0 )
bQFound = true;
}
}
if( bQFound && bYFound )
{
#if OSL_DEBUG_LEVEL > 1
fprintf( stderr, "setting FontSpecific font %s (file %s) to unicode\n",
pInfo->gfi->fontName,
rFileName.getStr()
);
#endif
nAdobeEncoding = 4;
m_aEncoding = RTL_TEXTENCODING_UNICODE;
bFillEncodingvector = false; // will be filled anyway, don't do the work twice
}
}
// ascend
m_nAscend = pInfo->gfi->fontBBox.ury;
// descend
// descends have opposite sign of our definition
m_nDescend = -pInfo->gfi->fontBBox.lly;
// fallback to ascender, descender
// interesting: the BBox seems to describe Ascender and Descender better
// as we understand it
if( m_nAscend == 0 )
m_nAscend = pInfo->gfi->ascender;
if( m_nDescend == 0)
m_nDescend = -pInfo->gfi->descender;
m_nLeading = m_nAscend + m_nDescend - 1000;
if( m_pMetrics )
delete m_pMetrics;
m_pMetrics = new PrintFontMetrics;
// mark all pages as queried (or clear if only global font info queiried)
memset( m_pMetrics->m_aPages, bOnlyGlobalAttributes ? 0 : 0xff, sizeof( m_pMetrics->m_aPages ) );
m_aGlobalMetricX.width = m_aGlobalMetricY.width =
pInfo->gfi->charwidth ? pInfo->gfi->charwidth : pInfo->gfi->fontBBox.urx;
m_aGlobalMetricX.height = m_aGlobalMetricY.height =
pInfo->gfi->capHeight ? pInfo->gfi->capHeight : pInfo->gfi->fontBBox.ury;
m_nXMin = pInfo->gfi->fontBBox.llx;
m_nYMin = pInfo->gfi->fontBBox.lly;
m_nXMax = pInfo->gfi->fontBBox.urx;
m_nYMax = pInfo->gfi->fontBBox.ury;
if( bFillEncodingvector || !bOnlyGlobalAttributes )
{
// fill in character metrics
// first transform the character codes to unicode
// note: this only works with single byte encodings
sal_Unicode* pUnicodes = (sal_Unicode*)alloca( pInfo->numOfChars * sizeof(sal_Unicode));
CharMetricInfo* pChar = pInfo->cmi;
for( i = 0; i < pInfo->numOfChars; i++, pChar++ )
{
if( nAdobeEncoding == 4 )
{
if( pChar->name )
{
pUnicodes[i] = 0;
std::list< sal_Unicode > aCodes = rManager.getUnicodeFromAdobeName( pChar->name );
for( std::list< sal_Unicode >::const_iterator it = aCodes.begin(); it != aCodes.end(); ++it )
{
if( *it != 0 )
{
m_aEncodingVector[ *it ] = pChar->code;
if( pChar->code == -1 )
m_aNonEncoded[ *it ] = pChar->name;
if( ! pUnicodes[i] ) // map the first
pUnicodes[i] = *it;
}
}
}
}
else if( pChar->code != -1 )
{
if( nAdobeEncoding == 3 && m_aEncoding == RTL_TEXTENCODING_SYMBOL )
{
pUnicodes[i] = pChar->code + 0xf000;
if( bFillEncodingvector )
m_aEncodingVector[ pUnicodes[i] ] = pChar->code;
continue;
}
if( m_aEncoding == RTL_TEXTENCODING_UNICODE )
{
pUnicodes[i] = (sal_Unicode)pChar->code;
continue;
}
ByteString aTranslate;
if( pChar->code & 0xff000000 )
aTranslate += (char)(pChar->code >> 24 );
if( pChar->code & 0xffff0000 )
aTranslate += (char)((pChar->code & 0x00ff0000) >> 16 );
if( pChar->code & 0xffffff00 )
aTranslate += (char)((pChar->code & 0x0000ff00) >> 8 );
aTranslate += (char)(pChar->code & 0xff);
String aUni( aTranslate, m_aEncoding );
pUnicodes[i] = *aUni.GetBuffer();
}
else
pUnicodes[i] = 0;
}
// now fill in the character metrics
// parseAFM.cxx effectively only supports direction 0 (horizontal)
pChar = pInfo->cmi;
CharacterMetric aMetric;
for( i = 0; i < pInfo->numOfChars; i++, pChar++ )
{
if( pChar->code == -1 && ! pChar->name )
continue;
if( bFillEncodingvector && pChar->name )
{
std::list< sal_Unicode > aCodes = rManager.getUnicodeFromAdobeName( pChar->name );
for( std::list< sal_Unicode >::const_iterator it = aCodes.begin(); it != aCodes.end(); ++it )
{
if( *it != 0 )
{
m_aEncodingVector[ *it ] = pChar->code;
if( pChar->code == -1 )
m_aNonEncoded[ *it ] = pChar->name;
}
}
}
aMetric.width = pChar->wx ? pChar->wx : pChar->charBBox.urx;
aMetric.height = pChar->wy ? pChar->wy : pChar->charBBox.ury - pChar->charBBox.lly;
if( aMetric.width == 0 && aMetric.height == 0 )
// guess something for e.g. space
aMetric.width = m_aGlobalMetricX.width/4;
if( ( nAdobeEncoding == 0 ) ||
( ( nAdobeEncoding == 3 ) && ( m_aEncoding != RTL_TEXTENCODING_SYMBOL ) ) )
{
if( pChar->code != -1 )
{
m_pMetrics->m_aMetrics[ pUnicodes[i] ] = aMetric;
if( bFillEncodingvector )
m_aEncodingVector[ pUnicodes[i] ] = pChar->code;
}
else if( pChar->name )
{
std::list< sal_Unicode > aCodes = rManager.getUnicodeFromAdobeName( pChar->name );
for( std::list< sal_Unicode >::const_iterator it = aCodes.begin(); it != aCodes.end(); ++it )
{
if( *it != 0 )
m_pMetrics->m_aMetrics[ *it ] = aMetric;
}
}
}
else if( nAdobeEncoding == 1 || nAdobeEncoding == 2 || nAdobeEncoding == 4)
{
if( pChar->name )
{
std::list< sal_Unicode > aCodes = rManager.getUnicodeFromAdobeName( pChar->name );
for( std::list< sal_Unicode >::const_iterator it = aCodes.begin(); it != aCodes.end(); ++it )
{
if( *it != 0 )
m_pMetrics->m_aMetrics[ *it ] = aMetric;
}
}
else if( pChar->code != -1 )
{
::std::pair< ::std::hash_multimap< sal_uInt8, sal_Unicode >::const_iterator,
::std::hash_multimap< sal_uInt8, sal_Unicode >::const_iterator >
aCodes = rManager.getUnicodeFromAdobeCode( pChar->code );
while( aCodes.first != aCodes.second )
{
if( (*aCodes.first).second != 0 )
{
m_pMetrics->m_aMetrics[ (*aCodes.first).second ] = aMetric;
if( bFillEncodingvector )
m_aEncodingVector[ (*aCodes.first).second ] = pChar->code;
}
++aCodes.first;
}
}
}
else if( nAdobeEncoding == 3 )
{
if( pChar->code != -1 )
{
sal_Unicode code = 0xf000 + pChar->code;
m_pMetrics->m_aMetrics[ code ] = aMetric;
// maybe should try to find the name in the convtabs ?
if( bFillEncodingvector )
m_aEncodingVector[ code ] = pChar->code;
}
}
}
m_pMetrics->m_aXKernPairs.clear();
m_pMetrics->m_aYKernPairs.clear();
// now fill in the kern pairs
// parseAFM.cxx effectively only supports direction 0 (horizontal)
PairKernData* pKern = pInfo->pkd;
KernPair aPair;
for( i = 0; i < pInfo->numOfPairs; i++, pKern++ )
{
// #i37703# broken kern table
if( ! pKern->name1 || ! pKern->name2 )
continue;
aPair.first = 0;
aPair.second = 0;
// currently we have to find the adobe character names
// in the already parsed character metrics to find
// the corresponding UCS2 code which is a bit dangerous
// since the character names are not required
// in the metric descriptions
pChar = pInfo->cmi;
for( int j = 0;
j < pInfo->numOfChars && ( aPair.first == 0 || aPair.second == 0 );
j++, pChar++ )
{
if( pChar->code != -1 )
{
if( ! strcmp( pKern->name1, pChar->name ? pChar->name : "" ) )
aPair.first = pUnicodes[ j ];
if( ! strcmp( pKern->name2, pChar->name ? pChar->name : "" ) )
aPair.second = pUnicodes[ j ];
}
}
if( aPair.first && aPair.second )
{
aPair.kern_x = pKern->xamt;
aPair.kern_y = pKern->yamt;
m_pMetrics->m_aXKernPairs.push_back( aPair );
}
}
m_pMetrics->m_bKernPairsQueried = true;
}
freeFontInfo( pInfo );
return true;
}
// -------------------------------------------------------------------------
OString PrintFontManager::s_aEmptyOString;
/*
* one instance only
*/
PrintFontManager& PrintFontManager::get()
{
static PrintFontManager* theManager = NULL;
if( ! theManager )
{
theManager = new PrintFontManager();
theManager->initialize();
}
return *theManager;
}
// -------------------------------------------------------------------------
/*
* the PrintFontManager
*/
PrintFontManager::PrintFontManager() :
m_nNextFontID( 1 ),
m_pAtoms( new MultiAtomProvider() ),
m_nNextDirAtom( 1 ),
m_pFontCache( NULL ),
m_bFontconfigSuccess( false )
{
for( unsigned int i = 0; i < sizeof( aAdobeCodes )/sizeof( aAdobeCodes[0] ); i++ )
{
m_aUnicodeToAdobename.insert( ::std::hash_multimap< sal_Unicode, ::rtl::OString >::value_type( aAdobeCodes[i].aUnicode, aAdobeCodes[i].pAdobename ) );
m_aAdobenameToUnicode.insert( ::std::hash_multimap< ::rtl::OString, sal_Unicode, ::rtl::OStringHash >::value_type( aAdobeCodes[i].pAdobename, aAdobeCodes[i].aUnicode ) );
if( aAdobeCodes[i].aAdobeStandardCode )
{
m_aUnicodeToAdobecode.insert( ::std::hash_multimap< sal_Unicode, sal_uInt8 >::value_type( aAdobeCodes[i].aUnicode, aAdobeCodes[i].aAdobeStandardCode ) );
m_aAdobecodeToUnicode.insert( ::std::hash_multimap< sal_uInt8, sal_Unicode >::value_type( aAdobeCodes[i].aAdobeStandardCode, aAdobeCodes[i].aUnicode ) );
}
#if 0
m_aUnicodeToAdobename[ aAdobeCodes[i].aUnicode ] = aAdobeCodes[i].pAdobename;
m_aAdobenameToUnicode[ aAdobeCodes[i].pAdobename ] = aAdobeCodes[i].aUnicode;
if( aAdobeCodes[i].aAdobeStandardCode )
{
m_aUnicodeToAdobecode[ aAdobeCodes[i].aUnicode ] = aAdobeCodes[i].aAdobeStandardCode;
m_aAdobecodeToUnicode[ aAdobeCodes[i].aAdobeStandardCode ] = aAdobeCodes[i].aUnicode;
}
#endif
}
}
// -------------------------------------------------------------------------
PrintFontManager::~PrintFontManager()
{
deinitFontconfig();
for( ::std::hash_map< fontID, PrintFont* >::const_iterator it = m_aFonts.begin(); it != m_aFonts.end(); ++it )
delete (*it).second;
delete m_pAtoms;
if( m_pFontCache )
delete m_pFontCache;
}
// -------------------------------------------------------------------------
const OString& PrintFontManager::getDirectory( int nAtom ) const
{
::std::hash_map< int, OString >::const_iterator it( m_aAtomToDir.find( nAtom ) );
return it != m_aAtomToDir.end() ? it->second : s_aEmptyOString;
}
// -------------------------------------------------------------------------
int PrintFontManager::getDirectoryAtom( const OString& rDirectory, bool bCreate )
{
int nAtom = 0;
::std::hash_map< OString, int, OStringHash >::const_iterator it
( m_aDirToAtom.find( rDirectory ) );
if( it != m_aDirToAtom.end() )
nAtom = it->second;
else if( bCreate )
{
nAtom = m_nNextDirAtom++;
m_aDirToAtom[ rDirectory ] = nAtom;
m_aAtomToDir[ nAtom ] = rDirectory;
}
return nAtom;
}
// -------------------------------------------------------------------------
int PrintFontManager::addFontFile( const ::rtl::OString& rFileName, int /*nFaceNum*/ )
{
rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
INetURLObject aPath( OStringToOUString( rFileName, aEncoding ), INET_PROT_FILE, INetURLObject::ENCODE_ALL );
OString aName( OUStringToOString( aPath.GetName(), aEncoding ) );
OString aDir( OUStringToOString( aPath.GetPath(), aEncoding ) );
int nDirID = getDirectoryAtom( aDir, true );
fontID nFontId = findFontFileID( nDirID, aName );
if( !nFontId )
{
::std::list< PrintFont* > aNewFonts;
if( analyzeFontFile( nDirID, aName, ::std::list<OString>(), aNewFonts ) )
{
for( ::std::list< PrintFont* >::iterator it = aNewFonts.begin();
it != aNewFonts.end(); ++it )
{
m_aFonts[ nFontId = m_nNextFontID++ ] = *it;
m_aFontFileToFontID[ aName ].insert( nFontId );
m_pFontCache->updateFontCacheEntry( *it, true );
}
}
}
return nFontId;
}
// -------------------------------------------------------------------------
bool PrintFontManager::analyzeFontFile( int nDirID, const OString& rFontFile, const ::std::list<OString>& rXLFDs, ::std::list< PrintFontManager::PrintFont* >& rNewFonts ) const
{
rNewFonts.clear();
OString aDir( getDirectory( nDirID ) );
OString aFullPath( aDir );
aFullPath += "/";
aFullPath += rFontFile;
// #i1872# reject unreadable files
if( access( aFullPath.getStr(), R_OK ) )
return false;
ByteString aExt( rFontFile.copy( rFontFile.lastIndexOf( '.' )+1 ) );
if( aExt.EqualsIgnoreCaseAscii( "pfb" ) || aExt.EqualsIgnoreCaseAscii( "pfa" ) )
{
// check for corresponding afm metric
// first look for an adjacent file
static const char* pSuffix[] = { ".afm", ".AFM" };
for( unsigned int i = 0; i < sizeof(pSuffix)/sizeof(pSuffix[0]); i++ )
{
ByteString aName( rFontFile );
aName.Erase( aName.Len()-4 );
aName.Append( pSuffix[i] );
ByteString aFilePath( aDir );
aFilePath.Append( '/' );
aFilePath.Append( aName );
ByteString aAfmFile;
if( access( aFilePath.GetBuffer(), R_OK ) )
{
// try in subdirectory afm instead
aFilePath = aDir;
aFilePath.Append( "/afm/" );
aFilePath.Append( aName );
if( ! access( aFilePath.GetBuffer(), R_OK ) )
{
aAfmFile = "afm/";
aAfmFile += aName;
}
}
else
aAfmFile = aName;
if( aAfmFile.Len() )
{
Type1FontFile* pFont = new Type1FontFile();
pFont->m_nDirectory = nDirID;
pFont->m_aFontFile = rFontFile;
pFont->m_aMetricFile = aAfmFile;
if( ! pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, false, true ) )
{
delete pFont;
pFont = NULL;
}
if( pFont && rXLFDs.size() )
getFontAttributesFromXLFD( pFont, rXLFDs );
if( pFont )
rNewFonts.push_back( pFont );
break;
}
}
}
else if( aExt.EqualsIgnoreCaseAscii( "afm" ) )
{
ByteString aFilePath( aDir );
aFilePath.Append( '/' );
aFilePath.Append( ByteString( rFontFile ) );
BuiltinFont* pFont = new BuiltinFont();
pFont->m_nDirectory = nDirID;
pFont->m_aMetricFile = rFontFile;
if( pFont->readAfmMetrics( aFilePath, m_pAtoms, false, true ) )
rNewFonts.push_back( pFont );
else
delete pFont;
}
else if( aExt.EqualsIgnoreCaseAscii( "ttf" )
|| aExt.EqualsIgnoreCaseAscii( "tte" ) // #i33947# for Gaiji support
|| aExt.EqualsIgnoreCaseAscii( "otf" ) ) // check for TTF- and PS-OpenType too
{
TrueTypeFontFile* pFont = new TrueTypeFontFile();
pFont->m_nDirectory = nDirID;
pFont->m_aFontFile = rFontFile;
pFont->m_nCollectionEntry = -1;
if( rXLFDs.size() )
getFontAttributesFromXLFD( pFont, rXLFDs );
// need to read the font anyway to get aliases inside the font file
if( ! analyzeTrueTypeFile( pFont ) )
{
delete pFont;
pFont = NULL;
}
else
rNewFonts.push_back( pFont );
}
else if( aExt.EqualsIgnoreCaseAscii( "ttc" ) )
{
// get number of ttc entries
int nLength = CountTTCFonts( aFullPath.getStr() );
if( nLength )
{
#if OSL_DEBUG_LEVEL > 1
fprintf( stderr, "%s contains %d fonts\n", aFullPath.getStr(), nLength );
#endif
for( int i = 0; i < nLength; i++ )
{
TrueTypeFontFile* pFont = new TrueTypeFontFile();
pFont->m_nDirectory = nDirID;
pFont->m_aFontFile = rFontFile;
pFont->m_nCollectionEntry = i;
if( nLength == 1 )
getFontAttributesFromXLFD( pFont, rXLFDs );
if( ! analyzeTrueTypeFile( pFont ) )
{
delete pFont;
pFont = NULL;
}
else
rNewFonts.push_back( pFont );
}
}
#if OSL_DEBUG_LEVEL > 1
else
fprintf( stderr, "CountTTCFonts( \"%s/%s\" ) failed\n", getDirectory(nDirID).getStr(), rFontFile.getStr() );
#endif
}
return ! rNewFonts.empty();
}
// -------------------------------------------------------------------------
fontID PrintFontManager::findFontBuiltinID( int nPSNameAtom ) const
{
fontID nID = 0;
::std::hash_map< fontID, PrintFont* >::const_iterator it;
for( it = m_aFonts.begin(); nID == 0 && it != m_aFonts.end(); ++it )
{
if( it->second->m_eType == fonttype::Builtin &&
it->second->m_nPSName == nPSNameAtom )
nID = it->first;
}
return nID;
}
// -------------------------------------------------------------------------
fontID PrintFontManager::findFontFileID( int nDirID, const OString& rFontFile ) const
{
fontID nID = 0;
::std::hash_map< OString, ::std::set< fontID >, OStringHash >::const_iterator set_it = m_aFontFileToFontID.find( rFontFile );
if( set_it != m_aFontFileToFontID.end() )
{
for( ::std::set< fontID >::const_iterator font_it = set_it->second.begin(); font_it != set_it->second.end() && ! nID; ++font_it )
{
::std::hash_map< fontID, PrintFont* >::const_iterator it = m_aFonts.find( *font_it );
if( it != m_aFonts.end() )
{
switch( it->second->m_eType )
{
case fonttype::Type1:
{
Type1FontFile* const pFont = static_cast< Type1FontFile* const >((*it).second);
if( pFont->m_nDirectory == nDirID &&
pFont->m_aFontFile == rFontFile )
nID = it->first;
}
break;
case fonttype::TrueType:
{
TrueTypeFontFile* const pFont = static_cast< TrueTypeFontFile* const >((*it).second);
if( pFont->m_nDirectory == nDirID &&
pFont->m_aFontFile == rFontFile )
nID = it->first;
}
break;
case fonttype::Builtin:
if( static_cast<const BuiltinFont*>((*it).second)->m_nDirectory == nDirID &&
static_cast<const BuiltinFont*>((*it).second)->m_aMetricFile == rFontFile )
nID = it->first;
break;
default:
break;
}
}
}
}
return nID;
}
// -------------------------------------------------------------------------
bool PrintFontManager::parseXLFD( const OString& rXLFD, XLFDEntry& rEntry )
{
sal_Int32 nIndex = 0;
OString aFoundry = WhitespaceToSpace( rXLFD.getToken( 1, '-', nIndex ) );
if( nIndex < 0 ) return false;
OString aFamilyXLFD = WhitespaceToSpace( rXLFD.getToken( 0, '-', nIndex ) );
if( nIndex < 0 ) return false;
OString aWeight = rXLFD.getToken( 0, '-', nIndex ).toAsciiLowerCase();
if( nIndex < 0 ) return false;
OString aSlant = rXLFD.getToken( 0, '-', nIndex ).toAsciiLowerCase();
if( nIndex < 0 ) return false;
OString aWidth = rXLFD.getToken( 0, '-', nIndex ).toAsciiLowerCase();
if( nIndex < 0 ) return false;
OString aAddStyle = rXLFD.getToken( 0, '-', nIndex ).toAsciiLowerCase();
if( nIndex < 0 ) return false;
OString aPitch = rXLFD.getToken( 4, '-', nIndex ).toAsciiLowerCase();
if( nIndex < 0 ) return false;
OString aRegEnc = WhitespaceToSpace( rXLFD.getToken( 1, '-', nIndex ).toAsciiLowerCase() );
if( nIndex < 0 ) return false;
OString aEnc = WhitespaceToSpace( rXLFD.getToken( 0, '-', nIndex ).toAsciiLowerCase() );
// capitalize words
sal_Int32 nFamIndex = 0;
OStringBuffer aFamilyName;
while( nFamIndex >= 0 )
{
OString aToken = aFamilyXLFD.getToken( 0, ' ', nFamIndex );
sal_Char aFirst = aToken.toChar();
if( aFirst >= 'a' && aFirst <= 'z' )
aFirst = aFirst - 'a' + 'A';
OStringBuffer aNewToken( aToken.getLength() );
aNewToken.append( aToken );
aNewToken.setCharAt( 0, aFirst );
if( aFamilyName.getLength() > 0 )
aFamilyName.append( ' ' );
aFamilyName.append( aNewToken.makeStringAndClear() );
}
rEntry.aFoundry = aFoundry;
rEntry.aFamily = aFamilyName.makeStringAndClear();
rEntry.aAddStyle = aAddStyle;
// evaluate weight
rEntry.eWeight = parseWeight( aWeight );
// evaluate slant
rEntry.eItalic = parseItalic( aSlant );
// evaluate width
rEntry.eWidth = parseWidth( aWidth );
// evaluate pitch
if( aPitch.toChar() == 'c' || aPitch.toChar() == 'm' )
rEntry.ePitch = pitch::Fixed;
else
rEntry.ePitch = pitch::Variable;
OString aToken = aEnc.toAsciiLowerCase();
// get encoding
if( aAddStyle.indexOf( "symbol" ) != -1 )
rEntry.aEncoding = RTL_TEXTENCODING_SYMBOL;
else
{
if( aToken.equals( "symbol" ) )
rEntry.aEncoding = RTL_TEXTENCODING_SYMBOL;
else
{
OStringBuffer aCharset( aRegEnc.getLength() + aEnc.getLength() + 1 );
aCharset.append( aRegEnc );
aCharset.append( '-' );
aCharset.append( aEnc );
rEntry.aEncoding = rtl_getTextEncodingFromUnixCharset( aCharset.getStr() );
}
}
// set correct mask flags
rEntry.nMask = 0;
if( rEntry.aFoundry != "*" ) rEntry.nMask |= XLFDEntry::MaskFoundry;
if( rEntry.aFamily != "*" ) rEntry.nMask |= XLFDEntry::MaskFamily;
if( rEntry.aAddStyle != "*" ) rEntry.nMask |= XLFDEntry::MaskAddStyle;
if( aWeight != "*" ) rEntry.nMask |= XLFDEntry::MaskWeight;
if( aSlant != "*" ) rEntry.nMask |= XLFDEntry::MaskItalic;
if( aWidth != "*" ) rEntry.nMask |= XLFDEntry::MaskWidth;
if( aPitch != "*" ) rEntry.nMask |= XLFDEntry::MaskPitch;
if( aRegEnc != "*" && aEnc != "*" ) rEntry.nMask |= XLFDEntry::MaskEncoding;
return true;
}
// -------------------------------------------------------------------------
void PrintFontManager::parseXLFD_appendAliases( const std::list< OString >& rXLFDs, std::list< XLFDEntry >& rEntries ) const
{
for( std::list< OString >::const_iterator it = rXLFDs.begin(); it != rXLFDs.end(); ++it )
{
XLFDEntry aEntry;
if( ! parseXLFD(*it, aEntry) )
continue;
rEntries.push_back( aEntry );
std::map< XLFDEntry, std::list< XLFDEntry > >::const_iterator alias_it =
m_aXLFD_Aliases.find( aEntry );
if( alias_it != m_aXLFD_Aliases.end() )
{
rEntries.insert( rEntries.end(), alias_it->second.begin(), alias_it->second.end() );
}
}
}
// -------------------------------------------------------------------------
void PrintFontManager::getFontAttributesFromXLFD( PrintFont* pFont, const std::list< OString >& rXLFDs ) const
{
bool bFamilyName = false;
std::list< XLFDEntry > aXLFDs;
parseXLFD_appendAliases( rXLFDs, aXLFDs );
for( std::list< XLFDEntry >::const_iterator it = aXLFDs.begin();
it != aXLFDs.end(); ++it )
{
// set family name or alias
int nFam =
m_pAtoms->getAtom( ATOM_FAMILYNAME,
OStringToOUString( it->aFamily, it->aAddStyle.indexOf( "utf8" ) != -1 ? RTL_TEXTENCODING_UTF8 : RTL_TEXTENCODING_ISO_8859_1 ),
sal_True );
if( ! bFamilyName )
{
bFamilyName = true;
pFont->m_nFamilyName = nFam;
switch( pFont->m_eType )
{
case fonttype::Type1:
static_cast<Type1FontFile*>(pFont)->m_aXLFD = rXLFDs.front();
break;
case fonttype::TrueType:
static_cast<TrueTypeFontFile*>(pFont)->m_aXLFD = rXLFDs.front();
break;
default:
break;
}
}
else
{
// make sure that aliases are unique
if( nFam != pFont->m_nFamilyName )
{
std::list< int >::const_iterator al_it;
for( al_it = pFont->m_aAliases.begin(); al_it != pFont->m_aAliases.end() && *al_it != nFam; ++al_it )
;
if( al_it == pFont->m_aAliases.end() )
pFont->m_aAliases.push_back( nFam );
}
// for the rest of the attributes there can only be one value;
// we'll trust the first one
continue;
}
// fill in weight
pFont->m_eWeight = it->eWeight;
// fill in slant
pFont->m_eItalic = it->eItalic;
// fill in width
pFont->m_eWidth = it->eWidth;
// fill in pitch
pFont->m_ePitch = it->ePitch;
// fill in encoding
pFont->m_aEncoding = it->aEncoding;
}
// handle iso8859-1 as ms1252 to fill the "gap" starting at 0x80
if( pFont->m_aEncoding == RTL_TEXTENCODING_ISO_8859_1 )
pFont->m_aEncoding = RTL_TEXTENCODING_MS_1252;
if( rXLFDs.begin() != rXLFDs.end() )
{
switch( pFont->m_eType )
{
case fonttype::Type1:
static_cast<Type1FontFile*>(pFont)->m_aXLFD = rXLFDs.front();
break;
case fonttype::TrueType:
static_cast<TrueTypeFontFile*>(pFont)->m_aXLFD = rXLFDs.front();
break;
default: break;
}
}
}
// -------------------------------------------------------------------------
OString PrintFontManager::getXLFD( PrintFont* pFont ) const
{
if( pFont->m_eType == fonttype::Type1 )
{
if( static_cast<Type1FontFile*>(pFont)->m_aXLFD.getLength() )
return static_cast<Type1FontFile*>(pFont)->m_aXLFD;
}
if( pFont->m_eType == fonttype::TrueType )
{
if( static_cast<TrueTypeFontFile*>(pFont)->m_aXLFD.getLength() )
return static_cast<TrueTypeFontFile*>(pFont)->m_aXLFD;
}
OStringBuffer aXLFD( 128 );
aXLFD.append( "-misc-" );
ByteString aFamily( String( m_pAtoms->getString( ATOM_FAMILYNAME, pFont->m_nFamilyName ) ), RTL_TEXTENCODING_UTF8 );
aFamily.SearchAndReplaceAll( '-',' ' );
aFamily.SearchAndReplaceAll( '?',' ' );
aFamily.SearchAndReplaceAll( '*',' ' );
aXLFD.append( OString( aFamily ) );
aXLFD.append( '-' );
switch( pFont->m_eWeight )
{
case weight::Thin: aXLFD.append("thin");break;
case weight::UltraLight: aXLFD.append("ultralight");break;
case weight::Light: aXLFD.append("light");break;
case weight::SemiLight: aXLFD.append("semilight");break;
case weight::Normal: aXLFD.append("normal");break;
case weight::Medium: aXLFD.append("medium");break;
case weight::SemiBold: aXLFD.append("semibold");break;
case weight::Bold: aXLFD.append("bold");break;
case weight::UltraBold: aXLFD.append("ultrabold");break;
case weight::Black: aXLFD.append("black");break;
default: break;
}
aXLFD.append('-');
switch( pFont->m_eItalic )
{
case italic::Upright: aXLFD.append('r');break;
case italic::Oblique: aXLFD.append('o');break;
case italic::Italic: aXLFD.append('i');break;
default: break;
}
aXLFD.append('-');
switch( pFont->m_eWidth )
{
case width::UltraCondensed: aXLFD.append("ultracondensed");break;
case width::ExtraCondensed: aXLFD.append("extracondensed");break;
case width::Condensed: aXLFD.append("condensed");break;
case width::SemiCondensed: aXLFD.append("semicondensed");break;
case width::Normal: aXLFD.append("normal");break;
case width::SemiExpanded: aXLFD.append("semiexpanded");break;
case width::Expanded: aXLFD.append("expanded");break;
case width::ExtraExpanded: aXLFD.append("extraexpanded");break;
case width::UltraExpanded: aXLFD.append("ultraexpanded");break;
default: break;
}
aXLFD.append("-utf8-0-0-0-0-");
aXLFD.append( pFont->m_ePitch == pitch::Fixed ? "m" : "p" );
aXLFD.append("-0-");
const char* pEnc = rtl_getBestUnixCharsetFromTextEncoding( pFont->m_aEncoding );
if( ! pEnc )
{
if( pFont->m_aEncoding == RTL_TEXTENCODING_ADOBE_STANDARD )
pEnc = "adobe-standard";
else
pEnc = "iso8859-1";
}
aXLFD .append( pEnc );
return aXLFD.makeStringAndClear();
}
// -------------------------------------------------------------------------
OUString PrintFontManager::convertTrueTypeName( void* pRecord ) const
{
NameRecord* pNameRecord = (NameRecord*)pRecord;
OUString aValue;
if(
( pNameRecord->platformID == 3 && ( pNameRecord->encodingID == 0 || pNameRecord->encodingID == 1 ) ) // MS, Unicode
||
( pNameRecord->platformID == 0 ) // Apple, Unicode
)
{
OUStringBuffer aName( pNameRecord->slen/2 );
const sal_uInt8* pNameBuffer = pNameRecord->sptr;
for(int n = 0; n < pNameRecord->slen/2; n++ )
aName.append( (sal_Unicode)getUInt16BE( pNameBuffer ) );
aValue = aName.makeStringAndClear();
}
else if( pNameRecord->platformID == 3 )
{
if( pNameRecord->encodingID >= 2 && pNameRecord->encodingID <= 6 )
{
/*
* and now for a special kind of madness:
* some fonts encode their byte value string as BE uint16
* (leading to stray zero bytes in the string)
* while others code two bytes as a uint16 and swap to BE
*/
OStringBuffer aName;
const sal_uInt8* pNameBuffer = pNameRecord->sptr;
for(int n = 0; n < pNameRecord->slen/2; n++ )
{
sal_Unicode aCode = (sal_Unicode)getUInt16BE( pNameBuffer );
sal_Char aChar = aCode >> 8;
if( aChar )
aName.append( aChar );
aChar = aCode & 0x00ff;
if( aChar )
aName.append( aChar );
}
switch( pNameRecord->encodingID )
{
case 2:
aValue = OStringToOUString( aName.makeStringAndClear(), RTL_TEXTENCODING_MS_932 );
break;
case 3:
aValue = OStringToOUString( aName.makeStringAndClear(), RTL_TEXTENCODING_MS_936 );
break;
case 4:
aValue = OStringToOUString( aName.makeStringAndClear(), RTL_TEXTENCODING_MS_950 );
break;
case 5:
aValue = OStringToOUString( aName.makeStringAndClear(), RTL_TEXTENCODING_MS_949 );
break;
case 6:
aValue = OStringToOUString( aName.makeStringAndClear(), RTL_TEXTENCODING_MS_1361 );
break;
}
}
}
return aValue;
}
// -------------------------------------------------------------------------
void PrintFontManager::analyzeTrueTypeFamilyName( void* pTTFont, ::std::list< OUString >& rNames ) const
{
OUString aFamily;
rNames.clear();
::std::set< OUString > aSet;
NameRecord* pNameRecords = NULL;
int nNameRecords = GetTTNameRecords( (TrueTypeFont*)pTTFont, &pNameRecords );
if( nNameRecords && pNameRecords )
{
LanguageType aLang = MsLangId::getSystemLanguage();
int nLastMatch = -1;
for( int i = 0; i < nNameRecords; i++ )
{
if( pNameRecords[i].nameID != 1 || pNameRecords[i].sptr == NULL )
continue;
int nMatch = -1;
if( pNameRecords[i].platformID == 0 ) // Unicode
nMatch = 4000;
else if( pNameRecords[i].platformID == 3 )
{
// this bases on the LanguageType actually being a Win LCID
if( pNameRecords[i].languageID == aLang )
nMatch = 8000;
else if( pNameRecords[i].languageID == LANGUAGE_ENGLISH_US )
nMatch = 2000;
else if( pNameRecords[i].languageID == LANGUAGE_ENGLISH ||
pNameRecords[i].languageID == LANGUAGE_ENGLISH_UK )
nMatch = 1500;
else
nMatch = 1000;
}
OUString aName = convertTrueTypeName( pNameRecords + i );
aSet.insert( aName );
if( nMatch > nLastMatch )
{
nLastMatch = nMatch;
aFamily = aName;
}
}
DisposeNameRecords( pNameRecords, nNameRecords );
}
if( aFamily.getLength() )
{
rNames.push_front( aFamily );
for( ::std::set< OUString >::const_iterator it = aSet.begin(); it != aSet.end(); ++it )
if( *it != aFamily )
rNames.push_back( *it );
}
return;
}
// -------------------------------------------------------------------------
bool PrintFontManager::analyzeTrueTypeFile( PrintFont* pFont ) const
{
bool bSuccess = false;
rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
ByteString aFile = getFontFile( pFont );
TrueTypeFont* pTTFont = NULL;
TrueTypeFontFile* pTTFontFile = static_cast< TrueTypeFontFile* >(pFont);
if( OpenTTFontFile( aFile.GetBuffer(), pTTFontFile->m_nCollectionEntry < 0 ? 0 : pTTFontFile->m_nCollectionEntry, &pTTFont ) == SF_OK )
{
TTGlobalFontInfo aInfo;
GetTTGlobalFontInfo( pTTFont, & aInfo );
::std::list< OUString > aNames;
analyzeTrueTypeFamilyName( pTTFont, aNames );
// set family name from XLFD if possible
if( ! pFont->m_nFamilyName )
{
if( aNames.begin() != aNames.end() )
{
pFont->m_nFamilyName = m_pAtoms->getAtom( ATOM_FAMILYNAME, aNames.front(), sal_True );
aNames.pop_front();
}
else
{
sal_Int32 dotIndex;
// poor font does not have a family name
// name it to file name minus the extension
dotIndex = pTTFontFile->m_aFontFile.lastIndexOf( '.' );
if ( dotIndex == -1 )
dotIndex = pTTFontFile->m_aFontFile.getLength();
pFont->m_nFamilyName = m_pAtoms->getAtom( ATOM_FAMILYNAME, OStringToOUString( pTTFontFile->m_aFontFile.copy( 0, dotIndex ), aEncoding ), sal_True );
}
}
for( ::std::list< OUString >::iterator it = aNames.begin(); it != aNames.end(); ++it )
{
if( it->getLength() )
{
int nAlias = m_pAtoms->getAtom( ATOM_FAMILYNAME, *it, sal_True );
if( nAlias != pFont->m_nFamilyName )
{
std::list< int >::const_iterator al_it;
for( al_it = pFont->m_aAliases.begin(); al_it != pFont->m_aAliases.end() && *al_it != nAlias; ++al_it )
;
if( al_it == pFont->m_aAliases.end() )
pFont->m_aAliases.push_back( nAlias );
}
}
}
if( aInfo.usubfamily )
pFont->m_aStyleName = OUString( aInfo.usubfamily );
pFont->m_nPSName = m_pAtoms->getAtom( ATOM_PSNAME, String( ByteString( aInfo.psname ), aEncoding ), sal_True );
switch( aInfo.weight )
{
case FW_THIN: pFont->m_eWeight = weight::Thin; break;
case FW_EXTRALIGHT: pFont->m_eWeight = weight::UltraLight; break;
case FW_LIGHT: pFont->m_eWeight = weight::Light; break;
case FW_MEDIUM: pFont->m_eWeight = weight::Medium; break;
case FW_SEMIBOLD: pFont->m_eWeight = weight::SemiBold; break;
case FW_BOLD: pFont->m_eWeight = weight::Bold; break;
case FW_EXTRABOLD: pFont->m_eWeight = weight::UltraBold; break;
case FW_BLACK: pFont->m_eWeight = weight::Black; break;
case FW_NORMAL:
default: pFont->m_eWeight = weight::Normal; break;
}
switch( aInfo.width )
{
case FWIDTH_ULTRA_CONDENSED: pFont->m_eWidth = width::UltraCondensed; break;
case FWIDTH_EXTRA_CONDENSED: pFont->m_eWidth = width::ExtraCondensed; break;
case FWIDTH_CONDENSED: pFont->m_eWidth = width::Condensed; break;
case FWIDTH_SEMI_CONDENSED: pFont->m_eWidth = width::SemiCondensed; break;
case FWIDTH_SEMI_EXPANDED: pFont->m_eWidth = width::SemiExpanded; break;
case FWIDTH_EXPANDED: pFont->m_eWidth = width::Expanded; break;
case FWIDTH_EXTRA_EXPANDED: pFont->m_eWidth = width::ExtraExpanded; break;
case FWIDTH_ULTRA_EXPANDED: pFont->m_eWidth = width::UltraExpanded; break;
case FWIDTH_NORMAL:
default: pFont->m_eWidth = width::Normal; break;
}
pFont->m_ePitch = aInfo.pitch ? pitch::Fixed : pitch::Variable;
pFont->m_eItalic = aInfo.italicAngle == 0 ? italic::Upright : ( aInfo.italicAngle < 0 ? italic::Italic : italic::Oblique );
// #104264# there are fonts that set italic angle 0 although they are
// italic; use macstyle bit here
if( aInfo.italicAngle == 0 && (aInfo.macStyle & 2) )
pFont->m_eItalic = italic::Italic;
pFont->m_aEncoding = aInfo.symbolEncoded ? RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UCS2;
pFont->m_aGlobalMetricY.width = pFont->m_aGlobalMetricX.width = aInfo.xMax - aInfo.xMin;
pFont->m_aGlobalMetricY.height = pFont->m_aGlobalMetricX.height = aInfo.yMax - aInfo.yMin;
if( aInfo.winAscent && aInfo.winDescent )
{
pFont->m_nAscend = aInfo.winAscent;
pFont->m_nDescend = aInfo.winDescent;
pFont->m_nLeading = pFont->m_nAscend + pFont->m_nDescend - 1000;
}
else if( aInfo.typoAscender && aInfo.typoDescender )
{
pFont->m_nLeading = aInfo.typoLineGap;
pFont->m_nAscend = aInfo.typoAscender;
pFont->m_nDescend = -aInfo.typoDescender;
}
else
{
pFont->m_nLeading = aInfo.linegap;
pFont->m_nAscend = aInfo.ascender;
pFont->m_nDescend = -aInfo.descender;
}
// last try: font bounding box
if( pFont->m_nAscend == 0 )
pFont->m_nAscend = aInfo.yMax;
if( pFont->m_nDescend == 0 )
pFont->m_nDescend = -aInfo.yMin;
if( pFont->m_nLeading == 0 )
pFont->m_nLeading = 15 * (pFont->m_nAscend+pFont->m_nDescend) / 100;
if( pFont->m_nAscend )
pFont->m_aGlobalMetricX.height = pFont->m_aGlobalMetricY.height = pFont->m_nAscend + pFont->m_nDescend;
// get bounding box
pFont->m_nXMin = aInfo.xMin;
pFont->m_nYMin = aInfo.yMin;
pFont->m_nXMax = aInfo.xMax;
pFont->m_nYMax = aInfo.yMax;
// get type flags
pTTFontFile->m_nTypeFlags = (unsigned int)aInfo.typeFlags;
// get vertical substitutions flag
pFont->m_bHaveVerticalSubstitutedGlyphs = DoesVerticalSubstitution( pTTFont, 1 );
CloseTTFont( pTTFont );
bSuccess = true;
}
#if OSL_DEBUG_LEVEL > 1
else
fprintf( stderr, "could not OpenTTFont \"%s\"\n", aFile.GetBuffer() );
#endif
return bSuccess;
}
// -------------------------------------------------------------------------
void PrintFontManager::initFontsAlias()
{
m_aXLFD_Aliases.clear();
rtl_TextEncoding aEnc = osl_getThreadTextEncoding();
for( std::list< OString >::const_iterator dir_it = m_aFontDirectories.begin();
dir_it != m_aFontDirectories.end(); ++dir_it )
{
OStringBuffer aDirName(512);
aDirName.append( *dir_it );
aDirName.append( "/fonts.alias" );
SvFileStream aStream( OStringToOUString( aDirName.makeStringAndClear(), aEnc ), STREAM_READ );
if( ! aStream.IsOpen() )
continue;
do
{
ByteString aLine;
aStream.ReadLine( aLine );
// get the alias and the pattern it gets translated to
ByteString aAlias = GetCommandLineToken( 0, aLine );
ByteString aMap = GetCommandLineToken( 1, aLine );
// remove eventual quotes
aAlias.EraseLeadingChars( '"' );
aAlias.EraseTrailingChars( '"' );
aMap.EraseLeadingChars( '"' );
aMap.EraseTrailingChars( '"' );
XLFDEntry aAliasEntry, aMapEntry;
parseXLFD( aAlias, aAliasEntry );
parseXLFD( aMap, aMapEntry );
if( aAliasEntry.nMask && aMapEntry.nMask )
m_aXLFD_Aliases[ aMapEntry ].push_back( aAliasEntry );
} while( ! aStream.IsEof() );
}
}
// code stolen from vcl's RegisterFontSubstitutors()
// TODO: use that method once psprint gets merged into vcl
static bool AreFCSubstitutionsEnabled()
{
// init font substitution defaults
int nDisableBits = 0;
#ifdef SOLARIS
// TODO: check the OS version and fc-data maintenance level
nDisableBits = 1; // disable "font fallback" here on default
#endif
// apply the environment variable if any
const char* pEnvStr = ::getenv( "SAL_DISABLE_FC_SUBST" );
if( pEnvStr )
{
//
if( (*pEnvStr >= '0') && (*pEnvStr <= '9') )
nDisableBits = (*pEnvStr - '0');
else
nDisableBits = ~0U; // no specific bits set: disable all
}
return ((nDisableBits & 3) == 0);
}
void PrintFontManager::initialize()
{
#ifdef CALLGRIND_COMPILE
CALLGRIND_TOGGLE_COLLECT();
CALLGRIND_ZERO_STATS();
#endif
long aDirEntBuffer[ (sizeof(struct dirent)+_PC_NAME_MAX)+1 ];
if( ! m_pFontCache )
{
#if OSL_DEBUG_LEVEL > 1
fprintf( stderr, "creating font cache ... " );
clock_t aStart;
struct tms tms;
aStart = times( &tms );
#endif
m_pFontCache = new FontCache();
#if OSL_DEBUG_LEVEL > 1
clock_t aStop = times( &tms );
fprintf( stderr, "done in %lf s\n", (double)(aStop - aStart)/(double)sysconf( _SC_CLK_TCK ) );
#endif
}
// initialize may be called twice in the future
{
for( ::std::hash_map< fontID, PrintFont* >::const_iterator it = m_aFonts.begin(); it != m_aFonts.end(); ++it )
delete (*it).second;
m_nNextFontID = 1;
m_aFonts.clear();
m_aFontDirectories.clear();
m_aPrivateFontDirectories.clear();
m_aOverrideFonts.clear();
}
#if OSL_DEBUG_LEVEL > 1
clock_t aStart;
clock_t aStep1;
clock_t aStep2;
clock_t aStep3;
int nBuiltinFonts = 0;
int nCached = 0;
struct tms tms;
aStart = times( &tms );
#endif
// first try fontconfig
m_bFontconfigSuccess = initFontconfig();
// part one - look for downloadable fonts
rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
const ::rtl::OUString &rSalPrivatePath = psp::getFontPath();
// search for the fonts in SAL_PRIVATE_FONTPATH first; those are
// the fonts installed with the office
if( rSalPrivatePath.getLength() )
{
OString aPath = rtl::OUStringToOString( rSalPrivatePath, aEncoding );
const bool bAreFCSubstitutionsEnabled = AreFCSubstitutionsEnabled();
sal_Int32 nIndex = 0;
do
{
OString aToken = aPath.getToken( 0, ';', nIndex );
normPath( aToken );
// if registering an app-specific fontdir with fontconfig fails
// and fontconfig-based substitutions are enabled
// then trying to use these app-specific fonts doesn't make sense
if( m_bFontconfigSuccess && !addFontconfigDir( aToken ) )
if( bAreFCSubstitutionsEnabled )
continue;
m_aFontDirectories.push_back( aToken );
m_aPrivateFontDirectories.push_back( getDirectoryAtom( aToken, true ) );
} while( nIndex >= 0 );
}
// protect against duplicate paths
std::hash_map< OString, int, OStringHash > visited_dirs;
// now that all global and local font dirs are known to fontconfig
// check that there are fonts actually managed by fontconfig
// also don't search directories that fontconfig already did
if( m_bFontconfigSuccess )
m_bFontconfigSuccess = (countFontconfigFonts( visited_dirs ) > 0);
// don't search through many directories fontconfig already told us about
if( ! m_bFontconfigSuccess )
ImplGetSVData()->mpDefInst->FillFontPathList( m_aFontDirectories );
// fill XLFD aliases from fonts.alias files
initFontsAlias();
// search for font files in each path
std::list< OString >::iterator dir_it;
for( dir_it = m_aFontDirectories.begin(); dir_it != m_aFontDirectories.end(); ++dir_it )
{
OString aPath( *dir_it );
// see if we were here already
if( visited_dirs.find( aPath ) != visited_dirs.end() )
continue;
visited_dirs[ aPath ] = 1;
// there may be ":unscaled" directories (see XFree86)
// it should be safe to ignore them since they should not
// contain any of our recognizeable fonts
// ask the font cache whether it handles this directory
std::list< PrintFont* > aCacheFonts;
if( m_pFontCache->listDirectory( aPath, aCacheFonts ) )
{
#if OSL_DEBUG_LEVEL > 1
fprintf( stderr, "adding cache directory: %s\n", aPath.getStr() );
#endif
for( ::std::list< PrintFont* >::iterator it = aCacheFonts.begin(); it != aCacheFonts.end(); ++it )
{
fontID aFont = m_nNextFontID++;
m_aFonts[ aFont ] = *it;
if( (*it)->m_eType == fonttype::Type1 )
m_aFontFileToFontID[ static_cast<Type1FontFile*>(*it)->m_aFontFile ].insert( aFont );
else if( (*it)->m_eType == fonttype::TrueType )
m_aFontFileToFontID[ static_cast<TrueTypeFontFile*>(*it)->m_aFontFile ].insert( aFont );
else if( (*it)->m_eType == fonttype::Builtin )
m_aFontFileToFontID[ static_cast<BuiltinFont*>(*it)->m_aMetricFile ].insert( aFont );
#if OSL_DEBUG_LEVEL > 1
if( (*it)->m_eType == fonttype::Builtin )
nBuiltinFonts++;
nCached++;
#if OSL_DEBUG_LEVEL > 2
fprintf( stderr, "adding cached font %d: \"%s\" from %s\n", aFont,
OUStringToOString( getFontFamily( aFont ), RTL_TEXTENCODING_MS_1252 ).getStr(),
getFontFileSysPath( aFont ).getStr() );
#endif
#endif
}
if( ! m_pFontCache->scanAdditionalFiles( aPath ) )
continue;
}
DIR* pDIR = opendir( aPath.getStr() );
struct dirent* pEntry = (struct dirent*)aDirEntBuffer;
if( pDIR )
{
// read fonts.dir if possible
::std::hash_map< OString, ::std::list<OString>, OStringHash > aFontsDir;
int nDirID = getDirectoryAtom( aPath, true );
// #i38367# no fonts.dir in our own directories anymore
std::list< int >::const_iterator priv_dir;
for( priv_dir = m_aPrivateFontDirectories.begin();
priv_dir != m_aPrivateFontDirectories.end() && *priv_dir != nDirID;
++priv_dir )
;
if( priv_dir == m_aPrivateFontDirectories.end() )
{
ByteString aGccDummy( aPath );
String aFontsDirPath( aGccDummy, aEncoding );
aFontsDirPath.AppendAscii( "/fonts.dir" );
SvFileStream aStream( aFontsDirPath, STREAM_READ );
if( aStream.IsOpen() )
{
ByteString aLine;
while( ! aStream.IsEof() )
{
aStream.ReadLine( aLine );
ByteString aFileName( GetCommandLineToken( 0, aLine ) );
ByteString aXLFD( aLine.Copy( aFileName.Len() ) );
if( aFileName.Len() && aXLFD.Len() )
aFontsDir[ aFileName ].push_back(aXLFD);
}
}
}
int nDirFonts = 0;
while( ! readdir_r( pDIR, (struct dirent*)aDirEntBuffer, &pEntry ) && pEntry )
{
OString aFileName( pEntry->d_name );
// ignore .afm files here
if( aFileName.getLength() > 3 &&
aFileName.lastIndexOf( ".afm" ) == aFileName.getLength()-4 )
continue;
struct stat aStat;
ByteString aFilePath( aPath );
aFilePath.Append( '/' );
aFilePath.Append( ByteString( aFileName ) );
if( ! stat( aFilePath.GetBuffer(), &aStat ) &&
S_ISREG( aStat.st_mode ) )
{
if( findFontFileID( nDirID, aFileName ) == 0 )
{
::std::list<OString> aXLFDs;
::std::hash_map< OString, ::std::list<OString>, OStringHash >::const_iterator it =
aFontsDir.find( aFileName );
if( it != aFontsDir.end() )
aXLFDs = (*it).second;
// fill in font attributes from XLFD rather
// than reading every file
::std::list< PrintFont* > aNewFonts;
if( analyzeFontFile( nDirID, aFileName, aXLFDs, aNewFonts ) )
{
for( ::std::list< PrintFont* >::iterator font_it = aNewFonts.begin(); font_it != aNewFonts.end(); ++font_it )
{
fontID aFont = m_nNextFontID++;
m_aFonts[ aFont ] = *font_it;
m_aFontFileToFontID[ aFileName ].insert( aFont );
m_pFontCache->updateFontCacheEntry( *font_it, false );
nDirFonts++;
#if OSL_DEBUG_LEVEL > 2
fprintf( stderr, "adding font %d: \"%s\" from %s\n", aFont,
OUStringToOString( getFontFamily( aFont ), RTL_TEXTENCODING_MS_1252 ).getStr(),
getFontFileSysPath( aFont ).getStr() );
#endif
}
}
}
}
}
closedir( pDIR );
m_pFontCache->updateDirTimestamp( nDirID );
if( ! nDirFonts )
m_pFontCache->markEmptyDir( nDirID );
}
}
#if OSL_DEBUG_LEVEL > 1
aStep1 = times( &tms );
#endif
// part two - look for metrics for builtin printer fonts
std::list< OUString > aMetricDirs;
psp::getPrinterPathList( aMetricDirs, PRINTER_METRICDIR );
std::list< OString > aEmptyFontsDir;
for( std::list< OUString >::const_iterator met_dir_it = aMetricDirs.begin(); met_dir_it != aMetricDirs.end(); ++met_dir_it )
{
OString aDir = OUStringToOString( *met_dir_it, aEncoding );
// ask the font cache whether it handles this directory
std::list< PrintFont* > aCacheFonts;
if( m_pFontCache->listDirectory( aDir, aCacheFonts ) )
{
#if OSL_DEBUG_LEVEL > 1
fprintf( stderr, "adding cache directory: %s\n", aDir.getStr() );
#endif
for( ::std::list< PrintFont* >::iterator it = aCacheFonts.begin(); it != aCacheFonts.end(); ++it )
{
fontID aFont = m_nNextFontID++;
m_aFonts[ aFont ] = *it;
if( (*it)->m_eType == fonttype::Type1 )
m_aFontFileToFontID[ static_cast<Type1FontFile*>(*it)->m_aFontFile ].insert( aFont );
else if( (*it)->m_eType == fonttype::TrueType )
m_aFontFileToFontID[ static_cast<TrueTypeFontFile*>(*it)->m_aFontFile ].insert( aFont );
else if( (*it)->m_eType == fonttype::Builtin )
m_aFontFileToFontID[ static_cast<BuiltinFont*>(*it)->m_aMetricFile ].insert( aFont );
#if OSL_DEBUG_LEVEL > 1
if( (*it)->m_eType == fonttype::Builtin )
nBuiltinFonts++;
nCached++;
#if OSL_DEBUG_LEVEL > 2
fprintf( stderr, "adding cached font %d: \"%s\" from %s\n", aFont,
OUStringToOString( getFontFamily( aFont ), RTL_TEXTENCODING_MS_1252 ).getStr(),
getFontFileSysPath( aFont ).getStr() );
#endif
#endif
}
continue;
}
DIR* pDIR = opendir( aDir.getStr() );
if( pDIR )
{
struct dirent* pDirEntry = (struct dirent*)aDirEntBuffer;
int nDirID = getDirectoryAtom( aDir, true );
int nDirFonts = 0;
while( ! readdir_r( pDIR, (struct dirent*)aDirEntBuffer, &pDirEntry ) && pDirEntry )
{
ByteString aFile( aDir );
aFile += '/';
aFile += pDirEntry->d_name;
struct stat aStat;
if( ! stat( aFile.GetBuffer(), &aStat )
&& S_ISREG( aStat.st_mode )
)
{
OString aFileName( pDirEntry->d_name, strlen( pDirEntry->d_name ) );
OString aExt( aFileName.copy( aFileName.lastIndexOf( '.' )+1 ) );
if( aExt.equalsIgnoreAsciiCase( "afm" ) )
{
::std::list< PrintFont* > aNewFonts;
analyzeFontFile( nDirID, aFileName, aEmptyFontsDir, aNewFonts );
for( ::std::list< PrintFont* >::iterator it = aNewFonts.begin(); it != aNewFonts.end(); ++it )
{
if( findFontBuiltinID( (*it)->m_nPSName ) == 0 )
{
m_aFontFileToFontID[ aFileName ].insert( m_nNextFontID );
m_aFonts[ m_nNextFontID++ ] = *it;
m_pFontCache->updateFontCacheEntry( *it, false );
#if OSL_DEBUG_LEVEL > 2
nBuiltinFonts++;
#endif
}
else
delete *it;
}
}
}
}
closedir( pDIR );
if( ! nDirFonts )
m_pFontCache->markEmptyDir( nDirID );
}
}
#if OSL_DEBUG_LEVEL > 1
aStep2 = times( &tms );
#endif
// part three - fill in family styles
::std::hash_map< fontID, PrintFont* >::iterator font_it;
for (font_it = m_aFonts.begin(); font_it != m_aFonts.end(); ++font_it)
{
::std::hash_map< int, family::type >::const_iterator it =
m_aFamilyTypes.find( font_it->second->m_nFamilyName );
if (it != m_aFamilyTypes.end())
continue;
const ::rtl::OUString& rFamily =
m_pAtoms->getString( ATOM_FAMILYNAME, font_it->second->m_nFamilyName);
family::type eType = matchFamilyName( rFamily );
m_aFamilyTypes[ font_it->second->m_nFamilyName ] = eType;
}
#if OSL_DEBUG_LEVEL > 1
aStep3 = times( &tms );
fprintf( stderr, "PrintFontManager::initialize: collected %d fonts (%d builtin, %d cached)\n", m_aFonts.size(), nBuiltinFonts, nCached );
double fTick = (double)sysconf( _SC_CLK_TCK );
fprintf( stderr, "Step 1 took %lf seconds\n", (double)(aStep1 - aStart)/fTick );
fprintf( stderr, "Step 2 took %lf seconds\n", (double)(aStep2 - aStep1)/fTick );
fprintf( stderr, "Step 3 took %lf seconds\n", (double)(aStep3 - aStep2)/fTick );
#endif
m_pFontCache->flush();
#ifdef CALLGRIND_COMPILE
CALLGRIND_DUMP_STATS();
CALLGRIND_TOGGLE_COLLECT();
#endif
}
// -------------------------------------------------------------------------
inline bool
equalPitch (psp::pitch::type from, psp::pitch::type to)
{
return from == to;
}
inline bool
equalWeight (psp::weight::type from, psp::weight::type to)
{
return from > to ? (from - to) <= 3 : (to - from) <= 3;
}
inline bool
equalItalic (psp::italic::type from, psp::italic::type to)
{
if ( (from == psp::italic::Italic) || (from == psp::italic::Oblique) )
return (to == psp::italic::Italic) || (to == psp::italic::Oblique);
return to == from;
}
inline bool
equalEncoding (rtl_TextEncoding from, rtl_TextEncoding to)
{
if ((from == RTL_TEXTENCODING_ISO_8859_1) || (from == RTL_TEXTENCODING_MS_1252))
return (to == RTL_TEXTENCODING_ISO_8859_1) || (to == RTL_TEXTENCODING_MS_1252);
return from == to;
}
namespace {
struct BuiltinFontIdentifier
{
OUString aFamily;
italic::type eItalic;
weight::type eWeight;
pitch::type ePitch;
rtl_TextEncoding aEncoding;
BuiltinFontIdentifier( const OUString& rFam,
italic::type eIt,
weight::type eWg,
pitch::type ePt,
rtl_TextEncoding enc ) :
aFamily( rFam ),
eItalic( eIt ),
eWeight( eWg ),
ePitch( ePt ),
aEncoding( enc )
{}
bool operator==( const BuiltinFontIdentifier& rRight ) const
{
return equalItalic( eItalic, rRight.eItalic ) &&
equalWeight( eWeight, rRight.eWeight ) &&
equalPitch( ePitch, rRight.ePitch ) &&
equalEncoding( aEncoding, rRight.aEncoding ) &&
aFamily.equalsIgnoreAsciiCase( rRight.aFamily );
}
};
struct BuiltinFontIdentifierHash
{
size_t operator()( const BuiltinFontIdentifier& rFont ) const
{
return rFont.aFamily.hashCode() ^ rFont.eItalic ^ rFont.eWeight ^ rFont.ePitch ^ rFont.aEncoding;
}
};
}
void PrintFontManager::getFontList( ::std::list< fontID >& rFontIDs, const PPDParser* pParser, bool bUseOverrideMetrics )
{
rFontIDs.clear();
std::hash_map< fontID, PrintFont* >::const_iterator it;
/*
* Note: there are two easy steps making this faster:
* first: insert the printer builtins first, then the not builtins,
* if they do not match.
* drawback: this would change the sequence of fonts; this could have
* subtle, unknown consequences in vcl font matching
* second: instead of comparing attributes to see whether a softfont
* is duplicate to a builtin one could simply compare the PSName (which is
* supposed to be unique), which at this point is just an int.
* drawback: this could change which fonts are listed; especially TrueType
* fonts often have a rather dubious PSName, so this could change the
* font list not so subtle.
* Until getFontList for a printer becomes a performance issue (which is
* currently not the case), best stay with the current algorithm.
*/
// fill sets of printer supported fonts
if( pParser )
{
std::set<int> aBuiltinPSNames;
std::hash_set< BuiltinFontIdentifier,
BuiltinFontIdentifierHash
> aBuiltinFonts;
std::map<int, fontID > aOverridePSNames;
if( bUseOverrideMetrics )
{
readOverrideMetrics();
for( std::vector<fontID>::const_iterator over = m_aOverrideFonts.begin();
over != m_aOverrideFonts.end(); ++over )
{
std::hash_map<fontID,PrintFont*>::const_iterator font_it = m_aFonts.find( *over );
DBG_ASSERT( font_it != m_aFonts.end(), "override to nonexistant font" );
if( font_it != m_aFonts.end() )
aOverridePSNames[ font_it->second->m_nPSName ] = *over;
}
}
int nFonts = pParser->getFonts();
for( int i = 0; i < nFonts; i++ )
aBuiltinPSNames.insert( m_pAtoms->getAtom( ATOM_PSNAME, pParser->getFont( i ) ) );
for( it = m_aFonts.begin(); it != m_aFonts.end(); ++it )
{
PrintFont* pFont = it->second;
if( it->second->m_eType == fonttype::Builtin &&
aBuiltinPSNames.find( pFont->m_nPSName ) != aBuiltinPSNames.end() )
{
bool bInsert = true;
if( bUseOverrideMetrics )
{
// in override case only use the override fonts, not their counterparts
std::map<int,fontID>::const_iterator over = aOverridePSNames.find( pFont->m_nPSName );
if( over != aOverridePSNames.end() && over->second != it->first )
bInsert = false;
}
else
{
// do not insert override fonts in non override case
if( std::find( m_aOverrideFonts.begin(), m_aOverrideFonts.end(), it->first ) != m_aOverrideFonts.end() )
bInsert = false;
}
if( bInsert )
{
aBuiltinFonts.insert( BuiltinFontIdentifier(
m_pAtoms->getString( ATOM_FAMILYNAME, pFont->m_nFamilyName ),
pFont->m_eItalic,
pFont->m_eWeight,
pFont->m_ePitch,
pFont->m_aEncoding
) );
}
}
}
for( it = m_aFonts.begin(); it != m_aFonts.end(); ++it )
{
PrintFont* pFont = it->second;
if( it->second->m_eType == fonttype::Builtin )
{
if( aBuiltinPSNames.find( pFont->m_nPSName ) != aBuiltinPSNames.end() )
{
bool bInsert = true;
if( bUseOverrideMetrics )
{
// in override case only use the override fonts, not their counterparts
std::map<int,fontID>::const_iterator over = aOverridePSNames.find( pFont->m_nPSName );
if( over != aOverridePSNames.end() && over->second != it->first )
bInsert = false;
}
else
{
// do not insert override fonts in non override case
if( std::find( m_aOverrideFonts.begin(), m_aOverrideFonts.end(), it->first ) != m_aOverrideFonts.end() )
bInsert = false;
}
if( bInsert )
rFontIDs.push_back( it->first );
}
}
else if( aBuiltinFonts.find( BuiltinFontIdentifier(
m_pAtoms->getString( ATOM_FAMILYNAME, pFont->m_nFamilyName ),
pFont->m_eItalic,
pFont->m_eWeight,
pFont->m_ePitch,
pFont->m_aEncoding
) ) == aBuiltinFonts.end() )
{
rFontIDs.push_back( it->first );
}
}
}
else // no specific printer
{
for( it = m_aFonts.begin(); it != m_aFonts.end(); ++it )
rFontIDs.push_back( it->first );
}
}
// -------------------------------------------------------------------------
void PrintFontManager::fillPrintFontInfo( PrintFont* pFont, FastPrintFontInfo& rInfo ) const
{
::std::hash_map< int, family::type >::const_iterator style_it =
m_aFamilyTypes.find( pFont->m_nFamilyName );
rInfo.m_eType = pFont->m_eType;
rInfo.m_aFamilyName = m_pAtoms->getString( ATOM_FAMILYNAME, pFont->m_nFamilyName );
rInfo.m_aStyleName = pFont->m_aStyleName;
rInfo.m_eFamilyStyle = style_it != m_aFamilyTypes.end() ? style_it->second : family::Unknown;
rInfo.m_eItalic = pFont->m_eItalic;
rInfo.m_eWidth = pFont->m_eWidth;
rInfo.m_eWeight = pFont->m_eWeight;
rInfo.m_ePitch = pFont->m_ePitch;
rInfo.m_aEncoding = pFont->m_aEncoding;
rInfo.m_bEmbeddable = (pFont->m_eType == fonttype::Type1);
rInfo.m_bSubsettable = (pFont->m_eType == fonttype::TrueType); // TODO: rename to SfntType
rInfo.m_aAliases.clear();
for( ::std::list< int >::iterator it = pFont->m_aAliases.begin(); it != pFont->m_aAliases.end(); ++it )
rInfo.m_aAliases.push_back( m_pAtoms->getString( ATOM_FAMILYNAME, *it ) );
}
// -------------------------------------------------------------------------
void PrintFontManager::fillPrintFontInfo( PrintFont* pFont, PrintFontInfo& rInfo ) const
{
if( ( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 ) ||
! pFont->m_pMetrics || pFont->m_pMetrics->isEmpty()
)
{
// might be a truetype font not analyzed or type1 without metrics read
if( pFont->m_eType == fonttype::Type1 )
pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, false, false );
else if( pFont->m_eType == fonttype::TrueType )
analyzeTrueTypeFile( pFont );
}
fillPrintFontInfo( pFont, static_cast< FastPrintFontInfo& >( rInfo ) );
rInfo.m_nAscend = pFont->m_nAscend;
rInfo.m_nDescend = pFont->m_nDescend;
rInfo.m_nLeading = pFont->m_nLeading;
rInfo.m_nWidth = pFont->m_aGlobalMetricX.width < pFont->m_aGlobalMetricY.width ? pFont->m_aGlobalMetricY.width : pFont->m_aGlobalMetricX.width;
}
// -------------------------------------------------------------------------
void PrintFontManager::getFontListWithInfo( ::std::list< PrintFontInfo >& rFonts, const PPDParser* pParser, bool bUseOverrideMetrics )
{
rFonts.clear();
::std::list< fontID > aFontList;
getFontList( aFontList, pParser, bUseOverrideMetrics );
::std::list< fontID >::iterator it;
for( it = aFontList.begin(); it != aFontList.end(); ++it )
{
PrintFontInfo aInfo;
aInfo.m_nID = *it;
fillPrintFontInfo( getFont( *it ), aInfo );
rFonts.push_back( aInfo );
}
}
// -------------------------------------------------------------------------
void PrintFontManager::getFontListWithFastInfo( ::std::list< FastPrintFontInfo >& rFonts, const PPDParser* pParser, bool bUseOverrideMetrics )
{
rFonts.clear();
::std::list< fontID > aFontList;
getFontList( aFontList, pParser, bUseOverrideMetrics );
::std::list< fontID >::iterator it;
for( it = aFontList.begin(); it != aFontList.end(); ++it )
{
FastPrintFontInfo aInfo;
aInfo.m_nID = *it;
fillPrintFontInfo( getFont( *it ), aInfo );
rFonts.push_back( aInfo );
}
}
// -------------------------------------------------------------------------
bool PrintFontManager::getFontInfo( fontID nFontID, PrintFontInfo& rInfo ) const
{
PrintFont* pFont = getFont( nFontID );
if( pFont )
{
rInfo.m_nID = nFontID;
fillPrintFontInfo( pFont, rInfo );
}
return pFont ? true : false;
}
// -------------------------------------------------------------------------
bool PrintFontManager::getFontFastInfo( fontID nFontID, FastPrintFontInfo& rInfo ) const
{
PrintFont* pFont = getFont( nFontID );
if( pFont )
{
rInfo.m_nID = nFontID;
fillPrintFontInfo( pFont, rInfo );
}
return pFont ? true : false;
}
// -------------------------------------------------------------------------
bool PrintFontManager::getFontBoundingBox( fontID nFontID, int& xMin, int& yMin, int& xMax, int& yMax )
{
bool bSuccess = false;
PrintFont* pFont = getFont( nFontID );
if( pFont )
{
if( pFont->m_nXMin == 0 && pFont->m_nYMin == 0 && pFont->m_nXMax == 0 && pFont->m_nYMax == 0 )
{
// might be a truetype font not analyzed or type1 without metrics read
if( pFont->m_eType == fonttype::Type1 || pFont->m_eType == fonttype::Builtin )
pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, false, true );
else if( pFont->m_eType == fonttype::TrueType )
analyzeTrueTypeFile( pFont );
}
bSuccess = true;
xMin = pFont->m_nXMin;
yMin = pFont->m_nYMin;
xMax = pFont->m_nXMax;
yMax = pFont->m_nYMax;
}
return bSuccess;
}
// -------------------------------------------------------------------------
int PrintFontManager::getFontFaceNumber( fontID nFontID ) const
{
int nRet = -1;
PrintFont* pFont = getFont( nFontID );
if( pFont && pFont->m_eType == fonttype::TrueType )
nRet = static_cast< TrueTypeFontFile* >(pFont)->m_nCollectionEntry;
return nRet;
}
// -------------------------------------------------------------------------
family::type PrintFontManager::matchFamilyName( const ::rtl::OUString& rFamily ) const
{
typedef struct {
const char* mpName;
sal_uInt16 mnLength;
family::type meType;
} family_t;
#define InitializeClass( p, a ) p, sizeof(p) - 1, a
const family_t pFamilyMatch[] = {
{ InitializeClass( "arial", family::Swiss ) },
{ InitializeClass( "arioso", family::Script ) },
{ InitializeClass( "avant garde", family::Swiss ) },
{ InitializeClass( "avantgarde", family::Swiss ) },
{ InitializeClass( "bembo", family::Roman ) },
{ InitializeClass( "bookman", family::Roman ) },
{ InitializeClass( "conga", family::Roman ) },
{ InitializeClass( "courier", family::Modern ) },
{ InitializeClass( "curl", family::Script ) },
{ InitializeClass( "fixed", family::Modern ) },
{ InitializeClass( "gill", family::Swiss ) },
{ InitializeClass( "helmet", family::Modern ) },
{ InitializeClass( "helvetica", family::Swiss ) },
{ InitializeClass( "international", family::Modern ) },
{ InitializeClass( "lucida", family::Swiss ) },
{ InitializeClass( "new century schoolbook", family::Roman ) },
{ InitializeClass( "palatino", family::Roman ) },
{ InitializeClass( "roman", family::Roman ) },
{ InitializeClass( "sans serif", family::Swiss ) },
{ InitializeClass( "sansserif", family::Swiss ) },
{ InitializeClass( "serf", family::Roman ) },
{ InitializeClass( "serif", family::Roman ) },
{ InitializeClass( "times", family::Roman ) },
{ InitializeClass( "utopia", family::Roman ) },
{ InitializeClass( "zapf chancery", family::Script ) },
{ InitializeClass( "zapfchancery", family::Script ) }
};
rtl::OString aFamily = rtl::OUStringToOString( rFamily, RTL_TEXTENCODING_ASCII_US );
sal_uInt32 nLower = 0;
sal_uInt32 nUpper = sizeof(pFamilyMatch) / sizeof(pFamilyMatch[0]);
while( nLower < nUpper )
{
sal_uInt32 nCurrent = (nLower + nUpper) / 2;
const family_t* pHaystack = pFamilyMatch + nCurrent;
sal_Int32 nComparison =
rtl_str_compareIgnoreAsciiCase_WithLength
(
aFamily.getStr(), aFamily.getLength(),
pHaystack->mpName, pHaystack->mnLength
);
if( nComparison < 0 )
nUpper = nCurrent;
else
if( nComparison > 0 )
nLower = nCurrent + 1;
else
return pHaystack->meType;
}
return family::Unknown;
}
// -------------------------------------------------------------------------
family::type PrintFontManager::getFontFamilyType( fontID nFontID ) const
{
PrintFont* pFont = getFont( nFontID );
if( !pFont )
return family::Unknown;
::std::hash_map< int, family::type >::const_iterator it =
m_aFamilyTypes.find( pFont->m_nFamilyName );
return (it != m_aFamilyTypes.end()) ? it->second : family::Unknown;
}
// -------------------------------------------------------------------------
const ::rtl::OUString& PrintFontManager::getFontFamily( fontID nFontID ) const
{
PrintFont* pFont = getFont( nFontID );
return m_pAtoms->getString( ATOM_FAMILYNAME, pFont ? pFont->m_nFamilyName : INVALID_ATOM );
}
// -------------------------------------------------------------------------
OString PrintFontManager::getAfmFile( PrintFont* pFont ) const
{
OString aMetricPath;
if( pFont )
{
switch( pFont->m_eType )
{
case fonttype::Type1:
{
Type1FontFile* pPSFont = static_cast< Type1FontFile* >(pFont);
aMetricPath = getDirectory( pPSFont->m_nDirectory );
aMetricPath += "/";
aMetricPath += pPSFont->m_aMetricFile;
}
break;
case fonttype::Builtin:
{
BuiltinFont* pBuiltinFont = static_cast< BuiltinFont* >(pFont);
aMetricPath = getDirectory( pBuiltinFont->m_nDirectory );
aMetricPath += "/";
aMetricPath += pBuiltinFont->m_aMetricFile;
}
break;
default: break;
}
}
return aMetricPath;
}
// -------------------------------------------------------------------------
OString PrintFontManager::getFontFile( PrintFont* pFont ) const
{
OString aPath;
if( pFont && pFont->m_eType == fonttype::Type1 )
{
Type1FontFile* pPSFont = static_cast< Type1FontFile* >(pFont);
::std::hash_map< int, OString >::const_iterator it = m_aAtomToDir.find( pPSFont->m_nDirectory );
aPath = it->second;
aPath += "/";
aPath += pPSFont->m_aFontFile;
}
else if( pFont && pFont->m_eType == fonttype::TrueType )
{
TrueTypeFontFile* pTTFont = static_cast< TrueTypeFontFile* >(pFont);
::std::hash_map< int, OString >::const_iterator it = m_aAtomToDir.find( pTTFont->m_nDirectory );
aPath = it->second;
aPath += "/";
aPath += pTTFont->m_aFontFile;
}
return aPath;
}
// -------------------------------------------------------------------------
const ::rtl::OUString& PrintFontManager::getPSName( fontID nFontID ) const
{
PrintFont* pFont = getFont( nFontID );
if( pFont && pFont->m_nPSName == 0 )
{
if( pFont->m_eType == fonttype::TrueType )
analyzeTrueTypeFile( pFont );
}
return m_pAtoms->getString( ATOM_PSNAME, pFont ? pFont->m_nPSName : INVALID_ATOM );
}
// -------------------------------------------------------------------------
const CharacterMetric& PrintFontManager::getGlobalFontMetric( fontID nFontID, bool bHorizontal ) const
{
static CharacterMetric aMetric;
PrintFont* pFont = getFont( nFontID );
return pFont ? ( bHorizontal ? pFont->m_aGlobalMetricX : pFont->m_aGlobalMetricY ) : aMetric;
}
// -------------------------------------------------------------------------
int PrintFontManager::getFontAscend( fontID nFontID ) const
{
PrintFont* pFont = getFont( nFontID );
if( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
{
// might be a truetype font not yet analyzed
if( pFont->m_eType == fonttype::TrueType )
analyzeTrueTypeFile( pFont );
else if( pFont->m_eType == fonttype::Type1 || pFont->m_eType == fonttype::Builtin )
pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, false, true );
}
return pFont->m_nAscend;
}
// -------------------------------------------------------------------------
int PrintFontManager::getFontDescend( fontID nFontID ) const
{
PrintFont* pFont = getFont( nFontID );
if( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
{
// might be a truetype font not yet analyzed
if( pFont->m_eType == fonttype::TrueType )
analyzeTrueTypeFile( pFont );
else if( pFont->m_eType == fonttype::Type1 || pFont->m_eType == fonttype::Builtin )
pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, false, true );
}
return pFont->m_nDescend;
}
// -------------------------------------------------------------------------
int PrintFontManager::getFontLeading( fontID nFontID ) const
{
PrintFont* pFont = getFont( nFontID );
if( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
{
// might be a truetype font not yet analyzed
if( pFont->m_eType == fonttype::TrueType )
analyzeTrueTypeFile( pFont );
}
return pFont->m_nLeading;
}
// -------------------------------------------------------------------------
bool PrintFontManager::hasVerticalSubstitutions( fontID nFontID ) const
{
PrintFont* pFont = getFont( nFontID );
if( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
{
// might be a truetype font not yet analyzed
if( pFont->m_eType == fonttype::TrueType )
analyzeTrueTypeFile( pFont );
}
return pFont->m_bHaveVerticalSubstitutedGlyphs;
}
// -------------------------------------------------------------------------
void PrintFontManager::hasVerticalSubstitutions( fontID nFontID,
const sal_Unicode* pCharacters, int nCharacters, bool* pHasSubst ) const
{
PrintFont* pFont = getFont( nFontID );
if( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
{
// might be a truetype font not yet analyzed
if( pFont->m_eType == fonttype::TrueType )
analyzeTrueTypeFile( pFont );
}
if( ! pFont->m_bHaveVerticalSubstitutedGlyphs )
memset( pHasSubst, 0, sizeof(bool)*nCharacters );
else
{
for( int i = 0; i < nCharacters; i++ )
{
sal_Unicode code = pCharacters[i];
if( ! pFont->m_pMetrics ||
! ( pFont->m_pMetrics->m_aPages[ code >> 11 ] & ( 1 << ( ( code >> 8 ) & 7 ) ) ) )
pFont->queryMetricPage( code >> 8, m_pAtoms );
::std::hash_map< sal_Unicode, bool >::const_iterator it = pFont->m_pMetrics->m_bVerticalSubstitutions.find( code );
pHasSubst[i] = it != pFont->m_pMetrics->m_bVerticalSubstitutions.end();
}
}
}
// -------------------------------------------------------------------------
OUString PrintFontManager::getFontXLFD( fontID nFontID ) const
{
PrintFont* pFont = getFont( nFontID );
OUString aRet;
if( pFont )
{
ByteString aXLFD( getXLFD( pFont ) );
rtl_TextEncoding aEncoding = aXLFD.GetToken( 6, '-' ).Search( "utf8" ) != STRING_NOTFOUND ? RTL_TEXTENCODING_UTF8 : RTL_TEXTENCODING_ISO_8859_1;
aRet = OStringToOUString( aXLFD, aEncoding );
}
return aRet;
}
// -------------------------------------------------------------------------
const ::std::list< KernPair >& PrintFontManager::getKernPairs( fontID nFontID, bool bVertical ) const
{
static ::std::list< KernPair > aEmpty;
PrintFont* pFont = getFont( nFontID );
if( ! pFont )
return aEmpty;
if( ! pFont->m_pMetrics || ! pFont->m_pMetrics->m_bKernPairsQueried )
pFont->queryMetricPage( 0, m_pAtoms );
if( ! pFont->m_pMetrics || ! pFont->m_pMetrics->m_bKernPairsQueried )
return aEmpty;
return bVertical ? pFont->m_pMetrics->m_aYKernPairs : pFont->m_pMetrics->m_aXKernPairs;
}
// -------------------------------------------------------------------------
bool PrintFontManager::isFontDownloadingAllowed( fontID nFont ) const
{
static const char* pEnable = getenv( "PSPRINT_ENABLE_TTF_COPYRIGHTAWARENESS" );
bool bRet = true;
if( pEnable && *pEnable )
{
PrintFont* pFont = getFont( nFont );
if( pFont && pFont->m_eType == fonttype::TrueType )
{
TrueTypeFontFile* pTTFontFile = static_cast<TrueTypeFontFile*>(pFont);
if( pTTFontFile->m_nTypeFlags & TYPEFLAG_INVALID )
{
TrueTypeFont* pTTFont = NULL;
ByteString aFile = getFontFile( pFont );
if( OpenTTFontFile( aFile.GetBuffer(), pTTFontFile->m_nCollectionEntry < 0 ? 0 : pTTFontFile->m_nCollectionEntry, &pTTFont ) == SF_OK )
{
// get type flags
TTGlobalFontInfo aInfo;
GetTTGlobalFontInfo( pTTFont, & aInfo );
pTTFontFile->m_nTypeFlags = (unsigned int)aInfo.typeFlags;
CloseTTFont( pTTFont );
}
}
unsigned int nCopyrightFlags = pTTFontFile->m_nTypeFlags & TYPEFLAG_COPYRIGHT_MASK;
// font embedding is allowed if either
// no restriction at all (bit 1 clear)
// printing allowed (bit 1 set, bit 2 set )
bRet = ! ( nCopyrightFlags & 0x02 ) || ( nCopyrightFlags & 0x04 );
}
}
return bRet;
}
// -------------------------------------------------------------------------
bool PrintFontManager::getMetrics( fontID nFontID, const sal_Unicode* pString, int nLen, CharacterMetric* pArray, bool bVertical ) const
{
PrintFont* pFont = getFont( nFontID );
if( ! pFont )
return false;
if( ( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
|| ! pFont->m_pMetrics || pFont->m_pMetrics->isEmpty()
)
{
// might be a font not yet analyzed
if( pFont->m_eType == fonttype::Type1 || pFont->m_eType == fonttype::Builtin )
pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, false, false );
else if( pFont->m_eType == fonttype::TrueType )
analyzeTrueTypeFile( pFont );
}
for( int i = 0; i < nLen; i++ )
{
if( ! pFont->m_pMetrics ||
! ( pFont->m_pMetrics->m_aPages[ pString[i] >> 11 ] & ( 1 << ( ( pString[i] >> 8 ) & 7 ) ) ) )
pFont->queryMetricPage( pString[i] >> 8, m_pAtoms );
pArray[i].width = pArray[i].height = -1;
if( pFont->m_pMetrics )
{
int effectiveCode = pString[i];
effectiveCode |= bVertical ? 1 << 16 : 0;
::std::hash_map< int, CharacterMetric >::const_iterator it =
pFont->m_pMetrics->m_aMetrics.find( effectiveCode );
// if no vertical metrics are available assume rotated horizontal metrics
if( bVertical && (it == pFont->m_pMetrics->m_aMetrics.end()) )
it = pFont->m_pMetrics->m_aMetrics.find( pString[i] );
// the character metrics are in it->second
if( it != pFont->m_pMetrics->m_aMetrics.end() )
pArray[ i ] = it->second;
}
}
return true;
}
// -------------------------------------------------------------------------
bool PrintFontManager::getMetrics( fontID nFontID, sal_Unicode minCharacter, sal_Unicode maxCharacter, CharacterMetric* pArray, bool bVertical ) const
{
PrintFont* pFont = getFont( nFontID );
if( ! pFont )
return false;
if( ( pFont->m_nAscend == 0 && pFont->m_nDescend == 0 )
|| ! pFont->m_pMetrics || pFont->m_pMetrics->isEmpty()
)
{
// might be a font not yet analyzed
if( pFont->m_eType == fonttype::Type1 || pFont->m_eType == fonttype::Builtin )
pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, false, false );
else if( pFont->m_eType == fonttype::TrueType )
analyzeTrueTypeFile( pFont );
}
sal_Unicode code = minCharacter;
do
{
if( ! pFont->m_pMetrics ||
! ( pFont->m_pMetrics->m_aPages[ code >> 11 ] & ( 1 << ( ( code >> 8 ) & 7 ) ) ) )
pFont->queryMetricPage( code >> 8, m_pAtoms );
pArray[ code - minCharacter ].width = -1;
pArray[ code - minCharacter ].height = -1;
if( pFont->m_pMetrics )
{
int effectiveCode = code;
effectiveCode |= bVertical ? 1 << 16 : 0;
::std::hash_map< int, CharacterMetric >::const_iterator it =
pFont->m_pMetrics->m_aMetrics.find( effectiveCode );
// if no vertical metrics are available assume rotated horizontal metrics
if( bVertical && (it == pFont->m_pMetrics->m_aMetrics.end()) )
it = pFont->m_pMetrics->m_aMetrics.find( code );
// the character metrics are in it->second
if( it != pFont->m_pMetrics->m_aMetrics.end() )
pArray[ code - minCharacter ] = it->second;
}
} while( code++ != maxCharacter );
return true;
}
// -------------------------------------------------------------------------
static bool createWriteablePath( const ByteString& rPath )
{
bool bSuccess = false;
if( access( rPath.GetBuffer(), W_OK ) )
{
int nPos = rPath.SearchBackward( '/' );
if( nPos != STRING_NOTFOUND )
while( nPos > 0 && rPath.GetChar( nPos ) == '/' )
nPos--;
if( nPos != STRING_NOTFOUND && nPos != 0 && createWriteablePath( rPath.Copy( 0, nPos+1 ) ) )
{
bSuccess = mkdir( rPath.GetBuffer(), 0777 ) ? false : true;
}
}
else
bSuccess = true;
return bSuccess;
}
// -------------------------------------------------------------------------
int PrintFontManager::importFonts( const ::std::list< OString >& rFiles, bool bLinkOnly, ImportFontCallback* pCallback )
{
int nSuccess = 0;
// find a directory with write access
rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
bool bCanWrite = false;
int nDirID = 0;
INetURLObject aDir;
for( ::std::list< int >::const_iterator dir_it = m_aPrivateFontDirectories.begin();
! bCanWrite && dir_it != m_aPrivateFontDirectories.end(); ++dir_it )
{
// check if we can create files in that directory
ByteString aDirPath = getDirectory( *dir_it );
if( createWriteablePath( aDirPath ) )
{
aDir = INetURLObject( OStringToOUString( aDirPath, aEncoding ), INET_PROT_FILE, INetURLObject::ENCODE_ALL );
nDirID = *dir_it;
bCanWrite = true;
}
}
if( bCanWrite )
{
for( ::std::list< OString >::const_iterator font_it = rFiles.begin();
font_it != rFiles.end(); ++font_it )
{
INetURLObject aFrom( OStringToOUString( *font_it, aEncoding ), INET_PROT_FILE, INetURLObject::ENCODE_ALL );
INetURLObject aTo( aDir );
aTo.Append( aFrom.GetName() );
if( pCallback )
pCallback->progress( aTo.PathToFileName() );
if( pCallback && pCallback->isCanceled() )
break;
if( ! access( ByteString( String(aTo.PathToFileName()), aEncoding ).GetBuffer(), F_OK ) )
{
if( ! ( pCallback ? pCallback->queryOverwriteFile( aTo.PathToFileName() ) : false ) )
continue;
}
// look for afm if necessary
OUString aAfmCopied;
FileBase::RC nError;
if( aFrom.getExtension().equalsIgnoreAsciiCaseAscii( "pfa" ) ||
aFrom.getExtension().equalsIgnoreAsciiCaseAscii( "pfb" ) )
{
INetURLObject aFromAfm( aFrom );
aFromAfm.setExtension( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "afm" ) ) );
if( access( ByteString( String(aFromAfm.PathToFileName()), aEncoding ).GetBuffer(), F_OK ) )
{
aFromAfm.setExtension( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "AFM" ) ) );
if( access( ByteString( String(aFromAfm.PathToFileName()), aEncoding ).GetBuffer(), F_OK ) )
{
aFromAfm.removeSegment();
aFromAfm.Append( String( RTL_CONSTASCII_USTRINGPARAM( "afm" ) ) );
aFromAfm.Append( aTo.GetName() );
aFromAfm.setExtension( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "afm" ) ) );
if( access( ByteString( String(aFromAfm.PathToFileName()), aEncoding ).GetBuffer(), F_OK ) )
{
aFromAfm.setExtension( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "AFM" ) ) );
if( access( ByteString( String(aFromAfm.PathToFileName()), aEncoding ).GetBuffer(), F_OK ) )
{
// give up
if( pCallback )
pCallback->importFontFailed( aTo.PathToFileName(), ImportFontCallback::NoAfmMetric );
continue;
}
}
}
}
INetURLObject aToAfm( aTo );
aToAfm.setExtension( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "afm" ) ) );
OUString aFromPath, aToPath;
if( bLinkOnly )
{
ByteString aLinkFromPath( String(aFromAfm.PathToFileName()),
aEncoding );
ByteString aLinkToPath( String(aToAfm.PathToFileName()),
aEncoding );
nError = (FileBase::RC)symlink( aLinkFromPath.GetBuffer(), aLinkToPath.GetBuffer() );
}
else
nError = File::copy( aFromAfm.GetMainURL(INetURLObject::DECODE_TO_IURI), aToAfm.GetMainURL(INetURLObject::DECODE_TO_IURI) );
if( nError )
{
if( pCallback )
pCallback->importFontFailed( aTo.PathToFileName(), ImportFontCallback::AfmCopyFailed );
continue;
}
aAfmCopied = aToPath;
}
if( bLinkOnly )
{
ByteString aFromPath( String(aFrom.PathToFileName()),
aEncoding );
ByteString aToPath( String(aTo.PathToFileName()), aEncoding );
nError = (FileBase::RC)symlink( aFromPath.GetBuffer(),
aToPath.GetBuffer() );
}
else
nError = File::copy( aFrom.GetMainURL(INetURLObject::DECODE_TO_IURI), aTo.GetMainURL(INetURLObject::DECODE_TO_IURI) );
// copy font file
if( nError )
{
if( aAfmCopied.getLength() )
File::remove( aAfmCopied );
if( pCallback )
pCallback->importFontFailed( aTo.PathToFileName(), ImportFontCallback::FontCopyFailed );
continue;
}
::std::list< PrintFont* > aNewFonts;
::std::list< PrintFont* >::iterator it;
if( analyzeFontFile( nDirID, OUStringToOString( aTo.GetName(), aEncoding ), ::std::list<OString>(), aNewFonts ) )
{
// remove all fonts for the same file
// discarding their font ids
::std::hash_map< fontID, PrintFont* >::iterator current, next;
current = m_aFonts.begin();
OString aFileName( OUStringToOString( aTo.GetName(), aEncoding ) );
while( current != m_aFonts.end() )
{
bool bRemove = false;
switch( current->second->m_eType )
{
case fonttype::Type1:
if( static_cast<Type1FontFile*>(current->second)->m_aFontFile == aFileName )
bRemove = true;
break;
case fonttype::TrueType:
if( static_cast<TrueTypeFontFile*>(current->second)->m_aFontFile == aFileName )
bRemove = true;
break;
default: break;
}
if( bRemove )
{
next = current;
++next;
m_aFontFileToFontID[ aFileName ].erase( current->first );
delete current->second;
m_aFonts.erase( current );
current = next;
}
else
++current;
}
DBG_ASSERT( !findFontFileID( nDirID, aFileName ), "not all fonts removed for file" );
nSuccess++;
for( it = aNewFonts.begin(); it != aNewFonts.end(); ++it )
{
m_aFontFileToFontID[ aFileName ].insert( m_nNextFontID );
m_aFonts[ m_nNextFontID++ ] = *it;
m_pFontCache->updateFontCacheEntry( *it, false );
}
}
}
m_pFontCache->updateDirTimestamp( nDirID );
m_pFontCache->flush();
}
else if( pCallback )
pCallback->importFontsFailed( ImportFontCallback::NoWritableDirectory );
return nSuccess;
}
// -------------------------------------------------------------------------
bool PrintFontManager::checkImportPossible() const
{
bool bSuccess = false;
// find a directory with write access
ByteString aDir;
for( std::list< int >::const_iterator dir_it = m_aPrivateFontDirectories.begin();
dir_it != m_aPrivateFontDirectories.end(); ++dir_it )
{
aDir = getDirectory( *dir_it );
if( createWriteablePath( aDir ) )
{
bSuccess = true;
break;
}
}
#if OSL_DEBUG_LEVEL > 1
if( bSuccess )
fprintf( stderr, "found writable %s\n", aDir.GetBuffer() );
#endif
return bSuccess;
}
// -------------------------------------------------------------------------
bool PrintFontManager::checkChangeFontPropertiesPossible( fontID /*nFontID*/ ) const
{
// since font properties are changed in the font cache file only nowadays
// they can always be changed
return true;
}
// -------------------------------------------------------------------------
bool PrintFontManager::changeFontProperties( fontID nFontID, const ::rtl::OUString& rXLFD )
{
ByteString aXLFD( OUStringToOString( rXLFD, RTL_TEXTENCODING_UTF8 ) );
ByteString aAddStyle = aXLFD.GetToken( '-', 6 );
if( aAddStyle.Search( "utf8" ) == STRING_NOTFOUND )
{
aAddStyle.Append( aAddStyle.Len() ? ";utf8" : "utf8" );
aXLFD.SetToken( 6, ';', aAddStyle );
}
PrintFont* pFont = getFont( nFontID );
std::list< OString > aDummyList;
aDummyList.push_back( aXLFD );
getFontAttributesFromXLFD( pFont, aDummyList );
pFont->m_bUserOverride = true;
m_pFontCache->updateFontCacheEntry( pFont, true );
return true;
}
// -------------------------------------------------------------------------
bool PrintFontManager::
getImportableFontProperties(
const OString& rFile,
::std::list< FastPrintFontInfo >& rFontProps
)
{
rFontProps.clear();
int nIndex = rFile.lastIndexOf( '/' );
OString aDir, aFile( rFile.copy( nIndex+1 ) );
if( nIndex != -1 )
aDir = rFile.copy( 0, nIndex );
int nDirID = getDirectoryAtom( aDir, true );
::std::list< PrintFont* > aFonts;
bool bRet = analyzeFontFile( nDirID, aFile, ::std::list<OString>(), aFonts );
while( aFonts.begin() != aFonts.end() )
{
PrintFont* pFont = aFonts.front();
aFonts.pop_front();
FastPrintFontInfo aInfo;
fillPrintFontInfo( pFont, aInfo );
rFontProps.push_back( aInfo );
delete pFont;
}
return bRet;
}
// -------------------------------------------------------------------------
bool PrintFontManager::getFileDuplicates( fontID nFont, ::std::list< fontID >& rFonts ) const
{
bool bRet = false;
rFonts.clear();
PrintFont* pSearchFont = getFont( nFont );
if( ! pSearchFont ||
pSearchFont->m_eType != fonttype::TrueType ||
static_cast<TrueTypeFontFile*>(pSearchFont)->m_nCollectionEntry == -1
)
return false;
OString aFile( getFontFileSysPath( nFont ) );
if( ! aFile.getLength() )
return false;
for( ::std::hash_map< fontID, PrintFont* >::const_iterator it = m_aFonts.begin(); it != m_aFonts.end(); ++it )
{
if( nFont != it->first )
{
OString aCompFile( getFontFile( it->second ) );
if( aCompFile == aFile )
{
rFonts.push_back( it->first );
bRet = true;
}
}
}
return bRet;
}
// -------------------------------------------------------------------------
bool PrintFontManager::removeFonts( const ::std::list< fontID >& rFonts )
{
bool bRet = true;
::std::list< fontID > aDuplicates;
for( ::std::list< fontID >::const_iterator it = rFonts.begin(); it != rFonts.end(); ++it )
{
::std::hash_map< fontID, PrintFont* >::const_iterator haveFont = m_aFonts.find( *it );
if( haveFont == m_aFonts.end() )
continue;
PrintFont* pFont = haveFont->second;
bool bRemoveDuplicates = getFileDuplicates( *it, aDuplicates );
ByteString aFile( getFontFile( pFont ) );
if( aFile.Len() )
{
#if OSL_DEBUG_LEVEL > 1
fprintf( stderr, "try unlink( \"%s\" ) ... ", aFile.GetBuffer() );
#endif
if( unlink( aFile.GetBuffer() ) )
{
bRet = false;
#if OSL_DEBUG_LEVEL > 1
fprintf( stderr, "failed\n" );
#endif
continue;
}
#if OSL_DEBUG_LEVEL > 1
fprintf( stderr, "succeeded\n" );
#endif
OString aAfm( getAfmFile( pFont ) );
if( aAfm.getLength() )
{
#if OSL_DEBUG_LEVEL > 1
fprintf( stderr, "unlink( \"%s\" )\n", aAfm.getStr() );
#endif
unlink( aAfm.getStr() );
}
m_aFonts.erase( *it );
delete pFont;
if( bRemoveDuplicates )
{
for( ::std::list< fontID >::iterator dup = aDuplicates.begin(); dup != aDuplicates.end(); ++dup )
{
m_aFontFileToFontID[ aFile ].erase( *dup );
PrintFont* pDup = m_aFonts[ *dup ];
m_aFonts.erase( *dup );
delete pDup;
}
}
}
}
return bRet;
}
// -------------------------------------------------------------------------
bool PrintFontManager::isPrivateFontFile( fontID nFont ) const
{
bool bRet = false;
int nDirID = -1;
PrintFont* pFont = getFont( nFont );
if( pFont )
{
switch( pFont->m_eType )
{
case fonttype::Type1: nDirID = static_cast< Type1FontFile* >(pFont)->m_nDirectory;break;
case fonttype::TrueType: nDirID = static_cast< TrueTypeFontFile* >(pFont)->m_nDirectory;break;
default: break;
}
}
if( nDirID != -1 )
{
for( ::std::list< int >::const_iterator it = m_aPrivateFontDirectories.begin(); it != m_aPrivateFontDirectories.end(); ++it )
{
if( nDirID == *it )
{
bRet = true;
break;
}
}
}
return bRet;
}
// -------------------------------------------------------------------------
bool PrintFontManager::getAlternativeFamilyNames( fontID nFont, ::std::list< OUString >& rNames ) const
{
rNames.clear();
PrintFont* pFont = getFont( nFont );
if( pFont && pFont->m_eType == fonttype::TrueType )
{
TrueTypeFontFile* pTTFontFile = static_cast< TrueTypeFontFile* >(pFont);
ByteString aFile( getFontFile( pFont ) );
TrueTypeFont* pTTFont;
if( OpenTTFontFile( aFile.GetBuffer(), pTTFontFile->m_nCollectionEntry < 0 ? 0 : pTTFontFile->m_nCollectionEntry, &pTTFont ) == SF_OK )
{
NameRecord* pNameRecords = NULL;
int nNameRecords = GetTTNameRecords( pTTFont, &pNameRecords );
for( int i = 0; i < nNameRecords; i++ )
{
if( pNameRecords[i].nameID != 1 ) // family name
continue;
OUString aFamily( convertTrueTypeName( pNameRecords+i ) );
if( aFamily.getLength()
&&
m_pAtoms->getAtom( ATOM_FAMILYNAME, aFamily, sal_True ) != pFont->m_nFamilyName
)
{
rNames.push_back( aFamily );
}
}
if( nNameRecords )
DisposeNameRecords( pNameRecords, nNameRecords );
CloseTTFont( pTTFont );
}
}
return rNames.begin() != rNames.end();
}
// -------------------------------------------------------------------------
// TODO: move most of this stuff into the central font-subsetting code
bool PrintFontManager::createFontSubset(
FontSubsetInfo& rInfo,
fontID nFont,
const OUString& rOutFile,
sal_GlyphId* pGlyphIds,
sal_uInt8* pNewEncoding,
sal_Int32* pWidths,
int nGlyphs,
bool bVertical
)
{
PrintFont* pFont = getFont( nFont );
if( !pFont )
return false;
switch( pFont->m_eType )
{
case psp::fonttype::TrueType: rInfo.m_nFontType = FontSubsetInfo::SFNT_TTF; break;
case psp::fonttype::Type1: rInfo.m_nFontType = FontSubsetInfo::ANY_TYPE1; break;
default:
return false;
}
// TODO: remove when Type1 subsetting gets implemented
if( pFont->m_eType != fonttype::TrueType )
return false;
// reshuffle array of requested glyphs to make sure glyph0==notdef
sal_uInt8 pEnc[256];
sal_uInt16 pGID[256];
sal_uInt8 pOldIndex[256];
memset( pEnc, 0, sizeof( pEnc ) );
memset( pGID, 0, sizeof( pGID ) );
memset( pOldIndex, 0, sizeof( pOldIndex ) );
if( nGlyphs > 256 )
return false;
int nChar = 1;
for( int i = 0; i < nGlyphs; i++ )
{
if( pNewEncoding[i] == 0 )
{
pOldIndex[ 0 ] = i;
}
else
{
DBG_ASSERT( !(pGlyphIds[i] & 0x007f0000), "overlong glyph id" );
DBG_ASSERT( (int)pNewEncoding[i] < nGlyphs, "encoding wrong" );
DBG_ASSERT( pEnc[pNewEncoding[i]] == 0 && pGID[pNewEncoding[i]] == 0, "duplicate encoded glyph" );
pEnc[ pNewEncoding[i] ] = pNewEncoding[i];
pGID[ pNewEncoding[i] ] = (sal_uInt16)pGlyphIds[ i ];
pOldIndex[ pNewEncoding[i] ] = i;
nChar++;
}
}
nGlyphs = nChar; // either input value or increased by one
// prepare system name for read access for subset source file
// TODO: since this file is usually already mmapped there is no need to open it again
const ByteString aFromFile = getFontFile( pFont );
TrueTypeFont* pTTFont = NULL; // TODO: rename to SfntFont
TrueTypeFontFile* pTTFontFile = static_cast< TrueTypeFontFile* >(pFont);
if( OpenTTFontFile( aFromFile.GetBuffer(), pTTFontFile->m_nCollectionEntry < 0 ? 0 : pTTFontFile->m_nCollectionEntry, &pTTFont ) != SF_OK )
return false;
// prepare system name for write access for subset file target
OUString aSysPath;
if( osl_File_E_None != osl_getSystemPathFromFileURL( rOutFile.pData, &aSysPath.pData ) )
return false;
const rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
const ByteString aToFile( OUStringToOString( aSysPath, aEncoding ) );
// do CFF subsetting if possible
int nCffLength = 0;
const sal_uInt8* pCffBytes = NULL;
if( GetSfntTable( pTTFont, O_CFF, &pCffBytes, &nCffLength ) )
{
rInfo.LoadFont( FontSubsetInfo::CFF_FONT, pCffBytes, nCffLength );
#if 1 // TODO: remove 16bit->long conversion when related methods handle non-16bit glyphids
sal_GlyphId aRequestedGlyphIds[256];
for( int i = 0; i < nGlyphs; ++i )
aRequestedGlyphIds[i] = pGID[i];
#endif
// create subset file at requested path
FILE* pOutFile = fopen( aToFile.GetBuffer(), "wb" );
// create font subset
const char* pGlyphSetName = NULL; // TODO: better name?
const bool bOK = rInfo.CreateFontSubset(
FontSubsetInfo::TYPE1_PFB,
pOutFile, pGlyphSetName,
aRequestedGlyphIds, pEnc, nGlyphs, pWidths );
fclose( pOutFile );
// cleanup before early return
CloseTTFont( pTTFont );
return bOK;
}
// do TTF->Type42 or Type3 subsetting
// fill in font info
psp::PrintFontInfo aFontInfo;
if( ! getFontInfo( nFont, aFontInfo ) )
return false;
rInfo.m_nAscent = aFontInfo.m_nAscend;
rInfo.m_nDescent = aFontInfo.m_nDescend;
rInfo.m_aPSName = getPSName( nFont );
int xMin, yMin, xMax, yMax;
getFontBoundingBox( nFont, xMin, yMin, xMax, yMax );
rInfo.m_aFontBBox = Rectangle( Point( xMin, yMin ), Size( xMax-xMin, yMax-yMin ) );
rInfo.m_nCapHeight = yMax; // Well ...
// fill in glyph advance widths
TTSimpleGlyphMetrics* pMetrics = GetTTSimpleGlyphMetrics( pTTFont,
pGID,
nGlyphs,
bVertical ? 1 : 0 );
if( pMetrics )
{
for( int i = 0; i < nGlyphs; i++ )
pWidths[pOldIndex[i]] = pMetrics[i].adv;
free( pMetrics );
}
else
{
CloseTTFont( pTTFont );
return false;
}
bool bSuccess = ( SF_OK == CreateTTFromTTGlyphs( pTTFont,
aToFile.GetBuffer(),
pGID,
pEnc,
nGlyphs,
0,
NULL,
0 ) );
CloseTTFont( pTTFont );
return bSuccess;
}
void PrintFontManager::getGlyphWidths( fontID nFont,
bool bVertical,
std::vector< sal_Int32 >& rWidths,
std::map< sal_Unicode, sal_uInt32 >& rUnicodeEnc )
{
PrintFont* pFont = getFont( nFont );
if( !pFont ||
(pFont->m_eType != fonttype::TrueType && pFont->m_eType != fonttype::Type1) )
return;
if( pFont->m_eType == fonttype::TrueType )
{
TrueTypeFont* pTTFont = NULL;
TrueTypeFontFile* pTTFontFile = static_cast< TrueTypeFontFile* >(pFont);
ByteString aFromFile = getFontFile( pFont );
if( OpenTTFontFile( aFromFile.GetBuffer(), pTTFontFile->m_nCollectionEntry < 0 ? 0 : pTTFontFile->m_nCollectionEntry, &pTTFont ) != SF_OK )
return;
int nGlyphs = GetTTGlyphCount( pTTFont );
if( nGlyphs > 0 )
{
rWidths.resize(nGlyphs);
std::vector<sal_uInt16> aGlyphIds(nGlyphs);
for( int i = 0; i < nGlyphs; i++ )
aGlyphIds[i] = sal_uInt16(i);
TTSimpleGlyphMetrics* pMetrics = GetTTSimpleGlyphMetrics( pTTFont,
&aGlyphIds[0],
nGlyphs,
bVertical ? 1 : 0 );
if( pMetrics )
{
for( int i = 0; i< nGlyphs; i++ )
rWidths[i] = pMetrics[i].adv;
free( pMetrics );
rUnicodeEnc.clear();
}
// fill the unicode map
// TODO: isn't this map already available elsewhere in the fontmanager?
const sal_uInt8* pCmapData = NULL;
int nCmapSize = 0;
if( GetSfntTable( pTTFont, O_cmap, &pCmapData, &nCmapSize ) )
{
CmapResult aCmapResult;
if( ParseCMAP( pCmapData, nCmapSize, aCmapResult ) )
{
const ImplFontCharMap aCharMap( aCmapResult );
for( sal_uInt32 cOld = 0;;)
{
// get next unicode covered by font
const sal_uInt32 c = aCharMap.GetNextChar( cOld );
if( c == cOld )
break;
cOld = c;
#if 1 // TODO: remove when sal_Unicode covers all of unicode
if( c > (sal_Unicode)~0 )
break;
#endif
// get the matching glyph index
const sal_GlyphId aGlyphId = aCharMap.GetGlyphIndex( c );
// update the requested map
rUnicodeEnc[ (sal_Unicode)c ] = aGlyphId;
}
}
}
}
CloseTTFont( pTTFont );
}
else if( pFont->m_eType == fonttype::Type1 )
{
if( ! pFont->m_aEncodingVector.size() )
pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, true, true );
if( pFont->m_pMetrics )
{
rUnicodeEnc.clear();
rWidths.clear();
rWidths.reserve( pFont->m_pMetrics->m_aMetrics.size() );
for( std::hash_map< int, CharacterMetric >::const_iterator it =
pFont->m_pMetrics->m_aMetrics.begin();
it != pFont->m_pMetrics->m_aMetrics.end(); ++it )
{
if( (it->first & 0x00010000) == 0 || bVertical )
{
rUnicodeEnc[ sal_Unicode(it->first & 0x0000ffff) ] = sal_uInt32(rWidths.size());
rWidths.push_back( it->second.width );
}
}
}
}
}
// -------------------------------------------------------------------------
const std::map< sal_Unicode, sal_Int32 >* PrintFontManager::getEncodingMap( fontID nFont, const std::map< sal_Unicode, rtl::OString >** pNonEncoded ) const
{
PrintFont* pFont = getFont( nFont );
if( !pFont ||
(pFont->m_eType != fonttype::Type1 && pFont->m_eType != fonttype::Builtin)
)
return NULL;
if( ! pFont->m_aEncodingVector.size() )
pFont->readAfmMetrics( getAfmFile( pFont ), m_pAtoms, true, true );
if( pNonEncoded )
*pNonEncoded = pFont->m_aNonEncoded.size() ? &pFont->m_aNonEncoded : NULL;
return pFont->m_aEncodingVector.size() ? &pFont->m_aEncodingVector : NULL;
}
// -------------------------------------------------------------------------
std::list< OString > PrintFontManager::getAdobeNameFromUnicode( sal_Unicode aChar ) const
{
std::pair< std::hash_multimap< sal_Unicode, rtl::OString >::const_iterator,
std::hash_multimap< sal_Unicode, rtl::OString >::const_iterator > range
= m_aUnicodeToAdobename.equal_range( aChar );
std::list< OString > aRet;
for( ; range.first != range.second; ++range.first )
aRet.push_back( range.first->second );
if( aRet.begin() == aRet.end() && aChar != 0 )
{
sal_Char aBuf[8];
sal_Int32 nChars = snprintf( (char*)aBuf, sizeof( aBuf ), "uni%.4hX", aChar );
aRet.push_back( OString( aBuf, nChars ) );
}
return aRet;
}
// -------------------------------------------------------------------------
std::list< sal_Unicode > PrintFontManager::getUnicodeFromAdobeName( const rtl::OString& rName ) const
{
std::pair< std::hash_multimap< rtl::OString, sal_Unicode, rtl::OStringHash >::const_iterator,
std::hash_multimap< rtl::OString, sal_Unicode, rtl::OStringHash >::const_iterator > range
= m_aAdobenameToUnicode.equal_range( rName );
std::list< sal_Unicode > aRet;
for( ; range.first != range.second; ++range.first )
aRet.push_back( range.first->second );
if( aRet.begin() == aRet.end() )
{
if( rName.getLength() == 7 && rName.indexOf( "uni" ) == 0 )
{
sal_Unicode aCode = (sal_Unicode)rName.copy( 3 ).toInt32( 16 );
aRet.push_back( aCode );
}
}
return aRet;
}
// -------------------------------------------------------------------------
namespace
{
OUString getString( const Any& rAny )
{
OUString aStr;
rAny >>= aStr;
return aStr;
}
bool getBool( const Any& rAny )
{
sal_Bool bBool = sal_False;
rAny >>= bBool;
return static_cast<bool>(bBool);
}
sal_Int32 getInt( const Any& rAny )
{
sal_Int32 n = 0;
rAny >>= n;
return n;
}
}
bool PrintFontManager::readOverrideMetrics()
{
if( ! m_aOverrideFonts.empty() )
return false;
css::uno::Reference< XMultiServiceFactory > xFact( comphelper::getProcessServiceFactory() );
if( !xFact.is() )
return false;
css::uno::Reference< XMaterialHolder > xMat(
xFact->createInstance( OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.psprint.CompatMetricOverride" ) ) ),
UNO_QUERY );
if( !xMat.is() )
return false;
Any aAny( xMat->getMaterial() );
Sequence< Any > aOverrideFonts;
if( ! (aAny >>= aOverrideFonts ) )
return false;
sal_Int32 nFonts = aOverrideFonts.getLength();
for( sal_Int32 i = 0; i < nFonts; i++ )
{
Sequence< NamedValue > aMetrics;
if( ! (aOverrideFonts.getConstArray()[i] >>= aMetrics) )
continue;
BuiltinFont* pFont = new BuiltinFont();
pFont->m_nDirectory = 0;
pFont->m_bUserOverride = false;
pFont->m_pMetrics = new PrintFontMetrics;
memset( pFont->m_pMetrics->m_aPages, 0xff, sizeof( pFont->m_pMetrics->m_aPages ) );
pFont->m_pMetrics->m_bKernPairsQueried = true;
sal_Int32 nProps = aMetrics.getLength();
const NamedValue* pProps = aMetrics.getConstArray();
for( sal_Int32 n = 0; n < nProps; n++ )
{
if( pProps[n].Name.equalsAscii( "FamilyName" ) )
pFont->m_nFamilyName = m_pAtoms->getAtom( ATOM_FAMILYNAME,
getString(pProps[n].Value),
sal_True );
else if( pProps[n].Name.equalsAscii( "PSName" ) )
pFont->m_nPSName = m_pAtoms->getAtom( ATOM_PSNAME,
getString(pProps[n].Value),
sal_True );
else if( pProps[n].Name.equalsAscii( "StyleName" ) )
pFont->m_aStyleName = getString(pProps[n].Value);
else if( pProps[n].Name.equalsAscii( "Italic" ) )
pFont->m_eItalic = static_cast<italic::type>(getInt(pProps[n].Value));
else if( pProps[n].Name.equalsAscii( "Width" ) )
pFont->m_eWidth = static_cast<width::type>(getInt(pProps[n].Value));
else if( pProps[n].Name.equalsAscii( "Weight" ) )
pFont->m_eWeight = static_cast<weight::type>(getInt(pProps[n].Value));
else if( pProps[n].Name.equalsAscii( "Pitch" ) )
pFont->m_ePitch = static_cast<pitch::type>(getInt(pProps[n].Value));
else if( pProps[n].Name.equalsAscii( "Encoding" ) )
pFont->m_aEncoding = static_cast<rtl_TextEncoding>(getInt(pProps[n].Value));
else if( pProps[n].Name.equalsAscii( "FontEncodingOnly" ) )
pFont->m_bFontEncodingOnly = getBool(pProps[n].Value);
else if( pProps[n].Name.equalsAscii( "GlobalMetricXWidth" ) )
pFont->m_aGlobalMetricX.width = getInt(pProps[n].Value);
else if( pProps[n].Name.equalsAscii( "GlobalMetricXHeight" ) )
pFont->m_aGlobalMetricX.height = getInt(pProps[n].Value);
else if( pProps[n].Name.equalsAscii( "GlobalMetricYWidth" ) )
pFont->m_aGlobalMetricY.width = getInt(pProps[n].Value);
else if( pProps[n].Name.equalsAscii( "GlobalMetricYHeight" ) )
pFont->m_aGlobalMetricY.height = getInt(pProps[n].Value);
else if( pProps[n].Name.equalsAscii( "Ascend" ) )
pFont->m_nAscend = getInt(pProps[n].Value);
else if( pProps[n].Name.equalsAscii( "Descend" ) )
pFont->m_nDescend = getInt(pProps[n].Value);
else if( pProps[n].Name.equalsAscii( "Leading" ) )
pFont->m_nLeading = getInt(pProps[n].Value);
else if( pProps[n].Name.equalsAscii( "XMin" ) )
pFont->m_nXMin = getInt(pProps[n].Value);
else if( pProps[n].Name.equalsAscii( "YMin" ) )
pFont->m_nYMin = getInt(pProps[n].Value);
else if( pProps[n].Name.equalsAscii( "XMax" ) )
pFont->m_nXMax = getInt(pProps[n].Value);
else if( pProps[n].Name.equalsAscii( "YMax" ) )
pFont->m_nYMax = getInt(pProps[n].Value);
else if( pProps[n].Name.equalsAscii( "VerticalSubstitutes" ) )
pFont->m_bHaveVerticalSubstitutedGlyphs = getBool(pProps[n].Value);
else if( pProps[n].Name.equalsAscii( "EncodingVector" ) )
{
Sequence< NamedValue > aEncoding;
pProps[n].Value >>= aEncoding;
sal_Int32 nEnc = aEncoding.getLength();
const NamedValue* pEnc = aEncoding.getConstArray();
for( sal_Int32 m = 0; m < nEnc; m++ )
{
sal_Unicode cCode = *pEnc[m].Name.getStr();
sal_Int32 nGlyph = getInt(pEnc[m].Value);
pFont->m_aEncodingVector[ cCode ] = nGlyph;
}
}
else if( pProps[n].Name.equalsAscii( "NonEncoded" ) )
{
Sequence< NamedValue > aEncoding;
pProps[n].Value >>= aEncoding;
sal_Int32 nEnc = aEncoding.getLength();
const NamedValue* pEnc = aEncoding.getConstArray();
for( sal_Int32 m = 0; m < nEnc; m++ )
{
sal_Unicode cCode = *pEnc[m].Name.getStr();
OUString aGlyphName( getString(pEnc[m].Value) );
pFont->m_aNonEncoded[ cCode ] = OUStringToOString(aGlyphName,RTL_TEXTENCODING_ASCII_US);
}
}
else if( pProps[n].Name.equalsAscii( "CharacterMetrics" ) )
{
// fill pFont->m_pMetrics->m_aMetrics
// expect triples of int: int -> CharacterMetric.{ width, height }
Sequence< sal_Int32 > aSeq;
pProps[n].Value >>= aSeq;
sal_Int32 nInts = aSeq.getLength();
const sal_Int32* pInts = aSeq.getConstArray();
for( sal_Int32 m = 0; m < nInts; m+=3 )
{
pFont->m_pMetrics->m_aMetrics[ pInts[m] ].width = static_cast<short int>(pInts[m+1]);
pFont->m_pMetrics->m_aMetrics[ pInts[m] ].height = static_cast<short int>(pInts[m+2]);
}
}
else if( pProps[n].Name.equalsAscii( "XKernPairs" ) )
{
// fill pFont->m_pMetrics->m_aXKernPairs
// expection name: <unicode1><unicode2> value: ((height << 16)| width)
Sequence< NamedValue > aKern;
pProps[n].Value >>= aKern;
KernPair aPair;
const NamedValue* pVals = aKern.getConstArray();
int nPairs = aKern.getLength();
for( int m = 0; m < nPairs; m++ )
{
if( pVals[m].Name.getLength() == 2 )
{
aPair.first = pVals[m].Name.getStr()[0];
aPair.second = pVals[m].Name.getStr()[1];
sal_Int32 nKern = getInt( pVals[m].Value );
aPair.kern_x = static_cast<short int>(nKern & 0xffff);
aPair.kern_y = static_cast<short int>((sal_uInt32(nKern) >> 16) & 0xffff);
pFont->m_pMetrics->m_aXKernPairs.push_back( aPair );
}
}
}
}
// sanity check
if( pFont->m_nPSName &&
pFont->m_nFamilyName &&
! pFont->m_pMetrics->m_aMetrics.empty() )
{
m_aOverrideFonts.push_back( m_nNextFontID );
m_aFonts[ m_nNextFontID++ ] = pFont;
}
else
{
DBG_ASSERT( 0, "override font failed" );
delete pFont;
}
}
return true;
}