81d48c0
From 58b48f188bbfd9a3382460d6de63848eb3db416d Mon Sep 17 00:00:00 2001
81d48c0
From: =?UTF-8?q?Caol=C3=A1n=20McNamara?= <caolanm@redhat.com>
81d48c0
Date: Thu, 27 Oct 2011 12:24:11 +0100
81d48c0
Subject: [PATCH] Resolves: fdo#32665 handle that FreeSerif lacks some glyphs
81d48c0
 in bold/italic
81d48c0
81d48c0
FreeSerif lacks glyphs in bold/italic variants that it has in the normal one. A
81d48c0
lot of our glyph fallback infrastructure, especially the caches don't expect
81d48c0
that a normal variant of a font with extra emboldening or extra font skew can
81d48c0
be a fallback for a bold/italic variant of itself which exists, but doesn't
81d48c0
have the missing glyphs that the normal one does.
81d48c0
81d48c0
We really need to improve our glyph/font caching, but we can get 90% of the
81d48c0
way there by excluding such cases from the caches.
81d48c0
---
81d48c0
 vcl/generic/fontmanager/fontconfig.cxx |   18 ++++++++-
81d48c0
 vcl/generic/fontmanager/fontsubst.cxx  |    6 +++-
81d48c0
 vcl/generic/glyphs/glyphcache.cxx      |    7 ++++
81d48c0
 vcl/inc/outfont.hxx                    |   19 ++++++++++
81d48c0
 vcl/inc/vcl/fontmanager.hxx            |    3 +-
81d48c0
 vcl/source/gdi/outdev3.cxx             |   60 ++++++++++++++++++++++----------
81d48c0
 6 files changed, 90 insertions(+), 23 deletions(-)
81d48c0
81d48c0
diff --git a/vcl/generic/fontmanager/fontconfig.cxx b/vcl/generic/fontmanager/fontconfig.cxx
81d48c0
index be91349..a4f5f7f 100644
375ba1f
--- a/vcl/unx/source/fontmanager/fontconfig.cxx
375ba1f
+++ b/vcl/unx/source/fontmanager/fontconfig.cxx
375ba1f
@@ -68,6 +68,9 @@
375ba1f
     #ifndef FC_EMBOLDEN
375ba1f
         #define FC_EMBOLDEN "embolden"
375ba1f
     #endif
375ba1f
+    #ifndef FC_MATRIX
375ba1f
+        #define FC_MATRIX "matrix"
375ba1f
+    #endif
375ba1f
     #ifndef FC_FONTFORMAT
375ba1f
         #define FC_FONTFORMAT "fontformat"
375ba1f
     #endif
f26e5ca
@@ -145,6 +148,7 @@
f26e5ca
     FcResult		(*m_pFcPatternGetString)(const FcPattern*,const char*,int,FcChar8**);
f26e5ca
     FcResult		(*m_pFcPatternGetInteger)(const FcPattern*,const char*,int,int*);
f26e5ca
     FcResult		(*m_pFcPatternGetDouble)(const FcPattern*,const char*,int,double*);
f26e5ca
+    FcResult		(*m_pFcPatternGetMatrix)(const FcPattern*,const char*,int,FcMatrix**);
f26e5ca
     FcResult		(*m_pFcPatternGetBool)(const FcPattern*,const char*,int,FcBool*);
f26e5ca
     void			(*m_pFcDefaultSubstitute)(FcPattern *);
f26e5ca
     FcPattern*		(*m_pFcFontSetMatch)(FcConfig*,FcFontSet**, int, FcPattern*,FcResult*);    
f26e5ca
@@ -255,6 +259,9 @@
f26e5ca
     FcResult FcPatternGetDouble( const FcPattern* pPattern, const char* object, int n, double* s )
f26e5ca
     { return m_pFcPatternGetDouble( pPattern, object, n, s ); }
f26e5ca
 
f26e5ca
+    FcResult FcPatternGetMatrix( const FcPattern* pPattern, const char* object, int n, FcMatrix** s )
f26e5ca
+    { return m_pFcPatternGetMatrix( pPattern, object, n, s ); }
f26e5ca
+
f26e5ca
     FcResult FcPatternGetBool( const FcPattern* pPattern, const char* object, int n, FcBool* s )
f26e5ca
     { return m_pFcPatternGetBool( pPattern, object, n, s ); }
