Files
core/DesktopEditor/fontengine/FontFile.cpp
Alexander Trofimov 76ee07f61c [copyright] Update copyright header
Co-authored-by: Alexander Trofimov <alexander.trofimov@onlyoffice.com>
Co-committed-by: Alexander Trofimov <alexander.trofimov@onlyoffice.com>
2026-05-14 08:23:56 +00:00

1575 lines
41 KiB
C++

/*
* Copyright (C) Ascensio System SIA, 2009-2026
*
* This program is a free software product. You can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License (AGPL)
* version 3 as published by the Free Software Foundation, together with the
* additional terms provided in the LICENSE file.
*
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For
* details, see the GNU AGPL at: https://www.gnu.org/licenses/agpl-3.0.html
*
* You can contact Ascensio System SIA by email at info@onlyoffice.com
* or by postal mail at 20A-6 Ernesta Birznieka-Upisha Street, Riga,
* LV-1050, Latvia, European Union.
*
* The interactive user interfaces in modified versions of the Program
* are required to display Appropriate Legal Notices in accordance with
* Section 5 of the GNU AGPL version 3.
*
* No trademark rights are granted under this License.
*
* All non-code elements of the Product, including illustrations,
* icon sets, and technical writing content, are licensed under the
* Creative Commons Attribution-ShareAlike 4.0 International License:
* https://creativecommons.org/licenses/by-sa/4.0/legalcode
*
* This license applies only to such non-code elements and does not
* modify or replace the licensing terms applicable to the Program's
* source code, which remains licensed under the GNU Affero General
* Public License v3.
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
#include "FontManager.h"
#include "internal/ftobjs.h"
#include "../common/Types.h"
#include "../common/File.h"
#ifdef GetCharWidth
#undef GetCharWidth
#endif
#ifndef max
#define max(a,b) (((a) > (b)) ? (a) : (b))
#endif
#ifndef min
#define min(a,b) (((a) < (b)) ? (a) : (b))
#endif
TFontCacheSizes* CCacheGlyphs::Get(const int& code)
{
std::map<int, TFontCacheSizes>* map = (m_pFile->m_bStringGID != 0) ? &m_mapGids : &m_mapUnicodes;
std::map<int, TFontCacheSizes>::iterator iter = map->find(code);
if (iter != map->end())
return &iter->second;
return NULL;
}
void CCacheGlyphs::Add(const TFontCacheSizes& item)
{
std::map<int, TFontCacheSizes>* map = (m_pFile->m_bStringGID != 0) ? &m_mapGids : &m_mapUnicodes;
std::map<int, TFontCacheSizes>::iterator iter = map->find(item.Unicode);
if (iter == map->end())
map->insert(std::pair<int, TFontCacheSizes>(item.Unicode, item));
else
iter->second = item;
}
void CCacheGlyphs::Clear(bool bIsFree)
{
if (bIsFree)
{
for (std::map<int, TFontCacheSizes>::iterator i = m_mapGids.begin(); i != m_mapGids.end(); i++)
i->second.oBitmap.bFreeData = TRUE;
for (std::map<int, TFontCacheSizes>::iterator i = m_mapUnicodes.begin(); i != m_mapUnicodes.end(); i++)
i->second.oBitmap.bFreeData = TRUE;
}
m_mapGids.clear();
m_mapUnicodes.clear();
}
FT_Error FT_Load_Glyph_Wrapper( FT_Face face,
FT_UInt glyph_index,
FT_Int32& load_flags, INT& bHintsSupport )
{
int nErr = FT_Load_Glyph(face, glyph_index, load_flags);
/*
FT_Err_Invalid_Glyph_Index = 0x10;
FT_Err_Invalid_Character_Code = 0x11;
FT_Err_Invalid_Glyph_Format = 0x12;
FT_Err_Cannot_Render_Glyph = 0x13;
FT_Err_Invalid_Outline = 0x14;
FT_Err_Invalid_Composite = 0x15;
FT_Err_Too_Many_Hints = 0x16;
FT_Err_Invalid_Pixel_Size = 0x17;
FT_Err_Invalid_Handle = 0x20;
FT_Err_Invalid_Library_Handle = 0x21;
FT_Err_Invalid_Driver_Handle = 0x22;
FT_Err_Invalid_Face_Handle = 0x23;
FT_Err_Invalid_Size_Handle = 0x24;
FT_Err_Invalid_Slot_Handle = 0x25;
FT_Err_Invalid_CharMap_Handle = 0x26;
FT_Err_Invalid_Cache_Handle = 0x27;
FT_Err_Invalid_Stream_Handle = 0x28;
FT_Err_Code_Overflow = 0x83;
FT_Err_Invalid_Reference = 0x86;
*/
if ((bHintsSupport == TRUE) && ((nErr > 0x10 && nErr < 0x28) || (nErr >= 0x83 && nErr <= 0x8D)))
{
int nErr2 = FT_Load_Glyph(face, glyph_index, 40970);
if (0 == nErr2)
{
bHintsSupport = FALSE;
load_flags = 40970;
nErr = 0;
}
}
return nErr;
}
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;
m_oCache.m_pFile = this;
}
CFontFile::~CFontFile()
{
RELEASEINTERFACE(m_pStream);
ClearCache();
if (m_pFace)
FT_Done_Face(m_pFace);
}
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, double unHorDpi, double 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(true);
}
void CFontFile::ClearCacheNoAttack(bool bIsFree)
{
m_oCache.Clear(bIsFree);
}
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 INT& bGID)
{
if (m_bStringGID == bGID)
return;
//ClearCache();
m_bStringGID = bGID;
}
INT CFontFile::GetStringGID()
{
return m_bStringGID;
}
void CFontFile::SetUseDefaultFont(const INT& bUse)
{
m_bUseDefaultFont = bUse;
}
INT 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::GetPanose(BYTE* pData)
{
memset(pData, 0, 10);
if (!m_pFace)
return;
TT_OS2 *pTable = (TT_OS2 *)FT_Get_Sfnt_Table( m_pFace, ft_sfnt_os2 );
if ( NULL == pTable )
return;
memcpy( pData, pTable->panose, 10 );
}
bool CFontFile::IsFixedWidth()
{
if (!m_pFace)
return false;
return FT_IS_FIXED_WIDTH( m_pFace ) != 0;
}
int CFontFile::IsUnicodeRangeAvailable(unsigned long ulBit, unsigned int un4ByteIndex)
{
if (!m_pFace)
return -1;
TT_OS2 *pOs2 = (TT_OS2 *)FT_Get_Sfnt_Table( m_pFace, ft_sfnt_os2 );
if ( NULL == pOs2 || 0xFFFF == pOs2->version )
return -1;
int nResult = 0;
unsigned long ulMult = 1;
for ( unsigned long ulIndex = 0; ulIndex < ulBit; ulIndex++ )
ulMult <<= 1;
switch(un4ByteIndex)
{
case 0: if ( pOs2->ulUnicodeRange1 & ulMult ) nResult = 1; break;
case 1: if ( pOs2->ulUnicodeRange2 & ulMult ) nResult = 1; break;
case 2: if ( pOs2->ulUnicodeRange3 & ulMult ) nResult = 1; break;
case 3: if ( pOs2->ulUnicodeRange4 & ulMult ) nResult = 1; break;
case 4: if ( pOs2->ulCodePageRange1 & ulMult ) nResult = 1; break;
case 5: if ( pOs2->ulCodePageRange2 & ulMult ) nResult = 1; break;
}
// Special branch for cases when charset can be specified not through
// ulCodePageRange values, but directly through Cmap type.
// Charset Name Charset Value(hex) Codepage number Platform_ID Encoding_ID Description
// -------------------------------------------------------------------------------------------------
//
// SYMBOL_CHARSET 2 (x02) 3 0 Symbol
// SHIFTJIS_CHARSET 128 (x80) 932 3 2 ShiftJIS
// GB2313_CHARSET 134 (x86) 936 3 3 PRC
// CHINESEBIG5_CHARSET 136 (x88) 950 3 4 Big5
// HANGEUL_CHARSET 129 (x81) 949 3 5 Wansung
// JOHAB_CHARSET 130 (x82) 1361 3 6 Johab
if ( 4 == un4ByteIndex && 0 == nResult )
{
for( int nIndex = 0; nIndex < m_pFace->num_charmaps; nIndex++ )
{
// Symbol
if ( 31 == ulBit && 0 == m_pFace->charmaps[nIndex]->encoding_id && 3 == m_pFace->charmaps[nIndex]->platform_id )
{
nResult = 1;
break;
}
// ShiftJIS
if ( 17 == ulBit && 2 == m_pFace->charmaps[nIndex]->encoding_id && 3 == m_pFace->charmaps[nIndex]->platform_id )
{
nResult = 1;
break;
}
// PRC
if ( 18 == ulBit && 3 == m_pFace->charmaps[nIndex]->encoding_id && 3 == m_pFace->charmaps[nIndex]->platform_id )
{
nResult = 1;
break;
}
// Big5
if ( 20 == ulBit && 4 == m_pFace->charmaps[nIndex]->encoding_id && 3 == m_pFace->charmaps[nIndex]->platform_id )
{
nResult = 1;
break;
}
// Wansung
if ( 19 == ulBit && 5 == m_pFace->charmaps[nIndex]->encoding_id && 3 == m_pFace->charmaps[nIndex]->platform_id )
{
nResult = 1;
break;
}
// Johab
if ( 21 == ulBit && 6 == m_pFace->charmaps[nIndex]->encoding_id && 3 == m_pFace->charmaps[nIndex]->platform_id )
{
nResult = 1;
break;
}
}
}
return nResult;
}
void CFontFile::UpdateStyles(const INT& bBold, const INT& bItalic)
{
std::string sStyle = GetStyleName();
// Check the original font style
INT bSrcBold = (-1 != sStyle.find("Bold"));
INT bSrcItalic = (-1 != sStyle.find("Italic"));
if (!bBold) // We need a non-bold font
{
m_bNeedDoBold = false;
}
else if (bBold) // We need to make the font bold
{
if (bSrcBold)
{
// Original font is already bold, no additional action needed
m_bNeedDoBold = false;
}
else
{
// Original font is not bold, so we apply boldness ourselves
m_bNeedDoBold = true;
}
}
if (!bItalic) // We need a non-italic font
{
SetItalic(false);
}
else if (bItalic) // We need to make the font italic
{
if (bSrcItalic)
{
// Original font is already italic, no additional action needed
SetItalic(false);
}
else
{
// Original font is not italic, so we apply italics ourselves
SetItalic(true);
}
}
}
void CFontFile::SetItalic(const INT& value)
{
if (m_bNeedDoItalic != value)
{
ClearCache();
m_bNeedDoItalic = value;
ResetFontMatrix();
}
}
void CFontFile::SetNeedBold(const INT& 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::wstring sFamilyName = GetCorrectSfntName(m_pFace->family_name);
if (m_sName == L"MS Mincho" || m_sName == L"Castellar")
m_bHintsSupport = FALSE;
}
// glyph methods
int CFontFile::SetCMapForCharCode(long lUnicode, int *pnCMapIndex)
{
*pnCMapIndex = -1;
if (!m_pFace || !m_pFace->num_charmaps)
return 0;
if ( m_bStringGID )
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 )
{
#if 0
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;
}
}
#endif
if ( nCharIndex = FT_Get_Char_Index( m_pFace, lUnicode ) )
{
*pnCMapIndex = nIndex;
}
}
}
return nCharIndex;
}
int CFontFile::SetCMapForCharCode2(long lUnicode)
{
if (m_bStringGID)
return lUnicode;
int nCMapIndex = 0;
TFontCacheSizes* pCachedGlyph = m_oCache.Get(lUnicode);
if (NULL == pCachedGlyph)
return SetCMapForCharCode( lUnicode, &nCMapIndex );
FT_Int unGID = pCachedGlyph->GID;
nCMapIndex = pCachedGlyph->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;
}
TFontCacheSizes CFontFile::CacheGlyph(const int& code, const bool& isRaster, CVectorWorker* pWorker, const bool& isFromPicker)
{
TFontCacheSizes oSizes;
oSizes.Unicode = code;
oSizes.eState = glyphstateMiss;
int nCMapIndex = 0;
int unGID = m_bStringGID ? code : SetCMapForCharCode(code, &nCMapIndex);
if (unGID <= 0 && !m_bStringGID)
{
if (-1 != m_nSymbolic && code < 0xF000)
unGID = SetCMapForCharCode(code + 0xF000, &nCMapIndex);
}
oSizes.GID = unGID;
oSizes.nCMapIndex = nCMapIndex;
if (unGID <= 0)
{
if (isFromPicker)
return oSizes;
if (!m_bStringGID)
{
// try to select the appropriate font
CFontFile* pPickFile = m_pFontManager->GetFontFileBySymbol(this, code);
if (!pPickFile)
return oSizes;
TFontCacheSizes oSizesCheck = pPickFile->CacheGlyph(code, isRaster, pWorker, true);
// file is in cache, but needs to be deleted here
RELEASEINTERFACE(pPickFile);
if (oSizesCheck.eState == glyphstateNormal)
return oSizesCheck;
}
if (m_nDefaultChar >= 0)
{
unGID = m_nDefaultChar;
oSizes.eState = glyphstateDefault;
}
else
{
oSizes.fAdvanceX = (m_pFace->size->metrics.max_advance >> 6) / 2.0f;
oSizes.fAdvanceY = oSizes.fAdvanceX;
return oSizes;
}
}
else
{
oSizes.eState = glyphstateNormal;
}
if (m_bIsNeedUpdateMatrix12)
UpdateMatrix2();
FT_Int32 _LOAD_MODE = m_bHintsSupport ? m_pFontManager->m_nLOAD_MODE : 40970;
if (0 != FT_Load_Glyph_Wrapper(m_pFace, unGID, _LOAD_MODE, m_bHintsSupport))
return oSizes;
FT_Glyph pGlyph = NULL;
if ( FT_Get_Glyph( m_pFace->glyph, &pGlyph ) )
return oSizes;
TT_OS2* pOS2 = (TT_OS2*)FT_Get_Sfnt_Table(m_pFace, ft_sfnt_os2);
bool bIsNeedBold = (m_bNeedDoBold == TRUE) ? true : false;
if (bIsNeedBold && pOS2 && pOS2->version != 0xFFFF && pOS2->usWeightClass >= 800)
bIsNeedBold = false;
if (pWorker)
{
if (bIsNeedBold)
FT_Outline_EmboldenXY(&((FT_OutlineGlyph)pGlyph)->outline, (m_unHorDpi * 64 / 25.4) / 3, 0);
FT_Outline_Decompose( &((FT_OutlineGlyph)pGlyph)->outline, pWorker->func_interface, pWorker->user );
return oSizes;
}
FT_BBox oBBox;
FT_Glyph_Get_CBox(pGlyph, 1, &oBBox);
FT_Done_Glyph(pGlyph);
FT_GlyphSlot pGlyphSlot = m_pFace->glyph;
oSizes.fAdvanceX = (float)(pGlyphSlot->linearHoriAdvance * m_dUnitsKoef / m_pFace->units_per_EM);
if (bIsNeedBold)
oSizes.fAdvanceX += 1;
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.fWidth = (float)(pGlyphSlot->metrics.width >> 6);
oSizes.oMetrics.fHeight = (float)(pGlyphSlot->metrics.height >> 6);
oSizes.oMetrics.fHoriAdvance = (float)(pGlyphSlot->metrics.horiAdvance >> 6);
oSizes.oMetrics.fHoriBearingX = (float)(pGlyphSlot->metrics.horiBearingX >> 6);
oSizes.oMetrics.fHoriBearingY = (float)(pGlyphSlot->metrics.horiBearingY >> 6);
oSizes.oMetrics.fVertAdvance = (float)(pGlyphSlot->metrics.vertAdvance >> 6);
oSizes.oMetrics.fVertBearingX = (float)(pGlyphSlot->metrics.vertBearingX >> 6);
oSizes.oMetrics.fVertBearingY = (float)(pGlyphSlot->metrics.vertBearingY >> 6);
if (isFromPicker && (0 == oSizes.oMetrics.fHoriAdvance && 0 == oSizes.oMetrics.fWidth))
{
oSizes.eState = glyphstateMiss;
return oSizes;
}
if (!isRaster)
return oSizes;
oSizes.bBitmap = true;
if (FT_Render_Glyph(pGlyphSlot, (FT_Render_Mode)m_pFontManager->m_nRENDER_MODE))
return oSizes;
TGlyphBitmap* pBitmap = &(oSizes.oBitmap);
pBitmap->nX = pGlyphSlot->bitmap_left;
pBitmap->nY = pGlyphSlot->bitmap_top;
pBitmap->nWidth = pGlyphSlot->bitmap.width;
pBitmap->nHeight = pGlyphSlot->bitmap.rows;
pBitmap->bAA = m_bAntiAliasing;
int nRowSize = 0;
if (m_bAntiAliasing)
{
if (bIsNeedBold)
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;
// Everything is deleted in cache (during cleanup or replacement)
pBitmap->bFreeData = FALSE;
int nIndex2;
unsigned char *pDstBuffer, *pSrcBuffer;
if (NULL != pBitmap->pData)
{
if ( !bIsNeedBold || !m_bAntiAliasing )
{
for ( nIndex2 = 0, pDstBuffer = pBitmap->pData, pSrcBuffer = pGlyphSlot->bitmap.buffer; nIndex2 < pBitmap->nHeight; ++nIndex2, pDstBuffer += nRowSize, pSrcBuffer += pGlyphSlot->bitmap.pitch )
{
memcpy( pDstBuffer, pSrcBuffer, nRowSize );
}
}
else
{
int nY, nX;
for ( nY = 0, pDstBuffer = pBitmap->pData, pSrcBuffer = pGlyphSlot->bitmap.buffer; nY < pBitmap->nHeight; ++nY, pDstBuffer += nRowSize, pSrcBuffer += pGlyphSlot->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];
}
}
}
}
}
return oSizes;
}
TFontCacheSizes CFontFile::GetChar(LONG lUnicode)
{
TFontCacheSizes* pCachedGlyph = m_oCache.Get(lUnicode);
if (NULL != pCachedGlyph)
return *pCachedGlyph;
TFontCacheSizes oSizes = CacheGlyph(lUnicode, false);
m_oCache.Add(oSizes);
return oSizes;
}
double CFontFile::GetCharWidth(int gid)
{
if (!m_pFace)
return 0;
if (0 != FT_Load_Glyph(m_pFace, gid, 40970))
return 0;
FT_Glyph pGlyph = NULL;
if (0 != FT_Get_Glyph(m_pFace->glyph, &pGlyph))
return 0;
double dRet = (double)(m_pFace->glyph->linearHoriAdvance * m_dUnitsKoef / m_pFace->units_per_EM);
FT_Done_Glyph(pGlyph);
return dRet;
}
int CFontFile::GetGIDByUnicode(int code)
{
int nCMapIndex = 0;
int unGID = m_bStringGID ? code : SetCMapForCharCode(code, &nCMapIndex);
if (unGID <= 0 && !m_bStringGID)
{
if (-1 != m_nSymbolic && code < 0xF000)
unGID = SetCMapForCharCode(code, &nCMapIndex);
}
return unGID;
}
int CFontFile::GetUnicodeByGID(int gid)
{
if (!m_pFace)
return 0;
FT_ULong charcode;
FT_UInt gindex;
charcode = FT_Get_First_Char(m_pFace, &gindex);
while (gindex != 0)
{
if (gindex == gid)
{
return charcode;
}
charcode = FT_Get_Next_Char(m_pFace, charcode, &gindex);
}
return 0;
}
INT CFontFile::GetString(CGlyphString& oString)
{
int nCountGlyph = oString.GetLength();
if (nCountGlyph <= 0)
return TRUE;
unsigned int unPrevGID = 0;
float fPenX = 0, fPenY = 0;
for (int nIndex = 0; nIndex < nCountGlyph; ++nIndex)
{
TGlyph* pCurGlyph = oString.GetAt(nIndex);
int unGID = 0;
int ushUnicode = pCurGlyph->lUnicode;
if (ushUnicode < 0) ushUnicode = 0;
TFontCacheSizes* pCacheGlyph = m_oCache.Get(ushUnicode);
if (!pCacheGlyph)
{
m_oCache.Add(CacheGlyph(ushUnicode, false));
pCacheGlyph = m_oCache.Get(ushUnicode);
}
if (true)
{
unGID = pCacheGlyph->GID;
if (glyphstateMiss == pCacheGlyph->eState)
{
oString.SetStartPoint (nIndex, fPenX, fPenY);
oString.SetBBox(nIndex, 0, 0, 0, 0);
oString.SetState (nIndex, glyphstateMiss);
double dAdvanceW = m_arrdFontMatrix[0] * pCacheGlyph->fAdvanceX;
fPenX += (float)(dAdvanceW + m_dCharSpacing);
unPrevGID = 0;
continue;
}
else if (glyphstateDefault == pCacheGlyph->eState)
{
oString.SetState(nIndex, glyphstateDefault);
}
else
{
oString.SetState(nIndex, glyphstateNormal);
}
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 = pCacheGlyph->oMetrics;
oString.SetBBox(nIndex, pCacheGlyph->oBBox.fMinX, pCacheGlyph->oBBox.fMaxY, pCacheGlyph->oBBox.fMaxX, pCacheGlyph->oBBox.fMinY);
double dAdvanceW = m_arrdFontMatrix[0] * pCacheGlyph->fAdvanceX;
fPenX += (float)(dAdvanceW + m_dCharSpacing);
pCurGlyph->bBitmap = pCacheGlyph->bBitmap;
pCurGlyph->oBitmap = pCacheGlyph->oBitmap;
}
unPrevGID = unGID;
}
oString.m_fEndX = fPenX + oString.m_fX;
oString.m_fEndY = fPenY + oString.m_fY;
return TRUE;
}
INT 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)
{
TGlyph* pCurGlyph = oString.GetAt(nIndex);
int nUnicode = pCurGlyph->lUnicode;
TFontCacheSizes* pCacheGlyph = m_oCache.Get(nUnicode);
if (!pCacheGlyph || !pCacheGlyph->bBitmap)
{
m_oCache.Add(CacheGlyph(nUnicode, true));
pCacheGlyph = m_oCache.Get(nUnicode);
}
if (nUnicode < 0) nUnicode = 0;
int unGID = 0;
if (true)
{
unGID = pCacheGlyph->GID;
if (glyphstateMiss == pCacheGlyph->eState)
{
oString.SetStartPoint (nIndex, fPenX, fPenY);
oString.SetBBox(nIndex, 0, 0, 0, 0);
oString.SetState (nIndex, glyphstateMiss);
double dAdvanceW = m_arrdFontMatrix[0] * pCacheGlyph->fAdvanceX;
fPenX += (float)(dAdvanceW + m_dCharSpacing);
unPrevGID = 0;
continue;
}
else if (glyphstateDefault == pCacheGlyph->eState)
{
oString.SetState(nIndex, glyphstateDefault);
}
else
{
oString.SetState(nIndex, glyphstateNormal);
}
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 = pCacheGlyph->oMetrics;
oString.SetBBox(nIndex, pCacheGlyph->oBBox.fMinX, pCacheGlyph->oBBox.fMaxY, pCacheGlyph->oBBox.fMaxX, pCacheGlyph->oBBox.fMinY);
double dAdvanceW = m_arrdFontMatrix[0] * pCacheGlyph->fAdvanceX;
fPenX += (float)(dAdvanceW + m_dCharSpacing);
pCurGlyph->bBitmap = pCacheGlyph->bBitmap;
pCurGlyph->oBitmap = pCacheGlyph->oBitmap;
}
unPrevGID = unGID;
}
oString.m_fEndX = fPenX + oString.m_fX;
oString.m_fEndY = fPenY + oString.m_fY;
return TRUE;
}
INT CFontFile::GetString2C(CGlyphString& oString)
{
unsigned int unPrevGID = 0;
float fPenX = 0, fPenY = 0;
TGlyph* pCurGlyph = oString.GetAt(0);
int nUnicode = pCurGlyph->lUnicode;
if (nUnicode < 0) nUnicode = 0;
TFontCacheSizes* pCacheGlyph = m_oCache.Get(nUnicode);
if (!pCacheGlyph || !pCacheGlyph->bBitmap)
{
m_oCache.Add(CacheGlyph(nUnicode, true));
pCacheGlyph = m_oCache.Get(nUnicode);
}
if (true)
{
if (glyphstateMiss == pCacheGlyph->eState)
{
return TRUE;
}
else if (glyphstateDefault == pCacheGlyph->eState)
{
pCurGlyph->eState = glyphstateDefault;
}
else
{
pCurGlyph->eState = glyphstateNormal;
}
pCurGlyph->oMetrics = pCacheGlyph->oMetrics;
pCurGlyph->bBitmap = pCacheGlyph->bBitmap;
pCurGlyph->oBitmap = pCacheGlyph->oBitmap;
}
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);
}
double dAdvanceW = m_arrdFontMatrix[0] * pCacheGlyph->fAdvanceX;
fPenX += (float)(dAdvanceW + m_dCharSpacing);
oString.m_fEndX = fPenX + oString.m_fX;
oString.m_fEndY = fPenY + oString.m_fY;
return TRUE;
}
std::wstring CFontFile::GetFontFormat()
{
if (!m_pFace)
return L"";
const char* sFormat = FT_Get_X11_Font_Format(m_pFace);
return NSFile::CUtf8Converter::GetUnicodeFromCharPtr(sFormat, strlen(sFormat));
}
NSFonts::EFontFormat CFontFile::GetFontFormatType(FT_Face pFace)
{
if (!pFace)
return NSFonts::fontUnknown;
std::string wsFormat( FT_Get_X11_Font_Format( pFace ) );
if ( "Windows FNT" == wsFormat )
return NSFonts::fontWindowsFNT;
else if ( "TrueType" == wsFormat )
return NSFonts::fontTrueType;
else if ( "CFF" == wsFormat )
return NSFonts::fontOpenType;
return NSFonts::fontUnknown;
}
unsigned int CFontFile::GetNameIndex(const std::wstring& wsName) const
{
if (!m_pFace)
return 0;
int nLen = wsName.length();
char* sName = new char[nLen + 1];
if (!sName)
return 0;
sName[nLen] = 0x00;
for (int nIndex = 0; nIndex < nLen; nIndex++)
{
sName[nIndex] = (char)(wsName[nIndex]);
}
unsigned int unGID = FT_Get_Name_Index(m_pFace, sName);
delete[] sName;
return unGID;
}
////////////////////////////////////////////////////////////////////////////////
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;
// Build a quadratic Bezier curve using a cubic Bezier curve. If p0, pC, p3 are
// the start, control, and end points respectively for a quadratic Bezier curve, then
// for the same curve treated as a cubic Bezier curve, points p0, p1, p2, p3 will be
// the start, two control, and end points. Where p1 and p2 are calculated as follows:
// p1 = (1/3) * (p0 + 2pC)
// p2 = (1/3) * (2pC + 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;
}
NSFonts::IFontPath* CFontFile::GetGlyphPath(int nCode)
{
static FT_Outline_Funcs pOutlineFuncs =
{
&GlyphPathMoveTo,
&GlyphPathLineTo,
&GlyphPathConicTo,
&GlyphPathCubicTo,
0, 0
};
TFreeTypeFontPath oGlyphPath;
oGlyphPath.pPath = new CFontPath();
oGlyphPath.bNeedClose = FALSE;
CVectorWorker oWorker;
oWorker.func_interface = &pOutlineFuncs;
oWorker.user = &oGlyphPath;
CacheGlyph(nCode, false, &oWorker);
return oGlyphPath.pPath;
}
bool CFontFile::IsItalic()
{
if (!m_pFace)
return false;
return ((m_pFace->style_flags & FT_STYLE_FLAG_ITALIC) != 0) ? true : false;
}
bool CFontFile::IsBold()
{
if (!m_pFace)
return false;
TT_OS2* pOS2 = (TT_OS2*)FT_Get_Sfnt_Table(m_pFace, ft_sfnt_os2);
if (pOS2 && pOS2->version != 0xFFFF && pOS2->usWeightClass >= 800)
return true;
return ((m_pFace->style_flags & FT_STYLE_FLAG_BOLD) != 0) ? true : false;
}
bool CFontFile::IsSymbolic(bool bIsOS2Check)
{
if (!m_pFace)
return false;
bool bIsSymbol = (-1 != m_nSymbolic) ? true : false;
if (!bIsSymbol && bIsOS2Check)
{
TT_OS2* pOS2 = (TT_OS2*)FT_Get_Sfnt_Table(m_pFace, ft_sfnt_os2);
if (NULL != pOS2)
{
if (0 == (pOS2->ulCodePageRange1 & 0xF0000000))
bIsSymbol = true;
}
}
return bIsSymbol;
}
int CFontFile::GetEmbeddingLicenceType()
{
if (!m_pFace)
return 0;
int nType = 0;
TT_OS2* pOS2 = (TT_OS2*)FT_Get_Sfnt_Table(m_pFace, ft_sfnt_os2);
if (NULL != pOS2)
return (int)pOS2->fsType;
return 0;
}
void CFontFile::FillFontSelectFormat(NSFonts::CFontSelectFormat& oFormat)
{
if (!m_pFace)
return;
if (NULL == oFormat.wsName)
oFormat.wsName = new std::wstring(m_sName);
if (NULL == oFormat.wsFamilyClass)
oFormat.wsFamilyClass = new std::wstring(GetCorrectSfntName(m_pFace->style_name));
if (NULL == oFormat.bItalic)
oFormat.bItalic = new INT(IsItalic() ? 1 : 0);
if (NULL == oFormat.bBold)
oFormat.bBold = new INT(IsBold() ? 1 : 0);
if (NULL == oFormat.bFixedWidth)
oFormat.bFixedWidth = new INT(IsFixedWidth() ? 1 : 0);
TT_OS2* pOS2 = (TT_OS2*)FT_Get_Sfnt_Table(m_pFace, ft_sfnt_os2);
if (NULL != pOS2)
{
if (NULL == oFormat.pPanose)
{
oFormat.pPanose = new BYTE[10];
memcpy((void*)oFormat.pPanose, pOS2->panose, 10);
}
if (NULL == oFormat.ulRange1)
oFormat.ulRange1 = new UINT(pOS2->ulUnicodeRange1);
if (NULL == oFormat.ulRange2)
oFormat.ulRange2 = new UINT(pOS2->ulUnicodeRange2);
if (NULL == oFormat.ulRange3)
oFormat.ulRange3 = new UINT(pOS2->ulUnicodeRange3);
if (NULL == oFormat.ulRange4)
oFormat.ulRange4 = new UINT(pOS2->ulUnicodeRange4);
if (NULL == oFormat.ulCodeRange1)
oFormat.ulCodeRange1 = new UINT(pOS2->ulCodePageRange1);
if (NULL == oFormat.ulCodeRange2)
oFormat.ulCodeRange2 = new UINT(pOS2->ulCodePageRange2);
if (NULL == oFormat.usWeight)
oFormat.usWeight = new USHORT(pOS2->usWeightClass);
if (NULL == oFormat.usWidth)
oFormat.usWidth = new USHORT(pOS2->usWidthClass);
if (0 != m_pFace->units_per_EM)
{
double dKoef = ( 1000 / (double)m_pFace->units_per_EM );
if (NULL == oFormat.shAvgCharWidth)
oFormat.shAvgCharWidth = new SHORT((SHORT)pOS2->xAvgCharWidth * dKoef);
if (NULL == oFormat.shAscent)
oFormat.shAscent = new SHORT((SHORT)pOS2->sTypoAscender * dKoef);
if (NULL == oFormat.shDescent)
oFormat.shDescent = new SHORT((SHORT)pOS2->sTypoDescender * dKoef);
if (NULL == oFormat.shLineGap)
oFormat.shLineGap = new SHORT((SHORT)pOS2->sTypoLineGap * dKoef);
if (NULL == oFormat.shXHeight)
oFormat.shXHeight = new SHORT((SHORT)pOS2->sxHeight * dKoef);
if (NULL == oFormat.shCapHeight)
oFormat.shCapHeight = new SHORT((SHORT)pOS2->sCapHeight * dKoef);
}
else
{
if (NULL == oFormat.shAvgCharWidth)
oFormat.shAvgCharWidth = new SHORT(pOS2->xAvgCharWidth);
if (NULL == oFormat.shAscent)
oFormat.shAscent = new SHORT(pOS2->sTypoAscender);
if (NULL == oFormat.shDescent)
oFormat.shDescent = new SHORT(pOS2->sTypoDescender);
if (NULL == oFormat.shLineGap)
oFormat.shLineGap = new SHORT(pOS2->sTypoLineGap);
if (NULL == oFormat.shXHeight)
oFormat.shXHeight = new SHORT(pOS2->sxHeight);
if (NULL == oFormat.shCapHeight)
oFormat.shCapHeight = new SHORT(pOS2->sCapHeight);
}
if (NULL == oFormat.nFontFormat)
oFormat.nFontFormat = new int((int)GetFontFormatType(m_pFace));
if (NULL == oFormat.usType)
oFormat.usType = new USHORT(pOS2->fsType);
}
}