From 6441cd60c3c903727487e0e10955bd51486e47d9 Mon Sep 17 00:00:00 2001 From: Michael Stahl Date: Tue, 27 Jan 2015 14:11:09 +0000 Subject: [PATCH] rhbz#1177022: vcl: fix PDF embedding of Type 1 fonts Change-Id: I03056c9e1cfb87f2f0e339db701954c150c8ea3c --- include/vcl/fontmanager.hxx | 7 ++++++- vcl/generic/fontmanager/fontmanager.cxx | 25 +++++++++++++++++++++- vcl/generic/print/genpspgraphics.cxx | 8 +++---- vcl/headless/svptext.cxx | 4 ++-- vcl/inc/generic/genpspgraphics.h | 4 ++-- vcl/inc/headless/svpgdi.hxx | 2 +- vcl/inc/salgdi.hxx | 8 +++++-- vcl/inc/unx/salgdi.h | 2 +- vcl/inc/win/salgdi.h | 2 +- vcl/source/gdi/pdfwriter_impl.cxx | 37 +++++++++++++++++++++++++++++++-- vcl/unx/generic/gdi/salgdi3.cxx | 4 ++-- vcl/win/source/gdi/salgdi3.cxx | 2 +- 12 files changed, 85 insertions(+), 20 deletions(-) diff --git a/include/vcl/fontmanager.hxx b/include/vcl/fontmanager.hxx index 7f8511d..675287e 100644 --- a/include/vcl/fontmanager.hxx +++ b/include/vcl/fontmanager.hxx @@ -202,7 +202,12 @@ class VCL_PLUGIN_PUBLIC PrintFontManager bool m_bHaveVerticalSubstitutedGlyphs; bool m_bUserOverride; + /// mapping from unicode (well, UCS-2) to font code std::map< sal_Unicode, sal_Int32 > m_aEncodingVector; + /// HACK for Type 1 fonts: if multiple UCS-2 codes map to the same + /// font code, this set contains the preferred one, i.e., the one that + /// is specified explicitly via "C" or "CH" in the AFM file + std::set m_aEncodingVectorPriority; std::map< sal_Unicode, OString > m_aNonEncoded; explicit PrintFont( fonttype::type eType ); @@ -458,7 +463,7 @@ public: // builtin; if ppNonEncoded is set and non encoded type1 glyphs exist // then *ppNonEncoded is set to the mapping for nonencoded glyphs. // the encoding vector contains -1 for non encoded glyphs - const std::map< sal_Unicode, sal_Int32 >* getEncodingMap( fontID nFontID, const std::map< sal_Unicode, OString >** ppNonEncoded ) const; + const std::map< sal_Unicode, sal_Int32 >* getEncodingMap( fontID nFontID, const std::map< sal_Unicode, OString >** ppNonEncoded, std::set const** ppPriority ) const; // evaluates copyright flags for TrueType fonts for printing/viewing // type1 fonts do not have such a feature, so return for them is true diff --git a/vcl/generic/fontmanager/fontmanager.cxx b/vcl/generic/fontmanager/fontmanager.cxx index 9f545cc..dd490d0 100644 --- a/vcl/generic/fontmanager/fontmanager.cxx +++ b/vcl/generic/fontmanager/fontmanager.cxx @@ -332,6 +332,7 @@ bool PrintFontManager::PrintFont::readAfmMetrics( MultiAtomProvider* pProvider, } m_aEncodingVector.clear(); + m_aEncodingVectorPriority.clear(); // fill in global info // PSName @@ -561,7 +562,10 @@ bool PrintFontManager::PrintFont::readAfmMetrics( MultiAtomProvider* pProvider, { pUnicodes[i] = pChar->code + 0xf000; if( bFillEncodingvector ) + { m_aEncodingVector[ pUnicodes[i] ] = pChar->code; + m_aEncodingVectorPriority.insert(pUnicodes[i]); + } continue; } @@ -622,7 +626,10 @@ bool PrintFontManager::PrintFont::readAfmMetrics( MultiAtomProvider* pProvider, { m_pMetrics->m_aMetrics[ pUnicodes[i] ] = aMetric; if( bFillEncodingvector ) + { m_aEncodingVector[ pUnicodes[i] ] = pChar->code; + m_aEncodingVectorPriority.insert(pUnicodes[i]); + } } else if( pChar->name ) { @@ -650,13 +657,21 @@ bool PrintFontManager::PrintFont::readAfmMetrics( MultiAtomProvider* pProvider, ::std::pair< ::boost::unordered_multimap< sal_uInt8, sal_Unicode >::const_iterator, ::boost::unordered_multimap< sal_uInt8, sal_Unicode >::const_iterator > aCodes = rManager.getUnicodeFromAdobeCode( pChar->code ); + bool bFirst = true; 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; + if (bFirst) // arbitrarily prefer the first one + { + m_aEncodingVectorPriority.insert((*aCodes.first).second); + bFirst = false; + } + } } ++aCodes.first; } @@ -670,7 +685,10 @@ bool PrintFontManager::PrintFont::readAfmMetrics( MultiAtomProvider* pProvider, m_pMetrics->m_aMetrics[ code ] = aMetric; // maybe should try to find the name in the convtabs ? if( bFillEncodingvector ) + { m_aEncodingVector[ code ] = pChar->code; + m_aEncodingVectorPriority.insert(code); + } } } } @@ -2474,7 +2492,7 @@ void PrintFontManager::getGlyphWidths( fontID nFont, // ------------------------------------------------------------------------- -const std::map< sal_Unicode, sal_Int32 >* PrintFontManager::getEncodingMap( fontID nFont, const std::map< sal_Unicode, OString >** pNonEncoded ) const +const std::map< sal_Unicode, sal_Int32 >* PrintFontManager::getEncodingMap( fontID nFont, const std::map< sal_Unicode, OString >** pNonEncoded, std::set const** ppPriority ) const { PrintFont* pFont = getFont( nFont ); if( !pFont || @@ -2488,6 +2506,11 @@ const std::map< sal_Unicode, sal_Int32 >* PrintFontManager::getEncodingMap( font if( pNonEncoded ) *pNonEncoded = pFont->m_aNonEncoded.size() ? &pFont->m_aNonEncoded : NULL; + if (ppPriority) + { + *ppPriority = &pFont->m_aEncodingVectorPriority; + } + return pFont->m_aEncodingVector.size() ? &pFont->m_aEncodingVector : NULL; } diff --git a/vcl/generic/print/genpspgraphics.cxx b/vcl/generic/print/genpspgraphics.cxx index 542986a..0c9d073 100644 --- a/vcl/generic/print/genpspgraphics.cxx +++ b/vcl/generic/print/genpspgraphics.cxx @@ -1046,7 +1046,7 @@ sal_Bool GenPspGraphics::CreateFontSubset( //-------------------------------------------------------------------------- -const Ucs2SIntMap* GenPspGraphics::GetFontEncodingVector( const PhysicalFontFace* pFont, const Ucs2OStrMap** pNonEncoded ) +const Ucs2SIntMap* GenPspGraphics::GetFontEncodingVector( const PhysicalFontFace* pFont, const Ucs2OStrMap** pNonEncoded, std::set const** ppPriority) { // in this context the pFont->GetFontId() is a valid PSP // font since they are the only ones left after the PDF @@ -1054,7 +1054,7 @@ const Ucs2SIntMap* GenPspGraphics::GetFontEncodingVector( const PhysicalFontFace // which this method was created). The correct way would // be to have the GlyphCache search for the PhysicalFontFace pFont psp::fontID aFont = pFont->GetFontId(); - return GenPspGraphics::DoGetFontEncodingVector( aFont, pNonEncoded ); + return GenPspGraphics::DoGetFontEncodingVector( aFont, pNonEncoded, ppPriority ); } //-------------------------------------------------------------------------- @@ -1073,7 +1073,7 @@ void GenPspGraphics::GetGlyphWidths( const PhysicalFontFace* pFont, GenPspGraphics::DoGetGlyphWidths( aFont, bVertical, rWidths, rUnicodeEnc ); } -const Ucs2SIntMap* GenPspGraphics::DoGetFontEncodingVector( fontID aFont, const Ucs2OStrMap** pNonEncoded ) +const Ucs2SIntMap* GenPspGraphics::DoGetFontEncodingVector( fontID aFont, const Ucs2OStrMap** pNonEncoded, std::set const** ppPriority) { psp::PrintFontManager& rMgr = psp::PrintFontManager::get(); @@ -1085,7 +1085,7 @@ const Ucs2SIntMap* GenPspGraphics::DoGetFontEncodingVector( fontID aFont, const return NULL; } - return rMgr.getEncodingMap( aFont, pNonEncoded ); + return rMgr.getEncodingMap( aFont, pNonEncoded, ppPriority ); } void GenPspGraphics::DoGetGlyphWidths( psp::fontID aFont, diff --git a/vcl/headless/svptext.cxx b/vcl/headless/svptext.cxx index 0a4bbd1..9c99101 100644 --- a/vcl/headless/svptext.cxx +++ b/vcl/headless/svptext.cxx @@ -340,7 +340,7 @@ sal_Bool SvpSalGraphics::CreateFontSubset( } -const Ucs2SIntMap* SvpSalGraphics::GetFontEncodingVector( const PhysicalFontFace* pFont, const Ucs2OStrMap** pNonEncoded ) +const Ucs2SIntMap* SvpSalGraphics::GetFontEncodingVector( const PhysicalFontFace* pFont, const Ucs2OStrMap** pNonEncoded, std::set const** ppPriority) { // in this context the pFont->GetFontId() is a valid PSP // font since they are the only ones left after the PDF @@ -348,7 +348,7 @@ const Ucs2SIntMap* SvpSalGraphics::GetFontEncodingVector( const PhysicalFontFace // which this method was created). The correct way would // be to have the GlyphCache search for the PhysicalFontFace pFont psp::fontID aFont = pFont->GetFontId(); - return GenPspGraphics::DoGetFontEncodingVector( aFont, pNonEncoded ); + return GenPspGraphics::DoGetFontEncodingVector(aFont, pNonEncoded, ppPriority); } diff --git a/vcl/inc/generic/genpspgraphics.h b/vcl/inc/generic/genpspgraphics.h index 74ccf65..bb45c75 100644 --- a/vcl/inc/generic/genpspgraphics.h +++ b/vcl/inc/generic/genpspgraphics.h @@ -62,7 +62,7 @@ public: static void DoFreeEmbedFontData( const void* pData, long nLen ); // helper methods for sharing with X11SalGraphics - static const Ucs2SIntMap* DoGetFontEncodingVector( psp::fontID aFont, const Ucs2OStrMap** pNonEncoded ); + static const Ucs2SIntMap* DoGetFontEncodingVector( psp::fontID aFont, const Ucs2OStrMap** pNonEncoded, std::set const** ppPriority ); static void DoGetGlyphWidths( psp::fontID aFont, bool bVertical, Int32Vector& rWidths, @@ -106,7 +106,7 @@ public: int nGlyphs, FontSubsetInfo& rInfo ); - virtual const Ucs2SIntMap* GetFontEncodingVector( const PhysicalFontFace*, const Ucs2OStrMap** ppNonEncoded ); + virtual const Ucs2SIntMap* GetFontEncodingVector( const PhysicalFontFace*, const Ucs2OStrMap** ppNonEncoded, std::set const** ppPriority ); virtual const void* GetEmbedFontData( const PhysicalFontFace*, const sal_Ucs* pUnicodes, sal_Int32* pWidths, diff --git a/vcl/inc/headless/svpgdi.hxx b/vcl/inc/headless/svpgdi.hxx index c36cfd3..b45a562 100644 --- a/vcl/inc/headless/svpgdi.hxx +++ b/vcl/inc/headless/svpgdi.hxx @@ -146,7 +146,7 @@ public: int nGlyphs, FontSubsetInfo& rInfo ); - virtual const Ucs2SIntMap* GetFontEncodingVector( const PhysicalFontFace*, const Ucs2OStrMap** ppNonEncoded ); + virtual const Ucs2SIntMap* GetFontEncodingVector( const PhysicalFontFace*, const Ucs2OStrMap** ppNonEncoded, std::set const** ppPriority ); virtual const void* GetEmbedFontData( const PhysicalFontFace*, const sal_Ucs* pUnicodes, sal_Int32* pWidths, diff --git a/vcl/inc/salgdi.hxx b/vcl/inc/salgdi.hxx index 323c66a..4b8effa 100644 --- a/vcl/inc/salgdi.hxx +++ b/vcl/inc/salgdi.hxx @@ -29,6 +29,7 @@ #include "sallayout.hxx" #include +#include class ImplDevFontList; @@ -278,8 +279,11 @@ public: // glyphs with only a name) exist it is set to the corresponding // map for non encoded glyphs; the encoding vector contains -1 // as encoding for these cases - virtual const Ucs2SIntMap* - GetFontEncodingVector( const PhysicalFontFace*, const Ucs2OStrMap** ppNonEncoded ) = 0; + virtual const Ucs2SIntMap* GetFontEncodingVector( + const PhysicalFontFace*, + const Ucs2OStrMap** ppNonEncoded, + std::set const** ppPriority) = 0; + // GetEmbedFontData: gets the font data for a font marked // embeddable by GetDevFontList or NULL in case of error diff --git a/vcl/inc/unx/salgdi.h b/vcl/inc/unx/salgdi.h index 9e3e9a5..3476149 100644 --- a/vcl/inc/unx/salgdi.h +++ b/vcl/inc/unx/salgdi.h @@ -242,7 +242,7 @@ public: int nGlyphs, FontSubsetInfo& rInfo ); - virtual const Ucs2SIntMap* GetFontEncodingVector( const PhysicalFontFace*, const Ucs2OStrMap** ppNonEncoded ); + virtual const Ucs2SIntMap* GetFontEncodingVector( const PhysicalFontFace*, const Ucs2OStrMap** ppNonEncoded, std::set const** ppPriority ); virtual const void* GetEmbedFontData( const PhysicalFontFace*, const sal_Ucs* pUnicodes, sal_Int32* pWidths, diff --git a/vcl/inc/win/salgdi.h b/vcl/inc/win/salgdi.h index b54c876..bf33acb 100644 --- a/vcl/inc/win/salgdi.h +++ b/vcl/inc/win/salgdi.h @@ -346,7 +346,7 @@ public: // glyphs with only a name) exist it is set to the corresponding // map for non encoded glyphs; the encoding vector contains -1 // as encoding for these cases - virtual const Ucs2SIntMap* GetFontEncodingVector( const PhysicalFontFace*, const Ucs2OStrMap** ppNonEncoded ); + virtual const Ucs2SIntMap* GetFontEncodingVector( const PhysicalFontFace*, const Ucs2OStrMap** ppNonEncoded, std::set const** ); // GetEmbedFontData: gets the font data for a font marked // embeddable by GetDevFontList or NULL in case of error diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx index 89355ad..c09b81b 100644 --- a/vcl/source/gdi/pdfwriter_impl.cxx +++ b/vcl/source/gdi/pdfwriter_impl.cxx @@ -3071,7 +3071,9 @@ std::map< sal_Int32, sal_Int32 > PDFWriterImpl::emitEmbeddedFont( const Physical sal_Int32 nFontDescriptor = 0; // prepare font encoding - const Ucs2SIntMap* pEncoding = m_pReferenceDevice->mpGraphics->GetFontEncodingVector( pFont, NULL ); + std::set const * pPriority(0); + const Ucs2SIntMap *const pEncoding = + m_pReferenceDevice->mpGraphics->GetFontEncodingVector( pFont, NULL, &pPriority ); sal_Int32 nToUnicodeStream = 0; sal_uInt8 nEncoding[256]; sal_Ucs nEncodedCodes[256]; @@ -3090,6 +3092,37 @@ std::map< sal_Int32, sal_Int32 > PDFWriterImpl::emitEmbeddedFont( const Physical if( it->second != -1 ) { sal_Int32 nCode = (sal_Int32)(it->second & 0x000000ff); + SAL_WARN_IF(nCode != it->second, "vcl.gdi", "emitEmbeddedFont: FIXME: cannot handle Type 1 font with code points > 256"); + if (nEncoding[nCode] != 0) + { + // should not have 2 identical mappings + assert(nEncodedCodes[nCode] != it->first); + if (pPriority) + { + bool bExist = pPriority->find(nEncodedCodes[nCode]) != pPriority->end(); + bool bIter = pPriority->find(it->first) != pPriority->end(); + SAL_WARN_IF(bExist && bIter, "vcl.gdi", "both are preferred? odd..."); + if (bExist) + { + continue; + } + // note: aUnicodes will contain the old one but that + // does not matter because there's nothing iterating it + } + else + { + // is this fallback important? let's prefer lower one + if (nEncodedCodes[nCode] < it->first) + { + SAL_WARN("vcl.gdi", "emitEmbeddedFont: ignoring code " << nCode << " mapping to " << it->first << " in favor of " << nEncodedCodes[nCode]); + continue; + } + else + { + SAL_WARN("vcl.gdi", "emitEmbeddedFont: ignoring code " << nCode << " mapping to " << nEncodedCodes[nCode] << " in favor of " << it->first); + } + } + } nEncoding[ nCode ] = static_cast( nCode ); nEncodedCodes[ nCode ] = it->first; pEncToUnicodeIndex[ nCode ] = static_cast(aUnicodes.size()); @@ -7067,7 +7100,7 @@ void PDFWriterImpl::registerGlyphs( int nGlyphs, const Ucs2SIntMap* pEncoding = NULL; const Ucs2OStrMap* pNonEncoded = NULL; getReferenceDevice()->ImplGetGraphics(); - pEncoding = m_pReferenceDevice->mpGraphics->GetFontEncodingVector( pCurrentFont, &pNonEncoded ); + pEncoding = m_pReferenceDevice->mpGraphics->GetFontEncodingVector( pCurrentFont, &pNonEncoded, 0 ); Ucs2SIntMap::const_iterator enc_it; Ucs2OStrMap::const_iterator nonenc_it; diff --git a/vcl/unx/generic/gdi/salgdi3.cxx b/vcl/unx/generic/gdi/salgdi3.cxx index d6a506971..c28c53d 100644 --- a/vcl/unx/generic/gdi/salgdi3.cxx +++ b/vcl/unx/generic/gdi/salgdi3.cxx @@ -778,7 +778,7 @@ void X11SalGraphics::FreeEmbedFontData( const void* pData, long nLen ) //-------------------------------------------------------------------------- -const Ucs2SIntMap* X11SalGraphics::GetFontEncodingVector( const PhysicalFontFace* pFont, const Ucs2OStrMap** pNonEncoded ) +const Ucs2SIntMap* X11SalGraphics::GetFontEncodingVector( const PhysicalFontFace* pFont, const Ucs2OStrMap** pNonEncoded, std::set const** ppPriority) { // in this context the pFont->GetFontId() is a valid PSP // font since they are the only ones left after the PDF @@ -786,7 +786,7 @@ const Ucs2SIntMap* X11SalGraphics::GetFontEncodingVector( const PhysicalFontFace // which this method was created). The correct way would // be to have the GlyphCache search for the PhysicalFontFace pFont psp::fontID aFont = pFont->GetFontId(); - return GenPspGraphics::DoGetFontEncodingVector( aFont, pNonEncoded ); + return GenPspGraphics::DoGetFontEncodingVector( aFont, pNonEncoded, ppPriority ); } //-------------------------------------------------------------------------- diff --git a/vcl/win/source/gdi/salgdi3.cxx b/vcl/win/source/gdi/salgdi3.cxx index 59f8f4e..7a465c4 100644 --- a/vcl/win/source/gdi/salgdi3.cxx +++ b/vcl/win/source/gdi/salgdi3.cxx @@ -2755,7 +2755,7 @@ void WinSalGraphics::FreeEmbedFontData( const void* pData, long /*nLen*/ ) } -const Ucs2SIntMap* WinSalGraphics::GetFontEncodingVector( const PhysicalFontFace* pFont, const Ucs2OStrMap** pNonEncoded ) +const Ucs2SIntMap* WinSalGraphics::GetFontEncodingVector( const PhysicalFontFace* pFont, const Ucs2OStrMap** pNonEncoded, std::set const**) { // TODO: even for builtin fonts we get here... why? if( !pFont->IsEmbeddable() ) -- 1.9.3