f26e5ca
     FcBool FcConfigAppFontAddFile( FcConfig* pConfig, const FcChar8* pFileName )
f26e5ca
@@ -381,6 +388,8 @@
f26e5ca
         loadSymbol( "FcPatternGetInteger" );
f26e5ca
     m_pFcPatternGetDouble = (FcResult(*)(const FcPattern*,const char*,int,double*))
f26e5ca
         loadSymbol( "FcPatternGetDouble" );
f26e5ca
+    m_pFcPatternGetMatrix = (FcResult(*)(const FcPattern*,const char*,int,FcMatrix**))
f26e5ca
+        loadSymbol( "FcPatternGetMatrix" );
f26e5ca
     m_pFcPatternGetBool = (FcResult(*)(const FcPattern*,const char*,int,FcBool*))
f26e5ca
         loadSymbol( "FcPatternGetBool" );
f26e5ca
     m_pFcConfigAppFontAddFile = (FcBool(*)(FcConfig*, const FcChar8*))
f26e5ca
@@ -453,6 +462,7 @@
f26e5ca
             m_pFcPatternGetString			&&
f26e5ca
             m_pFcPatternGetInteger			&&
f26e5ca
             m_pFcPatternGetDouble			&&
f26e5ca
+            m_pFcPatternGetMatrix			&&
f26e5ca
             m_pFcPatternGetBool				&&
f26e5ca
             m_pFcConfigAppFontAddFile				&&
f26e5ca
             m_pFcConfigAppFontAddDir				&&
f26e5ca
@@ -1260,7 +1270,7 @@
81d48c0
 rtl::OUString PrintFontManager::Substitute(const rtl::OUString& rFontName,
81d48c0
     rtl::OUString& rMissingCodes, const rtl::OString &rLangAttrib,
375ba1f
     italic::type &rItalic, weight::type &rWeight,
375ba1f
-    width::type &rWidth, pitch::type &rPitch) const
375ba1f
+    width::type &rWidth, pitch::type &rPitch, bool &rEmbolden, ItalicMatrix &rMatrix) const
81d48c0
 {
81d48c0
     rtl::OUString aName;
81d48c0
     FontCfgWrapper& rWrapper = FontCfgWrapper::get();
f26e5ca
@@ -1353,6 +1363,17 @@
81d48c0
                     rPitch = convertSpacing(val);
375ba1f
                 if ( FcResultMatch == rWrapper.FcPatternGetInteger( pSet->fonts[0], FC_WIDTH, 0, &val))
81d48c0
                     rWidth = convertWidth(val);
81d48c0
+                FcBool bEmbolden;
375ba1f
+                if (FcResultMatch == rWrapper.FcPatternGetBool(pSet->fonts[0], FC_EMBOLDEN, 0, &bEmbolden))
81d48c0
+                    rEmbolden = bEmbolden;
81d48c0
+                FcMatrix *pMatrix = 0;
375ba1f
+                if (FcResultMatch == rWrapper.FcPatternGetMatrix(pSet->fonts[0], FC_MATRIX, 0, &pMatrix))
81d48c0
+                {
81d48c0
+                    rMatrix.xx = pMatrix->xx;
81d48c0
+                    rMatrix.xy = pMatrix->xy;
81d48c0
+                    rMatrix.yx = pMatrix->yx;
81d48c0
+                    rMatrix.yy = pMatrix->yy;
81d48c0
+                }
81d48c0
             }
81d48c0
 
81d48c0
             // update rMissingCodes by removing resolved unicodes
81d48c0
diff --git a/vcl/generic/fontmanager/fontsubst.cxx b/vcl/generic/fontmanager/fontsubst.cxx
81d48c0
index 3bf2d07..2d187b1 100644
375ba1f
--- a/vcl/unx/source/gdi/salgdi3.cxx
375ba1f
+++ b/vcl/unx/source/gdi/salgdi3.cxx
375ba1f
@@ -1526,8 +1526,14 @@
375ba1f
         }
375ba1f
     }
375ba1f
 
81d48c0
+    bool bEmbolden = rFontSelData.mbEmbolden;
81d48c0
+    ItalicMatrix aMatrix = rFontSelData.maItalicMatrix;
375ba1f
+
81d48c0
     const psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
