Commit e5665754 authored by Elen.Subbotina's avatar Elen.Subbotina Committed by Alexander Trofimov

.....

git-svn-id: svn://fileserver/activex/AVS/Sources/TeamlabOffice/trunk/ServerComponents@61947 954022d7-b5bf-4e40-9824-e11837661b57
parent 46ea5f7e
#include "ApplicationFonts.h"
#include "../common/File.h"
#include "../common/Directory.h"
#include FT_SFNT_NAMES_H
#include "fontdictionaryworker.h"
#ifndef min
#define min(a,b) (((a) < (b)) ? (a) : (b))
#endif
///////////////////////////////////////////////////////////////////////////////////
CFontSelectFormat::CFontSelectFormat()
{
wsName = NULL;
wsAltName = NULL;
wsFamilyClass = NULL;
sFamilyClass = NULL;
bBold = NULL;
bItalic = NULL;
bFixedWidth = NULL;
pPanose = NULL;
ulRange1 = NULL;
ulRange2 = NULL;
ulRange3 = NULL;
ulRange4 = NULL;
ulCodeRange1 = NULL;
ulCodeRange2 = NULL;
usWeight = NULL;
usWidth = NULL;
nFontFormat = NULL;
unCharset = NULL;
shAvgCharWidth = NULL;
shAscent = NULL;
shDescent = NULL;
shLineGap = NULL;
shXHeight = NULL;
shCapHeight = NULL;
}
CFontSelectFormat::~CFontSelectFormat()
{
Destroy();
}
void CFontSelectFormat::CreateDuplicate(CFontSelectFormat& oFormat)
{
oFormat.Destroy();
if (NULL != wsName)
oFormat.wsName = new std::wstring(*wsName);
if (NULL != wsAltName)
oFormat.wsAltName = new std::wstring(*wsAltName);
if (NULL != wsFamilyClass)
oFormat.wsFamilyClass = new std::wstring(*wsFamilyClass);
if (NULL != sFamilyClass)
oFormat.sFamilyClass = new SHORT(*sFamilyClass);
if (NULL != bBold)
oFormat.bBold = new INT(*bBold);
if (NULL != bItalic)
oFormat.bItalic = new INT(*bItalic);
if (NULL != bFixedWidth)
oFormat.bFixedWidth = new INT(*bFixedWidth);
if (NULL != pPanose)
{
oFormat.pPanose = new BYTE[10];
memcpy( (void*)oFormat.pPanose , (const void *)pPanose, 10 );
}
if (NULL != ulRange1)
oFormat.ulRange1 = new ULONG(*ulRange1);
if (NULL != ulRange2)
oFormat.ulRange2 = new ULONG(*ulRange2);
if (NULL != ulRange3)
oFormat.ulRange3 = new ULONG(*ulRange3);
if (NULL != ulRange4)
oFormat.ulRange4 = new ULONG(*ulRange4);
if (NULL != ulCodeRange1)
oFormat.ulCodeRange1 = new ULONG(*ulCodeRange1);
if (NULL != ulCodeRange2)
oFormat.ulCodeRange2 = new ULONG(*ulCodeRange2);
if (NULL != usWeight)
oFormat.usWeight = new USHORT(*usWeight);
if (NULL != usWidth)
oFormat.usWidth = new USHORT(*usWidth);
if (NULL != nFontFormat)
oFormat.nFontFormat = new int(*nFontFormat);
if (NULL != unCharset)
oFormat.unCharset = new BYTE(*unCharset);
if (NULL != shAvgCharWidth)
oFormat.shAvgCharWidth = new SHORT(*shAvgCharWidth);
if (NULL != shAscent)
oFormat.shAscent = new SHORT(*shAscent);
if (NULL != shDescent)
oFormat.shDescent = new SHORT(*shDescent);
if (NULL != shLineGap)
oFormat.shLineGap = new SHORT(*shLineGap);
if (NULL != shXHeight)
oFormat.shXHeight = new SHORT(*shXHeight);
if (NULL != shCapHeight)
oFormat.shCapHeight = new SHORT(*shCapHeight);
}
void CFontSelectFormat::Destroy()
{
RELEASEOBJECT(wsName);
RELEASEOBJECT(wsAltName);
RELEASEOBJECT(wsFamilyClass);
RELEASEOBJECT(sFamilyClass);
RELEASEOBJECT(bBold);
RELEASEOBJECT(bItalic);
RELEASEOBJECT(bFixedWidth);
RELEASEARRAYOBJECTS(pPanose);
RELEASEOBJECT(ulRange1);
RELEASEOBJECT(ulRange2);
RELEASEOBJECT(ulRange3);
RELEASEOBJECT(ulRange4);
RELEASEOBJECT(ulCodeRange1);
RELEASEOBJECT(ulCodeRange2);
RELEASEOBJECT(usWeight);
RELEASEOBJECT(usWidth);
RELEASEOBJECT(nFontFormat);
RELEASEOBJECT(unCharset);
RELEASEOBJECT(shAvgCharWidth);
RELEASEOBJECT(shAscent);
RELEASEOBJECT(shDescent);
RELEASEOBJECT(shLineGap);
RELEASEOBJECT(shXHeight);
RELEASEOBJECT(shCapHeight);
}
///////////////////////////////////////////////////////////////////////////////////
CFontInfo::CFontInfo(const std::wstring& wsFontName,
const std::wstring& wsStyle,
const std::wstring& wsFontPath,
long lIndex,
INT bBold,
INT bItalic,
INT bFixedWidth,
BYTE* pPanose,
ULONG ulRange1,
ULONG ulRange2,
ULONG ulRange3,
ULONG ulRange4,
ULONG ulCodeRange1,
ULONG ulCodeRange2,
USHORT usWeigth,
USHORT usWidth,
SHORT sFamilyClass,
EFontFormat eFormat,
SHORT shAvgCharWidth,
SHORT shAscent,
SHORT shDescent,
SHORT shLineGap,
SHORT shXHeight,
SHORT shCapHeight)
{
m_wsFontName = wsFontName;
m_wsFontPath = wsFontPath;
m_wsStyle = wsStyle;
m_lIndex = lIndex;
m_bBold = bBold;
m_bItalic = bItalic;
m_bIsFixed = bFixedWidth;
if ( pPanose )
memcpy( (void*)m_aPanose, (const void *)pPanose, 10 );
else
memset( (void*)m_aPanose, 0x00, 10 );
m_ulUnicodeRange1 = ulRange1;
m_ulUnicodeRange2 = ulRange2;
m_ulUnicodeRange3 = ulRange3;
m_ulUnicodeRange4 = ulRange4;
m_ulCodePageRange1 = ulCodeRange1;
m_ulCodePageRange2 = ulCodeRange2;
m_usWeigth = usWeigth;
m_usWidth = usWidth;
m_sFamilyClass = sFamilyClass;
m_eFontFormat = eFormat;
m_shAvgCharWidth = shAvgCharWidth;
m_shAscent = shAscent;
m_shDescent = shDescent;
m_shLineGap = shLineGap;
m_shXHeight = shXHeight;
m_shCapHeight = shCapHeight;
}
CFontInfo::~CFontInfo()
{
}
INT CFontInfo::Equals(const CFontInfo *pFontInfo)
{
return (m_wsFontName == pFontInfo->m_wsFontName &&
m_wsStyle == pFontInfo->m_wsStyle &&
m_wsFontPath == pFontInfo->m_wsFontPath &&
m_bItalic == pFontInfo->m_bItalic &&
m_bBold == pFontInfo->m_bBold);
}
CFontInfo* CFontInfo::FromBuffer(BYTE*& pBuffer, std::wstring strDir)
{
// name
int lLen = *((int*)pBuffer);
pBuffer += sizeof(int);
int len2 = lLen >> 1;
wchar_t* sName = new wchar_t[len2 + 1];
for (int i = 0; i < len2; ++i)
{
sName[i] = (wchar_t)(pBuffer[2 * i] | (pBuffer[2 * i + 1] << 8));
if (sName[i] == wchar_t('\\'))
sName[i] = wchar_t('/');
if (0 == sName[i])
{
len2 = i;
break;
}
}
sName[len2] = 0;
std::wstring strName(sName, len2);
pBuffer += lLen;
RELEASEARRAYOBJECTS(sName);
// path
lLen = *((int*)pBuffer);
pBuffer += sizeof(int);
len2 = lLen >> 1;
sName = new wchar_t[len2 + 1];
for (int i = 0; i < len2; ++i)
{
sName[i] = (wchar_t)(pBuffer[2 * i] | (pBuffer[2 * i + 1] << 8));
if (sName[i] == wchar_t('\\'))
sName[i] = wchar_t('/');
if (0 == sName[i])
{
len2 = i;
break;
}
}
sName[len2] = 0;
std::wstring strPath(sName, len2);
pBuffer += lLen;
RELEASEARRAYOBJECTS(sName);
// index
LONG lIndex = *((int*)pBuffer);
pBuffer += sizeof(int);
// italic
INT bItalic = *((INT*)pBuffer);
pBuffer += sizeof(INT);
// bold
INT bBold = *((INT*)pBuffer);
pBuffer += sizeof(INT);
// FixedWidth
INT bFixedWidth = *((INT*)pBuffer);
pBuffer += sizeof(INT);
// Panose
lLen = *((int*)pBuffer); // должно быть равно 10
pBuffer += sizeof(int);
BYTE pPanose[10];
memcpy( (void *)pPanose, (const void *)pBuffer, 10 );
pBuffer += lLen;
// ulUnicodeRange1
UINT ulRange1 = *((UINT*)pBuffer);
pBuffer += sizeof(UINT);
// ulUnicodeRange2
UINT ulRange2 = *((UINT*)pBuffer);
pBuffer += sizeof(UINT);
// ulUnicodeRange3
UINT ulRange3 = *((UINT*)pBuffer);
pBuffer += sizeof(UINT);
// ulUnicodeRange4
UINT ulRange4 = *((UINT*)pBuffer);
pBuffer += sizeof(UINT);
// ulCodePageRange1
UINT ulCodeRange1 = *((UINT*)pBuffer);
pBuffer += sizeof(UINT);
// ulCodePageRange2
ULONG ulCodeRange2 = *((UINT*)pBuffer);
pBuffer += sizeof(UINT);
// usWeightClass
USHORT usWeight = *((USHORT*)pBuffer);
pBuffer += sizeof(USHORT);
// usWidthClass
USHORT usWidth = *((USHORT*)pBuffer);
pBuffer += sizeof(USHORT);
// sFamilyClass
SHORT sFamilyClass = *((SHORT*)pBuffer);
pBuffer += sizeof(SHORT);
// FontFormat
SHORT sFormat = *((SHORT*)pBuffer);
pBuffer += sizeof(SHORT);
// AvgCharWidth
SHORT shAvgCharWidth = *((SHORT*)pBuffer);
pBuffer += sizeof(SHORT);
// Ascent
SHORT shAscent = *((SHORT*)pBuffer);
pBuffer += sizeof(SHORT);
// Descent
SHORT shDescent = *((SHORT*)pBuffer);
pBuffer += sizeof(SHORT);
// LineGap
SHORT shLineGap = *((SHORT*)pBuffer);
pBuffer += sizeof(SHORT);
// XHeight
SHORT shXHeight = *((SHORT*)pBuffer);
pBuffer += sizeof(SHORT);
// CapHeight
SHORT shCapHeight = *((SHORT*)pBuffer);
pBuffer += sizeof(SHORT);
if (strPath.find(wchar_t('/')) == std::wstring::npos && strPath.find(wchar_t('\\')) == std::wstring::npos)
strPath = strDir + strPath;
CFontInfo* pInfo = new CFontInfo(strName,
L"",
strPath,
lIndex,
bBold,
bItalic,
bFixedWidth,
(BYTE*)pPanose,
ulRange1,
ulRange2,
ulRange3,
ulRange4,
ulCodeRange1,
ulCodeRange2,
usWeight,
usWidth,
sFamilyClass,
(EFontFormat)sFormat,
shAvgCharWidth,
shAscent,
shDescent,
shLineGap,
shXHeight,
shCapHeight );
return pInfo;
}
LONG CFontInfo::GetBufferLen(std::wstring strDirectory, bool bIsOnlyFileName)
{
std::wstring sPath = m_wsFontPath;
if (0 != strDirectory.length())
{
if (0 == sPath.find(strDirectory))
{
sPath = sPath.substr(strDirectory.length());
}
}
else if (bIsOnlyFileName)
{
size_t pos1 = sPath.find_last_of(wchar_t('/'));
size_t pos2 = sPath.find_last_of(wchar_t('\\'));
size_t pos = std::wstring::npos;
if (pos1 != std::wstring::npos)
pos = pos1;
if (pos2 != std::wstring::npos)
{
if (pos == std::wstring::npos)
pos = pos2;
else if (pos2 > pos)
pos = pos2;
}
if (pos != std::wstring::npos)
{
sPath = sPath.substr(pos + 1);
}
}
//return 4 * g_lSizeofLONG + 3 * g_lSizeofBOOL + (m_wsFontName.GetLength() + sPath.GetLength() + 2) * g_lSizeofWCHAR + 2 * g_lSizeofUSHORT + 6 * g_lSizeofULONG + 10 + 8 * g_lSizeofSHORT;
if (2 == sizeof(wchar_t))
{
return 4 * 4 + 3 * 4 + (m_wsFontName.length() + sPath.length() + 2) * 2 + 2 * 2 + 6 * 4 + 10 + 8 * 2;
}
NSFile::CStringUtf16 s1;
NSFile::CUtf8Converter::GetUtf16StringFromUnicode_4bytes2(m_wsFontName.c_str(), m_wsFontName.length(), s1);
NSFile::CStringUtf16 s2;
NSFile::CUtf8Converter::GetUtf16StringFromUnicode_4bytes2(sPath.c_str(), sPath.length(), s2);
return 4 * 4 + 3 * 4 + (s1.Length + s2.Length + 2) * 2 + 2 * 2 + 6 * 4 + 10 + 8 * 2;
}
void CFontInfo::ToBuffer(BYTE*& pBuffer, std::wstring strDirectory, bool bIsOnlyFileName)
{
// name
int lLen = 0;
if (2 == sizeof(wchar_t))
{
lLen = (m_wsFontName.length() + 1) * 2;
*((int*)(pBuffer)) = lLen;
pBuffer += 4;
memcpy(pBuffer, m_wsFontName.c_str(), lLen);
pBuffer += lLen;
// path
std::wstring sPath = m_wsFontPath;
if (0 != strDirectory.length())
{
if (0 == sPath.find(strDirectory))
{
sPath = sPath.substr(strDirectory.length());
}
}
else if (bIsOnlyFileName)
{
size_t pos1 = sPath.find_last_of(wchar_t('/'));
size_t pos2 = sPath.find_last_of(wchar_t('\\'));
size_t pos = std::wstring::npos;
if (pos1 != std::wstring::npos)
pos = pos1;
if (pos2 != std::wstring::npos)
{
if (pos == std::wstring::npos)
pos = pos2;
else if (pos2 > pos)
pos = pos2;
}
if (pos != std::wstring::npos)
{
sPath = sPath.substr(pos + 1);
}
}
lLen = (sPath.length() + 1) * 2;
*((INT*)(pBuffer)) = lLen;
pBuffer += sizeof(INT);
memcpy(pBuffer, sPath.c_str(), lLen);
pBuffer += lLen;
}
else
{
NSFile::CStringUtf16 s1;
NSFile::CUtf8Converter::GetUtf16StringFromUnicode_4bytes2(m_wsFontName.c_str(), m_wsFontName.length(), s1);
lLen = s1.Length + 2;
*((int*)(pBuffer)) = lLen;
pBuffer += 4;
memcpy(pBuffer, s1.Data, lLen);
pBuffer += lLen;
// path
std::wstring sPath = m_wsFontPath;
if (0 != strDirectory.length())
{
if (0 == sPath.find(strDirectory))
{
sPath = sPath.substr(strDirectory.length());
}
}
else if (bIsOnlyFileName)
{
size_t pos1 = sPath.find_last_of(wchar_t('/'));
size_t pos2 = sPath.find_last_of(wchar_t('\\'));
size_t pos = std::wstring::npos;
if (pos1 != std::wstring::npos)
pos = pos1;
if (pos2 != std::wstring::npos)
{
if (pos == std::wstring::npos)
pos = pos2;
else if (pos2 > pos)
pos = pos2;
}
if (pos != std::wstring::npos)
{
sPath = sPath.substr(pos + 1);
}
}
NSFile::CStringUtf16 s2;
NSFile::CUtf8Converter::GetUtf16StringFromUnicode_4bytes2(sPath.c_str(), sPath.length(), s2);
lLen = s2.Length + 2;
*((INT*)(pBuffer)) = lLen;
pBuffer += sizeof(INT);
memcpy(pBuffer, s2.Data, lLen);
pBuffer += lLen;
}
// index
*((INT*)(pBuffer)) = (INT)m_lIndex;
pBuffer += sizeof(INT);
// italic
*((INT*)(pBuffer)) = m_bItalic;
pBuffer += sizeof(INT);
// bold
*((INT*)(pBuffer)) = m_bBold;
pBuffer += sizeof(INT);
// FixedWidth
*((INT*)pBuffer) = m_bIsFixed;
pBuffer += sizeof(INT);
// Panose
lLen = 10;
*((INT*)(pBuffer)) = lLen;
pBuffer += sizeof(INT);
memcpy( (void *)pBuffer, (const void *)m_aPanose, lLen );
pBuffer += lLen;
// ulUnicodeRange1
*((UINT*)pBuffer) = (UINT)m_ulUnicodeRange1;
pBuffer += sizeof(UINT);
// ulUnicodeRange2
*((UINT*)pBuffer) = (UINT)m_ulUnicodeRange2;
pBuffer += sizeof(UINT);
// ulUnicodeRange3
*((UINT*)pBuffer) = (UINT)m_ulUnicodeRange3;
pBuffer += sizeof(UINT);
// ulUnicodeRange4
*((UINT*)pBuffer) = (UINT)m_ulUnicodeRange4;
pBuffer += sizeof(UINT);
// ulCodePageRange1
*((UINT*)pBuffer) = (UINT)m_ulCodePageRange1;
pBuffer += sizeof(UINT);
// ulCodePageRange2
*((UINT*)pBuffer) = (UINT)m_ulCodePageRange2;
pBuffer += sizeof(UINT);
// usWeightClass
*((USHORT*)pBuffer) = m_usWeigth;
pBuffer += sizeof(USHORT);
// usWidthClass
*((USHORT*)pBuffer) = m_usWidth;
pBuffer += sizeof(USHORT);
// sFamilyClass
*((SHORT*)pBuffer) = m_sFamilyClass;
pBuffer += sizeof(SHORT);
// FontFormat
*((SHORT*)pBuffer) = (SHORT)m_eFontFormat;
pBuffer += sizeof(SHORT);
// AvgCharWidth
*((SHORT*)pBuffer) = (SHORT)m_shAvgCharWidth;
pBuffer += sizeof(SHORT);
// Ascent
*((SHORT*)pBuffer) = (SHORT)m_shAscent;
pBuffer += sizeof(SHORT);
// Descent
*((SHORT*)pBuffer) = (SHORT)m_shDescent;
pBuffer += sizeof(SHORT);
// LineGap
*((SHORT*)pBuffer) = (SHORT)m_shLineGap;
pBuffer += sizeof(SHORT);
// XHeight
*((SHORT*)pBuffer) = (SHORT)m_shXHeight;
pBuffer += sizeof(SHORT);
// CapHeight
*((SHORT*)pBuffer) = (SHORT)m_shCapHeight;
pBuffer += sizeof(SHORT);
}
///////////////////////////////////////////////////////////////////////////////////
namespace NSCharsets
{
static void GetCodePageByCharset(unsigned char unCharset, unsigned long *pulBit, unsigned int *punLongIndex)
{
// Данная функция возвращает параметры, которые нужно посылать на вход
// функции AVSFontManager::IsUnicodeRangeAvailable
// Соответствие Charset -> Codepage: http://support.microsoft.com/kb/165478
// http://msdn.microsoft.com/en-us/library/cc194829.aspx
// Charset Name Charset Value(hex) Codepage number
// ------------------------------------------------------
//
// DEFAULT_CHARSET 1 (x01)
// SYMBOL_CHARSET 2 (x02)
// OEM_CHARSET 255 (xFF)
// ANSI_CHARSET 0 (x00) 1252
// RUSSIAN_CHARSET 204 (xCC) 1251
// EASTEUROPE_CHARSET 238 (xEE) 1250
// GREEK_CHARSET 161 (xA1) 1253
// TURKISH_CHARSET 162 (xA2) 1254
// BALTIC_CHARSET 186 (xBA) 1257
// HEBREW_CHARSET 177 (xB1) 1255
// ARABIC _CHARSET 178 (xB2) 1256
// SHIFTJIS_CHARSET 128 (x80) 932
// HANGEUL_CHARSET 129 (x81) 949
// GB2313_CHARSET 134 (x86) 936
// CHINESEBIG5_CHARSET 136 (x88) 950
// THAI_CHARSET 222 (xDE) 874
// JOHAB_CHARSET 130 (x82) 1361
// VIETNAMESE_CHARSET 163 (xA3) 1258
// MAC_CHARSET 77 (x4D)
// Соответсвие CodePage -> ulCodePageRange1 : http://www.microsoft.com/Typography/otspec/os2.htm#cpr
if ( punLongIndex )
*punLongIndex = 4;
if ( unCharset == 1 )
unCharset = GetDefaultCharset();
if ( pulBit )
{
switch( unCharset )
{
case 0x00: *pulBit = 0; break;
case 0xEE: *pulBit = 1; break;
case 0xCC: *pulBit = 2; break;
case 0xA1: *pulBit = 3; break;
case 0xA2: *pulBit = 4; break;
case 0xB1: *pulBit = 5; break;
case 0xB2: *pulBit = 6; break;
case 0xBA: *pulBit = 7; break;
case 0xA3: *pulBit = 8; break;
case 0xDE: *pulBit = 16; break;
case 0x80: *pulBit = 17; break;
case 0x86: *pulBit = 18; break;
case 0x81: *pulBit = 19; break;
case 0x88: *pulBit = 20; break;
case 0x82: *pulBit = 21; break;
case 0x4D: *pulBit = 29; break;
case 0x02: *pulBit = 31; break;
case 0xFF: *pulBit = 30; break;
default: *pulBit = 0; break;
}
}
}
static int GetDefaultCharset(INT bUseDefCharset)
{
if ( !bUseDefCharset )
return UNKNOWN_CHARSET;
/*
LOCALESIGNATURE LocSig;
GetLocaleInfo( GetSystemDefaultLCID(), LOCALE_FONTSIGNATURE, (LPWSTR)&LocSig, sizeof(LocSig) / sizeof(TCHAR) );
if ( LocSig.lsCsbDefault[0] & 1 )
return 0;
else if ( LocSig.lsCsbDefault[0] & 2 )
return 238;
else if ( LocSig.lsCsbDefault[0] & 4 )
return 204;
else if ( LocSig.lsCsbDefault[0] & 8 )
return 161;
else if ( LocSig.lsCsbDefault[0] & 16 )
return 162;
else if ( LocSig.lsCsbDefault[0] & 32 )
return 177;
else if ( LocSig.lsCsbDefault[0] & 64 )
return 178;
else if ( LocSig.lsCsbDefault[0] & 128 )
return 186;
else if ( LocSig.lsCsbDefault[0] & 256 )
return 163;
else if ( LocSig.lsCsbDefault[0] & 0x10000 )
return 222;
else if ( LocSig.lsCsbDefault[0] & 0x20000 )
return 128;
else if ( LocSig.lsCsbDefault[0] & 0x40000 )
return 134;
else if ( LocSig.lsCsbDefault[0] & 0x80000 )
return 129;
else if ( LocSig.lsCsbDefault[0] & 0x100000 )
return 136;
else if ( LocSig.lsCsbDefault[0] & 0x200000 )
return 130;
else if ( LocSig.lsCsbDefault[0] & 0x20000000 )
return 77;
else if ( LocSig.lsCsbDefault[0] & 0x40000000 )
return 255;
else if ( LocSig.lsCsbDefault[0] & 0x80000000 )
return 2;
*/
return 0;
}
}
int CFontList::GetCharsetPenalty(ULONG ulCandRanges[6], unsigned char unReqCharset)
{
// Penalty = 65000 (это самый весомый параметр)
if ( UNKNOWN_CHARSET == unReqCharset )
return 0;
unsigned long ulBit = 0;
unsigned int unLongIndex = 0;
NSCharsets::GetCodePageByCharset( unReqCharset, &ulBit, &unLongIndex );
int nMult = 1;
for ( int nIndex = 0; nIndex < (int)ulBit; nIndex++ )
nMult <<= 1;
if ( !(ulCandRanges[unLongIndex] & nMult) )
return 65000;
return 0;
}
int CFontList::GetSigPenalty(ULONG ulCandRanges[6], ULONG ulReqRanges[6], double dRangeWeight, double dRangeWeightSuferflouous)
{
double dPenalty = 0;
// Для начала просматриваем сколько вообще различных пространств надо.
// Исходя из их общего количества, находим вес 1 пропущеного пространства.
unsigned char arrCandidate[192], arrRequest[192];
memset( arrCandidate, 0x00, 192 );
memset( arrRequest, 0x00, 192 );
int nRangesCount = 0; // Количество необходимых пространств
int nAddCount = 0; // количество дополнительных(ненужных) пространств у кандидата
for ( int nIndex = 0; nIndex < 6; nIndex++ )
{
for ( unsigned long nBitCount = 0, nBit = 1; nBitCount < 32; nBitCount++, nBit *= 2 )
{
INT bReqAdd = FALSE;
if ( ulReqRanges[nIndex] & nBit )
{
arrRequest[ nIndex * 32 + nBitCount ] = 1;
nRangesCount++;
bReqAdd = TRUE;
}
if ( ulCandRanges[nIndex] & nBit )
{
arrCandidate[ nIndex * 32 + nBitCount ] = 1;
if ( !bReqAdd )
nAddCount++;
}
}
}
if ( 0 == nRangesCount )
return 0;
//double dRangeWeight = 1;//1000.0 / nRangesCount;
for ( int nIndex = 0; nIndex < 192; nIndex++ )
{
if ( 1 == arrRequest[nIndex] && 0 == arrCandidate[nIndex] )
dPenalty += dRangeWeight;
else if ( dRangeWeightSuferflouous != 0 && 0 == arrRequest[nIndex] && 1 == arrCandidate[nIndex] )
dPenalty += dRangeWeightSuferflouous;
}
return (int)dPenalty;
}
int CFontList::GetFixedPitchPenalty(INT bCandFixed, INT bReqFixed)
{
int nPenalty = 0;
// Если запрашивается моноширинный, а кандидат не моноширинный, то вес 15000
// Если запрашивается не моноширинный, а кандидат моноширинный, то вес 350
if ( bReqFixed && !bCandFixed )
nPenalty = 15000;
if ( !bReqFixed && bCandFixed )
nPenalty = 350;
return nPenalty;
}
int CFontList::GetFaceNamePenalty(std::wstring sCandName, std::wstring sReqName)
{
// На MSDN написано, что если имена не совпадают, то вес 10000.
// Мы будем сравнивать сколько совпало символов у запрашиваемого
// имени и с именем кандидата, без учета решистра, пробелов, запятых
// и тире.
/*
TODO:
sCandName.Remove(' '); sReqName.Remove(' ');
sCandName.Remove(','); sReqName.Remove(',');
sCandName.Remove('-'); sReqName.Remove('-');
sCandName.MakeLower(); sReqName.MakeLower();
*/
if ( 0 == sReqName.length() )
return 0;
if ( 0 == sCandName.length() )
return 10000;
if ( sReqName == sCandName )
return 0;
else if ( std::wstring::npos != sReqName.find( sCandName ) || std::wstring::npos != sCandName.find( sReqName ) )
return 1000;
return 10000;
}
int CFontList::GetFamilyUnlikelyPenalty(SHORT nCandFamilyClass, SHORT nReqFamilyClass)
{
// Requested a roman/modern/swiss family, but the candidate is
// decorative/script. Or requested decorative/script, and the
// candidate is roman/modern/swiss. Penalty = 50.
int nReqClassID = nReqFamilyClass >> 8;
int nCandClassID = nCandFamilyClass >> 8;
if ( 0 == nReqClassID ) // Unknown
return 0;
if ( 0 == nCandClassID ) // Unknown
return 50;
if ( ( nReqClassID <= 8 && nCandClassID > 8 ) || ( nReqClassID > 8 && nCandClassID <= 8 ) )
return 50;
return 0;
}
int CFontList::GetFamilyUnlikelyPenalty(int nCandFamilyClass, std::wstring sReqFamilyClass)
{
// Requested a roman/modern/swiss family, but the candidate is
// decorative/script. Or requested decorative/script, and the
// candidate is roman/modern/swiss. Penalty = 50.
int nCandClassID = nCandFamilyClass >> 8;
//sReqFamilyClass.MakeLower(); TODO:
if ( L"any" == sReqFamilyClass || L"unknown" == sReqFamilyClass )
return 0;
else if ( 0 == nCandClassID )
return 50;
else if ( ( ( L"swiss" == sReqFamilyClass ||
L"roman" == sReqFamilyClass ||
L"modern" == sReqFamilyClass ) && nCandClassID > 8 ) ||
( (L"decorative" == sReqFamilyClass || L"script" == sReqFamilyClass ) && nCandClassID <= 8 ) )
return 50;
return 0;
}
int CFontList::GetWidthPenalty(USHORT usCandWidth, USHORT usReqWidth)
{
// Penalty * width difference (Penalty = 50)
return abs( (int)usCandWidth - (int)usReqWidth ) * 50;
}
int CFontList::GetWeightPenalty(USHORT usCandWeight, USHORT usReqWeight)
{
// Penalty * ( weight difference / 10 ) (Penalty = 3)
return (3 * ( abs( (int)usCandWeight - (int)usReqWeight ) / 10 ));
}
int CFontList::GetItalicPenalty(INT bCandItalic, INT bReqItalic)
{
// Penalty = 4
if ( bCandItalic != bReqItalic )
return 4;
return 0;
}
int CFontList::GetBoldPenalty(INT bCandBold, INT bReqBold)
{
// SmallPenalty
// Penalty = 1
if ( bCandBold != bReqBold )
return 1;
return 0;
}
int CFontList::GetFontFormatPenalty(EFontFormat eCandFormat, EFontFormat eReqFormat)
{
// Вообще, на МSDN написано только про TrueType. Но мы будем сравнивать
// все типы форматов и при несовпадении даем вес = 4. Если формат не задан
// то по умолчанию считаем его TrueType.
if ( eReqFormat == fontUnknown )
{
// Считаем, что когда формат не известен, значит это 100% не TrueType.
if ( eCandFormat == fontTrueType )
return 4;
else
return 0;
}
if ( eCandFormat != eReqFormat )
return 4;
return 0;
}
int CFontList::GetPanosePenalty(BYTE *pCandPanose, BYTE *pReqPanose)
{
int nPenalty = 0;
for ( int nIndex = 0; nIndex < 10; nIndex++ )
{
if ( pCandPanose[nIndex] != pReqPanose[nIndex] && 0 != pReqPanose[nIndex] )
{
int nKoef = abs(pCandPanose[nIndex] - pReqPanose[nIndex]);
switch(nIndex)
{
case 0: nPenalty += 1000 * nKoef; break;
case 1: nPenalty += 100 * nKoef; break;
case 2: nPenalty += 100 * nKoef; break;
case 3: nPenalty += 100 * nKoef; break;
case 4: nPenalty += 100 * nKoef; break;
case 5: nPenalty += 100 * nKoef; break;
case 6: nPenalty += 100 * nKoef; break;
case 7: nPenalty += 100 * nKoef; break;
case 8: nPenalty += 100 * nKoef; break;
case 9: nPenalty += 100 * nKoef; break;
}
}
}
return nPenalty;
}
int CFontList::GetAvgWidthPenalty(SHORT shCandWidth, SHORT shReqWidth)
{
if ( 0 == shCandWidth && 0 != shReqWidth )
return 4000;
return abs( shCandWidth - shReqWidth ) * 4;
}
int CFontList::GetAscentPenalty(SHORT shCandAscent, SHORT shReqAscent)
{
if ( 0 == shCandAscent && 0 != shReqAscent )
return 100;
return abs( shCandAscent - shReqAscent ) / 10;
}
int CFontList::GetDescentPenalty(SHORT shCandDescent, SHORT shReqDescent)
{
if ( 0 == shCandDescent && 0 != shReqDescent )
return 100;
return abs( shCandDescent - shReqDescent ) / 10;
}
int CFontList::GetLineGapPenalty(SHORT shCandLineGap, SHORT shReqLineGap)
{
if ( 0 == shCandLineGap && 0 != shReqLineGap )
return 100;
return abs( shCandLineGap - shReqLineGap ) / 10;
}
int CFontList::GetXHeightPenalty(SHORT shCandXHeight, SHORT shReqXHeight)
{
if ( 0 == shCandXHeight && 0 != shReqXHeight )
return 50;
return abs( shCandXHeight - shReqXHeight ) / 20;
}
int CFontList::GetCapHeightPenalty(SHORT shCandCapHeight, SHORT shReqCapHeight)
{
if ( 0 == shCandCapHeight && 0 != shReqCapHeight )
return 50;
return abs( shCandCapHeight - shReqCapHeight ) / 20;
}
EFontFormat CFontList::GetFontFormat(FT_Face pFace)
{
std::string wsFormat( FT_Get_X11_Font_Format( pFace ) );
if ( "Windows FNT" == wsFormat )
return fontWindowsFNT;
else if ( "TrueType" == wsFormat )
return fontTrueType;
else if ( "CFF" == wsFormat )
return fontOpenType;
return fontUnknown;
}
void CFontList::ToBuffer(BYTE** pDstData, LONG* pLen, std::wstring strDirectory, bool bIsOnlyFileName)
{
LONG lDataSize = sizeof(INT);
size_t nFontsCount = (size_t)m_pList.GetCount();
for (size_t i = 0; i < nFontsCount; ++i)
{
lDataSize += m_pList[i]->GetBufferLen(strDirectory, bIsOnlyFileName);
}
BYTE* pData = new BYTE[lDataSize];
BYTE* pDataMem = pData;
*(INT*)pDataMem = (INT)nFontsCount;
pDataMem += sizeof(INT);
for (size_t i = 0; i < nFontsCount; ++i)
{
m_pList[i]->ToBuffer(pDataMem, strDirectory, bIsOnlyFileName);
}
*pDstData = pData;
*pLen = lDataSize;
}
CFontInfo* CFontList::GetByParams(CFontSelectFormat& oSelect)
{
int nFontsCount = m_pList.GetCount();
if (0 == nFontsCount)
return NULL;
#if 1
// дубликат не делаем!!! Серега создает объект только для подбора и дальше его не использует
NSFontDictionary::CorrectParamsFromDictionary(oSelect);
#endif
int nMinIndex = 0; // Номер шрифта в списке с минимальным весом
int nMinPenalty = 0; // Минимальный вес
int nDefPenalty = 2147483647;
for ( int nIndex = 0; nIndex < nFontsCount; ++nIndex )
{
int nCurPenalty = 0;
CFontInfo* pInfo = m_pList[nIndex];
if ( NULL != oSelect.pPanose )
{
nCurPenalty += GetPanosePenalty( pInfo->m_aPanose, oSelect.pPanose );
}
ULONG arrCandRanges[6] = { pInfo->m_ulUnicodeRange1, pInfo->m_ulUnicodeRange2, pInfo->m_ulUnicodeRange3, pInfo->m_ulUnicodeRange4, pInfo->m_ulCodePageRange1, pInfo->m_ulCodePageRange2 };
if (true)
{
if (NULL != oSelect.ulRange1 &&
NULL != oSelect.ulRange2 &&
NULL != oSelect.ulRange3 &&
NULL != oSelect.ulRange4 &&
NULL != oSelect.ulCodeRange1 &&
NULL != oSelect.ulCodeRange2)
{
ULONG arrReqRanges[6] = { *oSelect.ulRange1, *oSelect.ulRange2, *oSelect.ulRange3, *oSelect.ulRange4, *oSelect.ulCodeRange1, *oSelect.ulCodeRange2 };
nCurPenalty += GetSigPenalty( arrCandRanges, arrReqRanges, nCurPenalty >= 1000 ? 50 : 10, 10 );
}
}
unsigned char unCharset = UNKNOWN_CHARSET;
if (NULL != oSelect.unCharset)
unCharset = *oSelect.unCharset;
EFontFormat eFontFormat = fontTrueType;
if ( NULL != oSelect.bFixedWidth )
nCurPenalty += GetFixedPitchPenalty( pInfo->m_bIsFixed, *oSelect.bFixedWidth );
if ( oSelect.wsName != NULL && oSelect.wsAltName != NULL )
{
nCurPenalty += min( GetFaceNamePenalty( pInfo->m_wsFontName, *oSelect.wsName ), GetFaceNamePenalty( pInfo->m_wsFontName, *oSelect.wsAltName ) );
}
else if ( oSelect.wsName != NULL )
nCurPenalty += GetFaceNamePenalty( pInfo->m_wsFontName, *oSelect.wsName );
else if ( oSelect.wsAltName != NULL )
nCurPenalty += GetFaceNamePenalty( pInfo->m_wsFontName, *oSelect.wsAltName );
if ( NULL != oSelect.usWidth )
nCurPenalty += GetWidthPenalty( pInfo->m_usWidth, *oSelect.usWidth );
if ( NULL != oSelect.usWeight )
nCurPenalty += GetWeightPenalty( pInfo->m_usWeigth, *oSelect.usWeight );
if ( NULL != oSelect.bBold )
nCurPenalty += GetBoldPenalty( pInfo->m_bBold, *oSelect.bBold );
if ( NULL != oSelect.bItalic )
nCurPenalty += GetItalicPenalty( pInfo->m_bItalic, *oSelect.bItalic );
if ( NULL != oSelect.wsFamilyClass )
nCurPenalty += GetFamilyUnlikelyPenalty( pInfo->m_sFamilyClass, *oSelect.wsFamilyClass );
else if (NULL != oSelect.sFamilyClass)
nCurPenalty += GetFamilyUnlikelyPenalty( pInfo->m_sFamilyClass, *oSelect.sFamilyClass );
nCurPenalty += GetFontFormatPenalty( pInfo->m_eFontFormat, eFontFormat );
nCurPenalty += GetCharsetPenalty( arrCandRanges, unCharset );
if ( NULL != oSelect.shAvgCharWidth )
nCurPenalty += GetAvgWidthPenalty( pInfo->m_shAvgCharWidth, *oSelect.shAvgCharWidth );
if ( NULL != oSelect.shAscent )
nCurPenalty += GetAscentPenalty( pInfo->m_shAscent, *oSelect.shAscent );
if ( NULL != oSelect.shDescent )
nCurPenalty += GetDescentPenalty( pInfo->m_shDescent, *oSelect.shDescent );
if ( NULL != oSelect.shLineGap )
nCurPenalty += GetLineGapPenalty( pInfo->m_shLineGap, *oSelect.shLineGap );
if ( NULL != oSelect.shXHeight )
nCurPenalty += GetXHeightPenalty( pInfo->m_shXHeight, *oSelect.shXHeight );
if ( NULL != oSelect.shCapHeight )
nCurPenalty += GetCapHeightPenalty( pInfo->m_shCapHeight, *oSelect.shCapHeight );
if ( 0 == nIndex )
{
nMinIndex = 0;
nMinPenalty = nCurPenalty;
}
else if ( nCurPenalty < nMinPenalty )
{
nMinIndex = nIndex;
nMinPenalty = nCurPenalty;
}
if ( -1 != m_lDefIndex && nIndex == m_lDefIndex )
{
nDefPenalty = nCurPenalty;
}
// Нашелся шрифт, удовлетворяющий всем параметрам, дальше искать нет смысла
if ( 0 == nCurPenalty )
break;
}
if ( -1 != m_lDefIndex && nDefPenalty == nMinPenalty )
nMinIndex = m_lDefIndex;
return m_pList[nMinIndex];
}
CArray<CFontInfo*> CFontList::GetAllByName(const std::wstring& strFontName)
{
CArray<CFontInfo*> aRes;
for ( int nIndex = 0; nIndex < m_pList.GetCount(); ++nIndex )
{
CFontInfo* pInfo = m_pList[nIndex];
if(pInfo->m_wsFontName == strFontName)
aRes.Add(pInfo);
}
return aRes;
}
void CFontList::SetDefaultFont(std::wstring& sName)
{
m_lDefIndex = -1;
int nStyleMin = 100;
for ( int nIndex = 0; nIndex < m_pList.GetCount(); ++nIndex )
{
CFontInfo* pInfo = m_pList[nIndex];
if (pInfo->m_wsFontName == sName)
{
int nStyle = 0;
if (pInfo->m_bBold)
nStyle |= 2;
if (pInfo->m_bItalic)
nStyle |= 1;
if (nStyle < nStyleMin)
{
m_lDefIndex = nIndex;
nStyleMin = nStyle;
}
}
}
}
void CFontList::LoadFromArrayFiles(CArray<std::wstring>& oArray)
{
int nCount = oArray.GetCount();
FT_Library pLibrary = NULL;
if (FT_Init_FreeType(&pLibrary))
return;
FT_Parameter *pParams = (FT_Parameter *)::malloc( sizeof(FT_Parameter) * 4 );
pParams[0].tag = FT_MAKE_TAG( 'i', 'g', 'p', 'f' );
pParams[0].data = NULL;
pParams[1].tag = FT_MAKE_TAG( 'i', 'g', 'p', 's' );
pParams[1].data = NULL;
pParams[2].tag = FT_PARAM_TAG_IGNORE_PREFERRED_FAMILY;
pParams[2].data = NULL;
pParams[3].tag = FT_PARAM_TAG_IGNORE_PREFERRED_SUBFAMILY;
pParams[3].data = NULL;
// определяем размер буфера, чтобы не выделять много кусков, а обойтись одним
int nMaxFontSize = 0;
for (int nIndex = 0; nIndex < nCount; ++nIndex)
{
NSFile::CFileBinary oFile;
if (oFile.OpenFile(oArray[nIndex]))
{
int nSizeTmp = (int)oFile.GetFileSize();
if (nSizeTmp > 100000000)
{
// такие огромные шрифты не учитываем
oArray.RemoveAt(nIndex);
nIndex--;
nCount--;
}
if (nMaxFontSize < nSizeTmp)
nMaxFontSize = nSizeTmp;
}
}
BYTE* pDataFontFile = new BYTE[nMaxFontSize];
for (int nIndex = 0; nIndex < nCount; ++nIndex)
{
// open file
CFontStream oStream;
if (!oStream.CreateFromFile(oArray[nIndex], pDataFontFile))
continue;
FT_Open_Args oOpenArgs;
oOpenArgs.flags = FT_OPEN_MEMORY | FT_OPEN_PARAMS;
oOpenArgs.memory_base = oStream.m_pData;
oOpenArgs.memory_size = oStream.m_lSize;
oOpenArgs.num_params = 4;
oOpenArgs.params = pParams;
FT_Face pFace = NULL;
if (FT_Open_Face( pLibrary, &oOpenArgs, 0, &pFace ))
continue;
// TO DO: Шрифты, которые нельзя скейлить (т.е. изменять размер
// произвольно) мы не грузим. Возможно в будущем надо будет
// сделать, чтобы работал и такой вариант. (в Word такие шрифты
// не используются)
if ( !( pFace->face_flags & FT_FACE_FLAG_SCALABLE ) )
{
FT_Done_Face( pFace );
continue;
}
int nFacesCount = pFace->num_faces;
if ( FT_Done_Face( pFace ) )
continue;
for ( int nIndexFace = 0; nIndexFace < nFacesCount; nIndexFace++ )
{
if (FT_Open_Face( pLibrary, &oOpenArgs, nIndexFace, &pFace))
continue;
INT bBold = (pFace->style_flags & FT_STYLE_FLAG_BOLD ? 1 : 0);
INT bItalic = pFace->style_flags & FT_STYLE_FLAG_ITALIC;
const char* pPostName = FT_Get_Postscript_Name(pFace);
std::string sPostscriptName = "";
if (NULL != pPostName)
sPostscriptName = FT_Get_Postscript_Name(pFace);
int nNamesCount = FT_Get_Sfnt_Name_Count(pFace);
for (int nNameIndex = 0; nNameIndex < nNamesCount; ++nNameIndex)
{
FT_SfntName_ oSfntName;
FT_Get_Sfnt_Name( pFace, nNameIndex, &oSfntName );
if ( oSfntName.language_id == 0x0409 && oSfntName.name_id == 1 && oSfntName.platform_id == 3 )
{
// Family
int k= 10;
}
if ( oSfntName.language_id == 0x0409 && oSfntName.name_id == 16 && oSfntName.platform_id == 3 )
{
// Preffered family
int k= 10;
}
}
INT bFixedWidth = FT_IS_FIXED_WIDTH( pFace );
TT_OS2 *pOs2 = (TT_OS2 *)FT_Get_Sfnt_Table( pFace, ft_sfnt_os2 );
BYTE* pPanose = NULL;
ULONG ulRange1 = 0, ulRange2 = 0, ulRange3 = 0, ulRange4 = 0, ulCodeRange1 = 0, ulCodeRange2 = 0;
USHORT usWidth = 0, usWeight = 0;
SHORT sFamilyClass = 0;
SHORT shAvgCharWidth = 0, shAscent = 0, shDescent = 0, shLineGap = 0, shXHeight = 0, shCapHeight = 0;
if ( NULL != pOs2 )
{
pPanose = (BYTE *)pOs2->panose;
ulRange1 = pOs2->ulUnicodeRange1;
ulRange2 = pOs2->ulUnicodeRange2;
ulRange3 = pOs2->ulUnicodeRange3;
ulRange4 = pOs2->ulUnicodeRange4;
ulCodeRange1 = pOs2->ulCodePageRange1;
ulCodeRange2 = pOs2->ulCodePageRange2;
usWeight = pOs2->usWeightClass;
usWidth = pOs2->usWidthClass;
sFamilyClass = pOs2->sFamilyClass;
if ( 0 != pFace->units_per_EM )
{
double dKoef = ( 1000 / (double)pFace->units_per_EM );
shAvgCharWidth = (SHORT)(pOs2->xAvgCharWidth * dKoef);
shAscent = (SHORT)(pOs2->sTypoAscender * dKoef);
shDescent = (SHORT)(pOs2->sTypoDescender * dKoef);
shLineGap = (SHORT)(pOs2->sTypoLineGap * dKoef);
shXHeight = (SHORT)(pOs2->sxHeight * dKoef);
shCapHeight = (SHORT)(pOs2->sCapHeight * dKoef);
}
else
{
shAvgCharWidth = (SHORT)pOs2->xAvgCharWidth;
shAscent = (SHORT)pOs2->sTypoAscender;
shDescent = (SHORT)pOs2->sTypoDescender;
shLineGap = (SHORT)pOs2->sTypoLineGap;
shXHeight = (SHORT)pOs2->sxHeight;
shCapHeight = (SHORT)pOs2->sCapHeight;
}
}
if ( true )
{
// Специальная ветка для случаев, когда charset может быть задан не через значения
// ulCodePageRange, а непосредственно через тип Cmap.
// 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
for( int nIndex = 0; nIndex < pFace->num_charmaps; nIndex++ )
{
// Symbol
if ( !( ulCodeRange1 & 0x80000000 ) && 0 == pFace->charmaps[nIndex]->encoding_id && 3 == pFace->charmaps[nIndex]->platform_id )
ulCodeRange1 |= 0x80000000;
// ShiftJIS
if ( !( ulCodeRange1 & 0x00020000 ) && 2 == pFace->charmaps[nIndex]->encoding_id && 3 == pFace->charmaps[nIndex]->platform_id )
ulCodeRange1 |= 0x00020000;
// PRC
if ( !( ulCodeRange1 & 0x00040000 ) && 3 == pFace->charmaps[nIndex]->encoding_id && 3 == pFace->charmaps[nIndex]->platform_id )
ulCodeRange1 |= 0x00040000;
// Big5
if ( !( ulCodeRange1 & 0x00100000 ) && 4 == pFace->charmaps[nIndex]->encoding_id && 3 == pFace->charmaps[nIndex]->platform_id )
ulCodeRange1 |= 0x00100000;
// Wansung
if ( !( ulCodeRange1 & 0x00080000 ) && 5 == pFace->charmaps[nIndex]->encoding_id && 3 == pFace->charmaps[nIndex]->platform_id )
ulCodeRange1 |= 0x00080000;
// Johab
if ( !( ulCodeRange1 & 0x00200000 ) && 6 == pFace->charmaps[nIndex]->encoding_id && 3 == pFace->charmaps[nIndex]->platform_id )
ulCodeRange1 |= 0x00200000;
}
}
EFontFormat eFormat = GetFontFormat( pFace );
if (eFormat != fontTrueType)
{
FT_Done_Face( pFace );
continue;
}
std::string sFamilyName = "";
if (NULL != pFace->family_name)
sFamilyName = pFace->family_name;
std::string sStyleName = "";
if (NULL != pFace->style_name)
sStyleName = pFace->style_name;
std::wstring wsFamilyName = NSFile::CUtf8Converter::GetUnicodeFromCharPtr(sFamilyName);
std::wstring wsStyleName = NSFile::CUtf8Converter::GetUnicodeFromCharPtr(sStyleName);
CFontInfo* pFontInfo = new CFontInfo( wsFamilyName,
wsStyleName,
oArray[nIndex],
nIndexFace,
bBold,
bItalic,
bFixedWidth,
pPanose,
ulRange1,
ulRange2,
ulRange3,
ulRange4,
ulCodeRange1,
ulCodeRange2,
usWeight,
usWidth,
sFamilyClass,
eFormat,
shAvgCharWidth,
shAscent,
shDescent,
shLineGap,
shXHeight,
shCapHeight );
Add(pFontInfo);
FT_Done_Face( pFace );
}
}
RELEASEARRAYOBJECTS(pDataFontFile);
::free( pParams );
FT_Done_FreeType(pLibrary);
}
void CFontList::LoadFromFolder(const std::wstring& strDirectory)
{
CArray<std::wstring> oArray = NSDirectory::GetFiles(strDirectory, true);
this->LoadFromArrayFiles(oArray);
}
bool CFontList::CheckLoadFromFolderBin(const std::wstring& strDirectory)
{
std::wstring strPath = strDirectory + L"/font_selection.bin";
NSFile::CFileBinary oFile;
if (!oFile.OpenFile(strPath))
return false;
DWORD dwLen1 = (DWORD)oFile.GetFileSize();
DWORD dwLen2 = 0;
BYTE* pBuffer = new BYTE[dwLen1];
oFile.ReadFile(pBuffer, dwLen1, dwLen2);
m_lDefIndex = -1;
BYTE* _pBuffer = pBuffer;
int lCount = *((int*)_pBuffer);
_pBuffer += sizeof(int);
for (int nIndex = 0; nIndex < lCount; ++nIndex)
{
CFontInfo *pFontInfo = CFontInfo::FromBuffer(_pBuffer, strDirectory);
Add(pFontInfo);
}
RELEASEARRAYOBJECTS(pBuffer);
return true;
}
void CFontList::Add(CFontInfo* pInfo)
{
int nCount = m_pList.GetCount();
for ( int nIndex = 0; nIndex < nCount; ++nIndex )
{
if (m_pList[nIndex]->Equals(pInfo))
{
RELEASEOBJECT(pInfo);
return;
}
}
m_pList.Add(pInfo);
}
// ApplicationFonts
CApplicationFonts::CApplicationFonts()
{
m_oCache.m_pApplicationFontStreams = &m_oStreams;
}
CApplicationFonts::~CApplicationFonts()
{
}
CFontsCache* CApplicationFonts::GetCache()
{
return &m_oCache;
}
CFontList* CApplicationFonts::GetList()
{
return &m_oList;
}
CApplicationFontStreams* CApplicationFonts::GetStreams()
{
return &m_oStreams;
}
void CApplicationFonts::InitializeFromFolder(std::wstring strFolder, bool bIsCheckSelection)
{
if (bIsCheckSelection)
{
if (m_oList.CheckLoadFromFolderBin(strFolder))
return;
if (m_oList.CheckLoadFromFolderBin(NSFile::GetProcessDirectory()))
return;
}
m_oList.LoadFromFolder(strFolder);
m_oCache.m_pApplicationFontStreams = &m_oStreams;
}
void CApplicationFonts::Initialize(bool bIsCheckSelection)
{
if (bIsCheckSelection)
{
if (m_oList.CheckLoadFromFolderBin(NSFile::GetProcessDirectory()))
return;
}
#if defined(_WIN32) || defined (_WIN64)
//m_oList.LoadFromFolder(L"C:/Windows/Fonts");
InitFromReg();
#endif
#if defined(_LINUX) && !defined(_MAC)
m_oList.LoadFromFolder(L"/usr/share/fonts");
#endif
#if defined(_MAC) && !defined(_IOS)
m_oList.LoadFromFolder(L"/Library/Fonts/");
#endif
m_oCache.m_pApplicationFontStreams = &m_oStreams;
}
CFontManager* CApplicationFonts::GenerateFontManager()
{
CFontManager* pManager = new CFontManager();
pManager->m_pApplication = this;
return pManager;
}
#if defined(_WIN32) || defined (_WIN64)
#include <shlobj.h>
static long GetNextNameValue(HKEY key, const std::wstring& sSubkey, std::wstring& sName, std::wstring& sData)
{
static HKEY hkey = NULL; // registry handle, kept open between calls
static DWORD dwIndex = 0; // count of values returned
long retval;
// if all parameters are NULL then close key
if (sSubkey.length() == 0 && sName.length() == 0 && sData.length() == 0)
{
if (hkey)
RegCloseKey(hkey);
hkey = NULL;
return ERROR_SUCCESS;
}
// if subkey is specified then open key (first time)
if (sSubkey.length() != 0)
{
retval = RegOpenKeyExW(key, sSubkey.c_str(), 0, KEY_READ, &hkey);
if (retval != ERROR_SUCCESS)
{
return retval;
}
dwIndex = 0;
}
else
{
dwIndex++;
}
wchar_t szValueName[MAX_PATH];
DWORD dwValueNameSize = sizeof(szValueName)-1;
BYTE szValueData[MAX_PATH];
DWORD dwValueDataSize = sizeof(szValueData)-1;
DWORD dwType = 0;
retval = RegEnumValueW(hkey, dwIndex, szValueName, &dwValueNameSize, NULL,
&dwType, szValueData, &dwValueDataSize);
if (retval == ERROR_SUCCESS)
{
sName = std::wstring(szValueName);
sData = std::wstring((wchar_t*)szValueData);
}
return retval;
}
#endif
CArray<std::wstring> CApplicationFonts::GetSetupFontFiles()
{
#if defined(_WIN32) || defined (_WIN64)
// Ищем директорию с фонтами (обычно это C:\Windows\Fonts)
wchar_t wsWinFontDir[MAX_PATH];
wsWinFontDir[0] = (wchar_t)'\0';
if ( !SHGetSpecialFolderPathW( NULL, wsWinFontDir, CSIDL_FONTS, FALSE ) )
wsWinFontDir[0] = '\0';
std::wstring sWinFontDir(wsWinFontDir);
OSVERSIONINFO oVersion;
oVersion.dwOSVersionInfoSize = sizeof(oVersion);
GetVersionEx( &oVersion );
std::wstring wsPath = L"";
if ( oVersion.dwPlatformId == VER_PLATFORM_WIN32_NT )
wsPath = L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts\\";
else
wsPath = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Fonts\\";
std::wstring sName;
std::wstring sData;
std::map<std::wstring, bool> map_files;
CArray<std::wstring> oArray;
while (GetNextNameValue( HKEY_LOCAL_MACHINE, wsPath, sName, sData ) == ERROR_SUCCESS)
{
if (wsPath.length())
wsPath = L"";
NSFile::CFileBinary oFile;
if (oFile.OpenFile(sData))
{
oFile.CloseFile();
if (map_files.find(sData) == map_files.end())
{
oArray.Add(sData);
map_files.insert(map_files.begin(), std::pair<std::wstring,bool>(sData,true));
}
continue;
}
oFile.CloseFile();
std::wstring sFileInDir = sWinFontDir + L"\\" + sData;
if (oFile.OpenFile(sFileInDir))
{
oFile.CloseFile();
if (map_files.find(sFileInDir) == map_files.end())
{
oArray.Add(sFileInDir);
map_files.insert(map_files.begin(), std::pair<std::wstring,bool>(sFileInDir,true));
}
continue;
}
}
return oArray;
#endif
#if defined(__linux__) && !defined(_MAC)
return NSDirectory::GetFiles(L"/usr/share/fonts", true);
#endif
#if defined(_MAC) && !defined(_IOS)
return NSDirectory::GetFiles(L"/Library/Fonts", true);
#endif
#ifdef _IOS
// own realization (objective c code)
return GetSetupFontFiles_ios();
#endif
CArray<std::wstring> ret;
return ret;
}
void CApplicationFonts::InitializeFromArrayFiles(CArray<std::wstring>& files)
{
m_oList.LoadFromArrayFiles(files);
}
#if defined(_WIN32) || defined (_WIN64)
void CApplicationFonts::InitFromReg()
{
CArray<std::wstring> oArray = GetSetupFontFiles();
m_oList.LoadFromArrayFiles(oArray);
}
#endif
#ifndef _BUILD_APPLICATIONFONTS_H_
#define _BUILD_APPLICATIONFONTS_H_
#define UNKNOWN_CHARSET 3 // для случаев, когда задано значение DEFAULT_CHARSET, но
// на самом деле charset не учитывается
#include "FontManager.h"
class CFontSelectFormat
{
public:
std::wstring* wsName;
std::wstring* wsAltName;
std::wstring* wsFamilyClass;
SHORT* sFamilyClass;
INT* bBold;
INT* bItalic;
INT* bFixedWidth;
BYTE* pPanose;
ULONG* ulRange1;
ULONG* ulRange2;
ULONG* ulRange3;
ULONG* ulRange4;
ULONG* ulCodeRange1;
ULONG* ulCodeRange2;
USHORT* usWeight;
USHORT* usWidth;
int* nFontFormat;
BYTE* unCharset;
SHORT* shAvgCharWidth;
SHORT* shAscent;
SHORT* shDescent;
SHORT* shLineGap;
SHORT* shXHeight;
SHORT* shCapHeight;
public:
CFontSelectFormat();
~CFontSelectFormat();
void CreateDuplicate(CFontSelectFormat& oFormat);
void Destroy();
};
//-------------------------------------------------------------------------------------------------------------------------------
// CWinFontInfo
//-------------------------------------------------------------------------------------------------------------------------------
enum EFontFormat
{
fontWindowsFNT = 0, // *.fon
fontTrueType = 1, // *.ttf
fontOpenType = 2, // *.ttf, *.otf (CFF формат)
fontUnknown = 3
};
class CFontInfo
{
public:
CFontInfo(const std::wstring& wsFontName,
const std::wstring& wsStyle,
const std::wstring& wsFontPath,
long lIndex,
INT bBold,
INT bItalic,
INT bFixedWidth,
BYTE *pPanose,
ULONG ulRange1,
ULONG ulRange2,
ULONG ulRange3,
ULONG ulRange4,
ULONG ulCodeRange1,
ULONG ulCodeRange2,
USHORT usWeigth,
USHORT usWidth,
SHORT sFamilyClass,
EFontFormat eFormat,
SHORT shAvgCharWidth,
SHORT shAscent,
SHORT shDescent,
SHORT shLineGap,
SHORT shXHeight,
SHORT shCapHeight);
~CFontInfo();
INT Equals(const CFontInfo *pFontInfo);
static CFontInfo* FromBuffer(BYTE*& pBuffer, std::wstring strDir);
LONG GetBufferLen(std::wstring strDirectory = L"", bool bIsOnlyFileName = false);
void ToBuffer(BYTE*& pBuffer, std::wstring strDirectory = L"", bool bIsOnlyFileName = false);
public:
std::wstring m_wsFontName; // Имя шрифта
std::wstring m_wsFontPath; // Путь к файлу с шрифтом
long m_lIndex; // Номер шрифта в файле(если в файле больше 1 шрифта)
std::wstring m_wsStyle;
INT m_bBold; // Bold text
INT m_bItalic; // Italic text
INT m_bIsFixed; // Моноширинный шрифт?
BYTE m_aPanose[10];
ULONG m_ulUnicodeRange1; // Bits 0-31
ULONG m_ulUnicodeRange2; // Bits 32-63
ULONG m_ulUnicodeRange3; // Bits 64-95
ULONG m_ulUnicodeRange4; // Bits 96-127
ULONG m_ulCodePageRange1; // Bits 0-31
ULONG m_ulCodePageRange2; // Bits 32-63
USHORT m_usWeigth;
USHORT m_usWidth;
SHORT m_sFamilyClass;
EFontFormat m_eFontFormat;
SHORT m_shAvgCharWidth; // Средняя ширина символов
SHORT m_shAscent; // Ascent
SHORT m_shDescent; // Descent
SHORT m_shLineGap; // Межсимвольный интервал
SHORT m_shXHeight; // Высота буквы 'x' (в нижнем регистре)
SHORT m_shCapHeight; // Высота буквы 'H' (в верхнем регистре)
};
namespace NSCharsets
{
static void GetCodePageByCharset(unsigned char unCharset, unsigned long *pulBit, unsigned int *punLongIndex);
static int GetDefaultCharset(INT bUseDefCharset = TRUE);
}
class CFontList
{
private:
CArray<CFontInfo*> m_pList;
std::wstring m_sDirectory;
LONG m_lDefIndex; // Номер стандартного шрифта (-1, если не задан)
public:
CFontList()
{
m_lDefIndex = -1;
}
~CFontList()
{
int nCount = m_pList.GetCount();
for ( int nIndex = 0; nIndex < nCount; ++nIndex )
{
CFontInfo* pTemp = m_pList[nIndex];
RELEASEOBJECT(pTemp);
}
m_pList.RemoveAll();
}
CArray<CFontInfo*>* GetFonts() { return &m_pList; }
private:
int GetCharsetPenalty(ULONG ulCandRanges[6], unsigned char unReqCharset);
int GetSigPenalty(ULONG ulCandRanges[6], ULONG ulReqRanges[6], double dRangeWeight = 1, double dRangeWeightSuferflouous = 0);
int GetFixedPitchPenalty(INT bCandFixed, INT bReqFixed);
int GetFaceNamePenalty(std::wstring sCandName, std::wstring sReqName);
int GetFamilyUnlikelyPenalty(SHORT nCandFamilyClass, SHORT nReqFamilyClass);
int GetFamilyUnlikelyPenalty(int nCandFamilyClass, std::wstring sReqFamilyClass);
int GetWidthPenalty(USHORT usCandWidth, USHORT usReqWidth);
int GetWeightPenalty(USHORT usCandWeight, USHORT usReqWeight);
int GetItalicPenalty(INT bCandItalic, INT bReqItalic);
int GetBoldPenalty(INT bCandBold, INT bReqBold);
int GetFontFormatPenalty(EFontFormat eCandFormat, EFontFormat eReqFormat);
int GetPanosePenalty(BYTE *pCandPanose, BYTE *pReqPanose);
int GetAvgWidthPenalty(SHORT shCandWidth, SHORT shReqWidth);
int GetAscentPenalty(SHORT shCandAscent, SHORT shReqAscent);
int GetDescentPenalty(SHORT shCandDescent, SHORT shReqDescent);
int GetLineGapPenalty(SHORT shCandLineGap, SHORT shReqLineGap);
int GetXHeightPenalty(SHORT shCandXHeight, SHORT shReqXHeight);
int GetCapHeightPenalty(SHORT shCandCapHeight, SHORT shReqCapHeight);
public:
static EFontFormat GetFontFormat(FT_Face pFace);
void ToBuffer(BYTE** pDstData, LONG* pLen, std::wstring strDirectory = L"", bool bIsOnlyFileName = false);
public:
void LoadFromArrayFiles(CArray<std::wstring>& arrFiles);
void LoadFromFolder(const std::wstring& strDirectory);
bool CheckLoadFromFolderBin(const std::wstring& strDirectory);
void Add(CFontInfo* pInfo);
CFontInfo* GetByParams(CFontSelectFormat& oSelect);
CArray<CFontInfo*> GetAllByName(const std::wstring& strFontName);
void SetDefaultFont(std::wstring& sName);
};
class CApplicationFonts
{
private:
CApplicationFontStreams m_oStreams;
CFontsCache m_oCache;
CFontList m_oList;
public:
CApplicationFonts();
~CApplicationFonts();
public:
CFontsCache* GetCache();
CFontList* GetList();
CApplicationFontStreams* GetStreams();
void InitializeFromFolder(std::wstring strFolder, bool bIsCheckSelection = true);
void Initialize(bool bIsCheckSelection = true);
CArray<std::wstring> GetSetupFontFiles();
void InitializeFromArrayFiles(CArray<std::wstring>& files);
#if defined(_WIN32) || defined (_WIN64)
void InitFromReg();
#endif
#ifdef _IOS
CArray<std::wstring> GetSetupFontFiles_ios();
#endif
CFontManager* GenerateFontManager();
};
#endif
#include "ApplicationFonts.h"
#include "ApplicationFontsWorker.h"
#include "../common/File.h"
#include "../common/Directory.h"
#include "../editor/MemoryStream.h"
namespace NSFontsApplication
{
void string_replace(std::wstring& text, const std::wstring& replaceFrom, const std::wstring& replaceTo)
{
size_t posn = 0;
while (std::wstring::npos != (posn = text.find(replaceFrom, posn)))
{
text.replace(posn, replaceFrom.length(), replaceTo);
posn += replaceTo.length();
}
}
class CTextItem
{
protected:
wchar_t* m_pData;
size_t m_lSize;
wchar_t* m_pDataCur;
size_t m_lSizeCur;
public:
CTextItem()
{
m_pData = NULL;
m_lSize = 0;
m_pDataCur = m_pData;
m_lSizeCur = m_lSize;
}
CTextItem(const CTextItem& oSrc)
{
m_pData = NULL;
*this = oSrc;
}
CTextItem& operator=(const CTextItem& oSrc)
{
RELEASEMEM(m_pData);
m_lSize = oSrc.m_lSize;
m_lSizeCur = oSrc.m_lSizeCur;
m_pData = (wchar_t*)malloc(m_lSize * sizeof(wchar_t));
memcpy(m_pData, oSrc.m_pData, m_lSizeCur * sizeof(wchar_t));
m_pDataCur = m_pData + m_lSizeCur;
return *this;
}
CTextItem(const size_t& nLen)
{
m_lSize = nLen;
m_pData = (wchar_t*)malloc(m_lSize * sizeof(wchar_t));
m_lSizeCur = 0;
m_pDataCur = m_pData;
}
CTextItem(wchar_t* pData, const size_t& nLen)
{
m_lSize = nLen;
m_pData = (wchar_t*)malloc(m_lSize * sizeof(wchar_t));
memcpy(m_pData, pData, m_lSize * sizeof(wchar_t));
m_lSizeCur = m_lSize;
m_pDataCur = m_pData + m_lSize;
}
CTextItem(wchar_t* pData, BYTE* pUnicodeChecker = NULL)
{
size_t nLen = GetStringLen(pData);
m_lSize = nLen;
m_pData = (wchar_t*)malloc(m_lSize * sizeof(wchar_t));
memcpy(m_pData, pData, m_lSize * sizeof(wchar_t));
m_lSizeCur = m_lSize;
m_pDataCur = m_pData + m_lSize;
if (NULL != pUnicodeChecker)
{
wchar_t* pMemory = m_pData;
while (pMemory < m_pDataCur)
{
if (!pUnicodeChecker[*pMemory])
*pMemory = wchar_t(' ');
++pMemory;
}
}
}
virtual ~CTextItem()
{
RELEASEMEM(m_pData);
}
inline void AddSize(const size_t& nSize)
{
if (NULL == m_pData)
{
m_lSize = 1000;
if (nSize > m_lSize)
m_lSize = nSize;
m_pData = (wchar_t*)malloc(m_lSize * sizeof(wchar_t));
m_lSizeCur = 0;
m_pDataCur = m_pData;
return;
}
if ((m_lSizeCur + nSize) > m_lSize)
{
while ((m_lSizeCur + nSize) > m_lSize)
{
m_lSize *= 2;
}
wchar_t* pRealloc = (wchar_t*)realloc(m_pData, m_lSize * sizeof(wchar_t));
if (NULL != pRealloc)
{
// реаллок сработал
m_pData = pRealloc;
m_pDataCur = m_pData + m_lSizeCur;
}
else
{
wchar_t* pMalloc = (wchar_t*)malloc(m_lSize * sizeof(wchar_t));
memcpy(pMalloc, m_pData, m_lSizeCur * sizeof(wchar_t));
free(m_pData);
m_pData = pMalloc;
m_pDataCur = m_pData + m_lSizeCur;
}
}
}
public:
inline void operator+=(const std::wstring& oTemp)
{
WriteString(oTemp.c_str(), oTemp.length());
}
inline wchar_t operator[](const size_t& nIndex)
{
if (nIndex < m_lSizeCur)
return m_pData[nIndex];
return 0;
}
inline void AddSpace()
{
AddSize(1);
*m_pDataCur = wchar_t(' ');
++m_lSizeCur;
++m_pDataCur;
}
inline void CorrectUnicode(const BYTE* pUnicodeChecker)
{
if (NULL != pUnicodeChecker)
{
wchar_t* pMemory = m_pData;
while (pMemory < m_pDataCur)
{
if (!pUnicodeChecker[*pMemory])
*pMemory = wchar_t(' ');
++pMemory;
}
}
}
inline void RemoveLastSpaces()
{
wchar_t* pMemory = m_pDataCur - 1;
while ((pMemory > m_pData) && (wchar_t(' ') == *pMemory))
{
--pMemory;
--m_lSizeCur;
--m_pDataCur;
}
}
inline bool IsSpace()
{
if (1 != m_lSizeCur)
return false;
return (wchar_t(' ') == *m_pData);
}
public:
inline void WriteString(const wchar_t* pString, const size_t& nLen)
{
AddSize(nLen);
memcpy(m_pDataCur, pString, nLen * sizeof(wchar_t));
m_pDataCur += nLen;
m_lSizeCur += nLen;
}
inline size_t GetCurSize()
{
return m_lSizeCur;
}
inline size_t GetSize()
{
return m_lSize;
}
inline void Clear()
{
RELEASEMEM(m_pData);
m_pData = NULL;
m_lSize = 0;
m_pDataCur = m_pData;
m_lSizeCur = 0;
}
inline void ClearNoAttack()
{
m_pDataCur = m_pData;
m_lSizeCur = 0;
}
inline size_t GetStringLen(wchar_t* pData)
{
wchar_t* s = pData;
for (; *s != 0; ++s);
return (size_t)(s - pData);
}
inline std::wstring GetCString()
{
std::wstring str(m_pData, (int)m_lSizeCur);
return str;
}
inline wchar_t* GetBuffer()
{
return m_pData;
}
};
class CStringWriter : public CTextItem
{
public:
CStringWriter() : CTextItem()
{
}
virtual ~CStringWriter()
{
}
public:
inline void Write(CStringWriter& oWriter)
{
CTextItem::WriteString(oWriter.m_pData, oWriter.m_lSizeCur);
}
};
class CFontInfoJS
{
public:
std::wstring m_sName;
int m_lIndexR;
int m_lFaceIndexR;
int m_lIndexI;
int m_lFaceIndexI;
int m_lIndexB;
int m_lFaceIndexB;
int m_lIndexBI;
int m_lFaceIndexBI;
CFontInfoJS()
{
m_sName = L"";
m_lIndexR = -1;
m_lFaceIndexR = -1;
m_lIndexI = -1;
m_lFaceIndexI = -1;
m_lIndexB = -1;
m_lFaceIndexB = -1;
m_lIndexBI = -1;
m_lFaceIndexBI = -1;
}
CFontInfoJS(const CFontInfoJS& oSrc)
{
*this = oSrc;
}
CFontInfoJS& operator=(const CFontInfoJS& oSrc)
{
m_sName = oSrc.m_sName;
m_lIndexR = oSrc.m_lIndexR;
m_lIndexI = oSrc.m_lIndexI;
m_lIndexB = oSrc.m_lIndexB;
m_lIndexBI = oSrc.m_lIndexBI;
m_lFaceIndexR = oSrc.m_lFaceIndexR;
m_lFaceIndexI = oSrc.m_lFaceIndexI;
m_lFaceIndexB = oSrc.m_lFaceIndexB;
m_lFaceIndexBI = oSrc.m_lFaceIndexBI;
return *this;
}
};
static std::vector<std::wstring> SaveAllFontsJS(CApplicationFonts& applicationFonts, CStringWriter& oWriterJS)
{
std::vector<std::wstring> arrNames;
CArray<CFontInfo*>* pList = applicationFonts.GetList()->GetFonts();
#ifdef _IOS
int nOldCount = pList->GetCount();
for (int i = 0; i < nOldCount; i++)
{
CFontInfo* pInfo = pList->operator [](i);
if (pInfo->m_wsFontName.find(L".") == 0)
{
// странные шрифты какие-то есть в ios
pList->RemoveAt(i);
i--;
nOldCount--;
continue;
}
}
#endif
int nCount = pList->GetCount();
// сначала строим массив всех файлов шрифтов
std::map<std::wstring, LONG> mapFontFiles;
std::map<LONG, std::wstring> mapFontFiles2;
LONG lFontFiles = 0;
for (int i = 0; i < nCount; ++i)
{
CFontInfo* pInfo = pList->operator [](i);
if (mapFontFiles.find(pInfo->m_wsFontPath) == mapFontFiles.end())
{
mapFontFiles.insert(std::pair<std::wstring, LONG>(pInfo->m_wsFontPath, lFontFiles));
mapFontFiles2.insert(std::pair<LONG, std::wstring>(lFontFiles, pInfo->m_wsFontPath));
++lFontFiles;
}
}
// -----------------------------------------
// теперь строим массив всех шрифтов по имени
std::map<std::wstring, CFontInfoJS> mapFonts;
CArray<std::wstring> arrFonts;
for (int i = 0; i < nCount; ++i)
{
CFontInfo* pInfo = (CFontInfo*)pList->operator [](i);
std::wstring strPath = pInfo->m_wsFontPath;
std::wstring strName = pInfo->m_wsFontName;
int lFontIndex = 0;
int lFaceIndex = 0;
std::map<std::wstring, LONG>::iterator it = mapFontFiles.find(strPath);
lFontIndex = (int)it->second;
if (pInfo->m_lIndex >= 0)
lFaceIndex = (int)pInfo->m_lIndex;
std::map<std::wstring, CFontInfoJS>::iterator pPair = mapFonts.find(pInfo->m_wsFontName);
if (mapFonts.end() != pPair)
{
pPair->second.m_sName = pInfo->m_wsFontName;
if (pInfo->m_bBold && pInfo->m_bItalic)
{
pPair->second.m_lIndexBI = lFontIndex;
pPair->second.m_lFaceIndexBI = lFaceIndex;
}
else if (pInfo->m_bBold)
{
pPair->second.m_lIndexB = lFontIndex;
pPair->second.m_lFaceIndexB = lFaceIndex;
}
else if (pInfo->m_bItalic)
{
pPair->second.m_lIndexI = lFontIndex;
pPair->second.m_lFaceIndexI = lFaceIndex;
}
else
{
pPair->second.m_lIndexR = lFontIndex;
pPair->second.m_lFaceIndexR = lFaceIndex;
}
}
else
{
CFontInfoJS fontInfo;
fontInfo.m_sName = pInfo->m_wsFontName;
if (pInfo->m_bBold && pInfo->m_bItalic)
{
fontInfo.m_lIndexBI = lFontIndex;
fontInfo.m_lFaceIndexBI = lFaceIndex;
}
else if (pInfo->m_bBold)
{
fontInfo.m_lIndexB = lFontIndex;
fontInfo.m_lFaceIndexB = lFaceIndex;
}
else if (pInfo->m_bItalic)
{
fontInfo.m_lIndexI = lFontIndex;
fontInfo.m_lFaceIndexI = lFaceIndex;
}
else
{
fontInfo.m_lIndexR = lFontIndex;
fontInfo.m_lFaceIndexR = lFaceIndex;
}
mapFonts.insert(std::pair<std::wstring, CFontInfoJS>(fontInfo.m_sName, fontInfo));
arrFonts.Add(fontInfo.m_sName);
}
}
// -------------------------------------------
// теперь сортируем шрифты по имени ----------
int nCountFonts = arrFonts.GetCount();
for (int i = 0; i < nCountFonts; ++i)
{
for (int j = i + 1; j < nCountFonts; ++j)
{
if (arrFonts[i] > arrFonts[j])
{
std::wstring temp = arrFonts[i];
arrFonts[i] = arrFonts[j];
arrFonts[j] = temp;
}
}
}
// -------------------------------------------
// и самое главное. Здесь должен скидываться скрипт для работы со всеми шрифтами.
// все объекты, которые позволят не знать о существующих фонтах
if (true)
{
// сначала все файлы
size_t nCountFiles = mapFontFiles.size();
if (nCountFiles == 0)
oWriterJS += (L"window[\"__fonts_files\"] = []; \n\n");
else
{
std::wstring* pMassFiles = new std::wstring[nCountFiles];
for ( std::map<std::wstring, LONG>::iterator pos = mapFontFiles.begin(); pos != mapFontFiles.end(); ++pos)
{
std::wstring strFontId = pos->first;
string_replace(strFontId, L"\\\\", L"\\");
string_replace(strFontId, L"\\", L"/");
//int nStart = strFontId.find_last_of(wchar_t('\\'));
//strFontId = strFontId.substr(nStart + 1);
pMassFiles[pos->second] = strFontId;
}
oWriterJS += (L"window[\"__fonts_files\"] = [\n");
for (size_t nIndex = 0; nIndex < nCountFiles; ++nIndex)
{
oWriterJS += (L"\"");
oWriterJS += (pMassFiles[nIndex]);
if (nIndex != (nCountFiles - 1))
oWriterJS += (L"\",\n");
else
oWriterJS += (L"\"");
}
oWriterJS += (L"\n];\n\n");
delete [] pMassFiles;
}
oWriterJS += L"window[\"__fonts_infos\"] = [\n";
for (int index = 0; index < nCountFonts; ++index)
{
std::map<std::wstring, CFontInfoJS>::iterator pPair = mapFonts.find(arrFonts[index]);
char buffer[1000];
sprintf(buffer, "\",%d,%d,%d,%d,%d,%d,%d,%d]", pPair->second.m_lIndexR, pPair->second.m_lFaceIndexR,
pPair->second.m_lIndexI, pPair->second.m_lFaceIndexI,
pPair->second.m_lIndexB, pPair->second.m_lFaceIndexB,
pPair->second.m_lIndexBI, pPair->second.m_lFaceIndexBI);
std::string sBuffer(buffer);
oWriterJS += L"[\"";
oWriterJS += pPair->second.m_sName;
oWriterJS += NSFile::CUtf8Converter::GetUnicodeFromCharPtr(sBuffer);
if (index != (nCountFonts - 1))
oWriterJS += (L",\n");
else
oWriterJS += (L"\n");
arrNames.push_back(pPair->second.m_sName);
}
oWriterJS += (L"];\n\n");
if (true)
{
BYTE* pData = NULL;
LONG lLen = 0;
applicationFonts.GetList()->ToBuffer(&pData, &lLen, L"", true);
char* cData64 = NULL;
int nData64Dst = 0;
NSFile::CBase64Converter::Encode(pData, (int)lLen, cData64, nData64Dst, NSBase64::B64_BASE64_FLAG_NOCRLF);
std::wstring sData64 = NSFile::CUtf8Converter::GetUnicodeFromCharPtr(cData64, (LONG)nData64Dst, FALSE);
oWriterJS += (L"window[\"g_fonts_selection_bin\"] = \"");
oWriterJS += sData64;
oWriterJS += L"\";\n";
RELEASEARRAYOBJECTS(pData);
RELEASEARRAYOBJECTS(cData64);
}
}
return arrNames;
}
class CStreamReader
{
private:
BYTE* Data;
BYTE* DataEnd;
BYTE* DataCur;
public:
CStreamReader()
{
Data = NULL;
DataEnd = NULL;
DataCur = NULL;
}
CStreamReader(BYTE* pData, unsigned int nSize)
{
Data = pData;
DataEnd = Data + nSize;
DataCur = Data;
}
inline bool IsNoEnd()
{
return (DataCur < DataEnd);
}
inline void Skip(int count)
{
DataCur += count;
}
inline BYTE* GetCur()
{
return DataCur;
}
inline int GetInt32()
{
#ifdef _ARM_ALIGN_
int ret = 0;
memcpy(&ret, DataCur, sizeof(int));
DataCur += 4;
return ret;
#else
int ret = *((int*)DataCur);
DataCur += 4;
return ret;
#endif
}
inline BYTE GetUChar()
{
BYTE ret = *DataCur;
++DataCur;
return ret;
}
inline std::string GetString1()
{
int nLen = GetInt32();
if (0 == nLen)
return "";
std::string s((char*)DataCur, nLen);
DataCur += nLen;
return s;
}
};
}
CApplicationFontsWorker::CApplicationFontsWorker()
{
}
CApplicationFontsWorker::~CApplicationFontsWorker()
{
}
std::vector<std::wstring> CApplicationFontsWorker::CheckApplication(bool bIsNeedSystemFonts,
unsigned char* pDataSrc, unsigned int nLenSrc,
unsigned char*& pDataDst, unsigned int& nLenDst)
{
std::vector<std::wstring> arrNames;
CArray<std::wstring> fonts;
CApplicationFonts oFonts;
pDataDst = NULL;
nLenDst = 0;
if (bIsNeedSystemFonts)
{
fonts = oFonts.GetSetupFontFiles();
}
for (std::vector<std::wstring>::iterator iter = m_arAdditionalFolders.begin(); iter != m_arAdditionalFolders.end(); ++iter)
{
NSDirectory::GetFiles2(*iter, fonts);
}
if (NULL != pDataSrc)
{
// проверяем, поменялось ли чего
NSFontsApplication::CStreamReader oReader(pDataSrc, nLenSrc);
int nLenAllFonts = oReader.GetInt32();
oReader.Skip(nLenAllFonts);
CArray<std::wstring> arrOld;
int nCountCache = oReader.GetInt32();
for (int i = 0; i < nCountCache; ++i)
{
int nLen = oReader.GetInt32();
arrOld.Add(NSFile::CUtf8Converter::GetUnicodeStringFromUTF8(oReader.GetCur(), (LONG)nLen));
oReader.Skip(nLen);
}
if (fonts.GetCount() == arrOld.GetCount())
{
int nCountFonts = fonts.GetCount();
bool bIsBreak = false;
for (int i = 0 ; i < nCountFonts; ++i)
{
if (fonts[i] != arrOld[i])
{
bIsBreak = true;
break;
}
}
if (bIsBreak)
{
// ничего не поменялось
int nCountNames = oReader.GetInt32();
for (int i = 0; i < nCountNames; ++i)
{
int nLen = oReader.GetInt32();
arrNames.push_back(NSFile::CUtf8Converter::GetUnicodeStringFromUTF8(oReader.GetCur(), (LONG)nLen));
oReader.Skip(nLen);
}
return arrNames;
}
}
}
// произошли изменения
oFonts.InitializeFromArrayFiles(fonts);
NSFontsApplication::CStringWriter oWriterJS;
arrNames = NSFontsApplication::SaveAllFontsJS(oFonts, oWriterJS);
// теперь нужно записать новую дату
NSMemoryStream::CMemoryStream oStream;
std::string sAllFontsJS = NSFile::CUtf8Converter::GetUtf8StringFromUnicode2(oWriterJS.GetBuffer(), (LONG)oWriterJS.GetCurSize());
oStream.WriteStringA2(sAllFontsJS.c_str(), (int)sAllFontsJS.length());
int nCountF = fonts.GetCount();
oStream.WriteLONG((LONG)nCountF);
for (int i = 0; i < nCountF; ++i)
{
std::string sTmp = NSFile::CUtf8Converter::GetUtf8StringFromUnicode(fonts[i]);
oStream.WriteStringA2(sTmp.c_str(), (int)sTmp.length());
}
nCountF = (int)arrNames.size();
oStream.WriteLONG((LONG)nCountF);
for (std::vector<std::wstring>::iterator iter = arrNames.begin(); iter != arrNames.end(); ++iter)
{
std::string sTmp = NSFile::CUtf8Converter::GetUtf8StringFromUnicode(*iter);
oStream.WriteStringA2(sTmp.c_str(), (int)sTmp.length());
}
nLenDst = (unsigned int)oStream.GetSize();
pDataDst = new unsigned char[nLenDst];
memcpy(pDataDst, oStream.GetData(), (size_t)nLenDst);
return arrNames;
}
#ifndef _BUILD_APPLICATIONFONTSWORKER_H_
#define _BUILD_APPLICATIONFONTSWORKER_H_
#include <string>
#include <vector>
class CApplicationFontsWorker
{
public:
std::vector<std::wstring> m_arAdditionalFolders;
public:
CApplicationFontsWorker();
~CApplicationFontsWorker();
std::vector<std::wstring> CheckApplication(bool bIsNeedSystemFonts,
unsigned char* pDataSrc, unsigned int nLenSrc,
unsigned char*& pDataDst, unsigned int& nLenDst);
};
#endif // _BUILD_APPLICATIONFONTSWORKER_H_
#include "ApplicationFonts.h"
#include "../common/Directory.h"
#ifdef BOOL
#undef BOOL
#endif
#ifdef _IOS
#import <UIKit/UIKit.h>
CArray<std::wstring> CApplicationFonts::GetSetupFontFiles_ios()
{
CArray<std::wstring> oArray;
NSDirectory::GetFiles2(L"/System/Library/Fonts", oArray, true);
if (oArray.GetCount() == 0)
{
NSDirectory::GetFiles2(L"/Library/Fonts", oArray, true);
}
return oArray;
}
namespace NSDirectory
{
void GetFiles2_ios(std::wstring strDirectory, CArray<std::wstring>& oArray, bool bIsRecursion)
{
NSString* directoryPath = [ [ NSString alloc ]
initWithBytes : (char*)strDirectory.data()
length : strDirectory.size() * sizeof(wchar_t)
encoding : CFStringConvertEncodingToNSStringEncoding ( kCFStringEncodingUTF32LE ) ];
int count;
NSArray* directoryContent = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:directoryPath error:NULL];
for (count = 0; count < (int)[directoryContent count]; count++)
{
NSStringEncoding pEncode = CFStringConvertEncodingToNSStringEncoding ( kCFStringEncodingUTF32LE );
NSData* pSData = [[ directoryContent objectAtIndex:count] dataUsingEncoding : pEncode ];
std::wstring sTmp( (wchar_t*) [ pSData bytes ], [ pSData length] / sizeof ( wchar_t ) );
oArray.Add(sTmp);
}
}
}
#endif
#include "FontManager.h"
#include "internal/internal.h"
#include "internal/ftobjs.h"
#include "../common/Types.h"
#ifndef max
#define max(a,b) (((a) > (b)) ? (a) : (b))
#endif
#ifndef min
#define min(a,b) (((a) < (b)) ? (a) : (b))
#endif
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(true);
}
void CFontFile::ClearCacheNoAttack(bool bIsFree)
{
m_oCacheSizes.Clear(bIsFree);
::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 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::UpdateStyles(const INT& bBold, const INT& bItalic)
{
std::string sStyle = GetStyleName();
// Смотрим какой стиль у исходного шрифта
INT bSrcBold = (-1 != sStyle.find("Bold"));
INT 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 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::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 )
{
#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;
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();
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;
}
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)
{
// Сначала мы все рассчитываем исходя только из матрицы шрифта 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)
{
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 = 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 );
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;
}
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)
{
// Сначала мы все рассчитываем исходя только из матрицы шрифта 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);
pCurGlyph->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;
}
INT 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);
pCurGlyph->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;
}
pCurGlyph->oMetrics = oSizes.oMetrics;
pCurGlyph->bBitmap = oSizes.bBitmap;
pCurGlyph->oBitmap = oSizes.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);
}
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;
}
#ifndef _BUILD_FONT_ENGINE_FONTFILE_H_
#define _BUILD_FONT_ENGINE_FONTFILE_H_
// freetype
#include <ft2build.h>
#include FT_OUTLINE_H
#include FT_SIZES_H
#include FT_GLYPH_H
#include FT_TRUETYPE_IDS_H
#include FT_TRUETYPE_TABLES_H
#include FT_XFREE86_H
#include FT_ADVANCES_H
#include "FontPath.h"
#include "GlyphString.h"
//-------------------------------------------------------------------------------------------------------------------------------
// TODO: RasterHeep
//-------------------------------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------------------------------
// TODO: TFontCacheSizes
//-------------------------------------------------------------------------------------------------------------------------------
class TFontCacheSizes
{
public:
int ushUnicode; // Значение символа в юникоде
EGlyphState eState; // Есть ли символ в шрифте/стандартном шрифте
int nCMapIndex; // Номер таблицы 'cmap', в которой был найден данный символ
USHORT ushGID;
float fAdvanceX;
TBBox oBBox;
TMetrics oMetrics;
bool bBitmap;
TGlyphBitmap oBitmap;
public:
TFontCacheSizes()
{
fAdvanceX = 0;
}
~TFontCacheSizes()
{
}
};
class CFontCacheSizes
{
public:
CFontCacheSizes()
{
}
~CFontCacheSizes()
{
}
inline void Init()
{
m_arrSizes.RemoveAll();
}
inline void Clear(bool bIsFree = false)
{
if (bIsFree)
{
int nCount = m_arrSizes.GetCount();
for (int i = 0; i < nCount; ++i)
{
m_arrSizes[i].oBitmap.bFreeData = TRUE;
}
}
m_arrSizes.RemoveAll();
}
int Add(const TFontCacheSizes& oSizes)
{
m_arrSizes.Add( oSizes );
return m_arrSizes.GetSize() - 1;
}
inline TFontCacheSizes& Get(int nIndex)
{
return m_arrSizes[nIndex];
}
const TFontCacheSizes& operator[] (int nIndex) const
{
return m_arrSizes[nIndex];
}
TFontCacheSizes& operator[] (int nIndex)
{
return m_arrSizes[nIndex];
}
private:
CArray<TFontCacheSizes> m_arrSizes;
};
#define LOAD_MODE FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT | FT_LOAD_NO_BITMAP | FT_LOAD_LINEAR_DESIGN
#define REND_MODE FT_RENDER_MODE_NORMAL
#define FONT_ITALIC_ANGLE 0.3090169943749 // Синус 18 градусов (подбиралось под Word 2007)
#define MAX_UNICODE_VALUE 0x10FFFF
#define MAX_UNICODE_COUNT 0x110000
#define MAX_UNICODE_COUNT2 0x220000
#define FONT_CASHE_SIZES_SIZE 255
#define FONT_CACHE_SIZES_INDEXES_SIZE MAX_UNICODE_COUNT
#define FONT_CACHE_SIZES_INDEXES_SIZE_2 MAX_UNICODE_COUNT2 // MAX_UNICODE_COUNT * sizeof(unsigned short)
class CFontStream;
class CFontManager;
class CFontFile
{
public:
double m_arrdFontMatrix[6];
double m_arrdTextMatrix[6];
bool m_bAntiAliasing;
bool m_bUseKerning;
double m_dSize; // Размер шрифта
UINT m_unHorDpi; // Горизонтальное разрешение
UINT m_unVerDpi; // Вертикальное разрешение
INT m_bNeedDoItalic;
INT m_bNeedDoBold;
double m_dCharSpacing;
int m_nMinX; //
int m_nMinY; // Glyph BBox
int m_nMaxX; //
int m_nMaxY; //
CFontStream* m_pStream;
std::wstring m_sFileName;
int m_lFaceIndex;
FT_Face m_pFace;
double m_dUnitsKoef;
int m_nDefaultChar;
int m_nSymbolic;
double m_dTextScale;
INT m_bStringGID;
FT_Matrix m_oFontMatrix;
FT_Matrix m_oTextMatrix;
int m_nNum_charmaps;
int m_lAscender;
int m_lDescender;
int m_lLineHeight;
int m_lUnits_Per_Em;
// cache
CFontCacheSizes m_oCacheSizes;
// вот так экономим память. нету пока таких шрифтов, в которых глифов больше 0xFFFF
USHORT m_arrCacheSizesIndexs[FONT_CACHE_SIZES_INDEXES_SIZE];
INT m_bUseDefaultFont;
CFontFile* m_pDefaultFont;
INT m_bIsNeedUpdateMatrix12;
CFontManager* m_pFontManager;
INT m_bHintsSupport;
public:
CFontFile();
~CFontFile();
void SetDefaultFont(CFontFile* pDefFont);
void LoadDefaultCharAndSymbolicCmapIndex();
void ResetFontMatrix();
void ResetTextMatrix();
void CheckTextMatrix();
void UpdateMatrix0();
void UpdateMatrix1();
void UpdateMatrix2();
void SetSizeAndDpi(double dSize, UINT unHorDpi, UINT unVerDpi);
void ClearCache();
void ClearCacheNoAttack(bool bIsFree = false);
void Destroy();
bool SetTextMatrix(const double& fA, const double& fB, const double& fC, const double fD, double fE, double fF);
void SetFontMatrix(const double& fA, const double& fB, const double& fC, const double fD, double fE, double fF);
INT GetString(CGlyphString& oString);
INT GetString2(CGlyphString& oString);
INT GetString2C(CGlyphString& oString);
TFontCacheSizes GetChar(LONG lUnicode);
void AddToSizesCache(const TFontCacheSizes& oSizes);
int SetCMapForCharCode(long lUnicode, int *pnCMapIndex);
int SetCMapForCharCode2(long lUnicode);
int GetKerning(FT_UInt unPrevGID, FT_UInt unGID);
void SetStringGID(const INT& bGID);
INT GetStringGID();
void SetUseDefaultFont(const INT& bUse);
INT GetUseDefaultFont();
void SetCharSpacing(const double& dCharSpacing);
double GetCharSpacing();
std::string GetStyleName();
void UpdateStyles(const INT& bBold, const INT& bItalic);
void SetItalic(const INT& value);
void SetNeedBold(const INT& value);
int GetAscender();
int GetDescender();
int GetHeight();
int Units_Per_Em();
void CheckHintsSupport();
// path
CFontPath* GetGlyphPath(int nCode);
};
//-------------------------------------------------------------------------------------------------------------------------------
struct TFreeTypeFontPath
{
CFontPath* pPath;
INT bNeedClose;
};
static int GlyphPathMoveTo(const FT_Vector *pPoint, void *pPath);
static int GlyphPathLineTo(const FT_Vector *pPoint, void *pPath);
static int GlyphPathConicTo(const FT_Vector *pControlPoint, const FT_Vector *pEndPoint, void *pPath);
static int GlyphPathCubicTo(const FT_Vector *pFirstControlPoint, const FT_Vector *pSecondControlPoint, const FT_Vector *pEndPoint, void *pPath);
#endif // _BUILD_FONT_ENGINE_FONTFILE_H_
\ No newline at end of file
#include "ApplicationFonts.h"
#include "../common/File.h"
#include <stdio.h>
#include "ftsnames.h"
///////////////////////////////////////////////////////////////////////////////////////////////////////
CFontStream::CFontStream()
{
m_pData = NULL;
m_lSize = 0;
m_lRef = 1;
m_bIsAttach = false;
}
CFontStream::~CFontStream()
{
if (!m_bIsAttach)
RELEASEARRAYOBJECTS(m_pData);
}
int CFontStream::AddRef()
{
++m_lRef;
return m_lRef;
}
int CFontStream::Release()
{
int ret = --m_lRef;
if (0 == m_lRef)
delete this;
return ret;
}
INT CFontStream::CreateFromFile(const std::wstring& strFileName, BYTE* pDataUse)
{
NSFile::CFileBinary oFile;
if (!oFile.OpenFile(strFileName))
return FALSE;
m_lSize = oFile.GetFileSize();
if (NULL == pDataUse)
m_pData = new BYTE[m_lSize];
else
{
m_bIsAttach = true;
m_pData = pDataUse;
}
DWORD dwRead = 0;
DWORD dwNeedRead = (DWORD)m_lSize;
oFile.ReadFile(m_pData, dwNeedRead, dwRead);
if (dwNeedRead != dwRead)
{
if (!m_bIsAttach)
RELEASEARRAYOBJECTS(m_pData);
m_lSize = 0;
return FALSE;
}
oFile.CloseFile();
return true;
}
CApplicationFontStreams::CApplicationFontStreams()
{
}
CApplicationFontStreams::~CApplicationFontStreams()
{
for (std::map<std::wstring, CFontStream*>::iterator iter = m_mapStreams.begin(); iter != m_mapStreams.end(); ++iter)
{
CFontStream* pFile = iter->second;
RELEASEOBJECT(pFile);
}
}
CFontStream* CApplicationFontStreams::GetStream(const std::wstring &strFile)
{
CFontStream* pStream = m_mapStreams[strFile];
if (NULL != pStream)
return pStream;
pStream = new CFontStream();
pStream->CreateFromFile(strFile);
m_mapStreams[strFile] = pStream;
return pStream;
}
void CApplicationFontStreams::CheckStreams(std::map<std::wstring,bool> &mapFiles)
{
// TODO:
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
CFontFile* CFontManager::LoadFontFile(FT_Library library, CFontStream* pStream, LONG lFaceIndex)
{
FT_Open_Args oOpenArgs;
oOpenArgs.flags = FT_OPEN_MEMORY | FT_OPEN_PARAMS;
oOpenArgs.memory_base = pStream->m_pData;
oOpenArgs.memory_size = pStream->m_lSize;
FT_Parameter *pParams = (FT_Parameter *)::malloc( sizeof(FT_Parameter) * 4 );
pParams[0].tag = FT_MAKE_TAG( 'i', 'g', 'p', 'f' );
pParams[0].data = NULL;
pParams[1].tag = FT_MAKE_TAG( 'i', 'g', 'p', 's' );
pParams[1].data = NULL;
pParams[2].tag = FT_PARAM_TAG_IGNORE_PREFERRED_FAMILY;
pParams[2].data = NULL;
pParams[3].tag = FT_PARAM_TAG_IGNORE_PREFERRED_SUBFAMILY;
pParams[3].data = NULL;
oOpenArgs.params = pParams;
oOpenArgs.num_params = 4;
FT_Face pFace;
if ( FT_Open_Face( library, &oOpenArgs, lFaceIndex, &pFace ) )
return NULL;
::free(pParams);
CFontFile* pFont = new CFontFile();
pFont->m_lFaceIndex = lFaceIndex;
pFont->m_lUnits_Per_Em = pFace->units_per_EM;
pFont->m_lAscender = pFace->ascender;
pFont->m_lDescender = pFace->descender;
pFont->m_lLineHeight = pFace->height;
pFont->m_nNum_charmaps = pFace->num_charmaps;
pFont->m_pFace = pFace;
pFont->LoadDefaultCharAndSymbolicCmapIndex();
if (FT_Set_Char_Size(pFace, 0, (FT_F26Dot6)(pFont->m_dSize * 64), 0, 0))
{
FT_Done_Face(pFace);
delete pFont;
return NULL;
}
pFont->ResetTextMatrix();
pFont->ResetFontMatrix();
return pFont;
}
CFontFile* CFontsCache::LockFont(FT_Library library, const std::wstring& strFileName, const LONG& lFaceIndex, const double& dSize)
{
if (NULL == m_pApplicationFontStreams)
return NULL;
std::string sLock = NSFile::CUtf8Converter::GetUtf8StringFromUnicode2(strFileName.c_str(), strFileName.length(), false);
char buffer[50];
sprintf(buffer, "%d_%.2lf", lFaceIndex, dSize);
std::string s(buffer);
sLock += s;
CFontFile* pFile = m_mapFiles[sLock];
if (NULL != pFile)
return pFile;
CFontStream* pStream = m_pApplicationFontStreams->GetStream(strFileName);
pFile = CFontManager::LoadFontFile(library, pStream, lFaceIndex);
if (NULL == pFile)
return NULL;
pFile->m_pStream = pStream;
pFile->m_pStream->AddRef();
m_mapFiles[sLock] = pFile;
return pFile;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
CFontManager::CFontManager()
{
m_pLibrary = NULL;
FT_Init_FreeType(&m_pLibrary);
m_pFont = NULL;
m_pApplication = NULL;
m_pOwnerCache = NULL;
m_bStringGID = FALSE;
m_nLOAD_MODE = 40968;
m_lRef = 1;
m_bUseDefaultFont = FALSE;
m_fCharSpacing = 0;
m_lUnits_Per_Em = 0;
m_lAscender = 0;
m_lDescender = 0;
m_lLineHeight = 0;
}
CFontManager::~CFontManager()
{
if (m_pLibrary)
{
FT_Done_FreeType(m_pLibrary);
}
RELEASEOBJECT(m_pOwnerCache);
}
void CFontManager::SetOwnerCache(CFontsCache* pCache)
{
m_pOwnerCache = pCache;
}
void CFontManager::AfterLoad()
{
if (NULL == m_pFont)
{
m_lUnits_Per_Em = 0;
m_lAscender = 0;
m_lDescender = 0;
m_lLineHeight = 0;
}
else
{
m_lUnits_Per_Em = m_pFont->m_lUnits_Per_Em;
m_lAscender = m_pFont->m_lAscender;
m_lDescender = m_pFont->m_lDescender;
m_lLineHeight = m_pFont->m_lLineHeight;
m_pFont->CheckHintsSupport();
}
}
void CFontManager::Initialize()
{
}
double CFontManager::UpdateSize(const double &dOldSize, const double &dDpi, const double &dNewDpi)
{
if (0 == dNewDpi && 0 == dDpi)
return dOldSize;
else if (0 == dNewDpi)
return dOldSize * dDpi / 72.0;
else if (0 == dDpi)
return dOldSize * 72.0 / dNewDpi;
return dOldSize * dDpi / dNewDpi;
}
INT CFontManager::LoadString1(const std::wstring &wsBuffer, const float &fX, const float &fY)
{
if (NULL == m_pFont)
return FALSE;
m_oString.SetString(wsBuffer, fX, fY);
m_pFont->GetString(m_oString);
return TRUE;
}
INT CFontManager::LoadString2(const std::wstring &wsBuffer, const float &fX, const float &fY)
{
if (NULL == m_pFont)
return FALSE;
m_oString.SetString(wsBuffer, fX, fY);
m_pFont->GetString2(m_oString);
return TRUE;
}
INT CFontManager::LoadString3(const LONG& gid, const float &fX, const float &fY)
{
if (NULL == m_pFont)
return FALSE;
SetStringGID(TRUE);
m_oString.SetStringGID(gid, fX, fY);
m_pFont->GetString2(m_oString);
SetStringGID(FALSE);
return TRUE;
}
INT CFontManager::LoadString3C(const LONG& gid, const float &fX, const float &fY)
{
if (NULL == m_pFont)
return FALSE;
SetStringGID(TRUE);
m_oString.SetStringGID(gid, fX, fY);
m_pFont->GetString2C(m_oString);
SetStringGID(FALSE);
return TRUE;
}
INT CFontManager::LoadString2C(const LONG& code, const float &fX, const float &fY)
{
if (NULL == m_pFont)
return FALSE;
m_oString.SetStringGID(code, fX, fY);
m_pFont->GetString2C(m_oString);
return TRUE;
}
TFontCacheSizes CFontManager::MeasureChar(const LONG &lUnicode)
{
if (NULL == m_pFont)
{
TFontCacheSizes oRet;
return oRet;
}
return m_pFont->GetChar(lUnicode);
}
int CFontManager::GetKerning(UINT unPrevGID, UINT unGID)
{
if (NULL == m_pFont)
return 0;
return m_pFont->GetKerning(unPrevGID, unGID);
}
INT CFontManager::GetUnderline(float *pfStartX, float *pfStartY, float *pfEndX, float *pfEndY, float *pfSize)
{
if ( m_oString.GetLength() <= 0 || !m_pFont )
{
*pfStartX = 0;
*pfStartY = 0;
*pfEndX = 0;
*pfEndY = 0;
*pfSize = 0;
return FALSE;
}
float fStartX = m_oString.m_fX;
float fStartY = m_oString.m_fY;
float fEndX = m_oString.m_fEndX;
float fEndY = m_oString.m_fEndY;
short shUnderlinePos = m_pFont->m_pFace->underline_position;
short shUnderlineSize = m_pFont->m_pFace->underline_thickness;
float fKoef = (float)(m_pFont->m_dSize / 1000 * m_pFont->m_unVerDpi / 72.0f);
float fUnderlinePos = shUnderlinePos * fKoef;
float fUnderLineSize = shUnderlineSize * fKoef;
fStartY -= fUnderlinePos;
fEndY -= fUnderlinePos;
m_oString.Transform( &fStartX, &fStartY );
m_oString.Transform( &fEndX, &fEndY );
*pfStartX = fStartX;
*pfStartY = fStartY;
*pfEndX = fEndX;
*pfEndY = fEndY;
*pfSize = fUnderLineSize;
return TRUE;
}
TBBox CFontManager::MeasureString()
{
TBBox oBox;
oBox.fMinX = 0xFFFF;
oBox.fMinY = 0xFFFF;
oBox.fMaxX = -0xFFFF;
oBox.fMaxY = -0xFFFF;
int nLen = m_oString.GetLength();
if (nLen <= 0)
return oBox;
for (int nIndex = 0; nIndex < nLen; ++nIndex)
{
float fT, fB, fL, fR;
m_oString.GetBBox(&fL, &fT, &fR, &fB, nIndex);
if (oBox.fMaxX < fB)
oBox.fMaxX = fB;
if (oBox.fMinY > fT)
oBox.fMinY = fT;
if (oBox.fMinX > fL)
oBox.fMinX = fL;
if (oBox.fMaxX < fR)
oBox.fMaxX = fR;
}
return oBox;
}
TBBox CFontManager::MeasureString2()
{
TBBox oBox;
oBox.fMinX = 0;
oBox.fMinY = 0;
oBox.fMaxX = 0;
oBox.fMaxY = 0;
int nLen = m_oString.GetLength();
if (nLen <= 0)
return oBox;
m_oString.GetBBox2(&oBox.fMinX, &oBox.fMinY, &oBox.fMaxX, &oBox.fMaxY);
return oBox;
}
INT CFontManager::GetNextChar2(TGlyph*& pGlyph, float& fX, float& fY)
{
if (!m_oString.GetNext(pGlyph))
return FALSE;
if (glyphstateNormal == pGlyph->eState || (glyphstateDeafault == pGlyph->eState && NULL != m_pFont->m_pDefaultFont))
{
fX = m_oString.m_fX + pGlyph->fX + pGlyph->oBitmap.nX;
fY = m_oString.m_fY + pGlyph->fY - pGlyph->oBitmap.nY;
}
else
{
fX = m_oString.m_fX + pGlyph->fX;
fY = m_oString.m_fY + pGlyph->fY;
}
return TRUE;
}
INT CFontManager::SetTextMatrix(const double &fA, const double &fB, const double &fC, const double &fD, const double &fE, const double &fF)
{
if (NULL == m_pFont)
return FALSE;
if (fabs(fB) > 0.1)
{
int y = 0;
++y;
}
/*
if (m_pFont->SetTextMatrix(fA, fB, fC, fD, 0, 0))
m_oString.SetCTM((float)fA, (float)fB, (float)fC, (float)fD, 0, 0);
*/
m_pFont->SetTextMatrix(fA, fB, fC, fD, 0, 0);
m_oString.SetCTM((float)fA, (float)fB, (float)fC, (float)fD, 0, 0);
m_oString.SetTrans((float)fE, (float)fF);
return TRUE;
}
INT CFontManager::SetTextMatrix2(const double &fA, const double &fB, const double &fC, const double &fD, const double &fE, const double &fF)
{
if (NULL == m_pFont)
return FALSE;
m_pFont->SetTextMatrix(fA, fB, fC, fD, 0, 0);
m_oString.SetCTM((float)fA, (float)fB, (float)fC, (float)fD, 0, 0);
m_oString.SetTrans((float)fE, (float)fF);
return TRUE;
}
void CFontManager::SetStringGID(const INT &bStringGID)
{
m_bStringGID = bStringGID;
if (NULL == m_pFont)
return;
m_pFont->SetStringGID(m_bStringGID);
}
void CFontManager::SetCharSpacing(const double &dCharSpacing)
{
m_fCharSpacing = dCharSpacing;
if (NULL == m_pFont)
return;
m_pFont->SetCharSpacing(m_fCharSpacing);
}
INT CFontManager::GetStringPath(ISimpleGraphicsPath* pInterface)
{
if (NULL == pInterface)
return FALSE;
int nCount = m_oString.GetLength();
if ( !m_pFont || nCount <= 0 )
return FALSE;
CFontPath* pOverallPath = new CFontPath();
if (!pOverallPath)
return FALSE;
for (int nIndex = 0; nIndex < nCount; ++nIndex)
{
TGlyph* pCurGlyph = m_oString.GetAt(nIndex);
CFontPath* pPath = NULL;
if (glyphstateNormal == pCurGlyph->eState || (glyphstateDeafault == pCurGlyph->eState && NULL != m_pFont->m_pDefaultFont))
{
if (glyphstateNormal == pCurGlyph->eState)
{
pPath = m_pFont->GetGlyphPath(pCurGlyph->lUnicode);
}
else
{
pPath = m_pFont->m_pDefaultFont->GetGlyphPath(pCurGlyph->lUnicode);
}
}
if (!pPath)
continue;
pPath->Reverse();
pPath->ToMM(m_pFont->m_unHorDpi, m_pFont->m_unVerDpi);
pPath->Offset((pCurGlyph->fX * 25.4 * m_pFont->m_unHorDpi) + m_oString.m_fX,
(pCurGlyph->fY * 25.4 * m_pFont->m_unVerDpi) + m_oString.m_fY);
pOverallPath->Append(pPath);
delete pPath;
}
pOverallPath->ToInterface(pInterface);
delete pOverallPath;
return TRUE;
}
int CFontManager::AddRef()
{
++m_lRef;
return m_lRef;
}
int CFontManager::Release()
{
int ret = --m_lRef;
if (0 == m_lRef)
delete this;
return ret;
}
CFontInfo* CFontManager::GetFontInfoByParams(CFontSelectFormat& oFormat)
{
CFontInfo* pRes = NULL;
if (NULL != m_pApplication)
{
pRes = m_pApplication->GetList()->GetByParams(oFormat);
}
return pRes;
}
CArray<CFontInfo*> CFontManager::GetAllStylesByFontName(const std::wstring& strName)
{
CArray<CFontInfo*> aRes;
if (NULL != m_pApplication)
aRes = m_pApplication->GetList()->GetAllByName(strName);
return aRes;
}
INT CFontManager::LoadFontByName(const std::wstring& sName, const double& dSize, const LONG& lStyle, const double& dDpiX, const double& dDpiY)
{
if (NULL == m_pApplication)
return FALSE;
CFontSelectFormat oFormat;
oFormat.wsName = new std::wstring(sName);
oFormat.bBold = new INT(FALSE);
oFormat.bItalic = new INT(FALSE);
if (lStyle & 0x01)
*oFormat.bBold = TRUE;
if (lStyle & 0x02)
*oFormat.bItalic = TRUE;
CFontInfo* pInfo = m_pApplication->GetList()->GetByParams(oFormat);
if (NULL == pInfo)
return FALSE;
return LoadFontFromFile(pInfo->m_wsFontPath, pInfo->m_lIndex, dSize, dDpiX, dDpiY);
}
INT CFontManager::LoadFontFromFile(const std::wstring& sPath, const int& lFaceIndex, const double& dSize, const double& dDpiX, const double& dDpiY)
{
if (NULL == m_pApplication)
return FALSE;
CFontsCache* pCache = (m_pOwnerCache != NULL) ? m_pOwnerCache : m_pApplication->GetCache();
m_pFont = pCache->LockFont(m_pLibrary, sPath, lFaceIndex, dSize);
m_pFont->m_pFontManager = this;
m_pFont->SetSizeAndDpi(dSize, (UINT)dDpiX, (UINT)dDpiY);
return TRUE;
}
INT CFontManager::LoadFontFromFile2(CFontsCache* pCache, const std::wstring& sPath, const int& lFaceIndex, const double& dSize, const double& dDpiX, const double& dDpiY)
{
if (NULL == pCache)
return FALSE;
m_pFont = pCache->LockFont(m_pLibrary, sPath, lFaceIndex, dSize);
m_pFont->m_pFontManager = this;
m_pFont->SetSizeAndDpi(dSize, (UINT)dDpiX, (UINT)dDpiY);
return TRUE;
}
#ifndef _BUILD_FONT_ENGINE_FONTMANAGER_H_
#define _BUILD_FONT_ENGINE_FONTMANAGER_H_
#include "FontFile.h"
#include <map>
class CFontSelectFormat;
class CFontInfo;
class CFontStream
{
private:
int m_lRef;
public:
BYTE* m_pData;
LONG m_lSize;
bool m_bIsAttach;
public:
CFontStream();
virtual ~CFontStream();
virtual int AddRef();
virtual int Release();
public:
virtual INT CreateFromFile(const std::wstring& strFileName, BYTE* pDataUse = NULL);
};
class CApplicationFontStreams
{
private:
// этот мап нужно периодически опрашивать и удалять неиспользуемые стримы
std::map<std::wstring, CFontStream*> m_mapStreams;
public:
CApplicationFontStreams();
~CApplicationFontStreams();
public:
CFontStream* GetStream(const std::wstring& strFile);
void CheckStreams(std::map<std::wstring, bool>& mapFiles);
};
class CFontsCache
{
friend class CFontManager;
friend class CApplicationFonts;
private:
std::map<std::string, CFontFile*> m_mapFiles;
CApplicationFontStreams* m_pApplicationFontStreams;
public:
CFontsCache()
{
m_pApplicationFontStreams = NULL;
}
~CFontsCache()
{
for (std::map<std::string, CFontFile*>::iterator iter = m_mapFiles.begin(); iter != m_mapFiles.end(); ++iter)
{
CFontFile* pFile = iter->second;
RELEASEOBJECT(pFile);
}
}
public:
inline void SetStreams(CApplicationFontStreams* pStreams) { m_pApplicationFontStreams = pStreams; }
CFontFile* LockFont(FT_Library library, const std::wstring& strFileName, const LONG& lFaceIndex, const double& dSize);
};
class CApplicationFonts;
class CFontManager
{
friend class CApplicationFonts;
private:
int m_lRef;
public:
FT_Library m_pLibrary;
CFontFile* m_pFont;
CGlyphString m_oString;
std::wstring m_sName;
INT m_bUseDefaultFont;
double m_fCharSpacing;
INT m_bStringGID;
int m_lUnits_Per_Em;
int m_lAscender;
int m_lDescender;
int m_lLineHeight;
int m_nLOAD_MODE;
CApplicationFonts* m_pApplication;
CFontsCache* m_pOwnerCache;
public:
CFontManager();
~CFontManager();
public:
void AfterLoad();
void Initialize();
void SetOwnerCache(CFontsCache* pCache);
double UpdateSize(const double& dOldSize, const double& dDpi, const double& dNewDpi);
INT LoadString1(const std::wstring& wsBuffer, const float& fX, const float& fY);
INT LoadString2(const std::wstring& wsBuffer, const float& fX, const float& fY);
INT LoadString3(const LONG& gid, const float& fX, const float& fY);
INT LoadString3C(const LONG& gid, const float& fX, const float& fY);
INT LoadString2C(const LONG& wsBuffer, const float& fX, const float& fY);
int GetKerning(UINT unPrevGID, UINT unGID);
INT GetUnderline(float *pfStartX, float *pfStartY, float *pfEndX, float *pfEndY, float *pfSize);
TFontCacheSizes MeasureChar(const LONG& lUnicode);
TBBox MeasureString();
TBBox MeasureString2();
INT GetNextChar2(TGlyph*& pGlyph, float& fX, float& fY);
INT SetTextMatrix(const double& fA, const double& fB, const double& fC, const double& fD, const double& fE, const double& fF);
INT SetTextMatrix2(const double& fA, const double& fB, const double& fC, const double& fD, const double& fE, const double& fF);
void SetStringGID(const INT& bStringGID);
void SetCharSpacing(const double &dCharSpacing);
INT GetStringPath(ISimpleGraphicsPath* pPath);
// addref/release
virtual int AddRef();
virtual int Release();
CFontInfo* GetFontInfoByParams(CFontSelectFormat& oFormat);
CArray<CFontInfo*> GetAllStylesByFontName(const std::wstring& strName);
INT LoadFontByName(const std::wstring& sName, const double& dSize, const LONG& lStyle, const double& dDpiX, const double& dDpiY);
INT LoadFontFromFile(const std::wstring& sPath, const int& lFaceIndex, const double& dSize, const double& dDpiX, const double& dDpiY);
INT LoadFontFromFile2(CFontsCache* pCache, const std::wstring& sPath, const int& lFaceIndex, const double& dSize, const double& dDpiX, const double& dDpiY);
public:
static CFontFile* LoadFontFile(FT_Library library, CFontStream* pStream, LONG lFaceIndex);
};
#endif // _BUILD_FONT_ENGINE_FONTMANAGER_H_
\ No newline at end of file
#include "FontPath.h"
//-------------------------------------------------------------------------------------------------------------------------------
// CPath
//-------------------------------------------------------------------------------------------------------------------------------
// Path может быть в одном из трех следующий состояний:
//
// 1. Нет текущей точки -- ни одного или более законченных SubPaths
// [m_nCurSubpath == m_nPointsCount]
//
// 2. Одна точка в SubPaths
// [m_nCurSubpath == m_nPointsCount - 1]
//
// 3. Открытый SubPaths c двумя или более точками
// [m_nCurSubpath < m_nPointsCount - 1]
CFontPath::CFontPath()
{
m_pPoints = NULL;
m_pFlags = NULL;
m_nPointsCount = m_nSize = 0;
m_nCurSubpath = 0;
m_pHints = NULL;
m_nHintsCount = m_nHintsSize = 0;
}
CFontPath::CFontPath(CFontPath *pPath)
{
m_nPointsCount = pPath->m_nPointsCount;
m_nSize = pPath->m_nSize;
m_pPoints = (TPathPoint *)malloc( m_nSize * sizeof(TPathPoint) );
m_pFlags = (unsigned char *)malloc( m_nSize * sizeof(unsigned char) );
memcpy( m_pPoints, pPath->m_pPoints, m_nPointsCount * sizeof(TPathPoint) );
memcpy( m_pFlags, pPath->m_pFlags, m_nPointsCount * sizeof(unsigned char) );
m_nCurSubpath = pPath->m_nCurSubpath;
if ( pPath->m_pHints )
{
m_nHintsCount = m_nHintsSize = pPath->m_nHintsCount;
m_pHints = (TPathHint *)malloc( m_nHintsSize * sizeof(TPathHint) );
memcpy( m_pHints, pPath->m_pHints, m_nHintsCount * sizeof(TPathHint) );
}
else
{
m_pHints = NULL;
}
}
CFontPath::~CFontPath()
{
free( m_pPoints );
free( m_pFlags );
free( m_pHints );
}
void CFontPath::Resize(int nPointsCount)
{
if ( m_nPointsCount + nPointsCount > m_nSize )
{
if ( m_nSize == 0 )
{
m_nSize = 32;
}
while ( m_nSize < m_nPointsCount + nPointsCount )
{
m_nSize *= 2;
}
m_pPoints = (TPathPoint *)realloc( m_pPoints, m_nSize * sizeof(TPathPoint) );
m_pFlags = (unsigned char *)realloc( m_pFlags, m_nSize * sizeof(unsigned char) );
}
}
void CFontPath::Append(CFontPath *pPath)
{
m_nCurSubpath = m_nPointsCount + pPath->m_nCurSubpath;
Resize( pPath->m_nPointsCount );
for ( int nIndex = 0; nIndex < pPath->m_nPointsCount; ++nIndex )
{
m_pPoints[m_nPointsCount] = pPath->m_pPoints[nIndex];
m_pFlags[m_nPointsCount] = pPath->m_pFlags[nIndex];
++m_nPointsCount;
}
}
int CFontPath::MoveTo(double dX, double dY)
{
if ( OnePointSubpath() )
{
return -1;
}
Resize(1);
m_pPoints[m_nPointsCount].dX = dX;
m_pPoints[m_nPointsCount].dY = dY;
m_pFlags[m_nPointsCount] = PathFirst | PathLast;
m_nCurSubpath = m_nPointsCount++;
return 0;
}
int CFontPath::LineTo(double dX, double dY)
{
if ( NoCurrentPoint() )
{
return -1;
}
m_pFlags[m_nPointsCount - 1] &= ~PathLast;
Resize(1);
m_pPoints[m_nPointsCount].dX = dX;
m_pPoints[m_nPointsCount].dY = dY;
m_pFlags[m_nPointsCount] = PathLast;
++m_nPointsCount;
return 0;
}
int CFontPath::CurveTo(double dX1, double dY1, double dX2, double dY2, double dX3, double dY3)
{
if ( NoCurrentPoint() )
{
return -1;
}
m_pFlags[m_nPointsCount-1] &= ~PathLast;
Resize(3);
m_pPoints[m_nPointsCount].dX = dX1;
m_pPoints[m_nPointsCount].dY = dY1;
m_pFlags[m_nPointsCount] = PathCurve;
++m_nPointsCount;
m_pPoints[m_nPointsCount].dX = dX2;
m_pPoints[m_nPointsCount].dY = dY2;
m_pFlags[m_nPointsCount] = PathCurve;
++m_nPointsCount;
m_pPoints[m_nPointsCount].dX = dX3;
m_pPoints[m_nPointsCount].dY = dY3;
m_pFlags[m_nPointsCount] = PathLast;
++m_nPointsCount;
return 0;
}
int CFontPath::Close()
{
if ( NoCurrentPoint() )
{
return -1;
}
if ( m_nCurSubpath == m_nPointsCount - 1 || m_pPoints[m_nPointsCount - 1].dX != m_pPoints[m_nCurSubpath].dX || m_pPoints[m_nPointsCount - 1].dY != m_pPoints[m_nCurSubpath].dY )
{
LineTo( m_pPoints[m_nCurSubpath].dX, m_pPoints[m_nCurSubpath].dY );
}
m_pFlags[m_nCurSubpath] |= PathClosed;
m_pFlags[m_nPointsCount - 1] |= PathClosed;
m_nCurSubpath = m_nPointsCount;
return 0;
}
void CFontPath::AddStrokeAdjustHint(int nFirstControl, int nSecondControl, int nFirstPoint, int nLastPoint)
{
if ( m_nHintsCount == m_nHintsSize )
{
m_nHintsSize = m_nHintsCount ? 2 * m_nHintsCount : 8;
m_pHints = (TPathHint *)realloc( m_pHints, m_nHintsSize * sizeof(TPathHint) );
}
m_pHints[m_nHintsCount].nFirstControl = nFirstControl;
m_pHints[m_nHintsCount].nSecondControl = nSecondControl;
m_pHints[m_nHintsCount].nFirstPoint = nFirstPoint;
m_pHints[m_nHintsCount].nLastPoint = nLastPoint;
++m_nHintsCount;
}
void CFontPath::Offset(double dDx, double dDy)
{
for ( int nIndex = 0; nIndex < m_nPointsCount; ++nIndex )
{
m_pPoints[nIndex].dX += dDx;
m_pPoints[nIndex].dY += dDy;
}
}
void CFontPath::Reverse()
{
for ( int nIndex = 0; nIndex < m_nPointsCount; ++nIndex )
{
m_pPoints[nIndex].dY = -m_pPoints[nIndex].dY;
}
}
void CFontPath::ToMM(double dHorDpi, double dVerDpi)
{
for ( int nIndex = 0; nIndex < m_nPointsCount; ++nIndex )
{
m_pPoints[nIndex].dX *= 25.4 / dHorDpi;
m_pPoints[nIndex].dY *= 25.4 / dVerDpi;
}
}
INT CFontPath::GetCurPoint(double *pdX, double *pdY)
{
if ( NoCurrentPoint() )
{
return FALSE;
}
*pdX = m_pPoints[m_nPointsCount - 1].dX;
*pdY = m_pPoints[m_nPointsCount - 1].dY;
return TRUE;
}
INT CFontPath::ToInterface(ISimpleGraphicsPath* pPath)
{
if ( !pPath )
return FALSE;
for ( int nIndex = 0; nIndex < m_nPointsCount; )
{
TPathPoint oPoint = m_pPoints[nIndex];
unsigned char nFlag = m_pFlags[nIndex];
if ( nFlag & PathFirst )
{
pPath->_MoveTo( oPoint.dX, oPoint.dY );
nIndex++;
}
else if ( nFlag & PathCurve )
{
pPath->_CurveTo( m_pPoints[nIndex + 0].dX, m_pPoints[nIndex + 0].dY, m_pPoints[nIndex + 1].dX, m_pPoints[nIndex + 1].dY, m_pPoints[nIndex + 2].dX, m_pPoints[nIndex + 2].dY );
nIndex += 3;
}
else
{
pPath->_LineTo( oPoint.dX, oPoint.dY );
nIndex++;
}
if ( nFlag & PathClosed && nFlag & PathLast )
{
pPath->_Close();
}
}
return TRUE;
}
\ No newline at end of file
#ifndef _PATH_H
#define _PATH_H
#include "../common/Types.h"
#include <memory>
#include <string.h>
#include <stdlib.h>
#include "ftimage.h"
class ISimpleGraphicsPath
{
public:
virtual bool _MoveTo(double x, double y) = 0;
virtual bool _LineTo(double x, double y) = 0;
virtual bool _CurveTo(double x1, double y1, double x2, double y2, double x3, double y3) = 0;
virtual bool _Close() = 0;
};
//-------------------------------------------------------------------------------------------------------------------------------
// TPathPoint
//-------------------------------------------------------------------------------------------------------------------------------
struct TPathPoint
{
double dX;
double dY;
};
//-------------------------------------------------------------------------------------------------------------------------------
// CPath.nFlags
//-------------------------------------------------------------------------------------------------------------------------------
// Флаг для первой точки любого subpath
#define PathFirst 0x01
// Флаг для последней точки любого subpath
#define PathLast 0x02
// Если subpath замкнутый, тогда его последняя и первая точка должны совпадать, их флаг в данном случае следующий
#define PathClosed 0x04
// Флаг, означающий, что данная точка является контрольной для кривой Безье
#define PathCurve 0x08
//-------------------------------------------------------------------------------------------------------------------------------
// TPathHint
//-------------------------------------------------------------------------------------------------------------------------------
struct TPathHint
{
int nFirstControl;
int nSecondControl;
int nFirstPoint;
int nLastPoint;
};
//-------------------------------------------------------------------------------------------------------------------------------
// CFontPath
//-------------------------------------------------------------------------------------------------------------------------------
class CFontPath
{
public:
CFontPath();
~CFontPath();
void Append(CFontPath *pPath);
int MoveTo(double dX, double dY);
int LineTo(double dX, double dY);
int CurveTo(double dX1, double dY1, double dX2, double dY2, double dX3, double dY3);
int Close();
void Offset(double dDx, double dDy);
void Reverse();
void ToMM(double dHorDpi, double dVerDpi);
int GetCount()
{
return m_nPointsCount;
}
void GetPoint(int nIndex, double *pdX, double *pdY, unsigned char *punFlag)
{
*pdX = m_pPoints[nIndex].dX;
*pdY = m_pPoints[nIndex].dY;
*punFlag = m_pFlags[nIndex];
}
INT GetCurPoint(double *pdX, double *pdY);
// Добавляем флаг StrokeAdjust.
void AddStrokeAdjustHint(int nFirstControl, int nSecondControl, int nFirstPoint, int nLastPoint);
INT ToInterface(ISimpleGraphicsPath* pPath);
private:
CFontPath(CFontPath *pPath);
void Resize(int nPointsCount);
INT NoCurrentPoint()
{
return m_nCurSubpath == m_nPointsCount;
}
INT OnePointSubpath()
{
return m_nCurSubpath == m_nPointsCount - 1;
}
INT OpenSubpath()
{
return m_nCurSubpath < m_nPointsCount - 1;
}
private:
TPathPoint *m_pPoints; // Массив точек
unsigned char *m_pFlags; // Массив флагов, указыающих значение точки в SubPath
int m_nPointsCount; // Количество точек
int m_nSize; // Непосредственный размер массива
int m_nCurSubpath; // Номер первой точки последнего SubPath
TPathHint *m_pHints; //
int m_nHintsCount;
int m_nHintsSize;
};
#endif /* _PATH_H */
#include "GlyphString.h"
#include <stdlib.h>
#ifndef max
#define max(a,b) (((a) > (b)) ? (a) : (b))
#endif
#ifndef min
#define min(a,b) (((a) < (b)) ? (a) : (b))
#endif
#ifndef WIN32
#endif
TGlyphBitmap::TGlyphBitmap()
{
nX = 0;
nY = 0;
nWidth = 0;
nHeight = 0;
bAA = FALSE;
pData = NULL;
bFreeData = TRUE;
}
TGlyphBitmap::~TGlyphBitmap()
{
if (bFreeData && pData != NULL)
{
free(pData);
pData = NULL;
}
}
TGlyph::TGlyph()
{
}
TGlyph::~TGlyph()
{
}
////////////////////////////////
CGlyphString::CGlyphString()
{
m_fX = 0;
m_fY = 0;
m_fEndX = 0;
m_fEndY = 0;
m_nGlyphIndex = -1;
m_nGlyphsCount = 0;
m_pGlyphsBuffer = NULL;
m_arrCTM[0] = 1;
m_arrCTM[1] = 0;
m_arrCTM[2] = 0;
m_arrCTM[3] = 1;
m_arrCTM[4] = 0;
m_arrCTM[5] = 0;
m_fTransX = 0;
m_fTransY = 0;
m_dIDet = 1.0;
}
CGlyphString::CGlyphString(const std::wstring& wsString, float fX, float fY)
{
const wchar_t* pWchars = wsString.c_str();
m_nGlyphIndex = 0;
m_nGlyphsCount = wsString.length();
if ( m_nGlyphsCount > 0 )
{
m_pGlyphsBuffer = new TGlyph[m_nGlyphsCount];
if (sizeof(wchar_t) == 2)
{
int nEmpty = 0;
for ( int nIndex = 0; nIndex < m_nGlyphsCount; ++nIndex )
{
int code = (int)pWchars[nIndex];
if (code >= 0xD800 && code <= 0xDFFF && (nIndex + 1) < m_nGlyphsCount)
{
++nIndex;
++nEmpty;
code = 0x10000 + (((code & 0x3FF) << 10) | (0x03FF & pWchars[nIndex]));
}
m_pGlyphsBuffer[nIndex].lUnicode = code;
m_pGlyphsBuffer[nIndex].bBitmap = false;
}
m_nGlyphsCount -= nEmpty;
}
else
{
for ( int nIndex = 0; nIndex < m_nGlyphsCount; ++nIndex )
{
m_pGlyphsBuffer[nIndex].lUnicode = (long)pWchars[nIndex];
m_pGlyphsBuffer[nIndex].bBitmap = false;
}
}
}
else
{
m_pGlyphsBuffer = NULL;
}
m_fX = fX;
m_fY = fY;
m_arrCTM[0] = 1;
m_arrCTM[1] = 0;
m_arrCTM[2] = 0;
m_arrCTM[3] = 1;
m_arrCTM[4] = 0;
m_arrCTM[5] = 0;
m_fTransX = 0;
m_fTransY = 0;
}
CGlyphString::~CGlyphString()
{
if ( m_pGlyphsBuffer )
delete []m_pGlyphsBuffer;
}
void CGlyphString::SetString(const std::wstring& wsString, float fX, float fY)
{
m_fX = fX + m_fTransX;
m_fY = fY + m_fTransY;
if ( m_pGlyphsBuffer )
delete []m_pGlyphsBuffer;
const wchar_t* pWchars = wsString.c_str();
m_nGlyphIndex = 0;
m_nGlyphsCount = wsString.length();
if ( m_nGlyphsCount > 0 )
{
m_pGlyphsBuffer = new TGlyph[m_nGlyphsCount];
if (sizeof(wchar_t) == 2)
{
int nEmpty = 0;
for ( int nIndex = 0; nIndex < m_nGlyphsCount; ++nIndex )
{
int code = (int)pWchars[nIndex];
if (code >= 0xD800 && code <= 0xDFFF && (nIndex + 1) < m_nGlyphsCount)
{
++nIndex;
++nEmpty;
code = 0x10000 + (((code & 0x3FF) << 10) | (0x03FF & pWchars[nIndex]));
}
m_pGlyphsBuffer[nIndex].lUnicode = code;
m_pGlyphsBuffer[nIndex].bBitmap = false;
}
m_nGlyphsCount -= nEmpty;
}
else
{
for ( int nIndex = 0; nIndex < m_nGlyphsCount; ++nIndex )
{
m_pGlyphsBuffer[nIndex].lUnicode = (long)pWchars[nIndex];
m_pGlyphsBuffer[nIndex].bBitmap = false;
}
}
}
else
{
m_pGlyphsBuffer = NULL;
}
}
void CGlyphString::SetStringGID(const LONG& gid, float fX, float fY)
{
m_fX = fX + m_fTransX;
m_fY = fY + m_fTransY;
m_nGlyphsCount = 1;
m_nGlyphIndex = 0;
if (NULL == m_pGlyphsBuffer)
m_pGlyphsBuffer = new TGlyph[1];
// TODO:
// m_pGlyphsBuffer[0].Clear();
m_pGlyphsBuffer[0].lUnicode = gid;
m_pGlyphsBuffer[0].bBitmap = false;
}
void CGlyphString::Reset()
{
if ( m_pGlyphsBuffer )
delete []m_pGlyphsBuffer;
m_fX = 0;
m_fY = 0;
m_fEndX = 0;
m_fEndY = 0;
m_nGlyphIndex = -1;
m_nGlyphsCount = 0;
m_pGlyphsBuffer = NULL;
m_arrCTM[0] = 1;
m_arrCTM[1] = 0;
m_arrCTM[2] = 0;
m_arrCTM[3] = 1;
m_arrCTM[4] = 0;
m_arrCTM[5] = 0;
m_fTransX = 0;
m_fTransY = 0;
}
int CGlyphString::GetLength()
{
return m_nGlyphsCount;
}
void CGlyphString::SetBBox(int nIndex, float fLeft, float fTop, float fRight, float fBottom)
{
if ( m_nGlyphsCount <= 0 )
return;
int nCurIndex = min( m_nGlyphsCount - 1, max( 0, nIndex ) );
m_pGlyphsBuffer[nCurIndex].fLeft = fLeft;
m_pGlyphsBuffer[nCurIndex].fTop = fTop;
m_pGlyphsBuffer[nCurIndex].fRight = fRight;
m_pGlyphsBuffer[nCurIndex].fBottom = fBottom;
}
void CGlyphString::SetMetrics(int nIndex, float fWidth, float fHeight, float fHoriAdvance, float fHoriBearingX, float fHoriBearingY, float fVertAdvance, float fVertBearingX, float fVertBearingY)
{
if ( m_nGlyphsCount <= 0 )
return;
int nCurIndex = min( m_nGlyphsCount - 1, max( 0, nIndex ) );
m_pGlyphsBuffer[nCurIndex].oMetrics.fHeight = fHeight;
m_pGlyphsBuffer[nCurIndex].oMetrics.fHoriAdvance = fHoriAdvance;
m_pGlyphsBuffer[nCurIndex].oMetrics.fHoriBearingX = fHoriBearingX;
m_pGlyphsBuffer[nCurIndex].oMetrics.fHoriBearingY = fHoriBearingY;
m_pGlyphsBuffer[nCurIndex].oMetrics.fVertAdvance = fVertAdvance;
m_pGlyphsBuffer[nCurIndex].oMetrics.fVertBearingX = fVertBearingX;
m_pGlyphsBuffer[nCurIndex].oMetrics.fVertBearingY = fVertBearingY;
m_pGlyphsBuffer[nCurIndex].oMetrics.fWidth = fWidth;
}
void CGlyphString::SetStartPoint(int nIndex, float fX, float fY)
{
if ( m_nGlyphsCount <= 0 )
return;
int nCurIndex = min( m_nGlyphsCount - 1, max( 0, nIndex ) );
m_pGlyphsBuffer[nCurIndex].fX = fX;
m_pGlyphsBuffer[nCurIndex].fY = fY;
}
void CGlyphString::SetState(int nIndex, EGlyphState eState)
{
if ( m_nGlyphsCount <= 0 )
return;
int nCurIndex = min( m_nGlyphsCount - 1, max( 0, nIndex ) );
m_pGlyphsBuffer[nCurIndex].eState = eState;
}
void CGlyphString::GetBBox(float *pfLeft, float *pfTop, float *pfRight, float *pfBottom, int nIndex, int nType)
{
int nCurIndex = 0;
if ( nIndex < 0 )
{
if ( m_nGlyphsCount <= 0 || m_nGlyphIndex < 1 || m_nGlyphIndex > m_nGlyphsCount )
return;
nCurIndex = m_nGlyphIndex - 1;
}
else
{
if ( m_nGlyphsCount <= 0 )
return;
nCurIndex = min( m_nGlyphsCount - 1, max( 0, nIndex ) );
}
float fBottom = -m_pGlyphsBuffer[nCurIndex].fBottom;
float fRight = m_pGlyphsBuffer[nCurIndex].fRight;
float fLeft = m_pGlyphsBuffer[nCurIndex].fLeft;
float fTop = -m_pGlyphsBuffer[nCurIndex].fTop;
if ( 0 == nType && !( 1 == m_arrCTM[0] && 0 == m_arrCTM[1] && 0 == m_arrCTM[2] && 1 == m_arrCTM[3] && 0 == m_arrCTM[4] && 0 == m_arrCTM[5] ) )
{
// Применяем глобальную матрицу преобразования и пересчитываем BBox
float arrfX[4] = { fLeft, fLeft, fRight, fRight };
float arrfY[4] = { fTop, fBottom, fBottom, fTop };
float fMinX = (float)(arrfX[0] * m_arrCTM[0] + arrfY[0] * m_arrCTM[2]);
float fMinY = (float)(arrfX[0] * m_arrCTM[1] + arrfY[0] * m_arrCTM[3]);
float fMaxX = fMinX;
float fMaxY = fMinY;
for ( int nIndex = 1; nIndex < 4; nIndex++ )
{
float fX = (float)(arrfX[nIndex] * m_arrCTM[0] + arrfY[nIndex] * m_arrCTM[2]);
float fY = (float)(arrfX[nIndex] * m_arrCTM[1] + arrfY[nIndex] * m_arrCTM[3]);
fMaxX = max( fMaxX, fX );
fMinX = min( fMinX, fX );
fMaxY = max( fMaxY, fY );
fMinY = min( fMinY, fY );
}
fLeft = fMinX;
fRight = fMaxX;
fTop = fMinY;
fBottom = fMaxY;
}
*pfLeft = fLeft + m_pGlyphsBuffer[nCurIndex].fX + m_fX;
*pfRight = fRight + m_pGlyphsBuffer[nCurIndex].fX + m_fX;
*pfTop = fTop + m_pGlyphsBuffer[nCurIndex].fY + m_fY;
*pfBottom = fBottom + m_pGlyphsBuffer[nCurIndex].fY + m_fY;
}
void CGlyphString::GetBBox2(float *pfLeft, float *pfTop, float *pfRight, float *pfBottom)
{
if ( m_nGlyphsCount <= 0 )
{
*pfLeft = 0;
*pfRight = 0;
*pfBottom = 0;
*pfTop = 0;
}
float fBottom = 0;
float fRight = 0;
float fLeft = 0;
float fTop = 0;
for ( int nIndex = 0; nIndex < m_nGlyphsCount; nIndex++ )
{
fBottom = max( fBottom, -m_pGlyphsBuffer[nIndex].fBottom );
//fRight = max( fRight, m_pGlyphsBuffer[nIndex].fRight );
//fLeft = min( fLeft, m_pGlyphsBuffer[nIndex].fLeft );
fTop = min( fTop, -m_pGlyphsBuffer[nIndex].fTop );
}
if ( !( 1 == m_arrCTM[0] && 0 == m_arrCTM[1] && 0 == m_arrCTM[2] && 1 == m_arrCTM[3] && 0 == m_arrCTM[4] && 0 == m_arrCTM[5] ) )
{
// Применяем глобальную матрицу преобразования и пересчитываем BBox
float arrfX[4] = { fLeft, fLeft, fRight, fRight };
float arrfY[4] = { fTop, fBottom, fBottom, fTop };
float fMinX = (float)(arrfX[0] * m_arrCTM[0] + arrfY[0] * m_arrCTM[2]);
float fMinY = (float)(arrfX[0] * m_arrCTM[1] + arrfY[0] * m_arrCTM[3]);
float fMaxX = fMinX;
float fMaxY = fMinY;
for ( int nIndex = 1; nIndex < 4; nIndex++ )
{
float fX = (float)(arrfX[nIndex] * m_arrCTM[0] + arrfY[nIndex] * m_arrCTM[2]);
float fY = (float)(arrfX[nIndex] * m_arrCTM[1] + arrfY[nIndex] * m_arrCTM[3]);
fMaxX = max( fMaxX, fX );
fMinX = min( fMinX, fX );
fMaxY = max( fMaxY, fY );
fMinY = min( fMinY, fY );
}
fLeft = fMinX;
fRight = fMaxX;
fTop = fMinY;
fBottom = fMaxY;
}
fLeft += m_fX;
fRight += m_fX;
fTop += m_fY;
fBottom += m_fY;
*pfLeft = min( fLeft, min(m_fX, m_fEndX) );
*pfRight = max( fRight, max(m_fX, m_fEndX) );
*pfTop = min( fTop, min(m_fY, m_fEndY) );
*pfBottom = max( fBottom, max(m_fY, m_fEndY) );
}
void CGlyphString::SetCTM(float fA, float fB, float fC, float fD, float fE ,float fF)
{
m_arrCTM[0] = fA;
m_arrCTM[1] = fB;
m_arrCTM[2] = fC;
m_arrCTM[3] = fD;
m_arrCTM[4] = fE;
m_arrCTM[5] = fF;
double dDet = fA * fD - fB * fC;
if ( dDet < 0.001 && dDet >= 0 )
dDet = 0.001;
else if ( dDet > - 0.001 && dDet < 0 )
dDet = -0.001;
m_dIDet = 1 / dDet;
}
void CGlyphString::ResetCTM()
{
m_arrCTM[0] = 1;
m_arrCTM[1] = 0;
m_arrCTM[2] = 0;
m_arrCTM[3] = 1;
m_arrCTM[4] = 0;
m_arrCTM[5] = 0;
m_dIDet = 1;
}
void CGlyphString::Transform(float *pfX, float *pfY)
{
float fX = *pfX, fY = *pfY;
*pfX = (float) ( fX * m_arrCTM[0] + fY * m_arrCTM[2] + m_arrCTM[4] );
*pfY = (float) ( fX * m_arrCTM[1] + fY * m_arrCTM[3] + m_arrCTM[5] );
}
void CGlyphString::SetTrans(float fX, float fY)
{
m_fTransX = (float) ( m_dIDet * ( fX * m_arrCTM[3] - m_arrCTM[2] * fY ) );
m_fTransY = (float) ( m_dIDet * ( fY * m_arrCTM[0] - m_arrCTM[1] * fX ) );
}
TGlyph* CGlyphString::GetAt(int nIndex)
{
if ( m_nGlyphsCount <= 0 )
{
return NULL;
}
int nCurIndex = min( m_nGlyphsCount - 1, max( 0, nIndex ) );
return &(m_pGlyphsBuffer[nCurIndex]);
}
INT CGlyphString::GetNext(TGlyph*& pGlyph)
{
if ( m_nGlyphIndex >= m_nGlyphsCount || m_nGlyphIndex < 0 )
{
pGlyph = NULL;
return FALSE;
}
pGlyph = &m_pGlyphsBuffer[m_nGlyphIndex];
m_nGlyphIndex++;
return TRUE;
}
#ifndef _BUILD_GLYPH_STRING_H
#define _BUILD_GLYPH_STRING_H
#include "../common/Types.h"
#include "../common/Array.h"
#include <math.h>
#include <string>
//-------------------------------------------------------------------------------------------------------------------------------
// TGlyphBitmap
//-------------------------------------------------------------------------------------------------------------------------------
class TGlyphBitmap
{
public:
int nX; // Сдвиг по X начальной точки для рисования символа
int nY; // Сдвиг по Y начальной точки для рисования символа
int nWidth; // Ширина символа
int nHeight; // Высота символа
INT bAA; // Anti-aliased: True означает, что Bitmap 8-битный(т.е. с альфой); False - Bitmap 1-битный
BYTE* pData; // Bitmap data(картинка с символом)
INT bFreeData; // True, если память в pData нужно освободить
TGlyphBitmap();
~TGlyphBitmap();
};
enum EGlyphState
{
glyphstateNormal = 0, // символ отрисовался в нужном шрифте
glyphstateDeafault, // символ отрисовался в дефолтовом шрифте
glyphstateMiss // символ не отрисовался
};
struct TBBox
{
float fMinX;
float fMaxX;
float fMinY;
float fMaxY;
};
struct TMetrics
{
float fWidth;
float fHeight;
float fHoriBearingX;
float fHoriBearingY;
float fHoriAdvance;
float fVertBearingX;
float fVertBearingY;
float fVertAdvance;
};
class TGlyph
{
public:
long lUnicode; // Юникод
float fX; // Позиция глифа
float fY; // на BaseLine
float fLeft; //
float fTop; // BBox
float fRight; //
float fBottom; //
TMetrics oMetrics;
EGlyphState eState;
bool bBitmap;
TGlyphBitmap oBitmap;
public:
TGlyph();
~TGlyph();
};
namespace FontConstants
{
//---------------------------------------------------------------------------------------------------
// Константы связанные с CharMap: Platform, Encoding ID
//---------------------------------------------------------------------------------------------------
const long c_lUniPlatform = 0;
const long c_lMacPlatform = 1;
const long c_lWinPlatform = 3;
const long c_lWinEncSymbol = 0;
const long c_lWinEncUSC2 = 1;
const long c_lWinEncShiftJIS = 2;
const long c_lWinEncPRC = 3;
const long c_lWinEncBig5 = 4;
const long c_lWinEncWansung = 5;
const long c_lWinEncJohab = 6;
const long c_lWinEncUCS4 = 10;
//--------------------------------------------------------------------------
// FontStyle: face types and common styles
//--------------------------------------------------------------------------
enum FontStyle
{
FontStyleRegular = 0,
FontStyleBold = 1,
FontStyleItalic = 2,
FontStyleBoldItalic = 3,
FontStyleUnderline = 4,
FontStyleStrikeout = 8
};
//--------------------------------------------------------------------------
// Unit constants
//--------------------------------------------------------------------------
enum Unit
{
UnitWorld, // 0 -- World coordinate (non-physical unit)
UnitDisplay, // 1 -- Variable -- for PageTransform only
UnitPixel, // 2 -- Each unit is one device pixel.
UnitPoint, // 3 -- Each unit is a printer's point, or 1/72 inch.
UnitInch, // 4 -- Each unit is 1 inch.
UnitDocument, // 5 -- Each unit is 1/300 inch.
UnitMillimeter // 6 -- Each unit is 1 millimeter.
};
}
class CGlyphString
{
public:
CGlyphString();
CGlyphString(const std::wstring& wsString, float fX = 0, float fY = 0);
~CGlyphString();
void SetString(const std::wstring& wsString, float fX = 0, float fY = 0);
void SetStringGID(const LONG& gid, float fX = 0, float fY = 0);
void Reset();
int GetLength();
void SetBBox(int nIndex, float fLeft, float fTop, float fRight, float fBottom);
void SetMetrics(int nIndex, float fWidth, float fHeight, float fHoriAdvance, float fHoriBearingX, float fHoriBearingY, float fVertAdvance, float fVertBearingX, float fVertBearingY);
void SetStartPoint(int nIndex, float fX, float fY);
void SetState(int nIndex, EGlyphState eState);
void GetBBox(float *pfLeft, float *pfTop, float *pfRight, float *pfBottom, int nIndex = -1, int nType = 0);
void GetBBox2(float *pfLeft, float *pfTop, float *pfRight, float *pfBottom);
void SetCTM(float fA, float fB, float fC, float fD, float fE ,float fF);
void ResetCTM();
void Transform(float *pfX, float *pfY);
void SetTrans(float fX, float fY);
TGlyph* GetAt(int nIndex);
INT GetNext(TGlyph*& pGlyph);
public:
float m_fTransX;
float m_fTransY;
float m_fX; // Координаты начальной точки для рисования
float m_fY; //
float m_fEndX; // Координаты конечной точки
float m_fEndY; //
double m_arrCTM[6]; // Глобальная матрица преобразования
double m_dIDet; // (Детерминант матрицы преобразования)^(-1)
private:
TGlyph* m_pGlyphsBuffer; // Символы в данной строке
int m_nGlyphsCount; // Количество символов в строке
int m_nGlyphIndex; // Номер текущего символа
};
#endif /* _BUILD_GLYPH_STRING_H */
\ No newline at end of file

Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "font_engine", "font_engine.vcproj", "{C739151F-5384-41DF-A1A6-F089E2C1AD56}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{C739151F-5384-41DF-A1A6-F089E2C1AD56}.Debug|Win32.ActiveCfg = Debug|Win32
{C739151F-5384-41DF-A1A6-F089E2C1AD56}.Debug|Win32.Build.0 = Debug|Win32
{C739151F-5384-41DF-A1A6-F089E2C1AD56}.Release|Win32.ActiveCfg = Release|Win32
{C739151F-5384-41DF-A1A6-F089E2C1AD56}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9,00"
Name="font_engine"
ProjectGUID="{C739151F-5384-41DF-A1A6-F089E2C1AD56}"
Keyword="MFCProj"
TargetFrameworkVersion="131072"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Release|Win32"
OutputDirectory=".\Release"
IntermediateDirectory=".\Release"
ConfigurationType="4"
UseOfMFC="2"
ATLMinimizesCRunTimeLibraryUsage="false"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="2"
InlineFunctionExpansion="1"
AdditionalIncludeDirectories="&quot;../freetype-2.5.2/include&quot;"
PreprocessorDefinitions="WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE"
StringPooling="true"
RuntimeLibrary="2"
EnableFunctionLevelLinking="true"
PrecompiledHeaderFile=".\Release/font_engine.pch"
AssemblerListingLocation=".\Release/"
ObjectFile=".\Release/"
ProgramDataBaseFileName=".\Release/"
WarningLevel="3"
SuppressStartupBanner="true"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="NDEBUG"
Culture="2057"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
OutputFile=".\Release\font_engine.lib"
SuppressStartupBanner="true"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
SuppressStartupBanner="true"
OutputFile=".\Release/font_engine.bsc"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Debug|Win32"
OutputDirectory=".\Debug"
IntermediateDirectory=".\Debug"
ConfigurationType="4"
UseOfMFC="2"
ATLMinimizesCRunTimeLibraryUsage="false"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="&quot;../freetype-2.5.2/include&quot;"
PreprocessorDefinitions="WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
PrecompiledHeaderFile=".\Debug/font_engine.pch"
AssemblerListingLocation=".\Debug/"
ObjectFile=".\Debug/"
ProgramDataBaseFileName=".\Debug/"
WarningLevel="3"
SuppressStartupBanner="true"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="_DEBUG"
Culture="2057"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
OutputFile=".\Debug\font_engine.lib"
SuppressStartupBanner="true"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
SuppressStartupBanner="true"
OutputFile=".\Debug/font_engine.bsc"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
>
<File
RelativePath=".\ApplicationFonts.cpp"
>
</File>
<File
RelativePath=".\FontFile.cpp"
>
</File>
<File
RelativePath=".\FontManager.cpp"
>
</File>
<File
RelativePath=".\FontPath.cpp"
>
</File>
<File
RelativePath=".\GlyphString.cpp"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl"
>
<File
RelativePath=".\ApplicationFonts.h"
>
</File>
<File
RelativePath=".\FontFile.h"
>
</File>
<File
RelativePath=".\FontManager.h"
>
</File>
<File
RelativePath=".\FontPath.h"
>
</File>
<File
RelativePath=".\GlyphString.h"
>
</File>
</Filter>
<Filter
Name="Common"
>
<File
RelativePath="..\common\Directory.h"
>
</File>
<File
RelativePath="..\common\File.h"
>
</File>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8,00"
Name="font_engine"
ProjectGUID="{C739151F-5384-41DF-A1A6-F089E2C1AD56}"
RootNamespace="font_engine"
Keyword="MFCProj"
>
<Platforms>
<Platform
Name="Win32"
/>
<Platform
Name="x64"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Release|Win32"
OutputDirectory="$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="4"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="false"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="2"
InlineFunctionExpansion="1"
AdditionalIncludeDirectories="&quot;../freetype-2.5.2/include&quot;;&quot;..\freetype-2.5.2\include&quot;"
PreprocessorDefinitions="WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE"
StringPooling="true"
RuntimeLibrary="2"
EnableFunctionLevelLinking="true"
PrecompiledHeaderFile=""
AssemblerListingLocation="$(ConfigurationName)\"
ObjectFile="$(ConfigurationName)\"
ProgramDataBaseFileName="$(ConfigurationName)\"
WarningLevel="3"
SuppressStartupBanner="true"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="NDEBUG"
Culture="2057"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
OutputFile="$(OutDir)\$(ProjectName).lib"
SuppressStartupBanner="true"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
SuppressStartupBanner="true"
OutputFile=".\Release/font_engine.bsc"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|x64"
OutputDirectory="$(PlatformName)\$(ConfigurationName)"
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
ConfigurationType="4"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="false"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
TargetEnvironment="3"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="2"
InlineFunctionExpansion="1"
AdditionalIncludeDirectories="&quot;../freetype-2.5.2/include&quot;"
PreprocessorDefinitions="WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE"
StringPooling="true"
RuntimeLibrary="2"
EnableFunctionLevelLinking="true"
PrecompiledHeaderFile=""
AssemblerListingLocation="$(PlatformName)\$(ConfigurationName)\"
ObjectFile="$(PlatformName)\$(ConfigurationName)\"
ProgramDataBaseFileName="$(PlatformName)\$(ConfigurationName)\"
WarningLevel="3"
SuppressStartupBanner="true"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="NDEBUG"
Culture="2057"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
OutputFile="$(OutDir)\$(ProjectName).lib"
SuppressStartupBanner="true"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
SuppressStartupBanner="true"
OutputFile=".\Release/font_engine.bsc"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="4"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="false"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="&quot;../freetype-2.5.2/include&quot;"
PreprocessorDefinitions="WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
PrecompiledHeaderFile=""
AssemblerListingLocation="$(ConfigurationName)\"
ObjectFile="$(ConfigurationName)\"
ProgramDataBaseFileName="$(ConfigurationName)\"
WarningLevel="3"
SuppressStartupBanner="true"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="_DEBUG"
Culture="2057"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
OutputFile="$(OutDir)\$(ProjectName).lib"
SuppressStartupBanner="true"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
SuppressStartupBanner="true"
OutputFile=".\Debug/font_engine.bsc"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Debug|x64"
OutputDirectory="$(PlatformName)\$(ConfigurationName)"
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
ConfigurationType="4"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="false"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
TargetEnvironment="3"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="&quot;../freetype-2.5.2/include&quot;"
PreprocessorDefinitions="WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
PrecompiledHeaderFile=""
AssemblerListingLocation="$(PlatformName)\$(ConfigurationName)\"
ObjectFile="$(PlatformName)\$(ConfigurationName)\"
ProgramDataBaseFileName="$(PlatformName)\$(ConfigurationName)\"
WarningLevel="3"
SuppressStartupBanner="true"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="_DEBUG"
Culture="2057"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
OutputFile="$(OutDir)\$(ProjectName).lib"
SuppressStartupBanner="true"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
SuppressStartupBanner="true"
OutputFile=".\Debug/font_engine.bsc"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
>
<File
RelativePath=".\ApplicationFonts.cpp"
>
</File>
<File
RelativePath=".\FontFile.cpp"
>
</File>
<File
RelativePath=".\FontManager.cpp"
>
</File>
<File
RelativePath=".\FontPath.cpp"
>
</File>
<File
RelativePath=".\GlyphString.cpp"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl"
>
<File
RelativePath=".\ApplicationFonts.h"
>
</File>
<File
RelativePath=".\FontFile.h"
>
</File>
<File
RelativePath=".\FontManager.h"
>
</File>
<File
RelativePath=".\FontPath.h"
>
</File>
<File
RelativePath=".\GlyphString.h"
>
</File>
</Filter>
<Filter
Name="Common"
>
<File
RelativePath="..\common\Directory.h"
>
</File>
<File
RelativePath="..\common\File.h"
>
</File>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>
#ifndef _FONT_DICTIONARY_WORKER_H
#include "../freetype_names/FontMaps/FontDictionary.h"
#include "../common/File.h"
namespace NSFontDictionary
{
static bool CorrectParamsFromDictionary(CFontSelectFormat& oFormat)
{
if (NULL == oFormat.wsName)
return false;
int nNameLen = (int)oFormat.wsName->length();
if (nNameLen == 0)
return false;
bool bIsAscii = true;
const wchar_t* pName = oFormat.wsName->c_str();
for (int i = 0; i < nNameLen; ++i)
{
if (pName[i] > 255 || pName[i] < 0)
{
bIsAscii = false;
break;
}
}
const FD_Font* pFont = NULL;
if (bIsAscii)
{
int nStartIndex = FD_Ascii_Names_Offsets[pName[0]];
if (-1 != nStartIndex)
{
int nIndex = -1;
for (int i = nStartIndex; i < FONTS_DICT_ASCII_NAMES_COUNT; ++i)
{
const char* _name = FD_Ascii_Names[i].m_name;
if (pName[0] != (wchar_t)_name[0])
break;
bool bIsEqual = true;
for (int j = 1; j < nNameLen; ++j)
{
if ('\0' == _name[j] && j != (nNameLen - 1))
{
bIsEqual = false;
break;
}
if (pName[j] != (wchar_t)_name[j])
{
bIsEqual = false;
break;
}
}
if (bIsEqual)
{
nIndex = i;
break;
}
}
if (nIndex != -1)
{
const FD_FontMapRec* pRec = &FD_Ascii_Names[nIndex];
int nFontIndex = -1;
int nStyle = 0;
if (oFormat.bItalic != NULL && *oFormat.bItalic == TRUE)
nStyle |= 1;
if (oFormat.bBold != NULL && *oFormat.bBold == TRUE)
nStyle |= 2;
switch (nStyle)
{
case 1:
{
if (pRec->m_index_i != -1)
nFontIndex = pRec->m_index_i;
else if (pRec->m_index_bi != -1)
nFontIndex = pRec->m_index_bi;
else if (pRec->m_index_r != -1)
nFontIndex = pRec->m_index_r;
else
nFontIndex = pRec->m_index_b;
break;
}
case 2:
{
if (pRec->m_index_b != -1)
nFontIndex = pRec->m_index_b;
else if (pRec->m_index_bi != -1)
nFontIndex = pRec->m_index_bi;
else if (pRec->m_index_r != -1)
nFontIndex = pRec->m_index_r;
else
nFontIndex = pRec->m_index_i;
break;
}
case 3:
{
if (pRec->m_index_bi != -1)
nFontIndex = pRec->m_index_bi;
else if (pRec->m_index_b != -1)
nFontIndex = pRec->m_index_b;
else if (pRec->m_index_i != -1)
nFontIndex = pRec->m_index_i;
else
nFontIndex = pRec->m_index_r;
break;
}
case 0:
default:
{
if (pRec->m_index_r != -1)
nFontIndex = pRec->m_index_r;
else if (pRec->m_index_i != -1)
nFontIndex = pRec->m_index_i;
else if (pRec->m_index_b != -1)
nFontIndex = pRec->m_index_b;
else
nFontIndex = pRec->m_index_bi;
break;
}
}
if (nFontIndex != -1)
pFont = &FD_Ascii_Files[nFontIndex];
}
}
}
else
{
int nIndex = -1;
for (int i = 0; i < FONTS_DICT_UNICODE_NAMES_COUNT; ++i)
{
const wchar_t* _name = FD_Unicode_Names[i].m_name;
if (pName[0] != _name[0])
continue;
bool bIsEqual = true;
for (int j = 1; j < nNameLen; ++j)
{
if (((wchar_t)'\0') == _name[j] && j != (nNameLen - 1))
{
bIsEqual = false;
break;
}
if (pName[j] != _name[j])
{
bIsEqual = false;
break;
}
}
if (bIsEqual)
{
nIndex = i;
break;
}
}
if (nIndex != -1)
{
const FD_FontMapRecW* pRec = &FD_Unicode_Names[nIndex];
int nFontIndex = -1;
int nStyle = 0;
if (oFormat.bItalic != NULL && *oFormat.bItalic == TRUE)
nStyle |= 1;
if (oFormat.bBold != NULL && *oFormat.bBold == TRUE)
nStyle |= 2;
switch (nStyle)
{
case 1:
{
if (pRec->m_index_i != -1)
nFontIndex = pRec->m_index_i;
else if (pRec->m_index_bi != -1)
nFontIndex = pRec->m_index_bi;
else if (pRec->m_index_r != -1)
nFontIndex = pRec->m_index_r;
else
nFontIndex = pRec->m_index_b;
break;
}
case 2:
{
if (pRec->m_index_b != -1)
nFontIndex = pRec->m_index_b;
else if (pRec->m_index_bi != -1)
nFontIndex = pRec->m_index_bi;
else if (pRec->m_index_r != -1)
nFontIndex = pRec->m_index_r;
else
nFontIndex = pRec->m_index_i;
break;
}
case 3:
{
if (pRec->m_index_bi != -1)
nFontIndex = pRec->m_index_bi;
else if (pRec->m_index_b != -1)
nFontIndex = pRec->m_index_b;
else if (pRec->m_index_i != -1)
nFontIndex = pRec->m_index_i;
else
nFontIndex = pRec->m_index_r;
break;
}
case 0:
default:
{
if (pRec->m_index_r != -1)
nFontIndex = pRec->m_index_r;
else if (pRec->m_index_i != -1)
nFontIndex = pRec->m_index_i;
else if (pRec->m_index_b != -1)
nFontIndex = pRec->m_index_b;
else
nFontIndex = pRec->m_index_bi;
break;
}
}
if (nFontIndex != -1)
pFont = &FD_Ascii_Files[nFontIndex];
}
}
if (NULL == pFont)
return false;
// name - делаем ascii, чтобы сработал подбор
oFormat.Destroy();
LONG nLen = (LONG)strlen(pFont->m_name);
oFormat.wsName = new std::wstring(NSFile::CUtf8Converter::GetUnicodeStringFromUTF8((BYTE*)pFont->m_name, nLen));
// fixed
oFormat.bFixedWidth = new INT(pFont->m_bIsFixed == 1 ? TRUE : FALSE);
// panose
oFormat.pPanose = new BYTE[10];
memcpy(oFormat.pPanose, pFont->m_aPanose, 10);
// ranges
oFormat.ulRange1 = new ULONG(pFont->m_ulUnicodeRange1);
oFormat.ulRange2 = new ULONG(pFont->m_ulUnicodeRange2);
oFormat.ulRange3 = new ULONG(pFont->m_ulUnicodeRange3);
oFormat.ulRange4 = new ULONG(pFont->m_ulUnicodeRange4);
oFormat.ulCodeRange1 = new ULONG(pFont->m_ulCodePageRange1);
oFormat.ulCodeRange2 = new ULONG(pFont->m_ulCodePageRange2);
oFormat.usWeight = new USHORT(pFont->m_usWeigth);
oFormat.usWidth = new USHORT(pFont->m_usWidth);
oFormat.shAvgCharWidth = new SHORT(pFont->m_shAvgCharWidth);
oFormat.shAscent = new SHORT(pFont->m_shAscent);
oFormat.shDescent = new SHORT(pFont->m_shDescent);
oFormat.shXHeight = new SHORT(pFont->m_shXHeight);
oFormat.shCapHeight = new SHORT(pFont->m_shCapHeight);
return true;
}
}
#endif /* _FONT_DICTIONARY_WORKER_H */
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment