Resolves: fdo#47636 cache fontconfig font substitutions

But this time cache on *all* properties, not just the name, which doesn't cut
it, given the things fontconfig can do, e.g. fdo#41556

Change-Id: Idfc1dbac67b6912e4985570a0b7c6ccdf47fa4a5
This commit is contained in:
Caolán McNamara 2012-06-19 22:23:33 +01:00
parent 3a615029d0
commit 8c023fd645
3 changed files with 212 additions and 55 deletions

View file

@ -42,15 +42,27 @@
#include "salprn.hxx"
#include "region.h"
#include <list>
// ===========================================================================
// platform specific font substitution hooks
// ===========================================================================
struct FontSelectPatternAttributesHash
{
size_t operator()(const FontSelectPatternAttributes& rAttributes) const
{ return rAttributes.hashCode(); }
};
class FcPreMatchSubstititution
: public ImplPreMatchFontSubstitution
{
public:
bool FindFontSubstitute( FontSelectPattern& ) const;
typedef ::std::pair<FontSelectPatternAttributes, FontSelectPatternAttributes> value_type;
private:
typedef ::std::list<value_type> CachedFontMapType;
mutable CachedFontMapType maCachedFontMap;
};
class FcGlyphFallbackSubstititution
@ -135,6 +147,19 @@ namespace
rOrig.meWidthType == rNew.meWidthType
);
}
class equal
{
private:
const FontSelectPatternAttributes& mrAttributes;
public:
equal(const FontSelectPatternAttributes& rAttributes)
: mrAttributes(rAttributes)
{
}
bool operator()(const FcPreMatchSubstititution::value_type& rOther) const
{ return rOther.first == mrAttributes; }
};
}
//--------------------------------------------------------------------------
@ -149,11 +174,26 @@ bool FcPreMatchSubstititution::FindFontSubstitute( FontSelectPattern &rFontSelDa
|| 0 == rFontSelData.maSearchName.CompareIgnoreCaseToAscii( "opensymbol", 10) )
return false;
//Note: see fdo#41556 if you feel compelled to cache the results here,
//remember that fontconfig can return e.g. an italic font for a non-italic
//input and/or different fonts depending on fontsize, bold, etc settings so
//don't cache just on the name, cache on all the input and don't just
//return the original selection data with the fontname updated
//see fdo#41556 and fdo#47636
//fontconfig can return e.g. an italic font for a non-italic input and/or
//different fonts depending on fontsize, bold, etc settings so don't cache
//just on the name, cache map all the input and all the output not just map
//from original selection to output fontname
FontSelectPatternAttributes& rPatternAttributes = rFontSelData;
CachedFontMapType &rCachedFontMap = const_cast<CachedFontMapType &>(maCachedFontMap);
CachedFontMapType::iterator itr = std::find_if(rCachedFontMap.begin(), rCachedFontMap.end(), equal(rPatternAttributes));
if (itr != rCachedFontMap.end())
{
// Cached substitution
rFontSelData.copyAttributes(itr->second);
if (itr != rCachedFontMap.begin())
{
// MRU, move it to the front
rCachedFontMap.splice(rCachedFontMap.begin(), rCachedFontMap, itr);
}
return true;
}
rtl::OUString aDummy;
const FontSelectPattern aOut = GetFcSubstitute( rFontSelData, aDummy );
@ -178,7 +218,14 @@ bool FcPreMatchSubstititution::FindFontSubstitute( FontSelectPattern &rFontSelDa
#endif
if( bHaveSubstitute )
{
rCachedFontMap.push_front(value_type(rFontSelData, aOut));
//fairly arbitrary limit in this case, but I recall measuring max 8
//fonts as the typical max amount of fonts in medium sized documents
if (rCachedFontMap.size() > 8)
rCachedFontMap.pop_back();
rFontSelData = aOut;
}
return bHaveSubstitute;
}
@ -190,7 +237,7 @@ bool FcGlyphFallbackSubstititution::FindFontSubstitute( FontSelectPattern& rFont
{
// We dont' actually want to talk to Fontconfig at all for symbol fonts
if( rFontSelData.IsSymbolFont() )
return false;
return false;
// StarSymbol is a unicode font, but it still deserves the symbol flag
if( 0 == rFontSelData.maSearchName.CompareIgnoreCaseToAscii( "starsymbol", 10)
|| 0 == rFontSelData.maSearchName.CompareIgnoreCaseToAscii( "opensymbol", 10) )

View file

@ -71,6 +71,12 @@ public: // TODO: create matching interface class
FontWidth GetWidthType() const { return meWidthType; }
bool IsSymbolFont() const { return mbSymbolFlag; }
bool operator==(const ImplFontAttributes& rOther) const;
bool operator!=(const ImplFontAttributes& rOther) const
{
return !(*this == rOther);
}
public: // TODO: hide members behind accessor methods
String maName; // Font Family Name
String maStyleName; // Font Style Name
@ -109,7 +115,6 @@ public: // TODO: hide members behind accessor methods
// ----------------
// - PhysicalFontFace -
// ----------------
// DONE: rename ImplFontData to PhysicalFontFace
// TODO: no more direct access to members
// TODO: add reference counting
// TODO: get rid of height/width for scalable fonts
@ -152,24 +157,27 @@ friend class ImplDevFontListData;
PhysicalFontFace* mpNext;
};
// ----------------------
// - FontSelectPattern -
// ----------------------
class FontSelectPattern : public ImplFontAttributes
class FontSelectPatternAttributes : public ImplFontAttributes
{
public:
FontSelectPattern( const Font&, const String& rSearchName,
const Size&, float fExactHeight );
FontSelectPattern( const PhysicalFontFace&, const Size&,
float fExactHeight, int nOrientation, bool bVertical );
FontSelectPatternAttributes( const Font&, const String& rSearchName,
const Size&, float fExactHeight );
FontSelectPatternAttributes( const PhysicalFontFace&, const Size&,
float fExactHeight, int nOrientation, bool bVertical );
public: // TODO: change to private
size_t hashCode() const;
bool operator==(const FontSelectPatternAttributes& rOther) const;
bool operator!=(const FontSelectPatternAttributes& rOther) const
{
return !(*this == rOther);
}
public:
String maTargetName; // name of the font name token that is chosen
String maSearchName; // name of the font that matches best
int mnWidth; // width of font in pixel units
int mnHeight; // height of font in pixel units
float mfExactHeight; // requested height (in pixels with subpixel details)
float mfExactHeight; // requested height (in pixels with subpixel details)
int mnOrientation; // text orientation in 3600 system
LanguageType meLanguage; // text language
bool mbVertical; // vertical mode of requested font
@ -177,9 +185,20 @@ public: // TODO: change to private
bool mbEmbolden; // Force emboldening
ItalicMatrix maItalicMatrix; // Force matrix for slant
};
class FontSelectPattern : public FontSelectPatternAttributes
{
public:
FontSelectPattern( const Font&, const String& rSearchName,
const Size&, float fExactHeight );
FontSelectPattern( const PhysicalFontFace&, const Size&,
float fExactHeight, int nOrientation, bool bVertical );
public: // TODO: change to private
const PhysicalFontFace* mpFontData; // a matching PhysicalFontFace object
ImplFontEntry* mpFontEntry; // pointer to the resulting FontCache entry
void copyAttributes(const FontSelectPatternAttributes &rAttributes);
};
// -------------------

View file

@ -2139,21 +2139,17 @@ ImplGetDevSizeList* ImplDevFontList::GetDevSizeList( const String& rFontName ) c
return pGetDevSizeList;
}
// =======================================================================
FontSelectPattern::FontSelectPattern( const Font& rFont,
const String& rSearchName, const Size& rSize, float fExactHeight)
: maSearchName( rSearchName ),
mnWidth( rSize.Width() ),
mnHeight( rSize.Height() ),
mfExactHeight( fExactHeight),
mnOrientation( rFont.GetOrientation() ),
meLanguage( rFont.GetLanguage() ),
mbVertical( rFont.IsVertical() ),
mbNonAntialiased( false ),
mbEmbolden( false ),
mpFontData( NULL ),
mpFontEntry( NULL )
FontSelectPatternAttributes::FontSelectPatternAttributes( const Font& rFont,
const String& rSearchName, const Size& rSize, float fExactHeight )
: maSearchName( rSearchName )
, mnWidth( rSize.Width() )
, mnHeight( rSize.Height() )
, mfExactHeight( fExactHeight)
, mnOrientation( rFont.GetOrientation() )
, meLanguage( rFont.GetLanguage() )
, mbVertical( rFont.IsVertical() )
, mbNonAntialiased( false )
, mbEmbolden( false )
{
maTargetName = maName;
@ -2175,51 +2171,115 @@ FontSelectPattern::FontSelectPattern( const Font& rFont,
mnWidth = -mnWidth;
}
// -----------------------------------------------------------------------
FontSelectPattern::FontSelectPattern( const Font& rFont,
const String& rSearchName, const Size& rSize, float fExactHeight)
: FontSelectPatternAttributes(rFont, rSearchName, rSize, fExactHeight)
, mpFontData( NULL )
, mpFontEntry( NULL )
{
}
// NOTE: this ctor is still used on Windows. Do not remove.
FontSelectPattern::FontSelectPattern( const PhysicalFontFace& rFontData,
FontSelectPatternAttributes::FontSelectPatternAttributes( const PhysicalFontFace& rFontData,
const Size& rSize, float fExactHeight, int nOrientation, bool bVertical )
: ImplFontAttributes( rFontData ),
mnWidth( rSize.Width() ),
mnHeight( rSize.Height() ),
mfExactHeight( fExactHeight ),
mnOrientation( nOrientation ),
meLanguage( 0 ),
mbVertical( bVertical ),
mbNonAntialiased( false ),
mbEmbolden( false ),
mpFontData( &rFontData ),
mpFontEntry( NULL )
: ImplFontAttributes( rFontData )
, mnWidth( rSize.Width() )
, mnHeight( rSize.Height() )
, mfExactHeight( fExactHeight )
, mnOrientation( nOrientation )
, meLanguage( 0 )
, mbVertical( bVertical )
, mbNonAntialiased( false )
, mbEmbolden( false )
{
maTargetName = maSearchName = maName;
// NOTE: no normalization for width/height/orientation
}
FontSelectPattern::FontSelectPattern( const PhysicalFontFace& rFontData,
const Size& rSize, float fExactHeight, int nOrientation, bool bVertical )
: FontSelectPatternAttributes(rFontData, rSize, fExactHeight, nOrientation, bVertical)
, mpFontData( &rFontData )
, mpFontEntry( NULL )
{
}
void FontSelectPattern::copyAttributes(const FontSelectPatternAttributes &rAttributes)
{
static_cast<FontSelectPatternAttributes&>(*this) = rAttributes;
}
// =======================================================================
size_t ImplFontCache::IFSD_Hash::operator()( const FontSelectPattern& rFSD ) const
{
return rFSD.hashCode();
}
size_t FontSelectPatternAttributes::hashCode() const
{
// TODO: does it pay off to improve this hash function?
static FontNameHash aFontNameHash;
size_t nHash = aFontNameHash( rFSD.maSearchName );
size_t nHash = aFontNameHash( maSearchName );
#ifdef ENABLE_GRAPHITE
// check for features and generate a unique hash if necessary
if (rFSD.maTargetName.Search(grutils::GrFeatureParser::FEAT_PREFIX)
if (maTargetName.Search(grutils::GrFeatureParser::FEAT_PREFIX)
!= STRING_NOTFOUND)
{
nHash = aFontNameHash( rFSD.maTargetName );
nHash = aFontNameHash( maTargetName );
}
#endif
nHash += 11 * rFSD.mnHeight;
nHash += 19 * rFSD.meWeight;
nHash += 29 * rFSD.meItalic;
nHash += 37 * rFSD.mnOrientation;
nHash += 41 * rFSD.meLanguage;
if( rFSD.mbVertical )
nHash += 11 * mnHeight;
nHash += 19 * meWeight;
nHash += 29 * meItalic;
nHash += 37 * mnOrientation;
nHash += 41 * meLanguage;
if( mbVertical )
nHash += 53;
return nHash;
}
bool FontSelectPatternAttributes::operator==(const FontSelectPatternAttributes& rOther) const
{
if (static_cast<const ImplFontAttributes&>(*this) != static_cast<const ImplFontAttributes&>(rOther))
return false;
if (maTargetName != rOther.maTargetName)
return false;
if (maSearchName != rOther.maSearchName)
return false;
if (mnWidth != rOther.mnWidth)
return false;
if (mnHeight != rOther.mnHeight)
return false;
if (mfExactHeight != rOther.mfExactHeight)
return false;
if (mnOrientation != rOther.mnOrientation)
return false;
if (meLanguage != rOther.meLanguage)
return false;
if (mbVertical != rOther.mbVertical)
return false;
if (mbNonAntialiased != rOther.mbNonAntialiased)
return false;
if (mbEmbolden != rOther.mbEmbolden)
return false;
if (maItalicMatrix != rOther.maItalicMatrix)
return false;
return true;
}
// -----------------------------------------------------------------------
bool ImplFontCache::IFSD_Equal::operator()(const FontSelectPattern& rA, const FontSelectPattern& rB) const
@ -3332,6 +3392,37 @@ void OutputDevice::ImplInitAboveTextLineSize()
// -----------------------------------------------------------------------
bool ImplFontAttributes::operator==(const ImplFontAttributes& rOther) const
{
if (maName != rOther.maName)
return false;
if (maStyleName != rOther.maStyleName)
return false;
if (meWeight != rOther.meWeight)
return false;
if (meItalic != rOther.meItalic)
return false;
if (meFamily != rOther.meFamily)
return false;
if (mePitch != rOther.mePitch)
return false;
if (meWidthType != rOther.meWidthType)
return false;
if (mbSymbolFlag != rOther.mbSymbolFlag)
return false;
return true;
}
// -----------------------------------------------------------------------
ImplFontMetricData::ImplFontMetricData( const FontSelectPattern& rFontSelData )
: ImplFontAttributes( rFontSelData )
{