Files
core/DesktopEditor/fontengine/FontFile.cpp

1344 lines
40 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "FontManager.h"
#include "internal/internal.h"
#include "internal/ftobjs.h"
CFontFile::CFontFile()
{
m_pStream = NULL;
m_pFontManager = NULL;
m_pDefaultFont = NULL;
ClearCache();
memset(m_arrdFontMatrix, 0, 6 * sizeof(double));
memset(m_arrdTextMatrix, 0, 6 * sizeof(double));
m_bAntiAliasing = TRUE;
m_bUseKerning = FALSE;
m_dSize = 0;
m_unHorDpi = 0;
m_unVerDpi = 0;
m_bNeedDoItalic = FALSE;
m_bNeedDoBold = FALSE;
m_dCharSpacing = 0;
m_nMinX = 0;
m_nMinY = 0;
m_nMaxX = 0;
m_nMaxY = 0;
m_lFaceIndex = 0;
m_pFace = NULL;
m_dUnitsKoef = 0;
m_nDefaultChar = -1;
m_nSymbolic = -1;
m_dTextScale = 1.0;
m_bStringGID = FALSE;
m_nNum_charmaps = 0;
m_lAscender = 0;
m_lDescender = 0;
m_lLineHeight = 0;
m_lUnits_Per_Em = 0;
m_bUseDefaultFont = FALSE;
m_bIsNeedUpdateMatrix12 = FALSE;
m_bHintsSupport = TRUE;
}
CFontFile::~CFontFile()
{
RELEASEINTERFACE(m_pStream);
ClearCache();
}
void CFontFile::SetDefaultFont(CFontFile* pDefFont)
{
m_pDefaultFont = pDefFont;
}
void CFontFile::LoadDefaultCharAndSymbolicCmapIndex()
{
m_nDefaultChar = -1;
m_nSymbolic = -1;
TT_OS2* pTable = (TT_OS2*)FT_Get_Sfnt_Table( m_pFace, ft_sfnt_os2 );
if (NULL == pTable)
return;
m_nDefaultChar = pTable->usDefaultChar;
// version
if (0xFFFF == pTable->version)
return;
FT_ULong ulCodePageRange1 = pTable->ulCodePageRange1;
FT_ULong ulCodePageRange2 = pTable->ulCodePageRange2;
if (!(ulCodePageRange1 & 0x80000000) && !(ulCodePageRange1 == 0 && ulCodePageRange2 == 0))
return;
for (int nIndex = 0; nIndex < m_pFace->num_charmaps; ++nIndex)
{
// Symbol
if ( 0 == m_pFace->charmaps[nIndex]->encoding_id && 3 == m_pFace->charmaps[nIndex]->platform_id )
{
m_nSymbolic = nIndex;
break;
}
}
}
void CFontFile::ResetFontMatrix()
{
if (m_pDefaultFont)
m_pDefaultFont->ResetFontMatrix();
if ( m_bNeedDoItalic )
{
m_arrdFontMatrix[0] = 1;
m_arrdFontMatrix[1] = 0;
m_arrdFontMatrix[2] = FONT_ITALIC_ANGLE;
m_arrdFontMatrix[3] = 1;
m_arrdFontMatrix[4] = 0;
m_arrdFontMatrix[5] = 0;
}
else
{
m_arrdFontMatrix[0] = 1;
m_arrdFontMatrix[1] = 0;
m_arrdFontMatrix[2] = 0;
m_arrdFontMatrix[3] = 1;
m_arrdFontMatrix[4] = 0;
m_arrdFontMatrix[5] = 0;
}
UpdateMatrix0();
}
void CFontFile::ResetTextMatrix()
{
m_arrdTextMatrix[0] = 1;
m_arrdTextMatrix[1] = 0;
m_arrdTextMatrix[2] = 0;
m_arrdTextMatrix[3] = 1;
m_arrdTextMatrix[4] = 0;
m_arrdTextMatrix[5] = 0;
CheckTextMatrix();
}
void CFontFile::CheckTextMatrix()
{
m_bIsNeedUpdateMatrix12 = true;
if ((m_arrdTextMatrix[0] == 1) && (m_arrdTextMatrix[1] == 0) && (m_arrdTextMatrix[2] == 0) && (m_arrdTextMatrix[3] == 1))
{
m_bIsNeedUpdateMatrix12 = false;
if (m_pDefaultFont)
m_pDefaultFont->UpdateMatrix1();
UpdateMatrix1();
}
}
void CFontFile::UpdateMatrix0()
{
double m1 = m_arrdTextMatrix[2];
double m2 = m_arrdTextMatrix[3];
m_dTextScale = sqrt(m_arrdTextMatrix[2]*m_arrdTextMatrix[2] + m_arrdTextMatrix[3]*m_arrdTextMatrix[3]);
FT_BBox* bbox = &m_pFace->bbox;
FT_Pos xMin = bbox->xMin;
FT_Pos yMin = bbox->yMin;
FT_Pos xMax = bbox->xMax;
FT_Pos yMax = bbox->yMax;
if (m_lUnits_Per_Em == 0)
m_lUnits_Per_Em = m_pFace->units_per_EM = 2048;
int units_per_EM = m_lUnits_Per_Em;
double dDiv = xMax > 20000 ? 65536 : 1;
double del = dDiv * units_per_EM;
int nX = (int)((m_arrdFontMatrix[0] * xMin + m_arrdFontMatrix[2] * yMin) * m_dSize / del);
m_nMinX = m_nMaxX = nX;
int nY = (int)((m_arrdFontMatrix[1] * xMin + m_arrdFontMatrix[3] * yMin) * m_dSize / del);
m_nMinY = m_nMaxY = nY;
nX = (int)((m_arrdFontMatrix[0] * xMin + m_arrdFontMatrix[2] * yMax) * m_dSize / del);
if (nX < m_nMinX)
m_nMinX = nX;
else if (nX > m_nMaxX)
m_nMaxX = nX;
nY = (int)((m_arrdFontMatrix[1] * xMin + m_arrdFontMatrix[3] * yMax) * m_dSize / del);
if (nY < m_nMinY)
m_nMinY = nY;
else if (nY > m_nMaxY)
m_nMaxY = nY;
nX = (int)((m_arrdFontMatrix[0] * xMax + m_arrdFontMatrix[2] * yMin) * m_dSize / del);
if (nX < m_nMinX)
m_nMinX = nX;
else if (nX > m_nMaxX)
m_nMaxX = nX;
nY = (int)((m_arrdFontMatrix[1] * xMax + m_arrdFontMatrix[3] * yMin) * m_dSize / del);
if (nY < m_nMinY)
m_nMinY = nY;
else if (nY > m_nMaxY)
m_nMaxY = nY;
nX = (int)((m_arrdFontMatrix[0] * xMax + m_arrdFontMatrix[2] * yMax) * m_dSize / del);
if (nX < m_nMinX)
m_nMinX = nX;
else if (nX > m_nMaxX)
m_nMaxX = nX;
nY = (int)((m_arrdFontMatrix[1] * xMax + m_arrdFontMatrix[3] * yMax) * m_dSize / del);
if (nY < m_nMinY)
m_nMinY = nY;
else if (nY > m_nMaxY)
m_nMaxY = nY;
// This is a kludge: some buggy PDF generators embed fonts with zero bounding boxes.
if (m_nMaxX == m_nMinX)
{
m_nMinX = 0;
m_nMaxX = (int)(m_dSize);
}
if (m_nMaxY == m_nMinY)
{
m_nMinY = 0;
m_nMaxY = (int)((1.2 * m_dSize));
}
m_oFontMatrix.xx = (FT_Fixed)(m_arrdFontMatrix[0] * 65536);
m_oFontMatrix.yx = (FT_Fixed)(m_arrdFontMatrix[1] * 65536);
m_oFontMatrix.xy = (FT_Fixed)(m_arrdFontMatrix[2] * 65536);
m_oFontMatrix.yy = (FT_Fixed)(m_arrdFontMatrix[3] * 65536);
m_oTextMatrix.xx = (FT_Fixed)((m_arrdTextMatrix[0] / m_dTextScale) * 65536);
m_oTextMatrix.yx = (FT_Fixed)((m_arrdTextMatrix[1] / m_dTextScale) * 65536);
m_oTextMatrix.xy = (FT_Fixed)((m_arrdTextMatrix[2] / m_dTextScale) * 65536);
m_oTextMatrix.yy = (FT_Fixed)((m_arrdTextMatrix[3] / m_dTextScale) * 65536);
FT_Set_Transform( m_pFace, &m_oFontMatrix, NULL );
}
void CFontFile::UpdateMatrix1()
{
m_oFontMatrix.xx = (FT_Fixed)(m_arrdFontMatrix[0] * 65536);
m_oFontMatrix.yx = (FT_Fixed)(m_arrdFontMatrix[1] * 65536);
m_oFontMatrix.xy = (FT_Fixed)(m_arrdFontMatrix[2] * 65536);
m_oFontMatrix.yy = (FT_Fixed)(m_arrdFontMatrix[3] * 65536);
FT_Set_Transform( m_pFace, &m_oFontMatrix, NULL );
}
void CFontFile::UpdateMatrix2()
{
m_oFontMatrix.xx = (FT_Fixed)(( m_arrdFontMatrix[0] * m_arrdTextMatrix[0] + m_arrdFontMatrix[1] * m_arrdTextMatrix[2] ) * 65536);
m_oFontMatrix.yx = (FT_Fixed)(( m_arrdFontMatrix[0] * m_arrdTextMatrix[1] + m_arrdFontMatrix[1] * m_arrdTextMatrix[3] ) * 65536);
m_oFontMatrix.xy = (FT_Fixed)(( m_arrdFontMatrix[2] * m_arrdTextMatrix[0] + m_arrdFontMatrix[3] * m_arrdTextMatrix[2] ) * 65536);
m_oFontMatrix.yy = (FT_Fixed)(( m_arrdFontMatrix[2] * m_arrdTextMatrix[1] + m_arrdFontMatrix[3] * m_arrdTextMatrix[3] ) * 65536);
FT_Set_Transform( m_pFace, &m_oFontMatrix, NULL );
}
void CFontFile::SetSizeAndDpi(double dSize, UINT unHorDpi, UINT unVerDpi)
{
if (m_pDefaultFont)
m_pDefaultFont->SetSizeAndDpi(dSize, unHorDpi, unVerDpi);
double dOldSize = m_dSize;
double dNewSize = dSize;
double fKoef = dNewSize / dOldSize;
if (fKoef > 1.001 || fKoef < 0.999 || unHorDpi != m_unHorDpi || unVerDpi != m_unVerDpi)
{
m_unHorDpi = unHorDpi;
m_unVerDpi = unVerDpi;
if (fKoef > 1.001 || fKoef < 0.999)
{
m_dSize = dNewSize;
UpdateMatrix0();
}
m_dUnitsKoef = m_unHorDpi / 72.0 * m_dSize;
FT_Set_Char_Size(m_pFace, 0, (int)(dNewSize * 64), unHorDpi, unVerDpi);
ClearCache();
}
}
void CFontFile::ClearCache()
{
// TODO: total memory
ClearCacheNoAttack();
}
void CFontFile::ClearCacheNoAttack()
{
m_oCacheSizes.Clear();
::memset( m_arrCacheSizesIndexs, 0xFF, FONT_CACHE_SIZES_INDEXES_SIZE_2 );
}
void CFontFile::Destroy()
{
// TODO: total memory
}
bool CFontFile::SetTextMatrix(const double& fA, const double& fB, const double& fC, const double fD, double fE, double fF)
{
bool b1 = (m_arrdTextMatrix[0] == fA && m_arrdTextMatrix[1] == -fB && m_arrdTextMatrix[2] == -fC && m_arrdTextMatrix[3] == fD);
if (b1 && m_arrdTextMatrix[4] == fE && m_arrdTextMatrix[5] == fF)
return false;
if (m_pDefaultFont)
m_pDefaultFont->SetTextMatrix(fA, fB, fC, fD, fE, fF);
m_arrdTextMatrix[0] = fA;
m_arrdTextMatrix[1] = -fB;
m_arrdTextMatrix[2] = -fC;
m_arrdTextMatrix[3] = fD;
m_arrdTextMatrix[4] = fE;
m_arrdTextMatrix[5] = fF;
if (!b1)
{
ClearCache();
}
CheckTextMatrix();
return true;
}
void CFontFile::SetFontMatrix(const double& fA, const double& fB, const double& fC, const double fD, double fE, double fF)
{
if (m_pDefaultFont)
m_pDefaultFont->SetFontMatrix(fA, fB, fC, fD, fE, fF);
if (m_bNeedDoItalic)
{
m_arrdFontMatrix[0] = fA;
m_arrdFontMatrix[1] = fB;
m_arrdFontMatrix[2] = fC + fA * FONT_ITALIC_ANGLE;
m_arrdFontMatrix[3] = fD + fB * FONT_ITALIC_ANGLE;
m_arrdFontMatrix[4] = fE;
m_arrdFontMatrix[5] = fF;
}
else
{
m_arrdFontMatrix[0] = fA;
m_arrdFontMatrix[1] = fB;
m_arrdFontMatrix[2] = fC;
m_arrdFontMatrix[3] = fD;
m_arrdFontMatrix[4] = fE;
m_arrdFontMatrix[5] = fF;
}
ClearCache();
}
int CFontFile::GetKerning(UINT unPrevGID, UINT unGID)
{
FT_Vector delta;
FT_Get_Kerning(m_pFace, unPrevGID, unGID, 0, &delta);
return (delta.x >> 6);
}
void CFontFile::SetStringGID(const BOOL& bGID)
{
if (m_bStringGID == bGID)
return;
//ClearCache();
m_bStringGID = bGID;
}
BOOL CFontFile::GetStringGID()
{
return m_bStringGID;
}
void CFontFile::SetUseDefaultFont(const BOOL& bUse)
{
m_bUseDefaultFont = bUse;
}
BOOL CFontFile::GetUseDefaultFont()
{
return m_bUseDefaultFont;
}
void CFontFile::SetCharSpacing(const double& dCharSpacing)
{
m_dCharSpacing = dCharSpacing;
}
double CFontFile::GetCharSpacing()
{
return m_dCharSpacing;
}
std::string CFontFile::GetStyleName()
{
std::string s(m_pFace->style_name);
return s;
}
void CFontFile::UpdateStyles(const BOOL& bBold, const BOOL& bItalic)
{
std::string sStyle = GetStyleName();
// Смотрим какой стиль у исходного шрифта
BOOL bSrcBold = (-1 != sStyle.find("Bold"));
BOOL bSrcItalic = (-1 != sStyle.find("Italic"));
if (!bBold) // Нам нужен не жирный шрифт
{
m_bNeedDoBold = false;
}
else if (bBold) // Нам нужно сделать шрифт жирным
{
if (bSrcBold)
{
// Исходный шрифт уже жирный, поэтому ничего дополнительного делать не надо
m_bNeedDoBold = false;
}
else
{
// Иходный шрифт не жирный, поэтому жирность делаем сами
m_bNeedDoBold = true;
}
}
if (!bItalic) // Нам нужен не наклонный шрифт
{
SetItalic(false);
}
else if (bItalic) // Нам нужно сделать наклонный шрифт
{
if (bSrcItalic)
{
// Исходный шрифт уже наклонный, поэтому ничего дополнительного делать не надо
SetItalic(false);
}
else
{
// Иходный шрифт не наклонный, поэтому делаем его наклонным сами
SetItalic(true);
}
}
}
void CFontFile::SetItalic(const BOOL& value)
{
if (m_bNeedDoItalic != value)
{
ClearCache();
m_bNeedDoItalic = value;
ResetFontMatrix();
}
}
void CFontFile::SetNeedBold(const BOOL& value)
{
if (m_bNeedDoBold != value)
ClearCache();
m_bNeedDoBold = value;
}
int CFontFile::GetAscender()
{
return m_lAscender;
}
int CFontFile::GetDescender()
{
return m_lDescender;
}
int CFontFile::GetHeight()
{
return m_lLineHeight;
}
int CFontFile::Units_Per_Em()
{
return m_lUnits_Per_Em;
}
void CFontFile::CheckHintsSupport()
{
m_bHintsSupport = TRUE;
if (!m_pFace || !m_pFace->driver || !m_pFace->driver->clazz)
return;
std::string sName(m_pFace->driver->clazz->root.module_name);
if (sName != "truetype")
{
m_bHintsSupport = FALSE;
return;
}
std::string sFamilyName(m_pFace->family_name);
if (sFamilyName == "MS Mincho" || sFamilyName == "Castellar")
m_bHintsSupport = FALSE;
}
// glyph methods
int CFontFile::SetCMapForCharCode(long lUnicode, int *pnCMapIndex)
{
*pnCMapIndex = -1;
if (!m_pFace)
return 0;
if ( m_bStringGID || 0 == m_pFace->num_charmaps )
return lUnicode;
int nCharIndex = 0;
for ( int nIndex = 0; nIndex < m_pFace->num_charmaps; ++nIndex )
{
FT_CharMap pCharMap = m_pFace->charmaps[nIndex];
if ( FT_Set_Charmap( m_pFace, pCharMap ) )
continue;
FT_Encoding pEncoding = pCharMap->encoding;
if ( FT_ENCODING_UNICODE == pEncoding )
{
if ( nCharIndex = FT_Get_Char_Index( m_pFace, lUnicode ) )
{
*pnCMapIndex = nIndex;
return nCharIndex;
}
}
else if ( FT_ENCODING_NONE == pEncoding || FT_ENCODING_MS_SYMBOL == pEncoding || FT_ENCODING_APPLE_ROMAN == pEncoding )
{
FT_ULong charcode;
FT_UInt gindex;
charcode = FT_Get_First_Char( m_pFace, &gindex );
while ( gindex != 0 )
{
charcode = FT_Get_Next_Char( m_pFace, charcode, &gindex );
if ( charcode == lUnicode )
{
nCharIndex = gindex;
*pnCMapIndex = nIndex;
break;
}
}
if ( nCharIndex = FT_Get_Char_Index( m_pFace, lUnicode ) )
{
*pnCMapIndex = nIndex;
}
}
}
return nCharIndex;
}
int CFontFile::SetCMapForCharCode2(long lUnicode)
{
if (m_bStringGID)
return lUnicode;
FT_Int unGID;
int nCMapIndex = 0;
int nCacheIndex = m_arrCacheSizesIndexs[lUnicode];
if ( 0xFFFF == nCacheIndex )
{
return unGID = SetCMapForCharCode( lUnicode, &nCMapIndex );
}
else
{
TFontCacheSizes& oSizes = m_oCacheSizes[nCacheIndex];
unGID = oSizes.ushGID;
nCMapIndex = oSizes.nCMapIndex;
if ( 0 != m_pFace->num_charmaps )
{
int nCurCMapIndex = FT_Get_Charmap_Index( m_pFace->charmap );
if ( nCurCMapIndex != nCMapIndex )
{
nCMapIndex = max( 0, nCMapIndex );
FT_Set_Charmap( m_pFace, m_pFace->charmaps[nCMapIndex] );
}
}
}
return unGID;
}
void CFontFile::AddToSizesCache(const TFontCacheSizes& oSizes)
{
m_arrCacheSizesIndexs[oSizes.ushUnicode] = m_oCacheSizes.Add( oSizes );
}
TFontCacheSizes CFontFile::GetChar(LONG lUnicode)
{
FT_Face pFace = m_pFace;
FT_GlyphSlot pCurentGliph = pFace->glyph;
TFontCacheSizes oSizes;
LONG ushUnicode = lUnicode;
// Сначала мы все рассчитываем исходя только из матрицы шрифта FontMatrix
if (m_bIsNeedUpdateMatrix12)
{
if (m_pDefaultFont)
m_pDefaultFont->UpdateMatrix1();
m_pDefaultFont->UpdateMatrix1();
}
LONG unGID = 0;
USHORT charSymbolObj = m_arrCacheSizesIndexs[ushUnicode];
if (0xFFFF == charSymbolObj)
{
int nCMapIndex = 0;
unGID = SetCMapForCharCode(ushUnicode, &nCMapIndex);
oSizes.ushUnicode = ushUnicode;
if (!((unGID > 0) || (-1 != m_nSymbolic && (ushUnicode < 0xF000) && 0 < (unGID = SetCMapForCharCode(ushUnicode + 0xF000, &nCMapIndex)))))
{
// Пробуем загрузить через стандартный шрифт
if ((FALSE == m_bUseDefaultFont) || (NULL == m_pDefaultFont) || (0 >= (unGID = m_pDefaultFont->SetCMapForCharCode(ushUnicode, &nCMapIndex))))
{
if (m_nDefaultChar < 0)
{
oSizes.ushGID = -1;
oSizes.eState = glyphstateMiss;
oSizes.fAdvanceX = (pFace->size->metrics.max_advance >> 6) / 2.0f;
return oSizes;
}
else
{
unGID = m_nDefaultChar;
oSizes.eState = glyphstateNormal;
pFace = m_pFace;
pCurentGliph = pFace->glyph;
}
}
else
{
oSizes.eState = glyphstateDeafault;
pFace = m_pDefaultFont->m_pFace;
pCurentGliph = pFace->glyph;
}
}
else
{
oSizes.eState = glyphstateNormal;
}
oSizes.ushGID = (USHORT)unGID;
oSizes.nCMapIndex = nCMapIndex;
FT_Int32 _LOAD_MODE = m_bHintsSupport ? m_pFontManager->m_nLOAD_MODE : 40970;
if (0 != FT_Load_Glyph(pFace, unGID, _LOAD_MODE))
return oSizes;
FT_Glyph pGlyph = NULL;
if ( FT_Get_Glyph( pFace->glyph, &pGlyph ) )
{
return oSizes;
}
FT_BBox oBBox;
FT_Glyph_Get_CBox( pGlyph, ft_glyph_bbox_gridfit, &oBBox );
FT_Done_Glyph( pGlyph );
oSizes.fAdvanceX = (float)(pFace->glyph->linearHoriAdvance * m_dUnitsKoef / pFace->units_per_EM);
oSizes.oBBox.fMinX = (float)(oBBox.xMin >> 6);
oSizes.oBBox.fMaxX = (float)(oBBox.xMax >> 6);
oSizes.oBBox.fMinY = (float)(oBBox.yMin >> 6);
oSizes.oBBox.fMaxY = (float)(oBBox.yMax >> 6);
oSizes.oMetrics.fHeight = (float)(pFace->glyph->metrics.height >> 6);
oSizes.oMetrics.fHoriAdvance = (float)(pFace->glyph->metrics.horiAdvance >> 6);
oSizes.oMetrics.fHoriBearingX = (float)(pFace->glyph->metrics.horiBearingX >> 6);
oSizes.oMetrics.fHoriBearingY = (float)(pFace->glyph->metrics.horiBearingY >> 6);
oSizes.oMetrics.fVertAdvance = (float)(pFace->glyph->metrics.vertAdvance >> 6);
oSizes.oMetrics.fVertBearingX = (float)(pFace->glyph->metrics.vertBearingX >> 6);
oSizes.oMetrics.fVertBearingY = (float)(pFace->glyph->metrics.vertBearingY >> 6);
oSizes.oMetrics.fWidth = (float)(pFace->glyph->metrics.width >> 6);
oSizes.bBitmap = false;
oSizes.oBitmap.nX = 0;
oSizes.oBitmap.nY = 0;
oSizes.oBitmap.nHeight = 0;
oSizes.oBitmap.nWidth = 0;
oSizes.oBitmap.bFreeData = FALSE;
oSizes.oBitmap.pData = NULL;
oSizes.oBitmap.bAA = FALSE;
if (m_bNeedDoBold)
oSizes.fAdvanceX += 1;
AddToSizesCache( oSizes );
}
else
{
oSizes = m_oCacheSizes[charSymbolObj];
}
if (m_bIsNeedUpdateMatrix12)
{
if (m_pDefaultFont)
m_pDefaultFont->UpdateMatrix2();
UpdateMatrix2();
}
return oSizes;
}
BOOL CFontFile::GetString2(CGlyphString& oString)
{
int nCountGlyph = oString.GetLength();
if (nCountGlyph <= 0)
return TRUE;
//if (1 == nCountGlyph)
// return GetString2C(oString);
unsigned int unPrevGID = 0;
float fPenX = 0, fPenY = 0;
for (int nIndex = 0; nIndex < nCountGlyph; ++nIndex)
{
// Сначала мы все рассчитываем исходя только из матрицы шрифта FontMatrix
if (m_bIsNeedUpdateMatrix12)
{
if (m_pDefaultFont)
m_pDefaultFont->UpdateMatrix1();
UpdateMatrix1();
}
FT_Face pFace = m_pFace;
FT_GlyphSlot pCurentGliph = pFace->glyph;
TGlyph* pCurGlyph = oString.GetAt(nIndex);
int ushUnicode = pCurGlyph->lUnicode;
int unGID = 0;
USHORT charSymbolObj = m_arrCacheSizesIndexs[ushUnicode];
if (0xFFFF == charSymbolObj || m_oCacheSizes[charSymbolObj].bBitmap == false)
{
int nCMapIndex = 0;
unGID = SetCMapForCharCode(ushUnicode, &nCMapIndex);
TFontCacheSizes oSizes;
oSizes.ushUnicode = ushUnicode;
if (!((unGID > 0) || (-1 != m_nSymbolic && (ushUnicode < 0xF000) && 0 < (unGID = SetCMapForCharCode(ushUnicode + 0xF000, &nCMapIndex)))))
{
// Пробуем загрузить через стандартный шрифт
if (FALSE == m_bUseDefaultFont || NULL == m_pDefaultFont || 0 >= (unGID = m_pDefaultFont->SetCMapForCharCode(ushUnicode, &nCMapIndex)))
{
if (m_nDefaultChar < 0)
{
oSizes.ushGID = -1;
oSizes.eState = glyphstateMiss;
oSizes.fAdvanceX = (m_pFace->size->metrics.max_advance >> 6) / 2.0f;
return FALSE;
}
else
{
unGID = m_nDefaultChar;
oSizes.eState = glyphstateNormal;
pFace = m_pFace;
pCurentGliph = pFace->glyph;
}
}
else
{
oSizes.eState = glyphstateDeafault;
pFace = m_pDefaultFont->m_pFace;
pCurentGliph = pFace->glyph;
}
}
else
{
oSizes.eState = glyphstateNormal;
}
oSizes.ushGID = unGID;
oSizes.nCMapIndex = nCMapIndex;
if (m_bIsNeedUpdateMatrix12)
{
if (m_pDefaultFont)
m_pDefaultFont->UpdateMatrix2();
UpdateMatrix2();
}
FT_Int32 _LOAD_MODE = m_bHintsSupport ? m_pFontManager->m_nLOAD_MODE : 40970;
if (0 != FT_Load_Glyph(pFace, unGID, _LOAD_MODE))
return FALSE;
FT_Glyph pGlyph = NULL;
if ( FT_Get_Glyph( pFace->glyph, &pGlyph ) )
return FALSE;
FT_BBox oBBox;
FT_Glyph_Get_CBox(pGlyph, 1, &oBBox);
FT_Done_Glyph(pGlyph);
pCurentGliph = pFace->glyph;
oSizes.fAdvanceX = (float)(pFace->glyph->linearHoriAdvance * m_dUnitsKoef / pFace->units_per_EM);
oSizes.oBBox.fMinX = (float)(oBBox.xMin >> 6);
oSizes.oBBox.fMaxX = (float)(oBBox.xMax >> 6);
oSizes.oBBox.fMinY = (float)(oBBox.yMin >> 6);
oSizes.oBBox.fMaxY = (float)(oBBox.yMax >> 6);
oSizes.oMetrics.fHeight = (float)(pFace->glyph->metrics.height >> 6);
oSizes.oMetrics.fHoriAdvance = (float)(pFace->glyph->metrics.horiAdvance >> 6);
oSizes.oMetrics.fHoriBearingX = (float)(pFace->glyph->metrics.horiBearingX >> 6);
oSizes.oMetrics.fHoriBearingY = (float)(pFace->glyph->metrics.horiBearingY >> 6);
oSizes.oMetrics.fVertAdvance = (float)(pFace->glyph->metrics.vertAdvance >> 6);
oSizes.oMetrics.fVertBearingX = (float)(pFace->glyph->metrics.vertBearingX >> 6);
oSizes.oMetrics.fVertBearingY = (float)(pFace->glyph->metrics.vertBearingY >> 6);
oSizes.oMetrics.fWidth = (float)(pFace->glyph->metrics.width >> 6);
oSizes.bBitmap = true;
if (FT_Render_Glyph(pCurentGliph, REND_MODE))
return FALSE;
TGlyphBitmap *pBitmap = &(pCurGlyph->oBitmap);
pBitmap->nX = pCurentGliph->bitmap_left;
pBitmap->nY = pCurentGliph->bitmap_top;
pBitmap->nWidth = pCurentGliph->bitmap.width;
pBitmap->nHeight = pCurentGliph->bitmap.rows;
pBitmap->bAA = m_bAntiAliasing;
int nRowSize = 0;
if ( m_bAntiAliasing )
{
if ( m_bNeedDoBold )
pBitmap->nWidth++;
nRowSize = pBitmap->nWidth;
}
else
{
nRowSize = (pBitmap->nWidth + 7) >> 3;
}
if (0 != (nRowSize * pBitmap->nHeight))
pBitmap->pData = (unsigned char *)malloc( nRowSize * pBitmap->nHeight );
else
pBitmap->pData = NULL;
pBitmap->bFreeData = FALSE; // Все удаляется в кэше (во время очистки или замены)
int nIndex2;
unsigned char *pDstBuffer, *pSrcBuffer;
if (NULL != pBitmap->pData)
{
//double dKoef = ( 255 + 10 ) / (double)255;
if ( !m_bNeedDoBold || !m_bAntiAliasing )
{
for ( nIndex2 = 0, pDstBuffer = pBitmap->pData, pSrcBuffer = pCurentGliph->bitmap.buffer; nIndex2 < pBitmap->nHeight; ++nIndex2, pDstBuffer += nRowSize, pSrcBuffer += pCurentGliph->bitmap.pitch )
{
memcpy( pDstBuffer, pSrcBuffer, nRowSize );
}
}
else
{
int nY, nX;
for ( nY = 0, pDstBuffer = pBitmap->pData, pSrcBuffer = pCurentGliph->bitmap.buffer; nY < pBitmap->nHeight; ++nY, pDstBuffer += nRowSize, pSrcBuffer += pCurentGliph->bitmap.pitch )
{
for ( nX = pBitmap->nWidth - 1; nX >= 0; nX-- )
{
if ( 0 != nX )
{
int nFirstByte, nSecondByte;
if ( pBitmap->nWidth - 1 == nX )
nFirstByte = 0;
else
nFirstByte = pSrcBuffer[nX];
nSecondByte = pSrcBuffer[nX - 1];
pDstBuffer[nX] = min( 255, nFirstByte + nSecondByte);
}
else
{
pDstBuffer[nX] = pSrcBuffer[nX];
}
}
}
}
}
oSizes.bBitmap = pCurGlyph->bBitmap;
oSizes.oBitmap.bAA = pBitmap->bAA;
oSizes.oBitmap.bFreeData = pBitmap->bFreeData;
oSizes.oBitmap.nX = pBitmap->nX;
oSizes.oBitmap.nY = pBitmap->nY;
oSizes.oBitmap.nWidth = pBitmap->nWidth;
oSizes.oBitmap.nHeight = pBitmap->nHeight;
oSizes.oBitmap.pData = pBitmap->pData;
AddToSizesCache( oSizes );
charSymbolObj = m_arrCacheSizesIndexs[oSizes.ushUnicode];
}
if (0xFFFF != charSymbolObj)
{
TFontCacheSizes& oSizes = m_oCacheSizes[charSymbolObj];
int nCMapIndex = oSizes.nCMapIndex;
if (glyphstateMiss == oSizes.eState)
{
oString.SetStartPoint (nIndex, fPenX, fPenY);
oString.SetBBox(nIndex, 0, 0, 0, 0);
oString.SetState (nIndex, glyphstateMiss);
fPenX += (float)(oSizes.fAdvanceX + m_dCharSpacing);
unPrevGID = 0;
continue;
}
else if (glyphstateDeafault == oSizes.eState)
{
oString.SetState(nIndex, glyphstateDeafault);
}
else
{
oString.SetState(nIndex, glyphstateNormal);
}
if ( 0 != pFace->num_charmaps )
{
int nCurCMapIndex = FT_Get_Charmap_Index( pFace->charmap );
if ( nCurCMapIndex != nCMapIndex )
{
nCMapIndex = max( 0, nCMapIndex );
FT_Set_Charmap( pFace, pFace->charmaps[nCMapIndex] );
}
}
if (m_bUseKerning && unPrevGID && (nIndex >= 0 && oString.GetAt(nIndex)->eState == oString.GetAt(nIndex - 1)->eState))
{
fPenX += GetKerning(unPrevGID, unGID);
}
float fX = oString.m_fX + fPenX;
float fY = oString.m_fY + fPenY;
float fXX = (float)(oString.m_arrCTM[4] + fX * oString.m_arrCTM[0] + fY * oString.m_arrCTM[2] - oString.m_fX);
float fYY = (float)(oString.m_arrCTM[5] + fX * oString.m_arrCTM[1] + fY * oString.m_arrCTM[3] - oString.m_fY);
oString.SetStartPoint(nIndex, fXX, fYY);
oString.GetAt(nIndex)->oMetrics = oSizes.oMetrics;
oString.SetBBox(nIndex, oSizes.oBBox.fMinX, oSizes.oBBox.fMaxY, oSizes.oBBox.fMaxX, oSizes.oBBox.fMinY);
fPenX += (float)(oSizes.fAdvanceX + m_dCharSpacing);
if (m_bNeedDoBold)
{
// Когда текст делаем жирным сами, то мы увеличиваем расстояние на 1 пиксель в ширину (независимо от DPI и размера текста всегда 1 пиксель)
fPenX += 1;
}
pCurGlyph->bBitmap = oSizes.bBitmap;
pCurGlyph->oBitmap = oSizes.oBitmap;
}
unPrevGID = unGID;
}
oString.m_fEndX = fPenX + oString.m_fX;
oString.m_fEndY = fPenY + oString.m_fY;
if (m_bIsNeedUpdateMatrix12)
{
if (m_pDefaultFont)
m_pDefaultFont->UpdateMatrix2();
UpdateMatrix2();
}
return TRUE;
}
BOOL CFontFile::GetString2C(CGlyphString& oString)
{
unsigned int unPrevGID = 0;
float fPenX = 0, fPenY = 0;
// Сначала мы все рассчитываем исходя только из матрицы шрифта FontMatrix
if (m_bIsNeedUpdateMatrix12)
{
if (m_pDefaultFont)
m_pDefaultFont->UpdateMatrix1();
UpdateMatrix1();
}
FT_Face pFace = m_pFace;
FT_GlyphSlot pCurentGliph = pFace->glyph;
TGlyph* pCurGlyph = oString.GetAt(0);
int ushUnicode = pCurGlyph->lUnicode;
int unGID = 0;
USHORT charSymbolObj = m_arrCacheSizesIndexs[ushUnicode];
if (0xFFFF == charSymbolObj || m_oCacheSizes[charSymbolObj].bBitmap == false)
{
int nCMapIndex = 0;
unGID = SetCMapForCharCode(ushUnicode, &nCMapIndex);
TFontCacheSizes oSizes;
oSizes.ushUnicode = ushUnicode;
if (!((unGID > 0) || (-1 != m_nSymbolic && (ushUnicode < 0xF000) && 0 < (unGID = SetCMapForCharCode(ushUnicode + 0xF000, &nCMapIndex)))))
{
// Пробуем загрузить через стандартный шрифт
if (FALSE == m_bUseDefaultFont || NULL == m_pDefaultFont || 0 >= (unGID = m_pDefaultFont->SetCMapForCharCode(ushUnicode, &nCMapIndex)))
{
if (m_nDefaultChar < 0)
{
oSizes.ushGID = -1;
oSizes.eState = glyphstateMiss;
oSizes.fAdvanceX = (m_pFace->size->metrics.max_advance >> 6) / 2.0f;
return FALSE;
}
else
{
unGID = m_nDefaultChar;
oSizes.eState = glyphstateNormal;
pFace = m_pFace;
pCurentGliph = pFace->glyph;
}
}
else
{
oSizes.eState = glyphstateDeafault;
pFace = m_pDefaultFont->m_pFace;
pCurentGliph = pFace->glyph;
}
}
else
{
oSizes.eState = glyphstateNormal;
}
oSizes.ushGID = unGID;
oSizes.nCMapIndex = nCMapIndex;
if (m_bIsNeedUpdateMatrix12)
{
if (m_pDefaultFont)
m_pDefaultFont->UpdateMatrix2();
UpdateMatrix2();
}
FT_Int32 _LOAD_MODE = m_bHintsSupport ? m_pFontManager->m_nLOAD_MODE : 40970;
if (0 != FT_Load_Glyph(pFace, unGID, _LOAD_MODE))
return FALSE;
FT_Glyph pGlyph = NULL;
if ( FT_Get_Glyph( pFace->glyph, &pGlyph ) )
return FALSE;
FT_BBox oBBox;
FT_Glyph_Get_CBox(pGlyph, 1, &oBBox);
FT_Done_Glyph(pGlyph);
pCurentGliph = pFace->glyph;
oSizes.fAdvanceX = (float)(pFace->glyph->linearHoriAdvance * m_dUnitsKoef / pFace->units_per_EM);
oSizes.oBBox.fMinX = (float)(oBBox.xMin >> 6);
oSizes.oBBox.fMaxX = (float)(oBBox.xMax >> 6);
oSizes.oBBox.fMinY = (float)(oBBox.yMin >> 6);
oSizes.oBBox.fMaxY = (float)(oBBox.yMax >> 6);
oSizes.oMetrics.fHeight = (float)(pFace->glyph->metrics.height >> 6);
oSizes.oMetrics.fHoriAdvance = (float)(pFace->glyph->metrics.horiAdvance >> 6);
oSizes.oMetrics.fHoriBearingX = (float)(pFace->glyph->metrics.horiBearingX >> 6);
oSizes.oMetrics.fHoriBearingY = (float)(pFace->glyph->metrics.horiBearingY >> 6);
oSizes.oMetrics.fVertAdvance = (float)(pFace->glyph->metrics.vertAdvance >> 6);
oSizes.oMetrics.fVertBearingX = (float)(pFace->glyph->metrics.vertBearingX >> 6);
oSizes.oMetrics.fVertBearingY = (float)(pFace->glyph->metrics.vertBearingY >> 6);
oSizes.oMetrics.fWidth = (float)(pFace->glyph->metrics.width >> 6);
oSizes.bBitmap = true;
if (FT_Render_Glyph(pCurentGliph, REND_MODE))
return FALSE;
TGlyphBitmap *pBitmap = &(pCurGlyph->oBitmap);
pBitmap->nX = pCurentGliph->bitmap_left;
pBitmap->nY = pCurentGliph->bitmap_top;
pBitmap->nWidth = pCurentGliph->bitmap.width;
pBitmap->nHeight = pCurentGliph->bitmap.rows;
pBitmap->bAA = m_bAntiAliasing;
int nRowSize = 0;
if ( m_bAntiAliasing )
{
if ( m_bNeedDoBold )
pBitmap->nWidth++;
nRowSize = pBitmap->nWidth;
}
else
{
nRowSize = (pBitmap->nWidth + 7) >> 3;
}
if (0 != (nRowSize * pBitmap->nHeight))
pBitmap->pData = (unsigned char *)malloc( nRowSize * pBitmap->nHeight );
else
pBitmap->pData = NULL;
pBitmap->bFreeData = FALSE; // Все удаляется в кэше (во время очистки или замены)
int nIndex2;
unsigned char *pDstBuffer, *pSrcBuffer;
if (NULL != pBitmap->pData)
{
//double dKoef = ( 255 + 10 ) / (double)255;
if ( !m_bNeedDoBold || !m_bAntiAliasing )
{
for ( nIndex2 = 0, pDstBuffer = pBitmap->pData, pSrcBuffer = pCurentGliph->bitmap.buffer; nIndex2 < pBitmap->nHeight; ++nIndex2, pDstBuffer += nRowSize, pSrcBuffer += pCurentGliph->bitmap.pitch )
{
memcpy( pDstBuffer, pSrcBuffer, nRowSize );
}
}
else
{
int nY, nX;
for ( nY = 0, pDstBuffer = pBitmap->pData, pSrcBuffer = pCurentGliph->bitmap.buffer; nY < pBitmap->nHeight; ++nY, pDstBuffer += nRowSize, pSrcBuffer += pCurentGliph->bitmap.pitch )
{
for ( nX = pBitmap->nWidth - 1; nX >= 0; nX-- )
{
if ( 0 != nX )
{
int nFirstByte, nSecondByte;
if ( pBitmap->nWidth - 1 == nX )
nFirstByte = 0;
else
nFirstByte = pSrcBuffer[nX];
nSecondByte = pSrcBuffer[nX - 1];
pDstBuffer[nX] = min( 255, nFirstByte + nSecondByte);
}
else
{
pDstBuffer[nX] = pSrcBuffer[nX];
}
}
}
}
}
oSizes.bBitmap = pCurGlyph->bBitmap;
oSizes.oBitmap.bAA = pBitmap->bAA;
oSizes.oBitmap.bFreeData = pBitmap->bFreeData;
oSizes.oBitmap.nX = pBitmap->nX;
oSizes.oBitmap.nY = pBitmap->nY;
oSizes.oBitmap.nWidth = pBitmap->nWidth;
oSizes.oBitmap.nHeight = pBitmap->nHeight;
oSizes.oBitmap.pData = pBitmap->pData;
AddToSizesCache( oSizes );
charSymbolObj = m_arrCacheSizesIndexs[oSizes.ushUnicode];
}
if (0xFFFF != charSymbolObj)
{
TFontCacheSizes& oSizes = m_oCacheSizes[charSymbolObj];
int nCMapIndex = oSizes.nCMapIndex;
if (glyphstateMiss == oSizes.eState)
{
return TRUE;
}
else if (glyphstateDeafault == oSizes.eState)
{
pCurGlyph->eState = glyphstateDeafault;
}
else
{
pCurGlyph->eState = glyphstateNormal;
}
// кернинга нету пока.
if (true)
{
float fX = oString.m_fX + fPenX;
float fY = oString.m_fY + fPenY;
pCurGlyph->fX = (float)(oString.m_arrCTM[4] + fX * oString.m_arrCTM[0] + fY * oString.m_arrCTM[2] - oString.m_fX);
pCurGlyph->fY = (float)(oString.m_arrCTM[5] + fX * oString.m_arrCTM[1] + fY * oString.m_arrCTM[3] - oString.m_fY);
}
pCurGlyph->oMetrics = oSizes.oMetrics;
pCurGlyph->bBitmap = oSizes.bBitmap;
pCurGlyph->oBitmap = oSizes.oBitmap;
}
fPenX += (float)(m_oCacheSizes[charSymbolObj].fAdvanceX + m_dCharSpacing);
if (m_bNeedDoBold)
{
// Когда текст делаем жирным сами, то мы увеличиваем расстояние на 1 пиксель в ширину (независимо от DPI и размера текста всегда 1 пиксель)
fPenX += m_unHorDpi/72.f;
}
oString.m_fEndX = fPenX + oString.m_fX;
oString.m_fEndY = fPenY + oString.m_fY;
if (m_bIsNeedUpdateMatrix12)
{
if (m_pDefaultFont)
m_pDefaultFont->UpdateMatrix2();
UpdateMatrix2();
}
return TRUE;
}
////////////////////////////////////////////////////////////////////////////////
static int GlyphPathMoveTo(const FT_Vector *pPoint, void *pPath)
{
TFreeTypeFontPath *pGlyphPath = (TFreeTypeFontPath *)pPath;
if ( pGlyphPath->bNeedClose )
{
pGlyphPath->pPath->Close();
pGlyphPath->bNeedClose = FALSE;
}
pGlyphPath->pPath->MoveTo( (double)pPoint->x / 64.0, (double)pPoint->y / 64.0 );
return 0;
}
static int GlyphPathLineTo(const FT_Vector *pPoint, void *pPath)
{
TFreeTypeFontPath *pGlyphPath = (TFreeTypeFontPath *)pPath;
pGlyphPath->pPath->LineTo( (double)pPoint->x / 64.0, (double)pPoint->y / 64.0 );
pGlyphPath->bNeedClose = TRUE;
return 0;
}
static int GlyphPathConicTo(const FT_Vector *pControlPoint, const FT_Vector *pEndPoint, void *pPath)
{
TFreeTypeFontPath *pGlyphPath = (TFreeTypeFontPath *)pPath;
double dX0, dY0;
if ( !pGlyphPath->pPath->GetCurPoint( &dX0, &dY0 ) )
{
return 0;
}
double dXc = (double)pControlPoint->x / 64.0;
double dYc = (double)pControlPoint->y / 64.0;
double dX3 = (double)pEndPoint->x / 64.0;
double dY3 = (double)pEndPoint->y / 64.0;
// Строим кривую Безье второго порядка, с помощью кривой Безье третего порядка. Если p0, pC, p3 -
// начальная, контрольная и конечная точки, соответственно, для кривой Безье второго порядка. Тогда
// для этой же кривой, рассматриваемой как кривая Безье третьего порядка, точки p0, p1, p2, p3 будут
// начальной, две контрольные, конечная точки. Где p1 и p2 рассчитываются по следующим формулам:
// p1 = (1/3) * (p0 + 2pС)
// p2 = (1/3) * (2pС + p3)
double dX1 = (double)(1.0 / 3.0) * (dX0 + (double)2 * dXc);
double dY1 = (double)(1.0 / 3.0) * (dY0 + (double)2 * dYc);
double dX2 = (double)(1.0 / 3.0) * ((double)2 * dXc + dX3);
double dY2 = (double)(1.0 / 3.0) * ((double)2 * dYc + dY3);
pGlyphPath->pPath->CurveTo( dX1, dY1, dX2, dY2, dX3, dY3 );
pGlyphPath->bNeedClose = TRUE;
return 0;
}
static int GlyphPathCubicTo(const FT_Vector *pFirstControlPoint, const FT_Vector *pSecondControlPoint, const FT_Vector *pEndPoint, void *pPath)
{
TFreeTypeFontPath *pGlyphPath = (TFreeTypeFontPath *)pPath;
double dX1 = (double)pFirstControlPoint->x / 64.0;
double dY1 = (double)pFirstControlPoint->y / 64.0;
double dX2 = (double)pSecondControlPoint->x / 64.0;
double dY2 = (double)pSecondControlPoint->y / 64.0;
double dX3 = (double)pEndPoint->x / 64.0;
double dY3 = (double)pEndPoint->y / 64.0;
pGlyphPath->pPath->CurveTo( dX1, dY1, dX2, dY2, dX3, dY3 );
pGlyphPath->bNeedClose = TRUE;
return 0;
}
CFontPath* CFontFile::GetGlyphPath(int nCode)
{
FT_UInt unGID = SetCMapForCharCode2( nCode );
if (unGID <= 0)
return NULL;
static FT_Outline_Funcs pOutlineFuncs =
{
&GlyphPathMoveTo,
&GlyphPathLineTo,
&GlyphPathConicTo,
&GlyphPathCubicTo,
0, 0
};
FT_GlyphSlot oSlot = m_pFace->glyph;
// TO DO: Пропустить нулевой (".notdef") символ в TrueType
if ( FT_Load_Glyph( m_pFace, unGID, FT_LOAD_NO_BITMAP ) )
return NULL;
FT_Glyph oGlyph;
if ( FT_Get_Glyph( oSlot, &oGlyph ) )
{
return NULL;
}
TFreeTypeFontPath oGlyphPath;
oGlyphPath.pPath = new CFontPath();
oGlyphPath.bNeedClose = FALSE;
FT_Outline_Decompose( &((FT_OutlineGlyph)oGlyph)->outline, &pOutlineFuncs, &oGlyphPath );
if ( oGlyphPath.bNeedClose )
{
oGlyphPath.pPath->Close();
}
FT_Done_Glyph( oGlyph );
return oGlyphPath.pPath;
}