Files
DocumentServer-v-9.2.0/core/DesktopEditor/fontengine/ApplicationFonts.cpp
T
Yajbir Singh f1b860b25c
check / markdownlint (push) Has been cancelled
check / spellchecker (push) Has been cancelled
updated
2025-12-11 19:03:17 +05:30

1994 lines
56 KiB
C++

/*
* (c) Copyright Ascensio System SIA 2010-2023
*
* This program is a free software product. You can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License (AGPL)
* version 3 as published by the Free Software Foundation. In accordance with
* Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
* that Ascensio System SIA expressly excludes the warranty of non-infringement
* of any third-party rights.
*
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For
* details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
*
* You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish
* street, Riga, Latvia, EU, LV-1050.
*
* The interactive user interfaces in modified source and object code versions
* of the Program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU AGPL version 3.
*
* Pursuant to Section 7(b) of the License you must retain the original Product
* logo when distributing the program. Pursuant to Section 7(e) we decline to
* grant you any rights under trademark law for use of our trademarks.
*
* All the Product's GUI elements, including illustrations and icon sets, as
* well as technical writing content are licensed under the terms of the
* Creative Commons Attribution-ShareAlike 4.0 International. See the License
* terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
*
*/
#include "ApplicationFonts.h"
#include "../common/File.h"
#include "../common/Directory.h"
#include "../common/SystemUtils.h"
#include FT_SFNT_NAMES_H
#include "internal/tttypes.h"
#include "internal/ftstream.h"
#include "fontdictionaryworker.h"
#include "../common/ByteBuilder.h"
#include "../../UnicodeConverter/UnicodeConverter.h"
#ifndef min
#define min(a,b) (((a) < (b)) ? (a) : (b))
#endif
namespace NSFonts
{
void makeLower(std::wstring& name)
{
int nLen = (int)name.length();
wchar_t* pStr = (wchar_t*)name.c_str();
for (int i = 0; i < nLen; ++i)
{
if (pStr[i] >= 'A' && pStr[i] <= 'Z')
pStr[i] = pStr[i] + 'a' - 'A';
}
}
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();
}
}
std::wstring prepareFont3000(std::wstring& name)
{
std::wstring sRet;
int nLen = (int)name.length();
wchar_t* pStr = (wchar_t*)name.c_str();
for (int i = 0; i < nLen; ++i)
{
if (pStr[i] == ' ' || pStr[i] == '-')
continue;
sRet.append(pStr + i, 1);
}
return sRet;
}
namespace NSBinarySerialize
{
template <class T>
T Read(BYTE*& pBuffer)
{
T ret = 0;
#ifdef _ARM_ALIGN_
memcpy(&ret, pBuffer, sizeof(T));
#else
ret = *((T*)pBuffer);
#endif
pBuffer += sizeof(T);
return ret;
}
template <class T>
void Write(BYTE*& pBuffer, const T& value)
{
#ifdef _ARM_ALIGN_
memcpy(pBuffer, &value, sizeof(T));
#else
*((T*)(pBuffer)) = value;
#endif
pBuffer += sizeof(T);
}
}
void WriteUtf8ToBuffer(BYTE*& pBuffer, const std::wstring& value)
{
std::string sUtf8 = U_TO_UTF8(value);
size_t len = sUtf8.length();
NSBinarySerialize::Write<INT>(pBuffer, (int)len);
memcpy(pBuffer, sUtf8.c_str(), len);
pBuffer += len;
}
std::wstring ReadUtf8FromBuffer(BYTE*& pBuffer)
{
int nLen = NSBinarySerialize::Read<INT>(pBuffer);
std::wstring value = NSFile::CUtf8Converter::GetUnicodeStringFromUTF8(pBuffer, (LONG)nLen);
pBuffer += nLen;
return value;
}
int GetUtf16BufferLen(const std::wstring& value)
{
int nLen = 0;
if (2 == sizeof(wchar_t))
{
nLen = value.length();
}
else
{
NSFile::CStringUtf16 sUtf16;
NSFile::CUtf8Converter::GetUtf16StringFromUnicode_4bytes2(value.c_str(), value.length(), sUtf16);
nLen = sUtf16.Length;
}
return (int)(2 * (nLen + 1)) + sizeof(INT);
}
void WriteUtf16ToBuffer(BYTE*& pBuffer, const std::wstring& value)
{
if (2 == sizeof(wchar_t))
{
int nLen = (int)(2 * (value.length() + 1));
NSBinarySerialize::Write<INT>(pBuffer, nLen);
memcpy(pBuffer, value.c_str(), nLen);
pBuffer += nLen;
}
else
{
NSFile::CStringUtf16 sUtf16;
NSFile::CUtf8Converter::GetUtf16StringFromUnicode_4bytes2(value.c_str(), value.length(), sUtf16);
int nLen = sUtf16.Length + 2;
NSBinarySerialize::Write<INT>(pBuffer, nLen);
memcpy(pBuffer, sUtf16.Data, nLen);
pBuffer += nLen;
}
}
// new version
int GetUtf8BufferLen(const std::wstring& value)
{
std::string sUtf8 = U_TO_UTF8(value);
return (int)sUtf8.length() + sizeof(INT);
}
CFontInfo* FromBuffer(BYTE*& pBuffer, std::wstring strDir)
{
LONG lRecordLen = NSBinarySerialize::Read<INT>(pBuffer);
std::wstring sName = ReadUtf8FromBuffer(pBuffer);
int nNamesCount = NSBinarySerialize::Read<INT>(pBuffer);
std::vector<std::wstring> names;
for (int i = 0; i < nNamesCount; ++i)
names.push_back(ReadUtf8FromBuffer(pBuffer));
std::wstring sPath = ReadUtf8FromBuffer(pBuffer);
string_replace(sPath, L"\\", L"/");
LONG lIndex = NSBinarySerialize::Read<INT>(pBuffer);
INT bItalic = NSBinarySerialize::Read<INT>(pBuffer);
INT bBold = NSBinarySerialize::Read<INT>(pBuffer);
INT bFixedWidth = NSBinarySerialize::Read<INT>(pBuffer);
INT lLen = NSBinarySerialize::Read<INT>(pBuffer); // должно быть равно 10
BYTE pPanose[10];
memcpy( (void *)pPanose, (const void *)pBuffer, 10 );
pBuffer += lLen;
UINT ulRange1 = NSBinarySerialize::Read<UINT>(pBuffer);
UINT ulRange2 = NSBinarySerialize::Read<UINT>(pBuffer);
UINT ulRange3 = NSBinarySerialize::Read<UINT>(pBuffer);
UINT ulRange4 = NSBinarySerialize::Read<UINT>(pBuffer);
ULONG ulCodeRange1 = NSBinarySerialize::Read<UINT>(pBuffer);
ULONG ulCodeRange2 = NSBinarySerialize::Read<UINT>(pBuffer);
USHORT usWeight = NSBinarySerialize::Read<USHORT>(pBuffer);
USHORT usWidth = NSBinarySerialize::Read<USHORT>(pBuffer);
SHORT sFamilyClass = NSBinarySerialize::Read<SHORT>(pBuffer);
SHORT sFormat = NSBinarySerialize::Read<SHORT>(pBuffer);
SHORT shAvgCharWidth = NSBinarySerialize::Read<SHORT>(pBuffer);
SHORT shAscent = NSBinarySerialize::Read<SHORT>(pBuffer);
SHORT shDescent = NSBinarySerialize::Read<SHORT>(pBuffer);
SHORT shLineGap = NSBinarySerialize::Read<SHORT>(pBuffer);
SHORT shXHeight = NSBinarySerialize::Read<SHORT>(pBuffer);
SHORT shCapHeight = NSBinarySerialize::Read<SHORT>(pBuffer);
USHORT usType = NSBinarySerialize::Read<USHORT>(pBuffer);
bool bIsRelative = false;
if (sPath.find(wchar_t('/')) == std::wstring::npos)
bIsRelative = true;
else if (!sPath.empty() && sPath[0] == wchar_t('.'))
bIsRelative = true;
if (bIsRelative)
sPath = strDir + L"/" + sPath;
CFontInfo* pInfo = new CFontInfo(sName,
L"",
sPath,
lIndex,
bBold,
bItalic,
bFixedWidth,
(BYTE*)pPanose,
ulRange1,
ulRange2,
ulRange3,
ulRange4,
ulCodeRange1,
ulCodeRange2,
usWeight,
usWidth,
sFamilyClass,
(EFontFormat)sFormat,
shAvgCharWidth,
shAscent,
shDescent,
shLineGap,
shXHeight,
shCapHeight,
usType);
for (std::vector<std::wstring>::iterator iter = names.begin(); iter != names.end(); iter++)
pInfo->names.push_back(*iter);
return pInfo;
}
LONG GetBufferLen(CFontInfo* pInfo, CFontListToBufferSerializer& oSerializer)
{
std::wstring sPath = pInfo->m_wsFontPath;
if (0 != oSerializer.m_strDirectory.length() && 0 == sPath.find(oSerializer.m_strDirectory))
{
sPath = sPath.substr(oSerializer.m_strDirectory.length());
}
else if (oSerializer.m_bIsOnlynames)
{
sPath = NSFile::GetFileName(sPath);
}
LONG len = 0;
if (0 == oSerializer.m_nVersion)
{
len += GetUtf16BufferLen(pInfo->m_wsFontName);
len += GetUtf16BufferLen(sPath);
}
else
{
len += GetUtf8BufferLen(pInfo->m_wsFontName);
len += sizeof(INT);
int nNamesCount = (int)pInfo->names.size();
for (int i = 0; i < nNamesCount; ++i)
len += GetUtf8BufferLen(pInfo->names[i]);
len += GetUtf8BufferLen(sPath);
}
len += (4 * 4 + 4 + 10 + 6 * 4 + 10 * 2);
if (oSerializer.m_nVersion >= 2)
{
// вначале пишем длину
len += 4; // len
len += 2;
}
return len;
}
void ToBuffer(CFontInfo* pInfo, BYTE*& pBuffer, CFontListToBufferSerializer& oSerializer)
{
BYTE* pBufferBegin = pBuffer;
if (oSerializer.m_nVersion >= 2)
{
NSBinarySerialize::Write<INT>(pBuffer, 0);
}
std::wstring sPath = pInfo->m_wsFontPath;
if (0 != oSerializer.m_strDirectory.length() && 0 == sPath.find(oSerializer.m_strDirectory))
{
sPath = sPath.substr(oSerializer.m_strDirectory.length());
}
else if (oSerializer.m_bIsOnlynames)
{
sPath = NSFile::GetFileName(sPath);
}
if (0 == oSerializer.m_nVersion)
{
WriteUtf16ToBuffer(pBuffer, pInfo->m_wsFontName);
WriteUtf16ToBuffer(pBuffer, sPath);
}
else
{
WriteUtf8ToBuffer(pBuffer, pInfo->m_wsFontName);
int nNamesCount = (int)pInfo->names.size();
NSBinarySerialize::Write<INT>(pBuffer, nNamesCount);
for (int i = 0; i < nNamesCount; ++i)
WriteUtf8ToBuffer(pBuffer, pInfo->names[i]);
WriteUtf8ToBuffer(pBuffer, sPath);
}
NSBinarySerialize::Write<INT>(pBuffer, (INT)pInfo->m_lIndex);
NSBinarySerialize::Write<INT>(pBuffer, pInfo->m_bItalic);
NSBinarySerialize::Write<INT>(pBuffer, pInfo->m_bBold);
NSBinarySerialize::Write<INT>(pBuffer, pInfo->m_bIsFixed);
// Panose
INT lLen = 10;
NSBinarySerialize::Write<INT>(pBuffer, lLen);
memcpy( (void *)pBuffer, (const void *)pInfo->m_aPanose, lLen );
pBuffer += lLen;
NSBinarySerialize::Write<UINT>(pBuffer, pInfo->m_ulUnicodeRange1);
NSBinarySerialize::Write<UINT>(pBuffer, pInfo->m_ulUnicodeRange2);
NSBinarySerialize::Write<UINT>(pBuffer, pInfo->m_ulUnicodeRange3);
NSBinarySerialize::Write<UINT>(pBuffer, pInfo->m_ulUnicodeRange4);
NSBinarySerialize::Write<UINT>(pBuffer, pInfo->m_ulCodePageRange1);
NSBinarySerialize::Write<UINT>(pBuffer, pInfo->m_ulCodePageRange2);
NSBinarySerialize::Write<USHORT>(pBuffer, pInfo->m_usWeigth);
NSBinarySerialize::Write<USHORT>(pBuffer, pInfo->m_usWidth);
NSBinarySerialize::Write<SHORT>(pBuffer, pInfo->m_sFamilyClass);
NSBinarySerialize::Write<SHORT>(pBuffer, pInfo->m_eFontFormat);
NSBinarySerialize::Write<SHORT>(pBuffer, pInfo->m_shAvgCharWidth);
NSBinarySerialize::Write<SHORT>(pBuffer, pInfo->m_shAscent);
NSBinarySerialize::Write<SHORT>(pBuffer, pInfo->m_shDescent);
NSBinarySerialize::Write<SHORT>(pBuffer, pInfo->m_shLineGap);
NSBinarySerialize::Write<SHORT>(pBuffer, pInfo->m_shXHeight);
NSBinarySerialize::Write<SHORT>(pBuffer, pInfo->m_shCapHeight);
if (oSerializer.m_nVersion >= 2)
{
NSBinarySerialize::Write<USHORT>(pBuffer, pInfo->m_usType);
INT nLen = (INT)(pBuffer - pBufferBegin);
NSBinarySerialize::Write<INT>(pBufferBegin, nLen);
}
}
}
namespace NSCharsets
{
static int GetDefaultCharset(INT bUseDefCharset = TRUE)
{
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;
}
static void GetCodePageByCharset(unsigned char unCharset, unsigned int *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;
}
}
}
}
std::wstring CFontList::GetFontBySymbol(int symbol)
{
for (std::list<CFontRange>::iterator iter = m_listRanges.begin(); iter != m_listRanges.end() && !m_listRanges.empty(); iter++)
{
CFontRange& range = *iter;
if (symbol >= range.Start && symbol <= range.End)
{
return range.Name;
}
}
// search range by symbol
int _start = 0;
int _end = m_nRangesCount - 1;
int _center = 0;
if (_start > _end || m_pRanges == NULL)
return L"";
while (_start < _end)
{
_center = (_start + _end) >> 1;
CFontRange& _range = m_pRanges[_center];
if (_range.Start > symbol)
_end = _center - 1;
else if (_range.End < symbol)
_start = _center + 1;
else
{
m_listRanges.push_front(_range);
return m_pRanges[_center].Name;
}
}
if (_start > _end)
return L"";
CFontRange& _range = m_pRanges[_start];
if (_range.Start > symbol || _range.End < symbol)
return L"";
m_listRanges.push_front(_range);
return m_pRanges[_start].Name;
}
///////////////////////////////////////////////////////////////////////////////////
int CFontList::GetCharsetPenalty(UINT ulCandRanges[6], unsigned char unReqCharset)
{
// Penalty = 65000 (это самый весомый параметр)
if ( UNKNOWN_CHARSET == unReqCharset )
return 0;
unsigned int ulBit = 0;
unsigned int unLongIndex = 0;
NSCharsets::GetCodePageByCharset( unReqCharset, &ulBit, &unLongIndex );
unsigned int nMult = 1;
for ( unsigned int nIndex = 0; nIndex < ulBit; nIndex++ )
nMult <<= 1;
if ( !(ulCandRanges[unLongIndex] & nMult) )
return 65000;
return 0;
}
int CFontList::GetSigPenalty(UINT ulCandRanges[6], UINT ulReqRanges[6], double dRangeWeight, double dRangeWeightSuferflouous)
{
double dPenalty = 0;
// Для начала просматриваем сколько вообще различных пространств надо.
// Исходя из их общего количества, находим вес 1 пропущеного пространства.
bool isSuferflouous = (dRangeWeightSuferflouous < 1) ? false : true;
int nRangesCount = 0;
for ( int nIndex = 0; nIndex < 6; nIndex++ )
{
UINT nBit = 1;
UINT first = ulReqRanges[nIndex];
UINT second = ulReqRanges[nIndex];
for ( int bit = 0; bit < 32; ++bit, nBit <<= 1 )
{
if (first & nBit)
{
++nRangesCount;
if (!(second & nBit))
dPenalty += dRangeWeight;
}
if (isSuferflouous)
{
if (!(first & nBit) && (second & nBit))
dPenalty += dRangeWeightSuferflouous;
}
}
}
if (!nRangesCount)
return 0;
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;
}
CFontListNamePicker CFontList::m_oPicker;
int CFontList::GetFaceNamePenalty(const std::wstring& sCandName, const std::wstring& sReqName, bool bIsUseNamePicker)
{
if ( 0 == sReqName.length() )
return 0;
if ( 0 == sCandName.length() )
return 10000;
if ( sReqName == sCandName )
return 0;
bool bIsOneInAnother = false;
if (CFontListNamePicker::IsEqualsFontsAdvanced(sCandName, sReqName, &bIsOneInAnother))
return 100;
if (bIsOneInAnother)
{
if (m_oPicker.IsLikeFonts(sCandName, sReqName))
return 700;
return 1000;
}
if (bIsUseNamePicker)
{
if (m_oPicker.IsLikeFonts(sCandName, sReqName))
return 1000;
return m_oPicker.CheckEqualsFonts(sCandName, sReqName);
}
return 10000;
}
int CFontList::GetFaceNamePenalty2(NSFonts::CFontInfo* pInfo, const std::wstring& sReqName, bool bIsUseNamePicker)
{
int nMin = GetFaceNamePenalty(pInfo->m_wsFontName, sReqName, bIsUseNamePicker);
for (std::vector<std::wstring>::iterator i = pInfo->names.begin(); i != pInfo->names.end(); i++)
{
int nTmp = GetFaceNamePenalty(*i, sReqName, bIsUseNamePicker);
if (nTmp < nMin)
nMin = nTmp;
}
return nMin;
}
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(NSFonts::EFontFormat eCandFormat, NSFonts::EFontFormat eReqFormat)
{
// Вообще, на МSDN написано только про TrueType. Но мы будем сравнивать
// все типы форматов и при несовпадении даем вес = 4. Если формат не задан
// то по умолчанию считаем его TrueType.
if ( eReqFormat == NSFonts::fontUnknown )
{
// Считаем, что когда формат не известен, значит это 100% не TrueType.
if ( eCandFormat == NSFonts::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;
}
bool CFontList::CheckEmbeddingRights(const USHORT* ushRights, const USHORT& fsType)
{
if (!ushRights || NSFONTS_EMBEDDING_RIGHTS_ANY == *ushRights || 0 == fsType)
return true;
return ((NSFONTS_EMBEDDING_RIGHTS_PRINT_AND_PREVIEW == *ushRights && NSFonts::CFontInfo::CanEmbedForPreviewAndPrint(fsType))
|| (NSFONTS_EMBEDDING_RIGHTS_EDITABLE == *ushRights && NSFonts::CFontInfo::CanEmbedForEdit(fsType))
|| NSFonts::CFontInfo::CanEmbedForInstall(fsType));
}
NSFonts::EFontFormat CFontList::GetFontFormat(FT_Face pFace)
{
return CFontFile::GetFontFormatType(pFace);
}
void CFontList::ToBuffer(BYTE** pDstData, LONG* pLen, NSFonts::CFontListToBufferSerializer& oSerializer)
{
LONG lDataSize = sizeof(INT);
size_t nFontsCount = (size_t)m_pList.size();
for (std::vector<NSFonts::CFontInfo*>::iterator iter = m_pList.begin(); iter != m_pList.end(); iter++)
{
lDataSize += NSFonts::GetBufferLen(*iter, oSerializer);
}
BYTE* pData = new BYTE[lDataSize];
BYTE* pDataMem = pData;
NSFonts::NSBinarySerialize::Write<INT>(pDataMem, nFontsCount);
for (std::vector<NSFonts::CFontInfo*>::iterator iter = m_pList.begin(); iter != m_pList.end(); iter++)
{
NSFonts::ToBuffer(*iter, pDataMem, oSerializer);
}
*pDstData = pData;
*pLen = (LONG)(pDataMem - pData);
}
class CFontSelectFormatCorrection
{
private:
std::wstring* m_oldName;
INT* m_oldBold;
INT* m_oldItalic;
public:
CFontSelectFormatCorrection()
{
m_oldName = NULL;
m_oldBold = NULL;
m_oldItalic = NULL;
}
static CFontSelectFormatCorrection* CheckCorrection(NSFonts::CFontSelectFormat& oSelect)
{
// пробуем "подправить" настройки
std::wstring sName = *oSelect.wsName;
NSFonts::makeLower(sName);
INT* oldBold = NULL;
INT* oldItalic = NULL;
bool isCorrect = false;
if (std::wstring::npos != sName.find(L"bold"))
{
isCorrect = true;
size_t posn = 0;
while (std::wstring::npos != (posn = sName.find(L"bold", posn)))
sName.erase(posn, 4);
oldBold = oSelect.bBold;
if (!oSelect.bBold)
oSelect.bBold = new INT(TRUE);
}
if (std::wstring::npos != sName.find(L"italic") ||
std::wstring::npos != sName.find(L"oblique"))
{
isCorrect = true;
size_t posn = 0;
while (std::wstring::npos != (posn = sName.find(L"italic", posn)))
sName.erase(posn, 6);
while (std::wstring::npos != (posn = sName.find(L"oblique", posn)))
sName.erase(posn, 7);
oldItalic = oSelect.bItalic;
if (!oSelect.bItalic)
oSelect.bItalic = new INT(TRUE);
}
if (!isCorrect)
return NULL;
CFontSelectFormatCorrection* pCorrection = new CFontSelectFormatCorrection();
pCorrection->m_oldName = oSelect.wsName;
oSelect.wsName = new std::wstring(sName);
pCorrection->m_oldBold = oldBold;
pCorrection->m_oldItalic = oldItalic;
return pCorrection;
}
void Restore(NSFonts::CFontSelectFormat& oSelect)
{
RELEASEOBJECT((oSelect.wsName));
oSelect.wsName = m_oldName;
if (m_oldBold != oSelect.bBold)
{
RELEASEOBJECT((oSelect.bBold));
oSelect.bBold = m_oldBold;
}
if (m_oldItalic != oSelect.bItalic)
{
RELEASEOBJECT((oSelect.bItalic));
oSelect.bItalic = m_oldItalic;
}
m_oldName = NULL;
m_oldBold = NULL;
m_oldItalic = NULL;
}
};
NSFonts::CFontInfo* CFontList::GetByParams(NSFonts::CFontSelectFormat& oSelect, bool bIsDictionaryUse)
{
int nFontsCount = m_pList.size();
if (0 == nFontsCount)
return NULL;
if (bIsDictionaryUse)
{
// дубликат не делаем!!! Серега создает объект только для подбора и дальше его не использует
NSFontDictionary::CorrectParamsFromDictionary(oSelect);
}
int nMinIndex = 0; // Номер шрифта в списке с минимальным весом
int nMinPenalty = -1; // Минимальный вес
int nDefPenalty = 2147483647;
NSFonts::CFontInfo* pInfoMin = NULL;
CFontSelectFormatCorrection* pSelectCorrection = NULL;
while (true)
{
for (std::vector<NSFonts::CFontInfo*>::iterator iter = m_pList.begin(); iter != m_pList.end(); iter++)
{
int nCurPenalty = 0;
NSFonts::CFontInfo* pInfo = *iter;
if (!CheckEmbeddingRights(oSelect.usType, pInfo->m_usType))
continue;
if ( NULL != oSelect.pPanose )
{
nCurPenalty += GetPanosePenalty( pInfo->m_aPanose, oSelect.pPanose );
}
UINT 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)
{
UINT 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;
if ( NULL != oSelect.bFixedWidth )
nCurPenalty += GetFixedPitchPenalty( pInfo->m_bIsFixed, *oSelect.bFixedWidth );
int nNamePenalty = 0;
if ( oSelect.wsName != NULL )
nNamePenalty = GetFaceNamePenalty2( pInfo, *oSelect.wsName, true );
if ( oSelect.wsAltName != NULL )
{
int nTmp = GetFaceNamePenalty2( pInfo, *oSelect.wsAltName, true );
if (nTmp < nNamePenalty)
nNamePenalty = nTmp;
}
if ( oSelect.wsDefaultName != NULL )
{
int nTmp = GetFaceNamePenalty2( pInfo, *oSelect.wsDefaultName, true );
if (nTmp < 3000) // max value in picker
nTmp += 3000;
if (nTmp < nNamePenalty)
nNamePenalty = nTmp;
}
nCurPenalty += nNamePenalty;
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 );
// проверяем всегда!!! иначе только по имени может подобраться болд, и появляется зависимость от порядка шрифтов
nCurPenalty += GetBoldPenalty( pInfo->m_bBold, (NULL != oSelect.bBold) ? *oSelect.bBold : FALSE );
nCurPenalty += GetItalicPenalty( pInfo->m_bItalic, (NULL != oSelect.bItalic) ? *oSelect.bItalic : FALSE );
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, fontTrueType );
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 ( nMinPenalty < 0 )
{
pInfoMin = pInfo;
nMinPenalty = nCurPenalty;
}
else if ( nCurPenalty < nMinPenalty )
{
pInfoMin = pInfo;
nMinPenalty = nCurPenalty;
}
// Нашелся шрифт, удовлетворяющий всем параметрам, дальше искать нет смысла
if ( 0 == nCurPenalty )
break;
}
if (0 == nMinPenalty)
break;
if (NULL == oSelect.wsName || pSelectCorrection)
break;
pSelectCorrection = CFontSelectFormatCorrection::CheckCorrection(oSelect);
if (NULL == pSelectCorrection)
break;
}
if (pSelectCorrection)
{
pSelectCorrection->Restore(oSelect);
RELEASEOBJECT(pSelectCorrection);
}
return pInfoMin;
}
std::vector<NSFonts::CFontInfo*> CFontList::GetAllByName(const std::wstring& strFontName)
{
std::vector<NSFonts::CFontInfo*> aRes;
for (std::vector<NSFonts::CFontInfo*>::iterator iter = m_pList.begin(); iter != m_pList.end(); iter++)
{
NSFonts::CFontInfo* pInfo = *iter;
if (pInfo->m_wsFontName == strFontName)
aRes.push_back(pInfo);
}
return aRes;
}
void CFontList::Add(FT_Library pLibrary, FT_Parameter* pParams, const std::wstring& sFontPath, CFontStream* pStream, int nFlag)
{
if (!pLibrary || !pParams || !pStream)
return;
FT_Open_Args oOpenArgs;
oOpenArgs.flags = FT_OPEN_MEMORY | FT_OPEN_PARAMS;
oOpenArgs.memory_base = pStream->m_pData;
oOpenArgs.memory_size = pStream->m_lSize;
oOpenArgs.num_params = 4;
oOpenArgs.params = pParams;
FT_Face pFace = NULL;
if (FT_Open_Face( pLibrary, &oOpenArgs, 0, &pFace ))
return;
// TO DO: Шрифты, которые нельзя скейлить (т.е. изменять размер
// произвольно) мы не грузим. Возможно в будущем надо будет
// сделать, чтобы работал и такой вариант. (в Word такие шрифты
// не используются)
if ( !( pFace->face_flags & FT_FACE_FLAG_SCALABLE ) )
{
FT_Done_Face( pFace );
return;
}
int nFacesCount = pFace->num_faces;
if ( FT_Done_Face( pFace ) )
return;
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) ? 1 : 0;
const char* pPostName = FT_Get_Postscript_Name(pFace);
std::string sPostscriptName = "";
if (NULL != pPostName)
sPostscriptName = FT_Get_Postscript_Name(pFace);
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, usType = 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;
usType = pOs2->fsType;
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;
}
}
NSFonts::EFontFormat eFormat = GetFontFormat( pFace );
bool bSupportFont = ((eFormat == NSFonts::fontTrueType) || ((nFlag & 1) && (eFormat == NSFonts::fontOpenType)));
if (!bSupportFont)
{
FT_Done_Face( pFace );
continue;
}
std::wstring wsFamilyName = GetCorrectSfntName(pFace->family_name);
std::wstring wsStyleName = GetCorrectSfntName(pFace->style_name);
bool isBadASCII = (std::wstring::npos != wsFamilyName.find('?')) ? true : false;
#ifdef _MAC
if (wsFamilyName.find(L".") == 0)
{
FT_Done_Face( pFace );
continue;
}
#endif
NSFonts::CFontInfo* pFontInfo = new NSFonts::CFontInfo( wsFamilyName,
wsStyleName,
sFontPath,
nIndexFace,
bBold,
bItalic,
bFixedWidth,
pPanose,
ulRange1,
ulRange2,
ulRange3,
ulRange4,
ulCodeRange1,
ulCodeRange2,
usWeight,
usWidth,
sFamilyClass,
eFormat,
shAvgCharWidth,
shAscent,
shDescent,
shLineGap,
shXHeight,
shCapHeight,
usType);
if (pFace && FT_IS_SFNT(pFace))
{
TT_Face pTTFace = (TT_Face)pFace;
int nNamesCount = (int)pTTFace->num_names;
TT_NameRec* pNameRecs = pTTFace->name_table.names;
for (int nNameIndex = 0; nNameIndex < nNamesCount; ++nNameIndex)
{
TT_NameRec* rec = pNameRecs + nNameIndex;
if (rec->nameID != TT_NAME_ID_FONT_FAMILY || rec->stringLength <= 0)
continue;
std::string sEncoding = "";
switch (rec->platformID)
{
case TT_PLATFORM_APPLE_UNICODE:
{
sEncoding = "UTF-16BE";
break;
}
case TT_PLATFORM_MACINTOSH:
{
break;
}
case TT_PLATFORM_MICROSOFT:
{
switch (rec->encodingID)
{
case TT_MS_ID_SYMBOL_CS:
case TT_MS_ID_UNICODE_CS:
sEncoding = "UTF-16BE";
break;
case TT_MS_ID_UCS_4:
//sEncoding = "UCS4"; // см tt_
sEncoding = "UTF-16BE";
break;
//case TT_MS_ID_SJIS:
// sEncoding = "Shift-JIS";
// break;
//case TT_MS_ID_GB2312:
// sEncoding = "GB2312";
// break;
//case TT_MS_ID_BIG_5:
// sEncoding = "Big5";
// break;
default:
break;
}
}
default:
break;
}
if (!sEncoding.empty())
{
FT_Stream stream = pTTFace->name_table.stream;
FT_Memory memory = pFace->memory;
FT_Error error = 0;
if ( FT_QNEW_ARRAY ( rec->string, rec->stringLength ) ||
FT_STREAM_SEEK( rec->stringOffset ) ||
FT_STREAM_READ( rec->string, rec->stringLength ) )
{
FT_FREE( rec->string );
rec->stringLength = 0;
}
else
{
NSUnicodeConverter::CUnicodeConverter oConverter;
std::wstring sNameW = oConverter.toUnicode((char*)rec->string, (unsigned int)rec->stringLength, sEncoding.c_str());
if (std::wstring::npos == sNameW.find(wsFamilyName) && std::wstring::npos == wsFamilyName.find(sNameW))
{
std::vector<std::wstring>::iterator iter = pFontInfo->names.begin();
for (std::vector<std::wstring>::iterator iter = pFontInfo->names.begin(); iter != pFontInfo->names.end(); iter++)
{
if (*iter == sNameW)
break;
}
if (isBadASCII && pFontInfo->names.empty())
{
wsFamilyName = sNameW;
pFontInfo->m_wsFontName = wsFamilyName;
isBadASCII = false;
}
else if (iter == pFontInfo->names.end())
{
pFontInfo->names.push_back(sNameW);
#if 0
FILE* f = fopen("D:\\111.txt", "a+");
fprintf(f, "%s: %s\n", U_TO_UTF8(wsFamilyName).c_str(), U_TO_UTF8(sNameW).c_str());
fclose(f);
#endif
}
}
}
}
}
}
Add(pFontInfo);
FT_Done_Face( pFace );
}
}
void CFontList::Add(const std::wstring& sFontPath, NSFonts::IFontStream* pStream, int nFlag)
{
if (!pStream)
return;
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;
Add(pLibrary, pParams, sFontPath, (CFontStream*)pStream, nFlag);
::free( pParams );
FT_Done_FreeType(pLibrary);
}
void CFontList::LoadFromArrayFiles(std::vector<std::wstring>& oArray, int nFlag)
{
size_t nCount = oArray.size();
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 (size_t nIndex = 0; nIndex < nCount; ++nIndex)
{
NSFile::CFileBinary oFile;
if (oFile.OpenFile(oArray[nIndex]))
{
int nSizeTmp = (int)oFile.GetFileSize();
if (nSizeTmp > 100000000)
{
// такие огромные шрифты не учитываем
oArray.erase(oArray.begin() + nIndex, oArray.begin() + nIndex + 1);
nIndex--;
nCount--;
}
if (nMaxFontSize < nSizeTmp)
nMaxFontSize = nSizeTmp;
}
}
BYTE* pDataFontFile = new BYTE[nMaxFontSize];
for (size_t nIndex = 0; nIndex < nCount; ++nIndex)
{
if ((nFlag & 2) != 0)
{
std::wstring::size_type _pos_dfont = oArray[nIndex].find(L".dfont");
if (_pos_dfont != std::wstring::npos && _pos_dfont == (oArray[nIndex].length() - 6))
continue;
}
// open file
CFontStream oStream;
if (!oStream.CreateFromFile(oArray[nIndex], pDataFontFile))
continue;
Add(pLibrary, pParams, oArray[nIndex], &oStream, nFlag);
}
RELEASEARRAYOBJECTS(pDataFontFile);
::free( pParams );
FT_Done_FreeType(pLibrary);
}
void CFontList::LoadFromFolder(const std::wstring& strDirectory)
{
std::vector<std::wstring> oArray = NSDirectory::GetFiles(strDirectory, true);
this->LoadFromArrayFiles(oArray);
}
void CFontList::InitializeRanges(unsigned char* data)
{
RELEASEARRAYOBJECTS(m_pRanges)
NSMemoryUtils::CByteReader oReader(data);
m_nRangesCount = oReader.GetInt();
if (m_nRangesCount > 0)
m_pRanges = new CFontRange[m_nRangesCount];
for (int nIndex = 0; nIndex < m_nRangesCount; ++nIndex)
{
m_pRanges[nIndex].Name = oReader.GetStringUTF8();
m_pRanges[nIndex].Start = oReader.GetInt();
m_pRanges[nIndex].End = oReader.GetInt();
}
}
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);
CheckLoadFromSelectionBin(strDirectory, pBuffer, dwLen1);
RELEASEARRAYOBJECTS(pBuffer);
return true;
}
void CFontList::CheckLoadFromSelectionBin(const std::wstring& strDirectory, BYTE* pBuffer, DWORD nLen)
{
BYTE* _pBuffer = pBuffer;
int lCount = NSFonts::NSBinarySerialize::Read<INT>(_pBuffer);
for (int nIndex = 0; nIndex < lCount; ++nIndex)
{
NSFonts::CFontInfo *pFontInfo = NSFonts::FromBuffer(_pBuffer, strDirectory);
Add(pFontInfo);
}
if ((_pBuffer - pBuffer) < nLen)
{
InitializeRanges(_pBuffer);
}
}
void CFontList::Add(NSFonts::CFontInfo* pInfo)
{
int nCount = m_pList.size();
for ( int nIndex = 0; nIndex < nCount; ++nIndex )
{
if (m_pList[nIndex]->m_wsFontName == pInfo->m_wsFontName &&
m_pList[nIndex]->m_bBold == pInfo->m_bBold &&
m_pList[nIndex]->m_bItalic == pInfo->m_bItalic)
{
bool bReplace = false;
NSFonts::CFontInfo* pOldInfo = m_pList[nIndex];
if (pInfo->m_bBold && pInfo->m_bItalic)
bReplace = !NSFonts::CFontInfo::IsStyleBoldItalic(pOldInfo->m_wsStyle);
else if (pInfo->m_bBold)
bReplace = !NSFonts::CFontInfo::IsStyleBold(pOldInfo->m_wsStyle);
else if (pInfo->m_bItalic)
bReplace = !NSFonts::CFontInfo::IsStyleItalic(pOldInfo->m_wsStyle);
else
bReplace = !NSFonts::CFontInfo::IsStyleRegular(pOldInfo->m_wsStyle);
if (bReplace)
{
m_pList[nIndex] = pInfo;
RELEASEOBJECT(pOldInfo);
}
else
{
RELEASEOBJECT(pInfo);
}
return;
}
}
m_pList.push_back(pInfo);
}
// ApplicationFonts
CApplicationFonts::CApplicationFonts() : NSFonts::IApplicationFonts()
{
m_oCache.m_pApplicationFontStreams = &m_oStreams;
}
CApplicationFonts::~CApplicationFonts()
{
}
NSFonts::IFontsCache* CApplicationFonts::GetCache()
{
return &m_oCache;
}
NSFonts::IFontList* CApplicationFonts::GetList()
{
return &m_oList;
}
NSFonts::IApplicationFontStreams* 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) && !defined(__ANDROID__)
m_oList.LoadFromFolder(L"/usr/share/fonts");
#endif
#if defined(_MAC) && !defined(_IOS)
m_oList.LoadFromFolder(L"/Library/Fonts/");
#endif
#ifdef __ANDROID__
m_oList.LoadFromFolder(L"/system/fonts");
#endif
#if defined(_IOS)
m_oList.LoadFromFolder(L"/System/Library/Fonts");
#endif
m_oCache.m_pApplicationFontStreams = &m_oStreams;
}
void CApplicationFonts::InitializeFromBin(BYTE* pData, unsigned int nLen)
{
m_oList.CheckLoadFromSelectionBin(L"", pData, (DWORD)nLen);
}
void CApplicationFonts::InitializeRanges(unsigned char* data)
{
m_oList.InitializeRanges(data);
}
NSFonts::IFontManager* CApplicationFonts::GenerateFontManager()
{
CFontManager* pManager = new CFontManager();
pManager->m_pApplication = this;
return pManager;
}
std::wstring CApplicationFonts::GetFontBySymbol(int symbol)
{
return m_oList.GetFontBySymbol(symbol);
}
#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 + 1;
}
// 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
std::vector<std::wstring> CApplicationFonts::GetSetupFontFiles(const bool& bIsUseUserFonts)
{
#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;
std::vector<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.push_back(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.push_back(sFileInDir);
map_files.insert(map_files.begin(), std::pair<std::wstring,bool>(sFileInDir,true));
}
continue;
}
}
sName = L"";
sData = L"";
GetNextNameValue(0, L"", sName, sData);
if (true)
{
std::vector<std::wstring> oArray2 = NSDirectory::GetFiles(L"C:\\Windows\\Fonts", true);
if (bIsUseUserFonts)
{
wchar_t sUserName[1000];
DWORD nUserNameLen = 1000 + 1;
GetUserNameW(sUserName, &nUserNameLen);
std::wstring strUserName(sUserName, nUserNameLen - 1);
NSDirectory::GetFiles2(L"C:\\Users\\" + strUserName + L"\\AppData\\Local\\Microsoft\\Windows\\Fonts", oArray2, false);
NSDirectory::GetFiles2(L"C:\\Users\\" + strUserName + L"\\AppData\\Local\\Microsoft\\FontCache\\4\\CloudFonts", oArray2, true);
}
for (std::vector<std::wstring>::iterator i = oArray2.begin(); i != oArray2.end(); i++)
{
if (map_files.end() == map_files.find(*i))
oArray.push_back(*i);
}
}
return oArray;
#endif
#if defined(__linux__) && !defined(_MAC) && !defined(__ANDROID__)
std::vector<std::wstring> _array = NSDirectory::GetFiles(L"/usr/share/fonts", true);
NSDirectory::GetFiles2(L"/usr/share/X11/fonts", _array, true);
NSDirectory::GetFiles2(L"/usr/X11R6/lib/X11/fonts", _array, true);
NSDirectory::GetFiles2(L"/run/host/fonts", _array, true);
if (bIsUseUserFonts)
NSDirectory::GetFiles2(L"/usr/local/share/fonts", _array, true);
#ifndef BUILDING_WASM_MODULE
std::wstring custom_fonts_path = NSSystemUtils::GetEnvVariable(L"CUSTOM_FONTS_PATH");
if (!custom_fonts_path.empty())
NSDirectory::GetFiles2(custom_fonts_path, _array, true);
#endif
return _array;
#endif
#if defined(_MAC) && !defined(_IOS)
std::vector<std::wstring> _array = NSDirectory::GetFiles(L"/Library/Fonts", true);
NSDirectory::GetFiles2(L"/System/Library/Fonts", _array, true);
std::set<std::wstring> installedList = GetInstalledFontsMac();
for (const auto& sysPath : installedList) {
if (0 == sysPath.find(L"/System/Library/Fonts/"))
continue;
if (0 == sysPath.find(L"/Library/Fonts/"))
continue;
_array.push_back(sysPath);
}
return _array;
#endif
#ifdef _IOS
std::vector<std::wstring> _array = NSDirectory::GetFiles(L"/System/Library/Fonts", true);
if (_array.empty())
NSDirectory::GetFiles2(L"/Library/Fonts", _array, true);
return _array;
#endif
#ifdef __ANDROID__
std::vector<std::wstring> _array = NSDirectory::GetFiles(L"/system/fonts", true);
return _array;
#endif
std::vector<std::wstring> ret;
return ret;
}
void CApplicationFonts::InitializeFromArrayFiles(std::vector<std::wstring>& files, int nFlag)
{
m_oList.LoadFromArrayFiles(files, nFlag);
}
#if defined(_WIN32) || defined (_WIN64)
void CApplicationFonts::InitFromReg()
{
std::vector<std::wstring> oArray = GetSetupFontFiles();
m_oList.LoadFromArrayFiles(oArray);
}
#endif
namespace NSFonts
{
// Symbols
class CApplicationFontsSymbols_Private
{
public:
FT_Library m_library;
FT_Parameter* m_params;
BYTE* m_pData;
CApplicationFontsSymbols_Private()
{
m_library = NULL;
m_pData = NULL;
m_params = NULL;
if (FT_Init_FreeType(&m_library))
return;
m_params = (FT_Parameter *)::malloc( sizeof(FT_Parameter) * 4 );
m_params[0].tag = FT_MAKE_TAG( 'i', 'g', 'p', 'f' );
m_params[0].data = NULL;
m_params[1].tag = FT_MAKE_TAG( 'i', 'g', 'p', 's' );
m_params[1].data = NULL;
m_params[2].tag = FT_PARAM_TAG_IGNORE_PREFERRED_FAMILY;
m_params[2].data = NULL;
m_params[3].tag = FT_PARAM_TAG_IGNORE_PREFERRED_SUBFAMILY;
m_params[3].data = NULL;
int nSize = 100000000;
m_pData = new BYTE[nSize];
}
~CApplicationFontsSymbols_Private()
{
RELEASEARRAYOBJECTS(m_pData);
if (m_params)
::free( m_params );
if (m_library)
FT_Done_FreeType(m_library);
}
};
CApplicationFontsSymbols::CApplicationFontsSymbols()
{
m_internal = new CApplicationFontsSymbols_Private();
}
CApplicationFontsSymbols::~CApplicationFontsSymbols()
{
RELEASEOBJECT(m_internal);
}
void CApplicationFontsSymbols::CheckSymbols(const std::wstring& sFile, const int& nFaceIndex, CApplicationFontsSymbolsChecker* pChecker)
{
CFontStream oStream;
if (!oStream.CreateFromFile(sFile, m_internal->m_pData))
return;;
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 = m_internal->m_params;
FT_Face pFace = NULL;
if (FT_Open_Face(m_internal->m_library, &oOpenArgs, nFaceIndex, &pFace))
return;
bool bIsASC = false;
if (pFace->family_name && (0 == strcmp(pFace->family_name, "ASCW3")))
bIsASC = true;
for (int nCharMap = 0; nCharMap < pFace->num_charmaps; nCharMap++)
{
FT_Set_Charmap(pFace, pFace->charmaps[nCharMap]);
FT_UInt indexG;
FT_ULong character = FT_Get_First_Char(pFace, &indexG);
while (indexG)
{
if (!bIsASC || (character < 35 || character > 255))
pChecker->Check((int)character, indexG);
character = FT_Get_Next_Char(pFace, character, &indexG);
}
}
FT_Done_Face( pFace );
}
}
//