Resolves: fdo#32665 handle that FreeSerif lacks some glyphs in bold/italic

FreeSerif lacks glyphs in bold/italic variants that it has in the normal one. A
lot of our glyph fallback infrastructure, especially the caches don't expect
that a normal variant of a font with extra emboldening or extra font skew can
be a fallback for a bold/italic variant of itself which exists, but doesn't
have the missing glyphs that the normal one does.

We really need to improve our glyph/font caching, but we can get 90% of the
way there by excluding such cases from the caches.
This commit is contained in:
Caolán McNamara 2011-10-27 12:24:11 +01:00
parent d9d82ffc6b
commit 58b48f188b
6 changed files with 90 additions and 23 deletions

View file

@ -68,6 +68,9 @@ using namespace psp;
#ifndef FC_EMBOLDEN
#define FC_EMBOLDEN "embolden"
#endif
#ifndef FC_MATRIX
#define FC_MATRIX "matrix"
#endif
#ifndef FC_FONTFORMAT
#define FC_FONTFORMAT "fontformat"
#endif
@ -747,7 +750,7 @@ static void addtopattern(FcPattern *pPattern,
rtl::OUString PrintFontManager::Substitute(const rtl::OUString& rFontName,
rtl::OUString& rMissingCodes, const rtl::OString &rLangAttrib,
FontItalic &rItalic, FontWeight &rWeight,
FontWidth &rWidth, FontPitch &rPitch) const
FontWidth &rWidth, FontPitch &rPitch, bool &rEmbolden, ItalicMatrix &rMatrix) const
{
rtl::OUString aName;
FontCfgWrapper& rWrapper = FontCfgWrapper::get();
@ -834,6 +837,17 @@ rtl::OUString PrintFontManager::Substitute(const rtl::OUString& rFontName,
rPitch = convertSpacing(val);
if (FcResultMatch == FcPatternGetInteger(pSet->fonts[0], FC_WIDTH, 0, &val))
rWidth = convertWidth(val);
FcBool bEmbolden;
if (FcResultMatch == FcPatternGetBool(pSet->fonts[0], FC_EMBOLDEN, 0, &bEmbolden))
rEmbolden = bEmbolden;
FcMatrix *pMatrix = 0;
if (FcResultMatch == FcPatternGetMatrix(pSet->fonts[0], FC_MATRIX, 0, &pMatrix))
{
rMatrix.xx = pMatrix->xx;
rMatrix.xy = pMatrix->xy;
rMatrix.yx = pMatrix->yx;
rMatrix.yy = pMatrix->yy;
}
}
// update rMissingCodes by removing resolved unicodes
@ -844,7 +858,7 @@ rtl::OUString PrintFontManager::Substitute(const rtl::OUString& rFontName,
FcCharSet* unicodes;
if (!FcPatternGetCharSet(pSet->fonts[0], FC_CHARSET, 0, &unicodes))
{
for( sal_Int32 nStrIndex = 0; nStrIndex < rMissingCodes.getLength(); )
for( sal_Int32 nStrIndex = 0; nStrIndex < rMissingCodes.getLength(); )
{
// also handle unicode surrogates
const sal_uInt32 nCode = rMissingCodes.iterateCodePoints( &nStrIndex );

View file

@ -127,10 +127,14 @@ static ImplFontSelectData GetFcSubstitute(const ImplFontSelectData &rFontSelData
FontWeight eWeight = rFontSelData.GetWeight();
FontWidth eWidth = rFontSelData.GetWidthType();
FontPitch ePitch = rFontSelData.GetPitch();
bool bEmbolden = rFontSelData.mbEmbolden;
ItalicMatrix aMatrix = rFontSelData.maItalicMatrix;
const psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
aRet.maSearchName = rMgr.Substitute( rFontSelData.maTargetName, rMissingCodes, aLangAttrib, eItalic, eWeight, eWidth, ePitch);
aRet.maSearchName = rMgr.Substitute( rFontSelData.maTargetName, rMissingCodes, aLangAttrib, eItalic, eWeight, eWidth, ePitch, bEmbolden, aMatrix );
aRet.maItalicMatrix = aMatrix;
aRet.mbEmbolden = bEmbolden;
aRet.meItalic = eItalic;
aRet.meWeight = eWeight;
aRet.meWidthType = eWidth;

View file

@ -163,6 +163,13 @@ bool GlyphCache::IFSD_Equal::operator()( const ImplFontSelectData& rA, const Imp
!= STRING_NOTFOUND) && rA.maTargetName != rB.maTargetName)
return false;
#endif
if (rA.mbEmbolden != rB.mbEmbolden)
return false;
if (rA.maItalicMatrix != rB.maItalicMatrix)
return false;
return true;
}

View file

@ -156,6 +156,22 @@ friend class ImplDevFontListData;
// - ImplFontSelectData -
// ----------------------
struct ItalicMatrix
{
double xx, xy, yx, yy;
ItalicMatrix() : xx(1), xy(0), yx(0), yy(1) {}
};
inline bool operator ==(const ItalicMatrix& a, const ItalicMatrix& b)
{
return a.xx == b.xx && a.xy == b.xy && a.yx == b.yx && a.yy == b.yy;
}
inline bool operator !=(const ItalicMatrix& a, const ItalicMatrix& b)
{
return a.xx != b.xx || a.xy != b.xy || a.yx != b.yx || a.yy != b.yy;
}
class ImplFontSelectData : public ImplFontAttributes
{
public:
@ -175,6 +191,9 @@ public: // TODO: change to private
bool mbVertical; // vertical mode of requested font
bool mbNonAntialiased; // true if antialiasing is disabled
bool mbEmbolden; // Force emboldening
ItalicMatrix maItalicMatrix; // Force matrix for slant
const ImplFontData* mpFontData; // a matching ImplFontData object
ImplFontEntry* mpFontEntry; // pointer to the resulting FontCache entry
};

View file

@ -37,6 +37,7 @@
#include "vcl/dllapi.h"
#include "vcl/helper.hxx"
#include "vcl/vclenum.hxx"
#include "outfont.hxx"
#include "com/sun/star/lang/Locale.hpp"
#include <vector>
@ -649,7 +650,7 @@ public:
rtl::OUString Substitute( const rtl::OUString& rFontName, rtl::OUString& rMissingCodes,
const rtl::OString& rLangAttrib, FontItalic& rItalic, FontWeight& rWeight,
FontWidth& rWidth, FontPitch& rPitch) const;
FontWidth& rWidth, FontPitch& rPitch, bool &rEmboldening, ItalicMatrix &rMatrix) const;
bool hasFontconfig() const { return m_bFontconfigSuccess; }
int FreeTypeCharIndex( void *pFace, sal_uInt32 aChar );

View file

@ -865,9 +865,11 @@ bool ImplFontData::IsBetterMatch( const ImplFontSelectData& rFSD, FontMatchStatu
if( rFSD.meWeight != WEIGHT_DONTKNOW )
{
// if not bold prefer light fonts to bold fonts
int nReqWeight = (int)rFSD.meWeight;
if ( rFSD.meWeight > WEIGHT_MEDIUM )
// if not bold or requiring emboldening prefer light fonts to bold fonts
FontWeight ePatternWeight = rFSD.mbEmbolden ? WEIGHT_NORMAL : rFSD.meWeight;
int nReqWeight = (int)ePatternWeight;
if ( ePatternWeight > WEIGHT_MEDIUM )
nReqWeight += 100;
int nGivenWeight = (int)meWeight;
@ -897,14 +899,17 @@ bool ImplFontData::IsBetterMatch( const ImplFontSelectData& rFSD, FontMatchStatu
nMatch += 150;
}
if ( rFSD.meItalic == ITALIC_NONE )
// if requiring custom matrix to fake italic, prefer upright font
FontItalic ePatternItalic = rFSD.maItalicMatrix != ItalicMatrix() ? ITALIC_NONE : rFSD.meItalic;
if ( ePatternItalic == ITALIC_NONE )
{
if( meItalic == ITALIC_NONE )
nMatch += 900;
}
else
{
if( rFSD.meItalic == meItalic )
if( ePatternItalic == meItalic )
nMatch += 900;
else if( meItalic != ITALIC_NONE )
nMatch += 600;
@ -1457,22 +1462,31 @@ ImplDevFontListData* ImplDevFontList::GetGlyphFallbackFont( ImplFontSelectData&
else
rFontSelData.maSearchName = String();
// cache the result even if there was no match
for(;;)
//See fdo#32665 for an example. FreeSerif that has glyphs in normal
//font, but not in the italic or bold version
bool bSubSetOfFontRequiresPropertyFaking = rFontSelData.mbEmbolden || rFontSelData.maItalicMatrix != ItalicMatrix();
// cache the result even if there was no match, unless its from part of a font for which the properties need
// to be faked. We need to rework this cache to take into account that fontconfig can return different fonts
// for different input sizes, weights, etc. Basically the cache is way to naive
if (!bSubSetOfFontRequiresPropertyFaking)
{
if( !rFontSelData.mpFontEntry->GetFallbackForUnicode( cChar, rFontSelData.GetWeight(), &rFontSelData.maSearchName ) )
rFontSelData.mpFontEntry->AddFallbackForUnicode( cChar, rFontSelData.GetWeight(), rFontSelData.maSearchName );
if( nStrIndex >= aOldMissingCodes.getLength() )
break;
cChar = aOldMissingCodes.iterateCodePoints( &nStrIndex );
}
if( rFontSelData.maSearchName.Len() != 0 )
{
// remove cache entries that were still not resolved
for( nStrIndex = 0; nStrIndex < rMissingCodes.getLength(); )
for(;;)
{
cChar = rMissingCodes.iterateCodePoints( &nStrIndex );
rFontSelData.mpFontEntry->IgnoreFallbackForUnicode( cChar, rFontSelData.GetWeight(), rFontSelData.maSearchName );
if( !rFontSelData.mpFontEntry->GetFallbackForUnicode( cChar, rFontSelData.GetWeight(), &rFontSelData.maSearchName ) )
rFontSelData.mpFontEntry->AddFallbackForUnicode( cChar, rFontSelData.GetWeight(), rFontSelData.maSearchName );
if( nStrIndex >= aOldMissingCodes.getLength() )
break;
cChar = aOldMissingCodes.iterateCodePoints( &nStrIndex );
}
if( rFontSelData.maSearchName.Len() != 0 )
{
// remove cache entries that were still not resolved
for( nStrIndex = 0; nStrIndex < rMissingCodes.getLength(); )
{
cChar = rMissingCodes.iterateCodePoints( &nStrIndex );
rFontSelData.mpFontEntry->IgnoreFallbackForUnicode( cChar, rFontSelData.GetWeight(), rFontSelData.maSearchName );
}
}
}
}
@ -2180,6 +2194,7 @@ ImplFontSelectData::ImplFontSelectData( const Font& rFont,
meLanguage( rFont.GetLanguage() ),
mbVertical( rFont.IsVertical() ),
mbNonAntialiased( false ),
mbEmbolden( false ),
mpFontData( NULL ),
mpFontEntry( NULL )
{
@ -2215,6 +2230,7 @@ ImplFontSelectData::ImplFontSelectData( const ImplFontData& rFontData,
meLanguage( 0 ),
mbVertical( bVertical ),
mbNonAntialiased( false ),
mbEmbolden( false ),
mpFontData( &rFontData ),
mpFontEntry( NULL )
{
@ -2297,6 +2313,12 @@ bool ImplFontCache::IFSD_Equal::operator()(const ImplFontSelectData& rA, const I
return false;
#endif
if (rA.mbEmbolden != rB.mbEmbolden)
return false;
if (rA.maItalicMatrix != rB.maItalicMatrix)
return false;
return true;
}