Files
core/DesktopEditor/fontengine/ApplicationFontsWorker.cpp
2026-04-02 08:10:57 +03:00

1895 lines
52 KiB
C++
Raw Permalink 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 "ApplicationFontsWorker.h"
#include <map>
#include <set>
#include "../common/File.h"
#include "../common/Directory.h"
#include "../common/Array.h"
#include "../common/StringBuilder.h"
#include "../common/StringExt.h"
#include "../common/ByteBuilder.h"
#include "../graphics/pro/Fonts.h"
#include "../raster/BgraFrame.h"
#include "../graphics/pro/Graphics.h"
bool g_sort_font_names(const std::wstring& i, const std::wstring& j)
{
std::wstring s1 = i;
std::wstring s2 = j;
wchar_t symbol;
size_t len = s1.length();
for (size_t c = 0; c < len; ++c)
{
symbol = s1[c];
if (symbol >= 'A' && symbol <= 'Z')
s1[c] = symbol + 'a' - 'A';
}
len = s2.length();
for (size_t c = 0; c < len; ++c)
{
symbol = s2[c];
if (symbol >= 'A' && symbol <= 'Z')
s2[c] = symbol + 'a' - 'A';
}
return s1 < s2;
}
class CApplicationFontsWorker_private
{
public:
CApplicationFontsWorker_private(CApplicationFontsWorker* pMain)
{
m_pMain = pMain;
m_pBreaker = NULL;
m_bIsCheckThumbnailsMode = false;
}
~CApplicationFontsWorker_private()
{
}
public:
class CFontThumbnail
{
public:
std::wstring m_sFile;
std::wstring m_sName;
int m_lFaceIndex;
public:
CFontThumbnail()
{
m_sFile = L"";
m_sName = L"";
m_lFaceIndex = 0;
}
CFontThumbnail(const CFontThumbnail& oSrc)
{
m_sFile = oSrc.m_sFile;
m_sName = oSrc.m_sName;
m_lFaceIndex = oSrc.m_lFaceIndex;
}
CFontThumbnail& operator=(const CFontThumbnail& oSrc)
{
m_sFile = oSrc.m_sFile;
m_sName = oSrc.m_sName;
m_lFaceIndex = oSrc.m_lFaceIndex;
return *this;
}
};
public:
CApplicationFontsWorker* m_pMain;
CApplicationFontsWorkerBreaker* m_pBreaker;
std::vector<CFontThumbnail> m_arFonts;
bool m_bIsCheckThumbnailsMode;
std::map<std::wstring, std::wstring> m_mapAlternateEA;
class CFontInfoJS
{
public:
std::wstring m_sName;
int m_lIndexR;
int m_lFaceIndexR;
std::wstring m_sStyleR;
int m_lIndexI;
int m_lFaceIndexI;
std::wstring m_sStyleI;
int m_lIndexB;
int m_lFaceIndexB;
std::wstring m_sStyleB;
int m_lIndexBI;
int m_lFaceIndexBI;
std::wstring m_sStyleBI;
CFontInfoJS()
{
m_sName = L"";
m_lIndexR = -1;
m_lFaceIndexR = -1;
m_lIndexI = -1;
m_lFaceIndexI = -1;
m_lIndexB = -1;
m_lFaceIndexB = -1;
m_lIndexBI = -1;
m_lFaceIndexBI = -1;
m_sStyleR = L"";
m_sStyleI = L"";
m_sStyleB = L"";
m_sStyleBI = L"";
}
CFontInfoJS(const CFontInfoJS& oSrc)
{
*this = oSrc;
}
CFontInfoJS& operator=(const CFontInfoJS& oSrc)
{
m_sName = oSrc.m_sName;
m_lIndexR = oSrc.m_lIndexR;
m_lIndexI = oSrc.m_lIndexI;
m_lIndexB = oSrc.m_lIndexB;
m_lIndexBI = oSrc.m_lIndexBI;
m_lFaceIndexR = oSrc.m_lFaceIndexR;
m_lFaceIndexI = oSrc.m_lFaceIndexI;
m_lFaceIndexB = oSrc.m_lFaceIndexB;
m_lFaceIndexBI = oSrc.m_lFaceIndexBI;
m_sStyleR = oSrc.m_sStyleR;
m_sStyleI = oSrc.m_sStyleI;
m_sStyleB = oSrc.m_sStyleB;
m_sStyleBI = oSrc.m_sStyleBI;
return *this;
}
bool IsNeedUpdateR()
{
return !NSFonts::CFontInfo::IsStyleRegular(m_sStyleR);
}
bool IsNeedUpdateI()
{
return !NSFonts::CFontInfo::IsStyleItalic(m_sStyleI);
}
bool IsNeedUpdateB()
{
return !NSFonts::CFontInfo::IsStyleBold(m_sStyleB);
}
bool IsNeedUpdateBI()
{
return !NSFonts::CFontInfo::IsStyleBoldItalic(m_sStyleBI);
}
};
class CSymbolSimpleChecker : public NSFonts::CApplicationFontsSymbolsChecker
{
public:
int m_nMaxSymbols;
int* m_pSymbols;
int m_nPriority;
public:
CSymbolSimpleChecker()
{
}
virtual void Check(const int& nCode, const unsigned int& nIndex)
{
if (nCode > m_nMaxSymbols)
return;
if (m_pSymbols[nCode] == 0)
m_pSymbols[nCode] = m_nPriority;
else if (m_pSymbols[nCode] > m_nPriority)
m_pSymbols[nCode] = m_nPriority;
}
~CSymbolSimpleChecker()
{
}
};
class CSymbolSimpleChecker2 : public NSFonts::CApplicationFontsSymbolsChecker
{
public:
int m_nMaxSymbols;
int* m_pSymbols;
int m_nPriority;
int m_nStyle;
BYTE* m_pTmpSymbols;
int m_nMin;
int m_nMax;
public:
CSymbolSimpleChecker2(int* pSymbols, int nMax)
{
m_pSymbols = pSymbols;
m_nMaxSymbols = nMax;
m_pTmpSymbols = new BYTE[m_nMaxSymbols + 1];
memset(m_pTmpSymbols, 0, (m_nMaxSymbols + 1) * sizeof(BYTE));
m_nMin = m_nMaxSymbols + 1;
m_nMax = -1;
m_nStyle = 0;
}
void Apply1(int nMask)
{
BYTE* tmp = m_pTmpSymbols + m_nMin;
for (int i = m_nMin; i <= m_nMax; ++i, ++tmp)
{
if (nMask == *tmp)
{
if (m_pSymbols[i] == 0)
m_pSymbols[i] = m_nPriority;
else if (m_pSymbols[i] > m_nPriority)
m_pSymbols[i] = m_nPriority;
}
}
if (m_nMax >= m_nMin)
memset(m_pTmpSymbols, 0, (m_nMax - m_nMin) * sizeof(BYTE));
m_nMin = m_nMaxSymbols + 1;
m_nMax = -1;
}
void Apply2(int nMask, int nSumPriority)
{
int nSmallRangeLen = 10;
int nSmallRangeLenCJK = 30;
BYTE* tmp = m_pTmpSymbols + m_nMin;
BYTE* tmpLast = m_pTmpSymbols + m_nMax + 1;
BYTE* tmpFirst = NULL;
int* pSymbols = NULL;
int* pSymbolsLast = NULL;
int nPriority = 0;
int nFirstOffset = 0;
while (tmp < tmpLast)
{
if (nMask != *tmp)
{
++tmp;
continue;
}
tmpFirst = tmp;
int nCount = 1;
++tmp;
while (tmp < tmpLast && nMask == *tmp)
{
++tmp;
nCount++;
}
nFirstOffset = (int)(tmpFirst - m_pTmpSymbols);
pSymbols = m_pSymbols + nFirstOffset;
pSymbolsLast = pSymbols + nCount;
if (m_nPriority != 1)
{
if (nFirstOffset > 0x4DFF && nFirstOffset < 0x9FFF)
nPriority = (nCount > nSmallRangeLenCJK) ? m_nPriority : (m_nPriority + nSumPriority);
else
nPriority = (nCount > nSmallRangeLen) ? m_nPriority : (m_nPriority + nSumPriority);
}
else
{
// for ASCW3 font we allow small range length
nPriority = m_nPriority;
}
while (pSymbols < pSymbolsLast)
{
if (*pSymbols == 0)
*pSymbols = nPriority;
else if (*pSymbols > nPriority)
*pSymbols = nPriority;
++pSymbols;
}
}
if (m_nMax >= m_nMin)
memset(m_pTmpSymbols, 0, (m_nMax - m_nMin) * sizeof(BYTE));
m_nMin = m_nMaxSymbols + 1;
m_nMax = -1;
}
virtual void Check(const int& nCode, const unsigned int& nIndex)
{
if (nCode > m_nMaxSymbols)
return;
if (nCode > m_nMax)
m_nMax = nCode;
if (nCode < m_nMin)
m_nMin = nCode;
m_pTmpSymbols[nCode] |= m_nStyle;
}
~CSymbolSimpleChecker2()
{
RELEASEARRAYOBJECTS(m_pTmpSymbols);
}
};
class CFontPriority
{
public:
std::wstring name;
int priority;
CFontPriority()
{
priority = 0;
}
static bool Compare(const CFontPriority& p1, const CFontPriority& p2)
{
if (p1.priority != p2.priority)
return (p1.priority < p2.priority) ? true : false;
return (p1.name < p2.name) ? true : false;
}
};
public:
inline bool CheckBreak()
{
if (m_pBreaker && !m_pBreaker->IsFontsWorkerRunned())
return true;
return false;
}
bool IsEastAsianScript(const unsigned int& value)
{
// Bopomofo (3100312F)
// Bopomofo Extended (31A031BF)
// CJK Unified Ideographs (4E009FEA)
// CJK Unified Ideographs Extension A (34004DB5)
// CJK Unified Ideographs Extension B (200002A6D6)
// CJK Unified Ideographs Extension C (2A7002B734)
// CJK Unified Ideographs Extension D (2B7402B81D)
// CJK Unified Ideographs Extension E (2B8202CEA1)
// CJK Unified Ideographs Extension F (2CEB02EBE0)
// CJK Compatibility Ideographs (F900FAFF)
// CJK Compatibility Ideographs Supplement (2F8002FA1F)
// Kangxi Radicals (2F002FDF)
// CJK Radicals Supplement (2E802EFF)
// CJK Strokes (31C031EF)
// Ideographic Description Characters (2FF02FFF)
// Hangul Jamo (110011FF)
// Hangul Jamo Extended-A (A960A97F)
// Hangul Jamo Extended-B (D7B0D7FF)
// Hangul Compatibility Jamo (3130318F)
// Halfwidth and Fullwidth Forms (FF00FFEF)
// Hangul Syllables (AC00D7AF)
// Hiragana (3040309F)
// Kana Extended-A (1B1001B12F)
// Kana Supplement (1B0001B0FF)
// Kanbun (3190319F)
// Katakana (30A030FF)
// Katakana Phonetic Extensions (31F031FF)
// Lisu (A4D0A4FF)
// Miao (16F0016F9F)
// Nushu (1B1701B2FF)
// Tangut (17000187EC)
// Tangut Components (1880018AFF)
// Yi Syllables (A000A48F)
// Yi Radicals (A490A4CF)
return ((0x3100 <= value && value <= 0x312F)
|| (0x31A0 <= value && value <= 0x31BF)
|| (0x4E00 <= value && value <= 0x9FEA)
|| (0x3400 <= value && value <= 0x4DB5)
|| (0x20000 <= value && value <= 0x2A6D6)
|| (0x2A700 <= value && value <= 0x2B734)
|| (0x2B740 <= value && value <= 0x2B81D)
|| (0x2B820 <= value && value <= 0x2CEA1)
|| (0x2CEB0 <= value && value <= 0x2EBE0)
|| (0xF900 <= value && value <= 0xFAFF)
|| (0x2F800 <= value && value <= 0x2FA1F)
|| (0x2F00 <= value && value <= 0x2FDF)
|| (0x2E80 <= value && value <= 0x2EFF)
|| (0x31C0 <= value && value <= 0x31EF)
|| (0x2FF0 <= value && value <= 0x2FFF)
|| (0x1100 <= value && value <= 0x11FF)
|| (0xA960 <= value && value <= 0xA97F)
|| (0xD7B0 <= value && value <= 0xD7FF)
|| (0x3130 <= value && value <= 0x318F)
|| (0xFF00 <= value && value <= 0xFFEF)
|| (0xAC00 <= value && value <= 0xD7AF)
|| (0x3040 <= value && value <= 0x309F)
|| (0x1B100 <= value && value <= 0x1B12F)
|| (0x1B000 <= value && value <= 0x1B0FF)
|| (0x3190 <= value && value <= 0x319F)
|| (0x30A0 <= value && value <= 0x30FF)
|| (0x31F0 <= value && value <= 0x31FF)
|| (0xA4D0 <= value && value <= 0xA4FF)
|| (0x16F00 <= value && value <= 0x16F9F)
|| (0x1B170 <= value && value <= 0x1B2FF)
|| (0x17000 <= value && value <= 0x187EC)
|| (0x18800 <= value && value <= 0x18AFF)
|| (0xA000 <= value && value <= 0xA48F)
|| (0xA490 <= value && value <= 0xA4CF));
}
bool IsEastAsianName(const std::wstring& sName)
{
for (NSStringExt::CStringUnicodeIterator oIterator(sName); oIterator.Check(); oIterator.Next())
{
if (IsEastAsianScript(oIterator.Value()))
return true;
}
return false;
}
void CheckFontAlternateName(NSFonts::CFontInfo* info, std::map<std::wstring, std::wstring>& mapAlternate)
{
if (info->names.empty())
return;
if (!IsEastAsianName(info->m_wsFontName) && IsEastAsianName(info->names[0]))
{
mapAlternate.insert(std::pair<std::wstring, std::wstring>(info->m_wsFontName, info->names[0]));
}
}
std::wstring SaveWebFonts(const std::map<std::wstring, LONG>& mapFontFiles)
{
int nCountFiles = (int)mapFontFiles.size();
BYTE correct16[16] = {0xA0, 0x66, 0xD6, 0x20, 0x14, 0x96, 0x47, 0xfa, 0x95, 0x69, 0xB8, 0x50, 0xB0, 0x41, 0x49, 0x48};
int nCountIdSymbols = (nCountFiles >= 1000) ? 4 : 3;
BYTE encode[32];
std::wstring* pMassFiles2 = new std::wstring[nCountFiles];
int nCurrentId = 0;
for (std::map<std::wstring, LONG>::const_iterator pos = mapFontFiles.begin(); pos != mapFontFiles.end(); pos++)
{
std::wstring strFontId = pos->first;
std::wstring sId = std::to_wstring(nCurrentId++);
int nLenId = (int)sId.length();
while (nLenId < nCountIdSymbols)
{
sId = L"0" + sId;
++nLenId;
}
pMassFiles2[pos->second] = sId;
std::wstring sOutputFile = m_pMain->m_sWebFontsDirectory + L"/" + sId;
NSFile::CFileBinary::Copy(strFontId, sOutputFile);
NSFile::CFileBinary oFileDst;
if (oFileDst.OpenFile(sOutputFile, true))
{
DWORD dwRead = (DWORD)(oFileDst.GetFileSize());
if (dwRead > 32)
dwRead = 32;
DWORD dwWorked = 0;
oFileDst.SeekFile(0);
oFileDst.ReadFile(encode, dwRead, dwWorked);
for (DWORD k = 0; k < dwRead; ++k)
encode[k] ^= correct16[k & 0x0F];
oFileDst.SeekFile(0);
oFileDst.WriteFile(encode, dwRead);
oFileDst.CloseFile();
}
}
NSStringUtils::CStringBuilder oWriterJS;
oWriterJS.WriteString(L"window[\"__fonts_files\"] = [\n");
for (size_t nIndex = 0; nIndex < nCountFiles; ++nIndex)
{
oWriterJS.WriteString(L"\"");
oWriterJS.WriteString(pMassFiles2[nIndex]);
if (nIndex != (nCountFiles - 1))
oWriterJS.WriteString(L"\",\n");
else
oWriterJS.WriteString(L"\"");
}
oWriterJS.WriteString(L"\n];\n\n");
delete [] pMassFiles2;
return oWriterJS.GetData();
}
void SaveAllFontsJS(NSFonts::IApplicationFonts* applicationFonts, int nVersion = ONLYOFFICE_ALL_FONTS_VERSION)
{
if (CheckBreak()) return;
std::vector<NSFonts::CFontInfo*>* pList = applicationFonts->GetList()->GetFonts();
int nCount = (int)pList->size();
// first build array of all font files
std::map<std::wstring, LONG> mapFontFiles;
std::map<LONG, std::wstring> mapFontFiles2;
LONG lFontFiles = 0;
for (std::vector<NSFonts::CFontInfo*>::iterator i = pList->begin(); i != pList->end(); i++)
{
NSFonts::CFontInfo* pInfo = *i;
if (m_pMain->m_bIsGenerateThumbnailsEA)
CheckFontAlternateName(pInfo, m_mapAlternateEA);
if (mapFontFiles.find(pInfo->m_wsFontPath) == mapFontFiles.end())
{
mapFontFiles.insert(std::pair<std::wstring, LONG>(pInfo->m_wsFontPath, lFontFiles));
mapFontFiles2.insert(std::pair<LONG, std::wstring>(lFontFiles, pInfo->m_wsFontPath));
++lFontFiles;
}
}
// -----------------------------------------
if (CheckBreak()) return;
// now build array of all fonts by name
std::map<std::wstring, CFontInfoJS> mapFonts;
std::vector<std::wstring> arrFonts;
for (std::vector<NSFonts::CFontInfo*>::iterator i = pList->begin(); i != pList->end(); i++)
{
NSFonts::CFontInfo* pInfo = *i;
std::wstring strPath = pInfo->m_wsFontPath;
std::wstring strName = pInfo->m_wsFontName;
int lFontIndex = 0;
int lFaceIndex = 0;
std::map<std::wstring, LONG>::iterator it = mapFontFiles.find(strPath);
lFontIndex = it->second;
if (pInfo->m_lIndex >= 0)
lFaceIndex = (int)pInfo->m_lIndex;
std::map<std::wstring, CFontInfoJS>::iterator pPair = mapFonts.find(pInfo->m_wsFontName);
if (mapFonts.end() != pPair)
{
pPair->second.m_sName = pInfo->m_wsFontName;
if (pInfo->m_bBold && pInfo->m_bItalic)
{
if (pPair->second.IsNeedUpdateBI())
{
pPair->second.m_lIndexBI = lFontIndex;
pPair->second.m_lFaceIndexBI = lFaceIndex;
pPair->second.m_sStyleBI = pInfo->m_wsStyle;
}
}
else if (pInfo->m_bBold)
{
if (pPair->second.IsNeedUpdateB())
{
pPair->second.m_lIndexB = lFontIndex;
pPair->second.m_lFaceIndexB = lFaceIndex;
pPair->second.m_sStyleB = pInfo->m_wsStyle;
}
}
else if (pInfo->m_bItalic)
{
if (pPair->second.IsNeedUpdateI())
{
pPair->second.m_lIndexI = lFontIndex;
pPair->second.m_lFaceIndexI = lFaceIndex;
pPair->second.m_sStyleI = pInfo->m_wsStyle;
}
}
else
{
if (pPair->second.IsNeedUpdateR())
{
pPair->second.m_lIndexR = lFontIndex;
pPair->second.m_lFaceIndexR = lFaceIndex;
pPair->second.m_sStyleR = pInfo->m_wsStyle;
}
}
}
else
{
CFontInfoJS fontInfo;
fontInfo.m_sName = pInfo->m_wsFontName;
if (pInfo->m_bBold && pInfo->m_bItalic)
{
fontInfo.m_lIndexBI = lFontIndex;
fontInfo.m_lFaceIndexBI = lFaceIndex;
fontInfo.m_sStyleBI = pInfo->m_wsStyle;
}
else if (pInfo->m_bBold)
{
fontInfo.m_lIndexB = lFontIndex;
fontInfo.m_lFaceIndexB = lFaceIndex;
fontInfo.m_sStyleB = pInfo->m_wsStyle;
}
else if (pInfo->m_bItalic)
{
fontInfo.m_lIndexI = lFontIndex;
fontInfo.m_lFaceIndexI = lFaceIndex;
fontInfo.m_sStyleI = pInfo->m_wsStyle;
}
else
{
fontInfo.m_lIndexR = lFontIndex;
fontInfo.m_lFaceIndexR = lFaceIndex;
fontInfo.m_sStyleR = pInfo->m_wsStyle;
}
mapFonts.insert(std::pair<std::wstring, CFontInfoJS>(fontInfo.m_sName, fontInfo));
arrFonts.push_back(fontInfo.m_sName);
}
}
// -------------------------------------------
if (CheckBreak()) return;
// now sort fonts by name ----------
size_t nCountFonts = arrFonts.size();
#if 1
std::sort(arrFonts.begin(), arrFonts.end(), g_sort_font_names);
#else
for (size_t i = 0; i < nCountFonts; ++i)
{
for (size_t j = i + 1; j < nCountFonts; ++j)
{
if (arrFonts[i] > arrFonts[j])
{
std::wstring temp = arrFonts[i];
arrFonts[i] = arrFonts[j];
arrFonts[j] = temp;
}
}
}
#endif
std::wstring strFontSelectionBin = L"";
// whether to dump font_selection.bin
if (ONLYOFFICE_ALL_FONTS_VERSION == nVersion && !m_bIsCheckThumbnailsMode)
{
strFontSelectionBin = m_pMain->m_sDirectory + L"/font_selection.bin";
}
NSMemoryUtils::CByteBuilder* pRangeBuilder = NULL;
int nRangeBuilderCount = 0;
if (!strFontSelectionBin.empty())
{
pRangeBuilder = new NSMemoryUtils::CByteBuilder();
pRangeBuilder->WriteInt(0);
}
// most importantly, the script for working with all fonts should be dumped here.
// all objects that will allow not knowing about existing fonts
std::wstring sAllFontsPath = m_pMain->m_sDirectory + L"/AllFonts.js";
if (!m_pMain->m_sAllFontsJSPath.empty())
sAllFontsPath = m_pMain->m_sAllFontsJSPath;
if (nVersion != ONLYOFFICE_ALL_FONTS_VERSION)
sAllFontsPath += (L"." + std::to_wstring((int)(nVersion + 1)));
if (m_bIsCheckThumbnailsMode)
sAllFontsPath = L"";
// AllFonts.js for web is exactly the same, but with different paths
std::wstring sFontFilesWeb = L"";
size_t nFontFilesWeb1 = 0;
size_t nFontFilesWeb2 = 0;
if (!m_pMain->m_sWebFontsDirectory.empty() && !m_pMain->m_sWebAllFontsJSPath.empty() && !m_bIsCheckThumbnailsMode)
{
sFontFilesWeb = SaveWebFonts(mapFontFiles);
}
if (!sAllFontsPath.empty())
{
NSStringUtils::CStringBuilder oWriterJS;
int nAllFontsVersion = nVersion;
oWriterJS.WriteString(L"window[\"__all_fonts_js_version__\"] = ");
oWriterJS.AddInt(nAllFontsVersion);
oWriterJS.WriteString(L";\n\n");
nFontFilesWeb1 = oWriterJS.GetCurSize();
// first all files
size_t nCountFiles = mapFontFiles.size();
if (nCountFiles == 0)
oWriterJS.WriteString(L"window[\"__fonts_files\"] = []; \n\n");
else
{
std::wstring* pMassFiles = new std::wstring[nCountFiles];
for ( std::map<std::wstring, LONG>::iterator pos = mapFontFiles.begin(); pos != mapFontFiles.end(); ++pos)
{
std::wstring strFontId = pos->first;
NSStringUtils::string_replace(strFontId, L"\\\\", L"\\");
NSStringUtils::string_replace(strFontId, L"\\", L"/");
pMassFiles[pos->second] = strFontId;
}
oWriterJS.WriteString(L"window[\"__fonts_files\"] = [\n");
for (size_t nIndex = 0; nIndex < nCountFiles; ++nIndex)
{
oWriterJS.WriteString(L"\"");
oWriterJS.WriteString(pMassFiles[nIndex]);
if (nIndex != (nCountFiles - 1))
oWriterJS.WriteString(L"\",\n");
else
oWriterJS.WriteString(L"\"");
}
oWriterJS.WriteString(L"\n];\n\n");
nFontFilesWeb2 = oWriterJS.GetCurSize();
delete [] pMassFiles;
}
oWriterJS += L"window[\"__fonts_infos\"] = [\n";
std::map<std::wstring, int> mapFontIndexes;
for (int index = 0; index < nCountFonts; ++index)
{
std::map<std::wstring, CFontInfoJS>::iterator pPair = mapFonts.find(arrFonts[index]);
mapFontIndexes.insert(std::pair<std::wstring, int>(arrFonts[index], index));
oWriterJS += L"[\"";
std::wstring sNameCorrect = pPair->second.m_sName;
NSStringUtils::string_replace(sNameCorrect, L"\\", L"\\\\");
NSStringUtils::string_replace(sNameCorrect, L"\"", L"\\\"");
NSStringUtils::string_replace(sNameCorrect, L"\n", L"");
NSStringUtils::string_replace(sNameCorrect, L"\r", L"");
oWriterJS += sNameCorrect;
oWriterJS.AddSize(120);
oWriterJS.AddCharNoCheck('\"');
oWriterJS.AddCharNoCheck(',');
oWriterJS.AddIntNoCheck(pPair->second.m_lIndexR);
oWriterJS.AddCharNoCheck(',');
oWriterJS.AddIntNoCheck(pPair->second.m_lFaceIndexR);
oWriterJS.AddCharNoCheck(',');
oWriterJS.AddIntNoCheck(pPair->second.m_lIndexI);
oWriterJS.AddCharNoCheck(',');
oWriterJS.AddIntNoCheck(pPair->second.m_lFaceIndexI);
oWriterJS.AddCharNoCheck(',');
oWriterJS.AddIntNoCheck(pPair->second.m_lIndexB);
oWriterJS.AddCharNoCheck(',');
oWriterJS.AddIntNoCheck(pPair->second.m_lFaceIndexB);
oWriterJS.AddCharNoCheck(',');
oWriterJS.AddIntNoCheck(pPair->second.m_lIndexBI);
oWriterJS.AddCharNoCheck(',');
oWriterJS.AddIntNoCheck(pPair->second.m_lFaceIndexBI);
if (index != (nCountFonts - 1))
oWriterJS += (L"],\n");
else
oWriterJS += (L"]\n");
}
oWriterJS += (L"];\n\n");
if (true)
{
//DWORD dwTime = NSTimers::GetTickCount();
int nMaxSymbol = 0x10FFFF;
int* arSymbolsAll = new int[nMaxSymbol + 1];
memset(arSymbolsAll, 0, (nMaxSymbol + 1) * sizeof(int));
CSymbolSimpleChecker2 oAllChecker(arSymbolsAll, nMaxSymbol);
std::map<std::wstring, int> mapFontsPriorityStandard;
int nCurrentPriority = 1;
#define SET_FONT_PRIORITY(fontName) mapFontsPriorityStandard.insert(std::pair<std::wstring, int>(fontName, nCurrentPriority++))
SET_FONT_PRIORITY(L"ASCW3");
SET_FONT_PRIORITY(L"Arial");
SET_FONT_PRIORITY(L"Times New Roman");
SET_FONT_PRIORITY(L"Tahoma");
SET_FONT_PRIORITY(L"Cambria");
SET_FONT_PRIORITY(L"Calibri");
SET_FONT_PRIORITY(L"Verdana");
SET_FONT_PRIORITY(L"Georgia");
SET_FONT_PRIORITY(L"Open Sans");
SET_FONT_PRIORITY(L"Liberation Sans");
SET_FONT_PRIORITY(L"Helvetica");
SET_FONT_PRIORITY(L"Nimbus Sans L");
SET_FONT_PRIORITY(L"DejaVu Sans");
SET_FONT_PRIORITY(L"Liberation Serif");
SET_FONT_PRIORITY(L"Trebuchet MS");
SET_FONT_PRIORITY(L"Courier New");
SET_FONT_PRIORITY(L"Carlito");
SET_FONT_PRIORITY(L"Segoe UI");
SET_FONT_PRIORITY(L"SimSun");
SET_FONT_PRIORITY(L"MS Gothic");
SET_FONT_PRIORITY(L"Nirmala UI");
SET_FONT_PRIORITY(L"Batang");
SET_FONT_PRIORITY(L"MS Mincho");
SET_FONT_PRIORITY(L"Wingdings");
SET_FONT_PRIORITY(L"Microsoft JhengHei");
SET_FONT_PRIORITY(L"Microsoft JhengHei UI");
SET_FONT_PRIORITY(L"Microsoft YaHei");
SET_FONT_PRIORITY(L"PMingLiU");
SET_FONT_PRIORITY(L"MingLiU");
SET_FONT_PRIORITY(L"DFKai-SB");
SET_FONT_PRIORITY(L"FangSong");
SET_FONT_PRIORITY(L"KaiTi");
SET_FONT_PRIORITY(L"SimKai");
SET_FONT_PRIORITY(L"SimHei");
SET_FONT_PRIORITY(L"Meiryo");
#ifdef _MAC
SET_FONT_PRIORITY(L"PingFang SC");
SET_FONT_PRIORITY(L"PingFang TC");
SET_FONT_PRIORITY(L"PingFang HK");
SET_FONT_PRIORITY(L"Heiti SC");
SET_FONT_PRIORITY(L"Heiti TC");
SET_FONT_PRIORITY(L"Songti SC");
SET_FONT_PRIORITY(L"Songti TC");
#endif
SET_FONT_PRIORITY(L"Malgun Gothic");
SET_FONT_PRIORITY(L"Nanum Gothic");
SET_FONT_PRIORITY(L"NanumGothic");
SET_FONT_PRIORITY(L"Noto Sans KR");
SET_FONT_PRIORITY(L"TakaoGothic");
NSFonts::CApplicationFontsSymbols oApplicationChecker;
// font priorities by name (all styles)
// if font is from mapFontsPriorityStandard, priority is from that map
// otherwise - maximum size of font style files (max(regular,italic,bold,bolditalic))
std::vector<CFontPriority> arrFontsPriority;
for (int index = 0; index < nCountFonts; ++index)
{
std::map<std::wstring, CFontInfoJS>::iterator pPair = mapFonts.find(arrFonts[index]);
CFontInfoJS& info = pPair->second;
std::map<std::wstring, int>::iterator find = mapFontsPriorityStandard.find(arrFonts[index]);
if (find != mapFontsPriorityStandard.end())
{
CFontPriority f;
f.name = arrFonts[index];
f.priority = find->second;
arrFontsPriority.push_back(f);
continue;
}
int nSize = 0;
if (-1 != info.m_lIndexR)
{
NSFile::CFileBinary oFile;
if (oFile.OpenFile(mapFontFiles2[info.m_lIndexR]))
{
int nTmp = oFile.GetFileSize();
if (nTmp > nSize)
nSize = nTmp;
}
}
if (-1 != info.m_lIndexB)
{
NSFile::CFileBinary oFile;
if (oFile.OpenFile(mapFontFiles2[info.m_lIndexB]))
{
int nTmp = oFile.GetFileSize();
if (nTmp > nSize)
nSize = nTmp;
}
}
if (-1 != info.m_lIndexI)
{
NSFile::CFileBinary oFile;
if (oFile.OpenFile(mapFontFiles2[info.m_lIndexI]))
{
int nTmp = oFile.GetFileSize();
if (nTmp > nSize)
nSize = nTmp;
}
}
if (-1 != info.m_lIndexBI)
{
NSFile::CFileBinary oFile;
if (oFile.OpenFile(mapFontFiles2[info.m_lIndexBI]))
{
int nTmp = oFile.GetFileSize();
if (nTmp > nSize)
nSize = nTmp;
}
}
CFontPriority f;
f.name = arrFonts[index];
f.priority = nSize;
arrFontsPriority.push_back(f);
}
// sort by priority
std::sort(arrFontsPriority.begin(), arrFontsPriority.end(), CFontPriority::Compare);
// for convenience - create a map
std::map<std::wstring, int> mapFontsPriority;
int nIndexPriority = 1;
for (std::vector<CFontPriority>::iterator i = arrFontsPriority.begin(); i != arrFontsPriority.end(); i++)
{
CFontPriority& o = *i;
mapFontsPriority.insert(std::pair<std::wstring, int>(o.name, nIndexPriority));
nIndexPriority++;
}
int nSumPriority = (int)(arrFontsPriority.size() + 1);
bool bIsSmallRangesDetect = true;
for (int index = 0; index < nCountFonts; ++index)
{
std::map<std::wstring, CFontInfoJS>::iterator pPair = mapFonts.find(arrFonts[index]);
CFontInfoJS& info = pPair->second;
int nPriority = mapFontsPriority.find(arrFonts[index])->second;
oAllChecker.m_nPriority = nPriority;
int nCounterFonts = 0;
if (-1 != info.m_lIndexR)
nCounterFonts++;
if (-1 != info.m_lIndexB)
nCounterFonts++;
if (-1 != info.m_lIndexI)
nCounterFonts++;
if (-1 != info.m_lIndexBI)
nCounterFonts++;
if (1 == nCounterFonts && !bIsSmallRangesDetect)
{
// this mode is disabled (bIsSmallRangesDetect is always true)
std::wstring sPathC = L"";
int nFaceIndexC = 0;
if (-1 != info.m_lIndexR)
{
sPathC = mapFontFiles2[info.m_lIndexR];
nFaceIndexC = info.m_lFaceIndexR;
}
else if (-1 != info.m_lIndexB)
{
sPathC = mapFontFiles2[info.m_lIndexB];
nFaceIndexC = info.m_lFaceIndexB;
}
else if (-1 != info.m_lIndexI)
{
sPathC = mapFontFiles2[info.m_lIndexI];
nFaceIndexC = info.m_lFaceIndexI;
}
else if (-1 != info.m_lIndexBI)
{
sPathC = mapFontFiles2[info.m_lIndexBI];
nFaceIndexC = info.m_lFaceIndexBI;
}
CSymbolSimpleChecker checker;
checker.m_nMaxSymbols = nMaxSymbol;
checker.m_pSymbols = arSymbolsAll;
checker.m_nPriority = nPriority;
oApplicationChecker.CheckSymbols(sPathC, nFaceIndexC, &checker);
}
else
{
// for each font - analyze symbols. write m_nStyle to the
// symbol array (tmp buffer)
int nMask = 0;
if (-1 != info.m_lIndexR)
{
oAllChecker.m_nStyle = 1;
nMask |= 1;
oApplicationChecker.CheckSymbols(mapFontFiles2[info.m_lIndexR], info.m_lFaceIndexR, &oAllChecker);
}
if (-1 != info.m_lIndexB)
{
oAllChecker.m_nStyle = 2;
nMask |= 2;
oApplicationChecker.CheckSymbols(mapFontFiles2[info.m_lIndexB], info.m_lFaceIndexB, &oAllChecker);
}
if (-1 != info.m_lIndexI)
{
oAllChecker.m_nStyle = 4;
nMask |= 4;
oApplicationChecker.CheckSymbols(mapFontFiles2[info.m_lIndexI], info.m_lFaceIndexI, &oAllChecker);
}
if (-1 != info.m_lIndexBI)
{
oAllChecker.m_nStyle = 8;
nMask |= 8;
oApplicationChecker.CheckSymbols(mapFontFiles2[info.m_lIndexBI], info.m_lFaceIndexBI, &oAllChecker);
}
if (bIsSmallRangesDetect)
{
// check all symbols that exist in ALL font styles
// nSumPriority - is an addition for small range lengths, so that if there's
// a long range with higher priority - it will override it.
// for this, the addition is the number of fonts to be sufficient
oAllChecker.Apply2(nMask, nSumPriority);
}
else
{
// just check all symbols that exist in ALL font styles
oAllChecker.Apply1(nMask);
}
}
}
//dwTime = NSTimers::GetTickCount() - dwTime;
oWriterJS += L"window[\"__fonts_ranges\"] = [\n";
int nFontPriority = 0;
int nFontPriorityStart = 0;
int nTopBorder = nMaxSymbol + 1;
for (int i = 0; i < nTopBorder; ++i)
{
int nFontPriorityTestSym = arSymbolsAll[i];
int nFontPriorityTest = (nFontPriorityTestSym > nSumPriority) ? (nFontPriorityTestSym - nSumPriority) : nFontPriorityTestSym;
if (nFontPriority == nFontPriorityTest)
continue;
if (nFontPriority != 0)
{
++nRangeBuilderCount;
oWriterJS.AddInt(nFontPriorityStart);
oWriterJS.AddCharSafe(',');
oWriterJS.AddInt(i - 1);
oWriterJS.AddCharSafe(',');
oWriterJS.AddInt(mapFontIndexes.find(arrFontsPriority[nFontPriority - 1].name)->second);
oWriterJS.AddCharSafe(',');
if (pRangeBuilder)
{
pRangeBuilder->WriteStringUTF8(arrFontsPriority[nFontPriority - 1].name);
pRangeBuilder->WriteInt(nFontPriorityStart);
pRangeBuilder->WriteInt(i - 1);
}
}
nFontPriority = nFontPriorityTest;
nFontPriorityStart = i;
}
if (nFontPriority != 0)
{
++nRangeBuilderCount;
oWriterJS.AddInt(nFontPriorityStart);
oWriterJS.AddCharSafe(',');
oWriterJS.AddInt(nMaxSymbol - 1);
oWriterJS.AddCharSafe(',');
oWriterJS.AddInt(mapFontIndexes.find(arrFontsPriority[nFontPriority - 1].name)->second);
oWriterJS.AddCharSafe(',');
if (pRangeBuilder)
{
pRangeBuilder->WriteStringUTF8(arrFontsPriority[nFontPriority - 1].name);
pRangeBuilder->WriteInt(nFontPriorityStart);
pRangeBuilder->WriteInt(nMaxSymbol - 1);
}
}
oWriterJS.SetCurSize(oWriterJS.GetCurSize() - 1);
oWriterJS += (L"];\n\n");
delete[] arSymbolsAll;
}
if (true)
{
BYTE* pData = NULL;
LONG lLen = 0;
NSFonts::CFontListToBufferSerializer oSerializer(L"", false, nVersion);
applicationFonts->GetList()->ToBuffer(&pData, &lLen, oSerializer);
char* cData64 = NULL;
int nData64Dst = 0;
NSFile::CBase64Converter::Encode(pData, (int)lLen, cData64, nData64Dst, NSBase64::B64_BASE64_FLAG_NOCRLF);
std::wstring sData64 = NSFile::CUtf8Converter::GetUnicodeFromCharPtr(cData64, (LONG)nData64Dst, FALSE);
oWriterJS.WriteString(L"window[\"g_fonts_selection_bin\"] = \"");
oWriterJS.WriteString(sData64);
oWriterJS.WriteString(L"\";\n");
RELEASEARRAYOBJECTS(pData);
RELEASEARRAYOBJECTS(cData64);
}
NSFile::CFileBinary oFile;
oFile.CreateFileW(sAllFontsPath);
oFile.WriteStringUTF8(oWriterJS.GetData(), true);
oFile.CloseFile();
if (!sFontFilesWeb.empty())
{
NSFile::CFileBinary oFile;
oFile.CreateFileW(m_pMain->m_sWebAllFontsJSPath);
std::wstring sWebAllFonts = oWriterJS.GetSubData(0, nFontFilesWeb1) + sFontFilesWeb + oWriterJS.GetSubData(nFontFilesWeb2);
oFile.WriteStringUTF8(sWebAllFonts, true);
oFile.CloseFile();
}
}
if (!strFontSelectionBin.empty())
{
BYTE* pData = NULL;
LONG lLen = 0;
NSFonts::CFontListToBufferSerializer oSerializer(L"", false, ONLYOFFICE_ALL_FONTS_VERSION);
applicationFonts->GetList()->ToBuffer(&pData, &lLen, oSerializer);
NSFile::CFileBinary oFile;
oFile.CreateFileW(strFontSelectionBin);
oFile.WriteFile(pData, (DWORD)lLen);
if (pRangeBuilder)
{
size_t nPosCur = pRangeBuilder->GetCurSize();
pRangeBuilder->SetCurSize(0);
pRangeBuilder->WriteInt(nRangeBuilderCount);
pRangeBuilder->SetCurSize(nPosCur);
oFile.WriteFile(pRangeBuilder->GetData(), (DWORD)pRangeBuilder->GetCurSize());
// init ranges
applicationFonts->InitializeRanges(pRangeBuilder->GetData());
}
oFile.CloseFile();
RELEASEARRAYOBJECTS(pData);
}
RELEASEOBJECT(pRangeBuilder);
if (CheckBreak()) return;
if (m_pMain->m_bIsNeedThumbnails)
{
m_arFonts.clear();
m_arFonts.resize(nCountFonts);
for (int index = 0; index < nCountFonts; ++index)
{
std::map<std::wstring, CFontInfoJS>::iterator pPair = mapFonts.find(arrFonts[index]);
// thumbnail
int lFontIndex = 0;
int lFaceIndex = 0;
if (pPair->second.m_lIndexR != -1)
{
lFontIndex = pPair->second.m_lIndexR;
lFaceIndex = pPair->second.m_lFaceIndexR;
}
else if (pPair->second.m_lIndexI != -1)
{
lFontIndex = pPair->second.m_lIndexI;
lFaceIndex = pPair->second.m_lFaceIndexI;
}
else if (pPair->second.m_lIndexB != -1)
{
lFontIndex = pPair->second.m_lIndexB;
lFaceIndex = pPair->second.m_lFaceIndexB;
}
else if (pPair->second.m_lIndexBI != -1)
{
lFontIndex = pPair->second.m_lIndexBI;
lFaceIndex = pPair->second.m_lFaceIndexBI;
}
std::map<LONG, std::wstring>::iterator pPair2 = mapFontFiles2.find(lFontIndex);
std::wstring strFontPath = L"";
if (mapFontFiles2.end() != pPair2)
strFontPath = pPair2->second;
m_arFonts[index].m_sFile = strFontPath;
m_arFonts[index].m_sName = pPair->second.m_sName;
m_arFonts[index].m_lFaceIndex = lFaceIndex;
}
}
if (m_pMain->m_bSeparateThumbnails)
return;
if (m_pMain->m_bIsNeedThumbnails)
{
SaveThumbnails(applicationFonts);
}
}
void PrepareForThumbnails(NSFonts::IApplicationFonts* applicationFonts)
{
if (m_arFonts.empty())
{
m_bIsCheckThumbnailsMode = true;
SaveAllFontsJS(applicationFonts, -1);
m_bIsCheckThumbnailsMode = false;
}
}
void SaveThumbnails(NSFonts::IApplicationFonts* applicationFonts)
{
std::vector<std::wstring> arrFiles;
std::vector<double> arrScales;
std::vector<bool> arrEA;
bool bIsNeedCheck = false;
int nCountScales = m_pMain->m_arThumbnailsScales.size();
bool bIsEA = false;
while (true)
{
for (int iX = 0; iX < nCountScales; ++iX)
{
if (CheckBreak()) return;
double dScale = m_pMain->m_arThumbnailsScales[iX];
std::wstring strThumbnailPath = (m_pMain->m_sThumbnailsDirectory.empty() ?
m_pMain->m_sDirectory : m_pMain->m_sThumbnailsDirectory) + L"/fonts_thumbnail";
if (bIsEA)
strThumbnailPath += L"_ea";
int nScaleOut = (int)(dScale * 100 + 0.5);
if (nScaleOut == 100)
strThumbnailPath += L".png";
else if ((nScaleOut % 100) == 0)
strThumbnailPath += L"@" + std::to_wstring((int)(nScaleOut / 100)) + L"x.png";
else if ((nScaleOut % 10) == 0)
strThumbnailPath += L"@" + std::to_wstring((int)(nScaleOut / 100)) + L"." + std::to_wstring((int)((nScaleOut / 10) % 10)) + L"x.png";
else
strThumbnailPath += L"@" + std::to_wstring((int)(nScaleOut / 100)) + L"." + std::to_wstring((int)(nScaleOut % 100)) + L"x.png";
arrScales.push_back(dScale);
arrFiles.push_back(strThumbnailPath);
arrEA.push_back(bIsEA);
bool bIsFileExist = NSFile::CFileBinary::Exists(strThumbnailPath);
if (bIsFileExist && m_pMain->m_bIsRemoveOldThumbnails)
{
NSFile::CFileBinary::Remove(strThumbnailPath);
bIsFileExist = false;
}
if (!bIsFileExist)
bIsNeedCheck = true;
}
if (bIsEA || !m_pMain->m_bIsGenerateThumbnailsEA)
break;
bIsEA = true;
}
if (!bIsNeedCheck)
return;
NSFonts::IApplicationFonts* applicationFontsGood = applicationFonts;
if (NULL == applicationFontsGood)
{
applicationFontsGood = NSFonts::NSApplication::Create();
applicationFontsGood->InitializeFromFolder(m_pMain->m_sDirectory);
}
NSFonts::IFontManager* pManager = applicationFontsGood->GenerateFontManager();
NSFonts::IFontsCache* pCache = NSFonts::NSFontCache::Create();
pCache->SetStreams(applicationFontsGood->GetStreams());
pManager->SetOwnerCache(pCache);
PrepareForThumbnails(applicationFontsGood);
int nCountFonts = (int)m_arFonts.size();
nCountScales = arrScales.size();
for (int iX = 0; iX < nCountScales; ++iX)
{
if (CheckBreak()) return;
double dScale = arrScales[iX];
std::wstring strThumbnailPath = arrFiles[iX];
if (NSFile::CFileBinary::Exists(strThumbnailPath))
continue;
// create image for thumbnails
double dDpi = 96 * dScale;
LONG lH1_px = (LONG)(28 * dScale);
LONG lWidthPix = (LONG)(300 * dScale);
LONG lHeightPix = (LONG)(nCountFonts * lH1_px);
double dW_mm = 25.4 * lWidthPix / dDpi;
double dH1_mm = 25.4 * lH1_px / dDpi;
LONG lCountPixels = 4 * lWidthPix * lHeightPix;
BYTE* pImageData = new BYTE[lCountPixels];
memset(pImageData, 0xFF, lCountPixels);
CBgraFrame oFrame;
oFrame.put_Data(pImageData);
oFrame.put_Width((int)lWidthPix);
oFrame.put_Height((int)lHeightPix);
oFrame.put_Stride(4 * (int)lWidthPix);
for (LONG i = 3; i < lWidthPix * lHeightPix * 4; i += 4)
{
pImageData[i] = 0;
}
NSGraphics::IGraphicsRenderer* pRenderer = NSGraphics::Create();
pRenderer->CreateFromBgraFrame(&oFrame);
pRenderer->SetFontManager(pManager);
pRenderer->put_Width(lWidthPix * 25.4 / dDpi);
pRenderer->put_Height(lHeightPix * 25.4 / dDpi);
bIsEA = arrEA[iX];
for (int index = 0; index < nCountFonts; ++index)
{
if (CheckBreak()) return;
CFontThumbnail& font = m_arFonts[index];
pRenderer->put_FontPath(font.m_sFile);
pRenderer->put_FontFaceIndex(font.m_lFaceIndex);
pManager->LoadFontFromFile(font.m_sFile, font.m_lFaceIndex, 14, dDpi, dDpi);
bool bIsSymbol = false;
NSFonts::IFontFile* pFile = pManager->GetFile();
if (pFile)
bIsSymbol = pFile->IsSymbolic(false);
std::wstring sFontName = font.m_sName;
if (bIsEA)
{
std::map<std::wstring, std::wstring>::const_iterator iter = m_mapAlternateEA.find(sFontName);
if (iter != m_mapAlternateEA.end())
{
sFontName = iter->second;
}
}
if (bIsSymbol)
{
NSFonts::CFontSelectFormat oSelectFormat;
oSelectFormat.wsName = new std::wstring(L"Courier New");
NSFonts::CFontInfo* pInfoCur = pManager->GetFontInfoByParams(oSelectFormat);
if (NULL != pInfoCur)
{
pManager->LoadFontFromFile(pInfoCur->m_wsFontPath, 0, 14, dDpi, dDpi);
}
pRenderer->put_FontPath(pInfoCur->m_wsFontPath);
pRenderer->put_FontFaceIndex(0);
}
else if (pFile)
{
// we are in "no squares" mode
// but there are fonts where characters exist but have zero width.
// we create a fallback only for such fonts
bool bIsExistEmpty = false;
for (NSStringExt::CStringUnicodeIterator oIterator(sFontName); oIterator.Check(); oIterator.Next())
{
int nCMapIndex = 0;
int nGid = pFile->SetCMapForCharCode(oIterator.Value(), &nCMapIndex);
if (0 < nGid && 0.0001 > pFile->GetCharWidth(nGid))
{
bIsExistEmpty = true;
break;
}
}
if (bIsExistEmpty)
{
NSFonts::CFontSelectFormat oSelectFormat;
oSelectFormat.wsName = new std::wstring(L"Arial");
NSFonts::CFontInfo* pInfoCur = pManager->GetFontInfoByParams(oSelectFormat);
if (NULL != pInfoCur)
{
pManager->LoadFontFromFile(pInfoCur->m_wsFontPath, 0, 14, dDpi, dDpi);
}
pRenderer->put_FontPath(pInfoCur->m_wsFontPath);
pRenderer->put_FontFaceIndex(0);
}
}
pRenderer->PathCommandStart();
pRenderer->BeginCommand(c_nClipType);
pRenderer->PathCommandRect(0, 25.4 * (index * lH1_px) / dDpi, dW_mm, 25.4 * lH1_px / dDpi);
pRenderer->EndCommand(c_nClipType);
pRenderer->PathCommandEnd();
pRenderer->put_FontStringGID(FALSE);
pRenderer->put_FontCharSpace(0);
pRenderer->put_FontSize(14);
pRenderer->CommandDrawText(sFontName, 5, 25.4 * (index * lH1_px + lH1_px) / dDpi - 2, 0, 0);
pRenderer->BeginCommand(c_nResetClipType);
pRenderer->EndCommand(c_nResetClipType);
pRenderer->CloseFont();
pCache->Clear();
applicationFontsGood->GetStreams()->Clear();
}
RELEASEOBJECT(pRenderer);
oFrame.SaveFile(strThumbnailPath, 4);
LONG lBinarySize = lWidthPix * lHeightPix;
BYTE* pBinaryFormat = new BYTE[lBinarySize + 12];
pBinaryFormat[0] = 0xFF & (lWidthPix >> 24);
pBinaryFormat[1] = 0xFF & (lWidthPix >> 16);
pBinaryFormat[2] = 0xFF & (lWidthPix >> 8);
pBinaryFormat[3] = 0xFF & (lWidthPix >> 0);
pBinaryFormat[4] = 0xFF & (lH1_px >> 24);
pBinaryFormat[5] = 0xFF & (lH1_px >> 16);
pBinaryFormat[6] = 0xFF & (lH1_px >> 8);
pBinaryFormat[7] = 0xFF & (lH1_px >> 0);
pBinaryFormat[8] = 0xFF & (nCountFonts >> 24);
pBinaryFormat[9] = 0xFF & (nCountFonts >> 16);
pBinaryFormat[10] = 0xFF & (nCountFonts >> 8);
pBinaryFormat[11] = 0xFF & (nCountFonts >> 0);
BYTE* pBinaryFormatCur = pBinaryFormat + 12;
BYTE* pImageDataAlpha = pImageData + 3;
LONG nIndexCur = 0;
while (nIndexCur < lBinarySize)
{
*pBinaryFormatCur++ = *pImageDataAlpha;
if (0 != *pImageDataAlpha)
{
++nIndexCur;
pImageDataAlpha += 4;
}
else
{
LONG nIndexCur0 = nIndexCur;
LONG nIndexCurLimit = nIndexCur0 + 255;
if (nIndexCurLimit > lBinarySize)
nIndexCurLimit = lBinarySize;
while (nIndexCur < nIndexCurLimit)
{
++nIndexCur;
pImageDataAlpha += 4;
if (0 != *pImageDataAlpha)
break;
}
*pBinaryFormatCur++ = nIndexCur - nIndexCur0;
}
}
#if 0
BYTE* pPixelsValues = new BYTE[4 * lWidthPix * lHeightPix];
memset(pPixelsValues, 0x00, 4 * lWidthPix * lHeightPix);
CBgraFrame oFrameTest;
oFrameTest.put_Data(pPixelsValues);
oFrameTest.put_Width((int)lWidthPix);
oFrameTest.put_Height((int)lHeightPix);
oFrameTest.put_Stride(4 * (int)lWidthPix);
BYTE* binaryAlpha = pBinaryFormat;
LONG binaryIndex = 12;
LONG binaryLen = (LONG)(pBinaryFormatCur - pBinaryFormat);
BYTE* imagePixels = pPixelsValues;
LONG alphaIndex = 3;
int len0 = 0;
while (binaryIndex < binaryLen)
{
imagePixels[alphaIndex] = binaryAlpha[binaryIndex];
binaryIndex++;
alphaIndex += 4;
if (0 == binaryAlpha[binaryIndex - 1])
{
len0 = binaryAlpha[binaryIndex++] - 1;
while (len0 > 0)
{
len0--;
imagePixels[alphaIndex] = 0;
alphaIndex += 4;
}
}
else
{
imagePixels[alphaIndex - 5] = imagePixels[alphaIndex - 6] = imagePixels[alphaIndex - 7] = 0xFF - binaryAlpha[binaryIndex - 1];
}
}
oFrameTest.SaveFile(L"FILE", 4);
#endif
NSFile::CFileBinary oThumbnailBinary;
if (oThumbnailBinary.CreateFileW(strThumbnailPath + L".bin"))
{
oThumbnailBinary.WriteFile(pBinaryFormat, (DWORD)(pBinaryFormatCur - pBinaryFormat));
oThumbnailBinary.CloseFile();
}
RELEASEARRAYOBJECTS(pBinaryFormat);
}
RELEASEOBJECT(pManager);
if (applicationFonts == NULL)
RELEASEOBJECT(applicationFontsGood);
}
};
CApplicationFontsWorker::CApplicationFontsWorker()
{
m_bIsUseSystemFonts = true;
m_bIsUseSystemUserFonts = true;
m_bIsNeedThumbnails = true;
m_bIsUseOpenType = true;
m_bIsUseAllVersions = false;
m_bSeparateThumbnails = false;
m_bIsGenerateThumbnailsEA = true;
m_bIsCleanDirectory = true;
m_bIsRemoveOldThumbnails = false;
m_arThumbnailsScales.clear();
m_arThumbnailsScales.push_back(1);
m_arThumbnailsScales.push_back(1.25);
m_arThumbnailsScales.push_back(1.5);
m_arThumbnailsScales.push_back(1.75);
m_arThumbnailsScales.push_back(2);
m_pInternal = new CApplicationFontsWorker_private(this);
}
CApplicationFontsWorker::~CApplicationFontsWorker()
{
RELEASEOBJECT(m_pInternal);
}
NSFonts::IApplicationFonts* CApplicationFontsWorker::Check()
{
if (m_sDirectory.empty())
return NULL;
for (std::vector<std::wstring>::iterator i = m_arAdditionalFolders.begin(); i != m_arAdditionalFolders.end(); i++)
{
if (0 == i->find(L"./"))
*i = NSFile::GetProcessDirectory() + L"/" + i->substr(2);
else if (0 == i->find(L"../"))
*i = NSFile::GetProcessDirectory() + L"/" + *i;
}
std::wstring strAllFontsJSPath = m_sDirectory + L"/AllFonts.js";
std::wstring strFontsSelectionBin = m_sDirectory + L"/font_selection.bin";
std::vector<std::string> strFonts;
std::wstring strFontsCheckPath = m_sDirectory + L"/fonts.log";
// read the "old" font set
if (true)
{
NSFile::CFileBinary oFile;
if (oFile.OpenFile(strFontsCheckPath))
{
int nSize = oFile.GetFileSize();
char* pBuffer = new char[nSize];
DWORD dwReaden = 0;
oFile.ReadFile((BYTE*)pBuffer, nSize, dwReaden);
oFile.CloseFile();
int nStart = 0;
int nCur = nStart;
for (; nCur < nSize; ++nCur)
{
if (pBuffer[nCur] == '\n')
{
int nEnd = nCur - 1;
if (nEnd > nStart)
{
std::string s(pBuffer + nStart, nEnd - nStart + 1);
strFonts.push_back(s);
}
nStart = nCur + 1;
}
}
delete[] pBuffer;
}
#ifdef ONLYOFFICE_FONTS_VERSION
if (0 != strFonts.size())
{
// check version!!!
std::string sOO_Version = strFonts[0];
if (0 != sOO_Version.find("ONLYOFFICE_FONTS_VERSION_"))
{
strFonts.clear();
}
else
{
std::string sVersion = sOO_Version.substr(25);
int nVersion = std::stoi(sVersion);
if (nVersion != ONLYOFFICE_FONTS_VERSION)
strFonts.clear();
else
strFonts.erase(strFonts.begin());
}
}
#endif
}
// read the "new" font set
NSFonts::IApplicationFonts* pApplicationF = NSFonts::NSApplication::Create();
std::vector<std::wstring> strFontsW_CurSrc;
std::vector<std::wstring> strFontsW_Cur;
if (m_bIsUseSystemFonts)
strFontsW_CurSrc = pApplicationF->GetSetupFontFiles(m_bIsUseSystemUserFonts);
for (std::vector<std::wstring>::iterator i = m_arAdditionalFolders.begin(); i != m_arAdditionalFolders.end(); i++)
{
NSDirectory::GetFiles2(*i, strFontsW_CurSrc, true);
}
// remove folders that should not be parsed
strFontsW_Cur.reserve(strFontsW_CurSrc.size());
for (std::vector<std::wstring>::iterator i = strFontsW_CurSrc.begin(); i != strFontsW_CurSrc.end(); i++)
{
#ifdef _WIN32
if (i->find(L"\\.git\\") == std::wstring::npos)
strFontsW_Cur.push_back(*i);
//if (i->find(L"\\.svn\\") == std::wstring::npos)
// strFontsW_Cur.push_back(*i);
#else
if (i->find(L"/.git/") == std::wstring::npos)
strFontsW_Cur.push_back(*i);
//if (i->find(L"/.svn/") == std::wstring::npos)
// strFontsW_Cur.push_back(*i);
#endif
}
// sort (needed for comparison with the old set)
std::sort(strFontsW_Cur.begin(), strFontsW_Cur.end());
bool bIsEqual = true;
// if font counts in sets don't match - regeneration is needed
if (strFonts.size() != strFontsW_Cur.size())
bIsEqual = false;
if (bIsEqual)
{
// if sets don't match - regeneration is needed
int nCount = (int)strFonts.size();
for (int i = 0; i < nCount; ++i)
{
if (strFonts[i] != NSFile::CUtf8Converter::GetUtf8StringFromUnicode2(strFontsW_Cur[i].c_str(), (LONG)strFontsW_Cur[i].length()))
{
bIsEqual = false;
break;
}
}
}
if (bIsEqual)
{
// sets match - check if font_selection.bin was dumped
// if not - regeneration is needed
if (!NSFile::CFileBinary::Exists(strFontsSelectionBin))
bIsEqual = false;
}
if (!bIsEqual)
{
if (m_bIsCleanDirectory)
{
std::vector<std::wstring> arFiles = NSDirectory::GetFiles(m_sDirectory, false);
for (std::vector<std::wstring>::iterator fileIter = arFiles.begin(); fileIter != arFiles.end(); fileIter++)
{
NSFile::CFileBinary::Remove(*fileIter);
}
}
int nFlag = 3;
if (!m_bIsUseOpenType)
nFlag = 2;
// create new font set
NSStringUtils::CStringBuilder oFontsLog;
#ifdef ONLYOFFICE_FONTS_VERSION
oFontsLog.WriteString(L"ONLYOFFICE_FONTS_VERSION_");
oFontsLog.WriteString(std::to_wstring(ONLYOFFICE_FONTS_VERSION));
oFontsLog.WriteString(L"\n");
#endif
int nCount = (int)strFontsW_Cur.size();
for (int i = 0; i < nCount; ++i)
{
oFontsLog.WriteString(strFontsW_Cur[i]);
oFontsLog.WriteString(L"\n");
}
// read fonts
pApplicationF->InitializeFromArrayFiles(strFontsW_Cur, nFlag);
// dump everything
m_pInternal->SaveAllFontsJS(pApplicationF, ONLYOFFICE_ALL_FONTS_VERSION);
// support for old AllFonts.js version
if (m_bIsUseAllVersions)
{
for (int nVer = 0; nVer < ONLYOFFICE_ALL_FONTS_VERSION; ++nVer)
m_pInternal->SaveAllFontsJS(pApplicationF, nVer);
}
// dump new font set
if (!m_pInternal->CheckBreak())
NSFile::CFileBinary::SaveToFile(strFontsCheckPath, oFontsLog.GetData());
}
pApplicationF->Release();
pApplicationF = NULL;
if (!m_pInternal->m_pBreaker || m_pInternal->m_pBreaker->IsFontsWorkerRunned())
{
// no interruptions occurred
pApplicationF = NSFonts::NSApplication::Create();
pApplicationF->InitializeFromFolder(m_sDirectory);
}
else
{
// interrupted - clean up working directory
if (m_bIsCleanDirectory)
{
std::vector<std::wstring> arFiles = NSDirectory::GetFiles(m_sDirectory, false);
for (std::vector<std::wstring>::iterator fileIter = arFiles.begin(); fileIter != arFiles.end(); fileIter++)
{
NSFile::CFileBinary::Remove(*fileIter);
}
}
}
return pApplicationF;
}
void CApplicationFontsWorker::CheckThumbnails()
{
m_pInternal->SaveThumbnails(NULL);
}
void CApplicationFontsWorker::SetBreaker(CApplicationFontsWorkerBreaker* pChecker)
{
m_pInternal->m_pBreaker = pChecker;
}
std::string CApplicationFontsWorker::GetAllFonts()
{
std::string sAllFonts = "";
NSFile::CFileBinary::ReadAllTextUtf8A(m_sDirectory + L"/AllFonts.js", sAllFonts);
return sAllFonts;
}
std::vector<std::wstring> CApplicationFontsWorker::GetFontNames(NSFonts::IApplicationFonts* pFonts)
{
std::vector<std::wstring> arNames;
if (!pFonts || !pFonts->GetList())
return arNames;
std::vector<NSFonts::CFontInfo*>* arInfos = pFonts->GetList()->GetFonts();
std::map<std::wstring, bool> map;
for (std::vector<NSFonts::CFontInfo*>::iterator iter = arInfos->begin(); iter != arInfos->end(); iter++)
{
if (map.find((*iter)->m_wsFontName) == map.end())
arNames.push_back((*iter)->m_wsFontName);
}
std::sort(arNames.begin(), arNames.end());
return arNames;
}
std::vector<std::wstring> CApplicationFontsWorker::GetFontNamesWithExcludes(NSFonts::IApplicationFonts* pFonts, std::vector<std::wstring> excludes)
{
std::vector<std::wstring> arNames;
if (!pFonts || !pFonts->GetList())
return arNames;
std::vector<NSFonts::CFontInfo*>* arInfos = pFonts->GetList()->GetFonts();
std::map<std::wstring, bool> map;
for (std::vector<NSFonts::CFontInfo*>::iterator iter = arInfos->begin(); iter != arInfos->end(); iter++)
{
std::wstring fontName = (*iter)->m_wsFontName;
bool isExclude = false;
for (size_t i = 0; i < excludes.size(); ++i) {
if (fontName.find(excludes[i]) != std::string::npos) {
isExclude = true;
break;
}
}
if (isExclude) {
continue;
}
if (map.find(fontName) == map.end()) {
arNames.push_back(fontName);
map[fontName] = true;
}
}
std::sort(arNames.begin(), arNames.end());
return arNames;
}