/* * (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 #include #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 m_arFonts; bool m_bIsCheckThumbnailsMode; std::map 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 { // для шрифта ASCW3 допускаем маленькую длину range 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 (3100–312F) // Bopomofo Extended (31A0–31BF) // CJK Unified Ideographs (4E00–9FEA) // CJK Unified Ideographs Extension A (3400–4DB5) // CJK Unified Ideographs Extension B (20000–2A6D6) // CJK Unified Ideographs Extension C (2A700–2B734) // CJK Unified Ideographs Extension D (2B740–2B81D) // CJK Unified Ideographs Extension E (2B820–2CEA1) // CJK Unified Ideographs Extension F (2CEB0–2EBE0) // CJK Compatibility Ideographs (F900–FAFF) // CJK Compatibility Ideographs Supplement (2F800–2FA1F) // Kangxi Radicals (2F00–2FDF) // CJK Radicals Supplement (2E80–2EFF) // CJK Strokes (31C0–31EF) // Ideographic Description Characters (2FF0–2FFF) // Hangul Jamo (1100–11FF) // Hangul Jamo Extended-A (A960–A97F) // Hangul Jamo Extended-B (D7B0–D7FF) // Hangul Compatibility Jamo (3130–318F) // Halfwidth and Fullwidth Forms (FF00–FFEF) // Hangul Syllables (AC00–D7AF) // Hiragana (3040–309F) // Kana Extended-A (1B100–1B12F) // Kana Supplement (1B000–1B0FF) // Kanbun (3190–319F) // Katakana (30A0–30FF) // Katakana Phonetic Extensions (31F0–31FF) // Lisu (A4D0–A4FF) // Miao (16F00–16F9F) // Nushu (1B170–1B2FF) // Tangut (17000–187EC) // Tangut Components (18800–18AFF) // Yi Syllables (A000–A48F) // Yi Radicals (A490–A4CF) 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& mapAlternate) { if (info->names.empty()) return; if (!IsEastAsianName(info->m_wsFontName) && IsEastAsianName(info->names[0])) { mapAlternate.insert(std::pair(info->m_wsFontName, info->names[0])); } } std::wstring SaveWebFonts(const std::map& 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::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* pList = applicationFonts->GetList()->GetFonts(); int nCount = (int)pList->size(); // сначала строим массив всех файлов шрифтов std::map mapFontFiles; std::map mapFontFiles2; LONG lFontFiles = 0; for (std::vector::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(pInfo->m_wsFontPath, lFontFiles)); mapFontFiles2.insert(std::pair(lFontFiles, pInfo->m_wsFontPath)); ++lFontFiles; } } // ----------------------------------------- if (CheckBreak()) return; // теперь строим массив всех шрифтов по имени std::map mapFonts; std::vector arrFonts; for (std::vector::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::iterator it = mapFontFiles.find(strPath); lFontIndex = it->second; if (pInfo->m_lIndex >= 0) lFaceIndex = (int)pInfo->m_lIndex; std::map::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(fontInfo.m_sName, fontInfo)); arrFonts.push_back(fontInfo.m_sName); } } // ------------------------------------------- if (CheckBreak()) return; // теперь сортируем шрифты по имени ---------- 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""; // нужно ли скидывать 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); } // и самое главное. Здесь должен скидываться скрипт для работы со всеми шрифтами. // все объекты, которые позволят не знать о существующих фонтах 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 для веба точно такой же, но с другими путями 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(); // сначала все файлы 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::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 mapFontIndexes; for (int index = 0; index < nCountFonts; ++index) { std::map::iterator pPair = mapFonts.find(arrFonts[index]); mapFontIndexes.insert(std::pair(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 mapFontsPriorityStandard; int nCurrentPriority = 1; #define SET_FONT_PRIORITY(fontName) mapFontsPriorityStandard.insert(std::pair(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; // приоритеты шрифтов. по имени (все стили) // если шрифт из mapFontsPriorityStandard, то приоритет из этого map // иначе - максимальный размер из файлов-стиля шрифта (max(regular,italic,bold,bolditalic)) std::vector arrFontsPriority; for (int index = 0; index < nCountFonts; ++index) { std::map::iterator pPair = mapFonts.find(arrFonts[index]); CFontInfoJS& info = pPair->second; std::map::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); } // сортируем по приоритету std::sort(arrFontsPriority.begin(), arrFontsPriority.end(), CFontPriority::Compare); // для удобства - делаем map std::map mapFontsPriority; int nIndexPriority = 1; for (std::vector::iterator i = arrFontsPriority.begin(); i != arrFontsPriority.end(); i++) { CFontPriority& o = *i; mapFontsPriority.insert(std::pair(o.name, nIndexPriority)); nIndexPriority++; } int nSumPriority = (int)(arrFontsPriority.size() + 1); bool bIsSmallRangesDetect = true; for (int index = 0; index < nCountFonts; ++index) { std::map::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) { // отключили этот режим (bIsSmallRangesDetect всегда 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 { // каждый шрифт - анализируем на символы. в массив символов (tmp buffer) - // пишем m_nStyle 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) { // чекаем все символы, которые есть во ВСЕХ стилях шрифта // nSumPriority - это добавка для ranges маленькой длины, чтобы если есть // длинный диапазон но большим приоритетом - то он его перебьет. // для этого добавка - количество шрифтов. чтобы хватило oAllChecker.Apply2(nMask, nSumPriority); } else { // просто чекаем все символы, которые есть во ВСЕХ стилях шрифта 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::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::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 arrFiles; std::vector arrScales; std::vector 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; // создаем картинку для табнейлов 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::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) { // у нас режим "без квадратов" // но есть шрифты, в которых символы есть, но нулевой ширины. // только из-за таких шрифтов делаем заглушку 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::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 strFonts; std::wstring strFontsCheckPath = m_sDirectory + L"/fonts.log"; // читаем "старый" набор шрифтов 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 } // читаем "новый" набор шрифтов NSFonts::IApplicationFonts* pApplicationF = NSFonts::NSApplication::Create(); std::vector strFontsW_CurSrc; std::vector strFontsW_Cur; if (m_bIsUseSystemFonts) strFontsW_CurSrc = pApplicationF->GetSetupFontFiles(m_bIsUseSystemUserFonts); for (std::vector::iterator i = m_arAdditionalFolders.begin(); i != m_arAdditionalFolders.end(); i++) { NSDirectory::GetFiles2(*i, strFontsW_CurSrc, true); } // удаляем папки, которые не нужно парсить strFontsW_Cur.reserve(strFontsW_CurSrc.size()); for (std::vector::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 } // сортируем (нужно для сравнения для старого набора) std::sort(strFontsW_Cur.begin(), strFontsW_Cur.end()); bool bIsEqual = true; // если количество шрифтов в наборах не совпадают - то нужно перегенерировать if (strFonts.size() != strFontsW_Cur.size()) bIsEqual = false; if (bIsEqual) { // если наборы не совпадают - то нужно перегенерировать 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) { // наборы совпадают - скинут ли font_selection.bin // если нет - нужно перегенерировать if (!NSFile::CFileBinary::Exists(strFontsSelectionBin)) bIsEqual = false; } if (!bIsEqual) { if (m_bIsCleanDirectory) { std::vector arFiles = NSDirectory::GetFiles(m_sDirectory, false); for (std::vector::iterator fileIter = arFiles.begin(); fileIter != arFiles.end(); fileIter++) { NSFile::CFileBinary::Remove(*fileIter); } } int nFlag = 3; if (!m_bIsUseOpenType) nFlag = 2; // формируем новый набор шрифтов 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"); } // читаем шрифты pApplicationF->InitializeFromArrayFiles(strFontsW_Cur, nFlag); // скидываем все m_pInternal->SaveAllFontsJS(pApplicationF, ONLYOFFICE_ALL_FONTS_VERSION); // поддержка старой версии AllFonts.js if (m_bIsUseAllVersions) { for (int nVer = 0; nVer < ONLYOFFICE_ALL_FONTS_VERSION; ++nVer) m_pInternal->SaveAllFontsJS(pApplicationF, nVer); } // скидываем новый набор шрифтов if (!m_pInternal->CheckBreak()) NSFile::CFileBinary::SaveToFile(strFontsCheckPath, oFontsLog.GetData()); } pApplicationF->Release(); pApplicationF = NULL; if (!m_pInternal->m_pBreaker || m_pInternal->m_pBreaker->IsFontsWorkerRunned()) { // никаких прерываний не было pApplicationF = NSFonts::NSApplication::Create(); pApplicationF->InitializeFromFolder(m_sDirectory); } else { // прервали - подчищаем рабочую директорию if (m_bIsCleanDirectory) { std::vector arFiles = NSDirectory::GetFiles(m_sDirectory, false); for (std::vector::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 CApplicationFontsWorker::GetFontNames(NSFonts::IApplicationFonts* pFonts) { std::vector arNames; if (!pFonts || !pFonts->GetList()) return arNames; std::vector* arInfos = pFonts->GetList()->GetFonts(); std::map map; for (std::vector::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 CApplicationFontsWorker::GetFontNamesWithExcludes(NSFonts::IApplicationFonts* pFonts, std::vector excludes) { std::vector arNames; if (!pFonts || !pFonts->GetList()) return arNames; std::vector* arInfos = pFonts->GetList()->GetFonts(); std::map map; for (std::vector::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; }