Blob Blame History Raw
From 6441cd60c3c903727487e0e10955bd51486e47d9 Mon Sep 17 00:00:00 2001
From: Michael Stahl <mstahl@redhat.com>
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<sal_Unicode>                  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<sal_Unicode> 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<sal_Unicode> 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<sal_Unicode> 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<sal_Unicode> 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<sal_Unicode> 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<sal_Unicode> 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<sal_Unicode> 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<sal_Unicode> 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 <map>
+#include <set>
 
 
 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<sal_Unicode> 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<sal_Unicode> 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<sal_Unicode> 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<sal_Unicode> 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<sal_uInt8>( nCode );
                 nEncodedCodes[ nCode ] = it->first;
                 pEncToUnicodeIndex[ nCode ] = static_cast<sal_Int32>(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<sal_Unicode> 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<sal_Unicode> const**)
 {
     // TODO: even for builtin fonts we get here... why?
     if( !pFont->IsEmbeddable() )
-- 
1.9.3