void SFont::AddInstance( SFontInstance * pcInstance ) { g_cFontLock.Lock(); __assertw( g_cFontLock.IsLocked() ); m_cInstances[pcInstance->m_cInstanceProperties] = pcInstance; g_cFontLock.Unlock(); }
int SFontInstance::GetStringWidth( const char *pzString, int nLength ) { int nWidth = 0; g_cFontLock.Lock(); while( nLength > 0 ) { int nCharLen = utf8_char_length( *pzString ); if( nCharLen > nLength ) { break; } Glyph *pcGlyph = GetGlyph( FT_Get_Char_Index( m_pcFont->GetTTFace(), utf8_to_unicode( pzString ) ) ); pzString += nCharLen; nLength -= nCharLen; if( pcGlyph == NULL ) { dbprintf( "Error: GetStringWidth() failed to load glyph\n" ); continue; } nWidth += pcGlyph->m_nAdvance.x; } g_cFontLock.Unlock(); return ( nWidth ); }
SFontInstance::SFontInstance( SFont * pcFont, const FontProperty & cFP ) { m_bFixedWidth = pcFont->IsFixedWidth(); g_cFontLock.Lock(); m_pcFont = pcFont; m_nGlyphCount = pcFont->GetGlyphCount(); if( m_nGlyphCount > 0 ) { m_ppcGlyphTable = new Glyph *[m_nGlyphCount]; memset( m_ppcGlyphTable, 0, m_nGlyphCount * sizeof( Glyph * ) ); } else { m_ppcGlyphTable = NULL; } m_cInstanceProperties = cFP; FT_Face psFace = m_pcFont->GetTTFace(); if( psFace->face_flags & FT_FACE_FLAG_SCALABLE ) { FT_Set_Char_Size( psFace, m_cInstanceProperties.m_nPointSize, m_cInstanceProperties.m_nPointSize, 96, 96 ); } else { FT_Set_Pixel_Sizes( psFace, 0, ( m_cInstanceProperties.m_nPointSize * 96 / 72 ) / 64 ); } FT_Size psSize = psFace->size; m_nNomWidth = psSize->metrics.x_ppem; m_nNomHeight = psSize->metrics.y_ppem; if( psSize->metrics.descender > 0 ) { m_nDescender = -( psSize->metrics.descender + 63 ) / 64; // m_nLineGap = (psSize->metrics.height - (psSize->metrics.ascender + psSize->metrics.descender) + 63) / 64; } else { m_nDescender = ( psSize->metrics.descender + 63 ) / 64; // m_nLineGap = (psSize->metrics.height - (psSize->metrics.ascender - psSize->metrics.descender) + 63) / 64; } m_nAscender = ( psSize->metrics.ascender + 63 ) / 64; m_nLineGap = ( psSize->metrics.height + 63 ) / 64 - ( m_nAscender - m_nDescender ); m_nAdvance = ( psSize->metrics.max_advance + 63 ) / 64; // printf( "Size1(%d): %ld, %ld, %ld (%ld, %ld, %ld)\n", nPointSize, psSize->metrics.ascender, psSize->metrics.descender, psSize->metrics.height, // psSize->metrics.ascender / 64, psSize->metrics.descender / 64, psSize->metrics.height / 64 ); // Register our self with the font m_pcFont->AddInstance( this ); g_cFontLock.Unlock(); }
int FontServer::GetFamilyCount() const { int nCount; g_cFontLock.Lock(); nCount = m_cFamilies.size(); g_cFontLock.Unlock(); return ( nCount ); }
status_t SFontInstance::SetProperties( const FontProperty & cFP ) { g_cFontLock.Lock(); m_pcFont->RemoveInstance( this ); m_cInstanceProperties = cFP; FT_Face psFace = m_pcFont->GetTTFace(); if( psFace->face_flags & FT_FACE_FLAG_SCALABLE ) { FT_Set_Char_Size( psFace, m_cInstanceProperties.m_nPointSize, m_cInstanceProperties.m_nPointSize, 96, 96 ); } else { FT_Set_Pixel_Sizes( psFace, 0, ( m_cInstanceProperties.m_nPointSize * 96 / 72 ) / 64 ); } FT_Size psSize = psFace->size; m_nNomWidth = psSize->metrics.x_ppem; m_nNomHeight = psSize->metrics.y_ppem; if( psSize->metrics.descender > 0 ) { m_nDescender = -( psSize->metrics.descender + 63 ) / 64; // m_nLineGap = (psSize->metrics.height - (psSize->metrics.ascender + psSize->metrics.descender) + 63) / 64; } else { m_nDescender = ( psSize->metrics.descender + 63 ) / 64; // m_nLineGap = (psSize->metrics.height - (psSize->metrics.ascender - psSize->metrics.descender) + 63) / 64; } m_nAscender = ( psSize->metrics.ascender + 63 ) / 64; m_nLineGap = ( psSize->metrics.height + 63 ) / 64 - ( m_nAscender - m_nDescender ); m_nAdvance = ( psSize->metrics.max_advance + 63 ) / 64; // printf( "Size2(%d): %ld, %ld, %ld (%ld, %ld, %ld)\n", nPointSize, psSize->metrics.ascender, psSize->metrics.descender, psSize->metrics.height, // psSize->metrics.ascender / 64, psSize->metrics.descender / 64, psSize->metrics.height / 64 ); for( int i = 0; i < m_nGlyphCount; ++i ) { if( m_ppcGlyphTable[i] != NULL ) { delete[]reinterpret_cast < char *>( m_ppcGlyphTable[i] ); m_ppcGlyphTable[i] = NULL; } } m_pcFont->AddInstance( this ); g_cFontLock.Unlock(); return ( 0 ); }
SFontInstance::~SFontInstance() { g_cFontLock.Lock(); m_pcFont->RemoveInstance( this ); for( int i = 0; i < m_nGlyphCount; ++i ) { delete[]reinterpret_cast < char *>( m_ppcGlyphTable[i] ); } delete[]m_ppcGlyphTable; g_cFontLock.Unlock(); }
int FontServer::GetStyle( const std::string & cFamily, int nIndex, char *pzStyle, uint32 *pnFlags ) const { int nError = 0; g_cFontLock.Lock(); FontFamily *pcFamily = FindFamily( cFamily ); if( pcFamily != NULL ) { if( nIndex < int ( pcFamily->m_cFonts.size() ) ) { std::map <std::string, SFont * >::const_iterator i = pcFamily->m_cFonts.begin(); while( nIndex-- > 0 ) ++i; strcpy( pzStyle, ( *i ).first.c_str() ); *pnFlags = 0; if( ( *i ).second->IsFixedWidth() ) { *pnFlags |= FONT_IS_FIXED; } if( ( *i ).second->IsScalable() ) { *pnFlags |= FONT_IS_SCALABLE; if( ( *i ).second->GetBitmapSizes().size( ) > 0 ) { *pnFlags |= FONT_HAS_TUNED_SIZES; } } else { *pnFlags |= FONT_HAS_TUNED_SIZES; } nError = 0; } else { nError = EINVAL; } } else { nError = ENOENT; } g_cFontLock.Unlock(); return ( nError ); }
SFontInstance *FontServer::OpenInstance( const std::string & cFamily, const std::string & cStyle, const FontProperty & cFP ) { FontFamily *pcFamily; g_cFontLock.Lock(); if( ( pcFamily = FindFamily( cFamily ) ) ) { SFont *pcFont = pcFamily->FindStyle( cStyle ); if( pcFont != NULL ) { SFontInstance *pcInstance = pcFont->OpenInstance( cFP ); if( pcInstance != NULL ) { g_cFontLock.Unlock(); return ( pcInstance ); } } } g_cFontLock.Unlock(); return ( NULL ); }
int FontServer::GetStyleCount( const std::string & cFamily ) const { int nCount = -1; g_cFontLock.Lock(); FontFamily *pcFamily = FindFamily( cFamily ); if( pcFamily != NULL ) { nCount = pcFamily->m_cFonts.size(); } g_cFontLock.Unlock(); return ( nCount ); }
int FontServer::GetFamily( int nIndex, char *pzFamily, uint32 *pnFlags ) { int nError = EINVAL; g_cFontLock.Lock(); if( nIndex < int ( m_cFamilies.size() ) ) { std::map <std::string, FontFamily * >::const_iterator i = m_cFamilies.begin(); while( nIndex-- > 0 ) ++i; strcpy( pzFamily, ( *i ).first.c_str() ); nError = 0; } g_cFontLock.Unlock(); return ( nError ); }
void SFont::RemoveInstance( SFontInstance * pcInstance ) { g_cFontLock.Lock(); std::map <FontProperty, SFontInstance * >::iterator i; __assertw( g_cFontLock.IsLocked() ); i = m_cInstances.find( pcInstance->m_cInstanceProperties ); if( i != m_cInstances.end() ) { m_cInstances.erase( i ); } else { dbprintf( "Error: SFont::RemoveInstance could not find instance\n" ); } if( m_bDeleted && m_cInstances.empty() ) { dbprintf( "Last instance of deleted font %s, %s removed. Deleting font\n", m_pcFamily->GetName().c_str( ), m_cStyle.c_str( ) ); delete this; } g_cFontLock.Unlock(); }
int SFontInstance::GetStringLength( const char *pzString, int nLength, int nWidth, bool bIncludeLast ) { int nStrLen = 0; g_cFontLock.Lock(); while( nLength > 0 ) { int nCharLen = utf8_char_length( *pzString ); if( nCharLen > nLength ) { break; } Glyph *pcGlyph = GetGlyph( FT_Get_Char_Index( m_pcFont->GetTTFace(), utf8_to_unicode( pzString ) ) ); if( pcGlyph == NULL ) { dbprintf( "Error: GetStringLength() failed to load glyph\n" ); break; } if( nWidth < pcGlyph->m_nAdvance.x ) { if( bIncludeLast ) { nStrLen += nCharLen; } break; } pzString += nCharLen; nLength -= nCharLen; nStrLen += nCharLen; nWidth -= pcGlyph->m_nAdvance.x; } g_cFontLock.Unlock(); return ( nStrLen ); }
IPoint SFontInstance::GetTextExtent( const char *pzString, int nLength, uint32 nFlags, int nTargetWidth ) { IPoint cExt( 0, m_nAscender - m_nDescender ); if( ( nFlags & DTF_WRAP_SOFT ) && ( nTargetWidth <= 0 ) ) return cExt; g_cFontLock.Lock(); // Count rows. int i, nCharLength = 0; const char *p = pzString; std::list<int> vRowLens; if( nFlags & DTF_WRAP_SOFT ) { int nWordWidth = 0, nLineWidth = 0; // Width of word/line in pixels int nWordLength = 0, nLineLength = 0; // Length of word/line in bytes for( i = nLength; i > 0; p += nCharLength ) { // Get char length nCharLength = utf8_char_length( *p ); nWordLength += nCharLength; i -= nCharLength; // Get glyph width Glyph *pcGlyph = GetGlyph( FT_Get_Char_Index( m_pcFont->GetTTFace(), utf8_to_unicode( p ) ) ); if( NULL == pcGlyph ) continue; nWordWidth += pcGlyph->m_nAdvance.x; if( *p == ' ' || *p == '\t' || *p == '\n' ) { if( nLineWidth + nWordWidth > nTargetWidth ) { // Start a new line before this word vRowLens.push_back( nLineLength ); nLineWidth = nWordWidth; nLineLength = nWordLength; } else { // Continue the current line nLineWidth += nWordWidth; nLineLength += nWordLength; if( *p == '\n' ) { // Start a newline after this word vRowLens.push_back( nLineLength ); nLineWidth = nLineLength = 0; } } nWordWidth = nWordLength = 0; } } // Push back the last line. vRowLens.push_back( nLineLength ); } else vRowLens.push_back( nLength ); int nOffset = 0, nLineExtent; std::list<int>::iterator l; for( l = vRowLens.begin(); l != vRowLens.end(); l++ ) { int nLineLength = (*l); const char *pzLine = pzString + nOffset; nLineExtent = 0; while( nLineLength > 0 ) { if( !( nFlags & DTF_IGNORE_FMT ) ) { bool bDone; do { bDone = false; switch ( *pzLine ) { case '_': { if( !( nFlags & DTF_UNDERLINES ) ) bDone = true; else { pzLine++; nLineLength--; } break; } case '\n': { if( !( nFlags & DTF_WRAP_SOFT ) ) { cExt.y += m_nAscender - m_nDescender + m_nLineGap; if( nLineExtent > cExt.x ) cExt.x = nLineExtent; nLineExtent = 0; } pzLine++; nLineLength--; break; } case '\t': { int nSkip = TAB_STOP - int( cExt.x ) % TAB_STOP; if( nSkip < 2 ) nSkip = TAB_STOP; cExt.x += nSkip; pzLine++; nLineLength--; break; } case 27: { pzLine++; nLineLength--; if( nLineLength > 0 && *pzLine != '[' ) { pzLine++; nLineLength--; } break; } default: bDone = true; } // switch() } while( nLineLength > 0 && !bDone ); } // if() int nCharLen = utf8_char_length( *pzLine ); if( nCharLen > nLineLength ) break; Glyph *pcGlyph = GetGlyph( FT_Get_Char_Index( m_pcFont->GetTTFace(), utf8_to_unicode( pzLine ) ) ); pzLine += nCharLen; nLineLength -= nCharLen; if( pcGlyph == NULL ) { dbprintf( "Error: GetTextExtent() failed to load glyph\n" ); continue; } nLineExtent += pcGlyph->m_nAdvance.x; } // while() if( nLineExtent > cExt.x ) cExt.x = nLineExtent; if( nFlags & DTF_WRAP_SOFT ) cExt.y += m_nAscender - m_nDescender + m_nLineGap; nOffset += (*l); } // for() g_cFontLock.Unlock(); return ( cExt ); }
void FontServer::ScanDirectory( const char *pzPath ) { DIR *hDir; dirent *psEntry; g_cFontLock.Lock(); std::map <std::string, FontFamily * >::iterator cFamIter; for( cFamIter = m_cFamilies.begin(); cFamIter != m_cFamilies.end( ); ++cFamIter ) { std::map <std::string, SFont * >::iterator cStyleIter; for( cStyleIter = ( *cFamIter ).second->m_cFonts.begin(); cStyleIter != ( *cFamIter ).second->m_cFonts.end( ); ++cStyleIter ) { ( *cStyleIter ).second->SetDeletedFlag( true ); } } if( ( hDir = opendir( pzPath ) ) ) { int nCount = 0; while( ( psEntry = readdir( hDir ) ) ) { FT_Face psFace; FT_Error nError; char zFullPath[PATH_MAX]; if( strcmp( psEntry->d_name, "." ) == 0 || strcmp( psEntry->d_name, ".." ) == 0 ) { continue; } strcpy( zFullPath, pzPath ); pathcat( zFullPath, psEntry->d_name ); nError = FT_New_Face( m_hFTLib, zFullPath, 0, &psFace ); if( nError != 0 ) { continue; } FT_CharMap psCharMap; int i; for( i = 0; i < psFace->num_charmaps; i++ ) { psCharMap = psFace->charmaps[i]; if( psCharMap->platform_id == 3 && psCharMap->encoding_id == 1 ) { // Windows unicode goto found; } } for( i = 0; i < psFace->num_charmaps; i++ ) { psCharMap = psFace->charmaps[i]; if( psCharMap->platform_id == 1 && psCharMap->encoding_id == 0 ) { // Apple unicode goto found; } } for( i = 0; i < psFace->num_charmaps; i++ ) { psCharMap = psFace->charmaps[i]; if( psCharMap->platform_id == 3 && psCharMap->encoding_id == 0 ) { // Windows symbol goto found; } } for( i = 0; i < psFace->num_charmaps; i++ ) { psCharMap = psFace->charmaps[i]; if( psCharMap->platform_id == 0 && psCharMap->encoding_id == 0 ) { // Apple roman goto found; } } for( i = 0; i < psFace->num_charmaps; i++ ) { psCharMap = psFace->charmaps[i]; dbprintf( "platform=%d, encoding=%d\n", psCharMap->platform_id, psCharMap->encoding_id ); } FT_Done_Face( psFace ); dbprintf( "Error: failed to find character map\n" ); continue; found: psFace->charmap = psCharMap; FontFamily *pcFamily = FindFamily( psFace->family_name ); if( NULL == pcFamily ) { try { pcFamily = new FontFamily( psFace->family_name ); } catch( ... ) { continue; } m_cFamilies[psFace->family_name] = pcFamily; } SFont *pcFont = pcFamily->FindStyle( psFace->style_name ); if( pcFont != NULL ) { pcFont->SetDeletedFlag( false ); FT_Done_Face( psFace ); continue; } else { try { pcFont = new SFont( pcFamily, psFace ); } catch( ... ) { continue; } } __assertw( NULL != pcFont ); #if 0 dbprintf( "Font : '%s'-'%s' (%d) added\n", psFace->family_name, psFace->style_name, psFace->num_fixed_sizes ); if( psFace->num_fixed_sizes > 0 ) { for( int j = 0; j < psFace->num_fixed_sizes; ++j ) { dbprintf( " Size %d : %dx%d\n", j, psFace->available_sizes[j].width, psFace->available_sizes[j].height ); } } #endif nCount++; } dbprintf( "Directory '%s' scanned %d fonts found\n", pzPath, nCount ); closedir( hDir ); } restart: for( cFamIter = m_cFamilies.begin(); cFamIter != m_cFamilies.end( ); ++cFamIter ) { std::map <std::string, SFont * >::iterator cStyleIter; for( cStyleIter = ( *cFamIter ).second->m_cFonts.begin(); cStyleIter != ( *cFamIter ).second->m_cFonts.end( ); ++cStyleIter ) { SFont *pcStyle = ( *cStyleIter ).second; if( pcStyle->IsDeleted() && pcStyle->GetInstanceCount( ) == 0 ) { dbprintf( "Deleting font %s:%s\n", pcStyle->GetFamily()->GetName( ).c_str( ), pcStyle->GetStyle( ).c_str( ) ); delete pcStyle; goto restart; } } } g_cFontLock.Unlock(); }
void FontServer::Unlock() { g_cFontLock.Unlock(); }