Files
DocumentServer-v-9.2.0/core/DesktopEditor/fontengine/ApplicationFonts.cpp
Yajbir Singh f1b860b25c
Some checks failed
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++
Raw Blame History

This file contains ambiguous Unicode characters

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

/*
* (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 );
}
}
//