81d48c0
-    aRet.maSearchName = rMgr.Substitute( rFontSelData.maTargetName, rMissingCodes, aLangAttrib, eItalic, eWeight, eWidth, ePitch);
81d48c0
+    aRet.maSearchName = rMgr.Substitute( rFontSelData.maTargetName, rMissingCodes, aLangAttrib, eItalic, eWeight, eWidth, ePitch, bEmbolden, aMatrix );
375ba1f
+
81d48c0
+    aRet.maItalicMatrix = aMatrix;
81d48c0
+    aRet.mbEmbolden  = bEmbolden;
375ba1f
 
375ba1f
     switch (eItalic)
375ba1f
     {
81d48c0
diff --git a/vcl/generic/glyphs/glyphcache.cxx b/vcl/generic/glyphs/glyphcache.cxx
81d48c0
index 5322b65..fa712bb 100644
375ba1f
--- a/vcl/source/glyphs/glyphcache.cxx
375ba1f
+++ b/vcl/source/glyphs/glyphcache.cxx
81d48c0
@@ -163,6 +163,13 @@ bool GlyphCache::IFSD_Equal::operator()( const ImplFontSelectData& rA, const Imp
81d48c0
         != STRING_NOTFOUND) && rA.maTargetName != rB.maTargetName)
81d48c0
         return false;
81d48c0
 #endif
81d48c0
+
81d48c0
+    if (rA.mbEmbolden != rB.mbEmbolden)
81d48c0
+        return false;
81d48c0
+
81d48c0
+    if (rA.maItalicMatrix != rB.maItalicMatrix)
81d48c0
+        return false;
81d48c0
+
81d48c0
     return true;
81d48c0
 }
81d48c0
 
81d48c0
diff --git a/vcl/inc/outfont.hxx b/vcl/inc/outfont.hxx
81d48c0
index faf2b00..857d944 100644
375ba1f
--- a/vcl/inc/vcl/outfont.hxx
375ba1f
+++ b/vcl/inc/vcl/outfont.hxx
81d48c0
@@ -175,6 +191,9 @@ public: // TODO: change to private
81d48c0
     bool                mbVertical;         // vertical mode of requested font
81d48c0
     bool                mbNonAntialiased;   // true if antialiasing is disabled
81d48c0
 
81d48c0
+    bool                mbEmbolden;         // Force emboldening
81d48c0
+    ItalicMatrix        maItalicMatrix;     // Force matrix for slant
81d48c0
+
81d48c0
     const ImplFontData* mpFontData;         // a matching ImplFontData object
81d48c0
     ImplFontEntry*      mpFontEntry;        // pointer to the resulting FontCache entry
81d48c0
 };
81d48c0
diff --git a/vcl/inc/vcl/fontmanager.hxx b/vcl/inc/vcl/fontmanager.hxx
81d48c0
index 0af5e14..4a110ad 100644
81d48c0
--- a/vcl/inc/vcl/fontmanager.hxx
81d48c0
+++ b/vcl/inc/vcl/fontmanager.hxx
12cbcee
@@ -36,6 +36,7 @@
12cbcee
 
12cbcee
 #include "vcl/dllapi.h"
12cbcee
 #include "vcl/helper.hxx"
12cbcee
+#include "vcl/vclenum.hxx"
12cbcee
 
12cbcee
 #include "com/sun/star/lang/Locale.hpp"
12cbcee
 
12cbcee
@@ -737,7 +738,7 @@
81d48c0
 
81d48c0
     rtl::OUString Substitute( const rtl::OUString& rFontName, rtl::OUString& rMissingCodes,
375ba1f
         const rtl::OString& rLangAttrib, italic::type& rItalic, weight::type& rWeight,
375ba1f
-        width::type& rWidth, pitch::type& rPitch) const;
375ba1f
+        width::type& rWidth, pitch::type& rPitch, bool &rEmboldening, ItalicMatrix &rMatrix) const;
81d48c0
     bool hasFontconfig() const { return m_bFontconfigSuccess; }
81d48c0
 
81d48c0
     int FreeTypeCharIndex( void *pFace, sal_uInt32 aChar );
