mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-05-28 17:16:29 +03:00
Added kerning cache in FontTrueType.
This commit is contained in:
@@ -246,6 +246,8 @@ class EE_API FontTrueType : public Font {
|
||||
mutable UnorderedMap<unsigned int, unsigned int> mClosestCharacterSize;
|
||||
mutable UnorderedMap<Uint32, Uint32> mCodePointIndexCache;
|
||||
mutable UnorderedMap<Uint32, std::tuple<Uint32, Uint32, bool>> mKeyCache;
|
||||
mutable UnorderedMap<Uint64, Float> mKerningCache; // For codepoints (getKerning)
|
||||
mutable UnorderedMap<Uint64, Float> mKerningGlyphCache; // For glyph indices
|
||||
FontHinting mHinting{ FontHinting::Full };
|
||||
FontAntialiasing mAntialiasing{ FontAntialiasing::Grayscale };
|
||||
FontTrueType* mFontBold{ nullptr };
|
||||
|
||||
@@ -235,6 +235,22 @@ static inline Uint64 getCodePointKey( Uint32 codePoint, bool bold, bool italics,
|
||||
( static_cast<EE::Uint64>( italics ) << 32 ) | codePoint;
|
||||
}
|
||||
|
||||
// Combine kerning parameters into a single 64-bit key for O(1) lookups.
|
||||
// - first/index1 : 21 bits (covers full Unicode range up to 0x10FFFF)
|
||||
// - second/index2: 21 bits
|
||||
// - characterSize: 12 bits (max font size 4095)
|
||||
// - bold : 1 bit
|
||||
// - italic : 1 bit
|
||||
// - outline : 8 bits (max outline thickness 2.55 scaled by 100)
|
||||
static inline Uint64 getKerningKey( Uint32 first, Uint32 second, unsigned int characterSize,
|
||||
bool bold, bool italic, Float outlineThickness ) {
|
||||
return ( static_cast<Uint64>( first & 0x1FFFFF ) << 43 ) |
|
||||
( static_cast<Uint64>( second & 0x1FFFFF ) << 22 ) |
|
||||
( static_cast<Uint64>( characterSize & 0xFFF ) << 10 ) |
|
||||
( static_cast<Uint64>( bold ) << 9 ) | ( static_cast<Uint64>( italic ) << 8 ) |
|
||||
( static_cast<Uint64>( static_cast<Uint32>( outlineThickness * 100.f ) & 0xFF ) );
|
||||
}
|
||||
|
||||
FontTrueType* FontTrueType::New( const std::string& FontName ) {
|
||||
return eeNew( FontTrueType, ( FontName ) );
|
||||
}
|
||||
@@ -455,7 +471,7 @@ bool FontTrueType::setFontFace( void* _face ) {
|
||||
|
||||
if ( mHasSvgGlyphs ) {
|
||||
#ifdef EE_TRUETYPE_SVG_FONT_ENABLED
|
||||
FT_Property_Set( static_cast<FT_Library>( mLibrary ), "ot-svg", "svg-hooks", &svg_hooks );
|
||||
FT_Property_Set( static_cast<FT_Library>( mLibrary ), "ot-svg", "svg-hooks", &svg_hooks );
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
@@ -800,44 +816,45 @@ Float FontTrueType::getKerning( Uint32 first, Uint32 second, unsigned int charac
|
||||
if ( first == 0 || second == 0 || isMonospace() )
|
||||
return 0.f;
|
||||
|
||||
Uint64 key = getKerningKey( first, second, characterSize, bold, italic, outlineThickness );
|
||||
auto it = mKerningCache.find( key );
|
||||
if ( it != mKerningCache.end() ) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
Float kerningVal = 0.f;
|
||||
FT_Face face = static_cast<FT_Face>( mFace );
|
||||
|
||||
if ( face && setCurrentSize( characterSize ) ) {
|
||||
auto glyph1 = getGlyph( first, characterSize, bold, italic, outlineThickness );
|
||||
auto glyph2 = getGlyph( second, characterSize, bold, italic, outlineThickness );
|
||||
|
||||
if ( glyph1.font != glyph2.font )
|
||||
return 0.f;
|
||||
|
||||
// Convert the characters to indices
|
||||
FT_UInt index1 = getGlyphIndex( first );
|
||||
FT_UInt index2 = getGlyphIndex( second );
|
||||
|
||||
// Retrieve position compensation deltas generated by FT_LOAD_FORCE_AUTOHINT flag
|
||||
auto firstRsbDelta = static_cast<Float>( glyph1.rsbDelta );
|
||||
auto secondLsbDelta = static_cast<Float>( glyph2.lsbDelta );
|
||||
|
||||
// Get the kerning vector
|
||||
FT_Vector kerning;
|
||||
kerning.x = kerning.y = 0;
|
||||
|
||||
if ( glyph1.font == glyph2.font ) {
|
||||
// Convert the characters to indices
|
||||
FT_UInt index1 = getGlyphIndex( first );
|
||||
FT_UInt index2 = getGlyphIndex( second );
|
||||
|
||||
// Get the kerning vector
|
||||
FT_Vector kerning;
|
||||
kerning.x = kerning.y = 0;
|
||||
if ( FT_HAS_KERNING( face ) )
|
||||
FT_Get_Kerning( face, index1, index2, FT_KERNING_UNFITTED, &kerning );
|
||||
|
||||
// X advance is already in pixels for bitmap fonts
|
||||
if ( !FT_IS_SCALABLE( face ) )
|
||||
return static_cast<Float>( kerning.x );
|
||||
if ( !FT_IS_SCALABLE( face ) ) {
|
||||
kerningVal = static_cast<Float>( kerning.x );
|
||||
} else {
|
||||
auto firstRsbDelta = static_cast<Float>( glyph1.rsbDelta );
|
||||
auto secondLsbDelta = static_cast<Float>( glyph2.lsbDelta );
|
||||
kerningVal = std::floor(
|
||||
( secondLsbDelta - firstRsbDelta + static_cast<float>( kerning.x ) + 32 ) /
|
||||
static_cast<float>( 1 << 6 ) );
|
||||
}
|
||||
}
|
||||
|
||||
// Return the X advance
|
||||
return std::floor(
|
||||
( secondLsbDelta - firstRsbDelta + static_cast<float>( kerning.x ) + 32 ) /
|
||||
static_cast<float>( 1 << 6 ) );
|
||||
} else {
|
||||
// Invalid font, or no kerning
|
||||
return 0.f;
|
||||
}
|
||||
|
||||
mKerningCache[key] = kerningVal;
|
||||
return kerningVal;
|
||||
}
|
||||
|
||||
Float FontTrueType::getKerningFromGlyphIndex( Uint32 index1, Uint32 index2,
|
||||
@@ -847,6 +864,13 @@ Float FontTrueType::getKerningFromGlyphIndex( Uint32 index1, Uint32 index2,
|
||||
if ( index1 == 0 || index2 == 0 || isMonospace() )
|
||||
return 0.f;
|
||||
|
||||
Uint64 key = getKerningKey( index1, index2, characterSize, bold, italic, outlineThickness );
|
||||
auto it = mKerningGlyphCache.find( key );
|
||||
if ( it != mKerningGlyphCache.end() ) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
Float kerningVal = 0.f;
|
||||
FT_Face face = static_cast<FT_Face>( mFace );
|
||||
|
||||
if ( face && setCurrentSize( characterSize ) ) {
|
||||
@@ -864,18 +888,17 @@ Float FontTrueType::getKerningFromGlyphIndex( Uint32 index1, Uint32 index2,
|
||||
|
||||
// X advance is already in pixels for bitmap fonts
|
||||
if ( !FT_IS_SCALABLE( face ) ) {
|
||||
return static_cast<Float>( kerning.x );
|
||||
kerningVal = static_cast<Float>( kerning.x );
|
||||
} else {
|
||||
// Get the X advance
|
||||
kerningVal = std::floor(
|
||||
( secondLsbDelta - firstRsbDelta + static_cast<float>( kerning.x ) + 32 ) /
|
||||
static_cast<float>( 1 << 6 ) );
|
||||
}
|
||||
|
||||
// Return the X advance
|
||||
Float val =
|
||||
std::floor( ( secondLsbDelta - firstRsbDelta + static_cast<float>( kerning.x ) + 32 ) /
|
||||
static_cast<float>( 1 << 6 ) );
|
||||
return val;
|
||||
} else {
|
||||
// Invalid font, or no kerning
|
||||
return 0.f;
|
||||
}
|
||||
|
||||
mKerningGlyphCache[key] = kerningVal;
|
||||
return kerningVal;
|
||||
}
|
||||
|
||||
Float FontTrueType::getLineSpacing( unsigned int characterSize ) const {
|
||||
@@ -1062,6 +1085,8 @@ void FontTrueType::cleanup() {
|
||||
mFontBoldItalicCb = 0;
|
||||
mPages.clear();
|
||||
std::vector<Uint8>().swap( mPixelBuffer );
|
||||
mKerningCache.clear();
|
||||
mKerningGlyphCache.clear();
|
||||
mCodePointIndexCache.clear();
|
||||
mKeyCache.clear();
|
||||
mClosestCharacterSize.clear();
|
||||
@@ -1768,6 +1793,8 @@ void FontTrueType::clearCache() {
|
||||
mClosestCharacterSize.clear();
|
||||
mCodePointIndexCache.clear();
|
||||
mKeyCache.clear();
|
||||
mKerningCache.clear();
|
||||
mKerningGlyphCache.clear();
|
||||
Text::GlobalInvalidationId++;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user