81d48c0
diff --git a/vcl/source/gdi/outdev3.cxx b/vcl/source/gdi/outdev3.cxx
81d48c0
index b0f59cd..3cc438c 100755
81d48c0
--- a/vcl/source/gdi/outdev3.cxx
81d48c0
+++ b/vcl/source/gdi/outdev3.cxx
81d48c0
@@ -865,9 +865,11 @@ bool ImplFontData::IsBetterMatch( const ImplFontSelectData& rFSD, FontMatchStatu
81d48c0
 
81d48c0
     if( rFSD.meWeight != WEIGHT_DONTKNOW )
81d48c0
     {
81d48c0
-        // if not bold prefer light fonts to bold fonts
81d48c0
-        int nReqWeight = (int)rFSD.meWeight;
81d48c0
-        if ( rFSD.meWeight > WEIGHT_MEDIUM )
81d48c0
+        // if not bold or requiring emboldening prefer light fonts to bold fonts
81d48c0
+        FontWeight ePatternWeight = rFSD.mbEmbolden ? WEIGHT_NORMAL : rFSD.meWeight;
81d48c0
+
81d48c0
+        int nReqWeight = (int)ePatternWeight;
81d48c0
+        if ( ePatternWeight > WEIGHT_MEDIUM )
81d48c0
             nReqWeight += 100;
81d48c0
 
81d48c0
         int nGivenWeight = (int)meWeight;
81d48c0
@@ -897,14 +899,17 @@ bool ImplFontData::IsBetterMatch( const ImplFontSelectData& rFSD, FontMatchStatu
81d48c0
             nMatch += 150;
81d48c0
     }
81d48c0
 
81d48c0
-    if ( rFSD.meItalic == ITALIC_NONE )
81d48c0
+    // if requiring custom matrix to fake italic, prefer upright font
81d48c0
+    FontItalic ePatternItalic = rFSD.maItalicMatrix != ItalicMatrix() ? ITALIC_NONE : rFSD.meItalic;
81d48c0
+
81d48c0
+    if ( ePatternItalic == ITALIC_NONE )
81d48c0
     {
81d48c0
         if( meItalic == ITALIC_NONE )
81d48c0
             nMatch += 900;
81d48c0
     }
81d48c0
     else
81d48c0
     {
81d48c0
-        if( rFSD.meItalic == meItalic )
81d48c0
+        if( ePatternItalic == meItalic )
81d48c0
             nMatch += 900;
81d48c0
         else if( meItalic != ITALIC_NONE )
81d48c0
             nMatch += 600;
81d48c0
@@ -1457,22 +1462,31 @@ ImplDevFontListData* ImplDevFontList::GetGlyphFallbackFont( ImplFontSelectData&
81d48c0
             else
81d48c0
                 rFontSelData.maSearchName = String();
81d48c0
 
81d48c0
-            // cache the result even if there was no match
81d48c0
-            for(;;)
81d48c0
-            {
81d48c0
-                 if( !rFontSelData.mpFontEntry->GetFallbackForUnicode( cChar, rFontSelData.GetWeight(), &rFontSelData.maSearchName ) )
81d48c0
-                     rFontSelData.mpFontEntry->AddFallbackForUnicode( cChar, rFontSelData.GetWeight(), rFontSelData.maSearchName );
81d48c0
-                 if( nStrIndex >= aOldMissingCodes.getLength() )
81d48c0
-                     break;
81d48c0
-                 cChar = aOldMissingCodes.iterateCodePoints( &nStrIndex );
81d48c0
-            }
81d48c0
-            if( rFontSelData.maSearchName.Len() != 0 )
81d48c0
+            //See fdo#32665 for an example. FreeSerif that has glyphs in normal
81d48c0
+            //font, but not in the italic or bold version
81d48c0
+            bool bSubSetOfFontRequiresPropertyFaking = rFontSelData.mbEmbolden || rFontSelData.maItalicMatrix != ItalicMatrix();
81d48c0
+
81d48c0
+            // cache the result even if there was no match, unless its from part of a font for which the properties need
81d48c0
+            // to be faked. We need to rework this cache to take into account that fontconfig can return different fonts
81d48c0
+            // for different input sizes, weights, etc. Basically the cache is way to naive
81d48c0
+            if (!bSubSetOfFontRequiresPropertyFaking)
81d48c0
             {
81d48c0
-                // remove cache entries that were still not resolved
81d48c0
-                for( nStrIndex = 0; nStrIndex < rMissingCodes.getLength(); )
81d48c0
+                for(;;)
81d48c0
                 {
81d48c0
-                    cChar = rMissingCodes.iterateCodePoints( &nStrIndex );
81d48c0
-                    rFontSelData.mpFontEntry->IgnoreFallbackForUnicode( cChar, rFontSelData.GetWeight(), rFontSelData.maSearchName );
81d48c0
+                     if( !rFontSelData.mpFontEntry->GetFallbackForUnicode( cChar, rFontSelData.GetWeight(), &rFontSelData.maSearchName ) )
81d48c0
+                         rFontSelData.mpFontEntry->AddFallbackForUnicode( cChar, rFontSelData.GetWeight(), rFontSelData.maSearchName );
81d48c0
+                     if( nStrIndex >= aOldMissingCodes.getLength() )
81d48c0
+                         break;
81d48c0
+                     cChar = aOldMissingCodes.iterateCodePoints( &nStrIndex );
81d48c0
+                }
81d48c0
+                if( rFontSelData.maSearchName.Len() != 0 )
81d48c0
+                {
81d48c0
+                    // remove cache entries that were still not resolved
81d48c0
+                    for( nStrIndex = 0; nStrIndex < rMissingCodes.getLength(); )
81d48c0
+                    {
81d48c0
+                        cChar = rMissingCodes.iterateCodePoints( &nStrIndex );
81d48c0
+                        rFontSelData.mpFontEntry->IgnoreFallbackForUnicode( cChar, rFontSelData.GetWeight(), rFontSelData.maSearchName );
81d48c0
+                    }
81d48c0
                 }
81d48c0
             }
81d48c0
         }
81d48c0
@@ -2180,6 +2194,7 @@ ImplFontSelectData::ImplFontSelectData( const Font& rFont,
81d48c0
     meLanguage( rFont.GetLanguage() ),
81d48c0
     mbVertical( rFont.IsVertical() ),
81d48c0
     mbNonAntialiased( false ),
81d48c0
+    mbEmbolden( false ),
81d48c0
     mpFontData( NULL ),
81d48c0
     mpFontEntry( NULL )
81d48c0
 {
81d48c0
@@ -2215,6 +2230,7 @@ ImplFontSelectData::ImplFontSelectData( const ImplFontData& rFontData,
81d48c0
     meLanguage( 0 ),
81d48c0
     mbVertical( bVertical ),
81d48c0
     mbNonAntialiased( false ),
81d48c0
+    mbEmbolden( false ),
81d48c0
     mpFontData( &rFontData ),
81d48c0
     mpFontEntry( NULL )
81d48c0
 {
81d48c0
@@ -2297,6 +2313,12 @@ bool ImplFontCache::IFSD_Equal::operator()(const ImplFontSelectData& rA, const I
81d48c0
         return false;
81d48c0
 #endif
81d48c0
 
81d48c0
+    if (rA.mbEmbolden != rB.mbEmbolden)
81d48c0
+        return false;
81d48c0
+
81d48c0
+    if (rA.maItalicMatrix != rB.maItalicMatrix)
81d48c0
+        return false;
81d48c0
+
81d48c0
     return true;
81d48c0
 }
81d48c0
375ba1f
--- a/vcl/inc/vcl/vclenum.hxx	2011-10-27 15:10:10.402317337 +0100
375ba1f
+++ b/vcl/inc/vcl/vclenum.hxx	2011-10-27 15:10:29.561528762 +0100
375ba1f
@@ -326,6 +326,22 @@
375ba1f
 
375ba1f
 #endif
375ba1f
 
375ba1f
+struct ItalicMatrix
375ba1f
+{
375ba1f
+    double xx, xy, yx, yy;
375ba1f
+    ItalicMatrix() : xx(1), xy(0), yx(0), yy(1) {}
375ba1f
+};
375ba1f
+
375ba1f
+inline bool operator ==(const ItalicMatrix& a, const ItalicMatrix& b)
375ba1f
+{
375ba1f
+    return a.xx == b.xx && a.xy == b.xy && a.yx == b.yx && a.yy == b.yy;
375ba1f
+}
375ba1f
+
375ba1f
+inline bool operator !=(const ItalicMatrix& a, const ItalicMatrix& b)
375ba1f
+{
375ba1f
+    return a.xx != b.xx || a.xy != b.xy || a.yx != b.yx || a.yy != b.yy;
375ba1f
+}
375ba1f
+
375ba1f
 #endif	// _VCL_VCLENUM_HXX
375ba1f
 
375ba1f
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */