From 507afb473fdfd2ebe052e00bbf0020818219424f Mon Sep 17 00:00:00 2001 From: Svetlana Kulikova Date: Mon, 25 May 2026 17:29:34 +0300 Subject: [PATCH] All fonts to PdfFont --- PdfFile/PdfEditor.cpp | 4 +- PdfFile/PdfReader.cpp | 580 +++++----- PdfFile/PdfReader.h | 11 +- PdfFile/SrcReader/PdfAnnot.cpp | 165 +-- PdfFile/SrcReader/PdfAnnot.h | 19 +- PdfFile/SrcReader/PdfFont.cpp | 1297 ++++++++++++++++++++++- PdfFile/SrcReader/PdfFont.h | 29 +- PdfFile/SrcReader/RendererOutputDev.cpp | 1113 ------------------- PdfFile/SrcReader/RendererOutputDev.h | 2 - PdfFile/lib/xpdf/Object.h | 8 +- 10 files changed, 1636 insertions(+), 1592 deletions(-) diff --git a/PdfFile/PdfEditor.cpp b/PdfFile/PdfEditor.cpp index 83392b0d11..779743ec26 100644 --- a/PdfFile/PdfEditor.cpp +++ b/PdfFile/PdfEditor.cpp @@ -4515,7 +4515,7 @@ void CPdfEditor::ScanAndProcessFonts(PDFDoc* pPDFDocument, XRef* xref, Dict* pRe if (gfxFont->getEmbeddedFontID(&oEmbRef) || PdfReader::IsBaseFont(wsFontBaseName) || ((pFontLoc = gfxFont->locateFont(xref, false)) && NSStrings::GetStringFromUTF32(pFontLoc->path).length())) { std::wstring wsFileName, wsFontName; - PdfReader::RendererOutputDev::GetFont(xref, pFontManager, pFontList, gfxFont, wsFileName, wsFontName, false); + PdfReader::GetFont(xref, pFontManager, pFontList, gfxFont, wsFileName, wsFontName, false); // Collect information about embedded font if (!PdfReader::IsBaseFont(wsFontBaseName)) @@ -4533,7 +4533,7 @@ void CPdfEditor::ScanAndProcessFonts(PDFDoc* pPDFDocument, XRef* xref, Dict* pRe else { std::map mCodeToWidth, mCodeToUnicode, mCodeToGID; - int nDW = PdfReader::CollectFontWidths(gfxFont, oFont.getDict(), mCodeToWidth); + int nDW = PdfReader::CollectFontWidths(oFont.getDict(), mCodeToWidth); for (int nIndex = 0; nIndex < pFontEntry.unLenUnicode; ++nIndex) { if (pFontEntry.pCodeToUnicode[nIndex]) diff --git a/PdfFile/PdfReader.cpp b/PdfFile/PdfReader.cpp index 7d42004312..293b66e03d 100644 --- a/PdfFile/PdfReader.cpp +++ b/PdfFile/PdfReader.cpp @@ -40,7 +40,6 @@ #include "../DesktopEditor/graphics/IRenderer.h" #include "../DesktopEditor/common/Directory.h" #include "../DesktopEditor/common/StringExt.h" -#include "../DesktopEditor/graphics/pro/js/wasm/src/serialize.h" #include "../DesktopEditor/graphics/MetafileToRenderer.h" #include "../DesktopEditor/graphics/BaseThread.h" @@ -190,7 +189,7 @@ void CPdfReader::SetCMapMemory(BYTE* pData, DWORD nSizeData) if (m_vPDFContext.empty()) return; CPdfReaderContext* pPDFContext = m_vPDFContext.back(); - std::map mFonts = PdfReader::GetAllFonts(pPDFContext->m_pDocument, m_pFontManager, pPDFContext->m_pFontList, false); + std::map mFonts = PdfReader::GetAllFonts(pPDFContext->m_pDocument, m_pFontManager, pPDFContext->m_pFontList); m_mFonts.insert(mFonts.begin(), mFonts.end()); } void CPdfReader::SetCMapFolder(const std::wstring& sFolder) @@ -252,17 +251,34 @@ void CPdfReader::SetParams(COfficeDrawingPageParams* pParams) globalParams->setDrawAnnotations(bDraw); } -int CPdfReader::GetStartRefID(PDFDoc* _pDoc) +// ============================================================ +// CPdfReader::FindContext +// ============================================================ +CPdfReaderContext* CPdfReader::FindContext(PDFDoc* _pDoc) const { for (CPdfReaderContext* pPDFContext : m_vPDFContext) { if (!pPDFContext || !pPDFContext->m_pDocument) continue; - PDFDoc* pDoc = pPDFContext->m_pDocument; - if (_pDoc == pDoc) - return pPDFContext->m_nStartID; + if (pPDFContext->m_pDocument == _pDoc) + return pPDFContext; } - return -1; + return NULL; +} +int CPdfReader::GetStartRefID(PDFDoc* _pDoc) +{ + CPdfReaderContext* pContext = FindContext(_pDoc); + return pContext ? pContext->m_nStartID : -1; +} +PdfReader::CPdfFontList* CPdfReader::GetFontList(PDFDoc* _pDoc) +{ + CPdfReaderContext* pContext = FindContext(_pDoc); + return pContext ? pContext->m_pFontList : NULL; +} +std::string CPdfReader::GetPrefixForm(PDFDoc* _pDoc) +{ + CPdfReaderContext* pContext = FindContext(_pDoc); + return pContext ? pContext->m_sPrefixForm : ""; } int CPdfReader::GetNumPagesBefore(PDFDoc* _pDoc) { @@ -271,37 +287,12 @@ int CPdfReader::GetNumPagesBefore(PDFDoc* _pDoc) { if (!pPDFContext || !pPDFContext->m_pDocument) continue; - PDFDoc* pDoc = pPDFContext->m_pDocument; - if (_pDoc == pDoc) + if (pPDFContext->m_pDocument == _pDoc) return nPagesBefore; - nPagesBefore += pDoc->getNumPages(); + nPagesBefore += pPDFContext->m_pDocument->getNumPages(); } return -1; } -PdfReader::CPdfFontList* CPdfReader::GetFontList(PDFDoc* _pDoc) -{ - for (CPdfReaderContext* pPDFContext : m_vPDFContext) - { - if (!pPDFContext || !pPDFContext->m_pDocument) - continue; - PDFDoc* pDoc = pPDFContext->m_pDocument; - if (_pDoc == pDoc) - return pPDFContext->m_pFontList; - } - return NULL; -} -std::string CPdfReader::GetPrefixForm(PDFDoc* _pDoc) -{ - for (CPdfReaderContext* pPDFContext : m_vPDFContext) - { - if (!pPDFContext || !pPDFContext->m_pDocument) - continue; - PDFDoc* pDoc = pPDFContext->m_pDocument; - if (_pDoc == pDoc) - return pPDFContext->m_sPrefixForm; - } - return ""; -} int CPdfReader::FindRefNum(int nObjID, PDFDoc** _pDoc, int* _nStartRefID) { for (CPdfReaderContext* pPDFContext : m_vPDFContext) @@ -311,10 +302,8 @@ int CPdfReader::FindRefNum(int nObjID, PDFDoc** _pDoc, int* _nStartRefID) PDFDoc* pDoc = pPDFContext->m_pDocument; if (nObjID < pPDFContext->m_nStartID + pDoc->getXRef()->getNumObjects()) { - if (_pDoc) - *_pDoc = pDoc; - if (_nStartRefID) - *_nStartRefID = pPDFContext->m_nStartID; + if (_pDoc) *_pDoc = pDoc; + if (_nStartRefID) *_nStartRefID = pPDFContext->m_nStartID; return nObjID - pPDFContext->m_nStartID; } } @@ -328,22 +317,19 @@ int CPdfReader::GetPageIndex(int nAbsPageIndex, PDFDoc** _pDoc, PdfReader::CPdfF if (!pPDFContext || !pPDFContext->m_pDocument) continue; PDFDoc* pDoc = pPDFContext->m_pDocument; - int nPages = pDoc->getNumPages(); if (nAbsPageIndex < nTotalPages + nPages) { - if (_pDoc) - *_pDoc = pDoc; - if (pFontList) - *pFontList = pPDFContext->m_pFontList; - if (nStartRefID) - *nStartRefID = pPDFContext->m_nStartID; + if (_pDoc) *_pDoc = pDoc; + if (pFontList) *pFontList = pPDFContext->m_pFontList; + if (nStartRefID) *nStartRefID = pPDFContext->m_nStartID; return nAbsPageIndex - nTotalPages + 1; } nTotalPages += nPages; } return -1; } + int CPdfReader::GetError() { if (m_vPDFContext.empty()) @@ -412,6 +398,64 @@ int CPdfReader::GetNumPages() } return nNumPages; } + +// ============================================================ +// CPdfReader::ValidMetaData +// ============================================================ +bool ValidateXRefTable(BaseStream* str, GFileOffset nOffset, GString* pID2) +{ + Object oDict, oTID, oID, obj1; + char buf[100]; + + Stream* pSubStr = str->makeSubStream(nOffset + 5, gFalse, 0, &oDict); + int c = pSubStr->getChar(); + while (c != 't') + c = pSubStr->getChar(); + pSubStr->getBlock(buf, 6); + + Parser* parser = new Parser(NULL, new Lexer(NULL, pSubStr->getBaseStream()->makeSubStream(pSubStr->getPos(), gFalse, 0, &oDict)), gTrue); + parser->getObj(&obj1); + delete parser; + delete pSubStr; + + bool bRes = false; + if (obj1.isDict() && obj1.dictLookup("ID", &oTID)->isArray() && oTID.arrayGet(1, &oID)->isString()) + bRes = pID2->cmp(oID.getString()) != 0; + + obj1.free(); + oTID.free(); + oID.free(); + return bRes; +} +bool ValidateXRefStream(BaseStream* str, GFileOffset nOffset, GString* pID2) +{ + Object oDict, oTID, oID, obj1, obj2, obj3, obj4; + + Stream* pSubStr = str->makeSubStream(nOffset, gFalse, 0, &oDict); + Parser* parser = new Parser(NULL, new Lexer(NULL, pSubStr), gTrue); + parser->getObj(&obj1); + parser->getObj(&obj2); + parser->getObj(&obj3); + parser->getObj(&obj4); + + bool bRes = false; + if (obj1.isInt() && obj2.isInt() && obj3.isCmd("obj") && obj4.isStream()) + { + Dict* pPrevXRefDict = obj4.streamGetDict(); + if (pPrevXRefDict->lookup("ID", &oTID)->isArray() && oTID.arrayGet(1, &oID)->isString()) + bRes = pID2->cmp(oID.getString()) != 0; + oTID.free(); + oID.free(); + } + + obj4.free(); + obj3.free(); + obj2.free(); + obj1.free(); + delete parser; + + return bRes; +} bool CPdfReader::ValidMetaData() { if (m_vPDFContext.empty() || m_vPDFContext.size() != 1) @@ -445,9 +489,9 @@ bool CPdfReader::ValidMetaData() int nNumXRefTables = xref->getNumXRefTables(); if (bRes && nNumXRefTables > 1) { - GFileOffset nOffeset = xref->getXRefTablePos(nNumXRefTables - 2); + GFileOffset nOffset = xref->getXRefTablePos(nNumXRefTables - 2); BaseStream* str = pPDFContext->m_pDocument->getBaseStream(); - str->setPos(nOffeset); + str->setPos(nOffset); Object oDict, obj1, obj2, obj3, obj4; char buf[100]; @@ -455,52 +499,58 @@ bool CPdfReader::ValidMetaData() for (i = 0; i < n && Lexer::isSpace(buf[i]); ++i); // xref table if (i + 4 < n && buf[i] == 'x' && buf[i+1] == 'r' && buf[i+2] == 'e' && buf[i+3] == 'f' && Lexer::isSpace(buf[i+4])) - { - Stream* pSubStr = str->makeSubStream(nOffeset + i + 5, gFalse, 0, &oDict); - int c = pSubStr->getChar(); - while (c != 't') - c = pSubStr->getChar(); - pSubStr->getBlock(buf, 6); - - Parser* parser = new Parser(NULL, new Lexer(NULL, pSubStr->getBaseStream()->makeSubStream(pSubStr->getPos(), gFalse, 0, &oDict)), gTrue); - parser->getObj(&obj1); - delete parser; - delete pSubStr; - if (obj1.isDict() && obj1.dictLookup("ID", &oTID)->isArray() && oTID.arrayGet(1, &oID)->isString()) - { - bRes = oID2.getString()->cmp(oID.getString()) != 0; - } - obj1.free(); - oTID.free(); - } - else // xref stream - { - Stream* pSubStr = str->makeSubStream(nOffeset, gFalse, 0, &oDict); - Parser* parser = new Parser(NULL, new Lexer(NULL, pSubStr), gTrue); - parser->getObj(&obj1); - parser->getObj(&obj2); - parser->getObj(&obj3); - parser->getObj(&obj4); - if (obj1.isInt() && obj2.isInt() && obj3.isCmd("obj") && obj4.isStream()) - { - Dict* pPrevXRefDict = obj4.streamGetDict(); - if (pPrevXRefDict->lookup("ID", &oTID)->isArray() && oTID.arrayGet(1, &oID)->isString()) - { - bRes = oID2.getString()->cmp(oID.getString()) != 0; - } - oTID.free(); - } - obj4.free(); - obj3.free(); - obj2.free(); - obj1.free(); - delete parser; - } + bRes = ValidateXRefTable(str, nOffset + i + 5, oID2.getString()); + else + bRes = ValidateXRefStream(str, nOffset, oID2.getString()); } oID2.free(); oID.free(); return bRes; } + +// ============================================================ +// CPdfReader::MergePages +// ============================================================ +void CreatePasswords(const wchar_t* wsPassword, GString*& owner_pswd, GString*& user_pswd) +{ + owner_pswd = NULL; + user_pswd = NULL; + if (wsPassword) + { + owner_pswd = NSStrings::CreateString(wsPassword); + user_pswd = NSStrings::CreateString(wsPassword); + } +} +CPdfReaderContext* CPdfReader::CreateContext(const std::string& sPrefixForm, int nMaxID) +{ + CPdfReaderContext* pContext = new CPdfReaderContext(); + pContext->m_pFontList = new PdfReader::CPdfFontList(); + pContext->m_sPrefixForm = sPrefixForm; + if (nMaxID != 0) + pContext->m_nStartID = nMaxID; + else if (!m_vPDFContext.empty()) + pContext->m_nStartID = m_vPDFContext.back()->m_nStartID + m_vPDFContext.back()->m_pDocument->getXRef()->getNumObjects(); + return pContext; +} +bool CPdfReader::FinalizeMerge(CPdfReaderContext* pContext) +{ + PDFDoc* pDoc = pContext->m_pDocument; + m_vPDFContext.push_back(pContext); + + m_eError = pDoc ? pDoc->getErrorCode() : errMemory; + if (!pDoc || !pDoc->isOk()) + { + delete pContext; + m_vPDFContext.pop_back(); + return false; + } + + IsNeedCMap(); + std::map mFonts = PdfReader::GetAllFonts(pDoc, m_pFontManager, pContext->m_pFontList); + m_mFonts.insert(mFonts.begin(), mFonts.end()); + + return true; +} bool CPdfReader::MergePages(BYTE* pData, DWORD nLength, const wchar_t* wsPassword, int nMaxID, const std::string& sPrefixForm) { if (m_eError) @@ -530,25 +580,11 @@ bool CPdfReader::MergePages(BYTE* pData, DWORD nLength, const wchar_t* wsPasswor pContext->m_nStartID = nMaxID; else if (!m_vPDFContext.empty()) pContext->m_nStartID = m_vPDFContext.back()->m_nStartID + m_vPDFContext.back()->m_pDocument->getXRef()->getNumObjects(); - PDFDoc* pDoc = pContext->m_pDocument; - m_vPDFContext.push_back(pContext); RELEASEOBJECT(owner_pswd); RELEASEOBJECT(user_pswd); - m_eError = pDoc ? pDoc->getErrorCode() : errMemory; - if (!pDoc || !pDoc->isOk()) - { - // pData is freed - delete pContext; - m_vPDFContext.pop_back(); - return false; - } - - std::map mFonts = PdfReader::GetAllFonts(pDoc, m_pFontManager, pContext->m_pFontList, IsNeedCMap()); - m_mFonts.insert(mFonts.begin(), mFonts.end()); - - return true; + return FinalizeMerge(pContext); } bool CPdfReader::MergePages(const std::wstring& wsFile, const wchar_t* wsPassword, int nMaxID, const std::string& sPrefixForm) { @@ -574,25 +610,13 @@ bool CPdfReader::MergePages(const std::wstring& wsFile, const wchar_t* wsPasswor pContext->m_nStartID = nMaxID; else if (!m_vPDFContext.empty()) pContext->m_nStartID = m_vPDFContext.back()->m_nStartID + m_vPDFContext.back()->m_pDocument->getXRef()->getNumObjects(); - PDFDoc* pDoc = pContext->m_pDocument; - m_vPDFContext.push_back(pContext); RELEASEOBJECT(owner_pswd); RELEASEOBJECT(user_pswd); - m_eError = pDoc ? pDoc->getErrorCode() : errMemory; - if (!pDoc || !pDoc->isOk()) - { - delete pContext; - m_vPDFContext.pop_back(); - return false; - } - - std::map mFonts = PdfReader::GetAllFonts(pDoc, m_pFontManager, pContext->m_pFontList, IsNeedCMap()); - m_mFonts.insert(mFonts.begin(), mFonts.end()); - - return true; + return FinalizeMerge(pContext); } + bool CPdfReader::UnmergePages() { if (m_vPDFContext.size() <= 1) @@ -836,6 +860,141 @@ PDFDoc* CPdfReader::GetPDFDocument(int PDFIndex) return NULL; } +// ============================================================ +// CPdfReader::GetInfo +// ============================================================ +std::wstring GetMetaString(Object& oInfo, const char* sName, const wchar_t* wsName) +{ + std::wstring sRes; + Object obj1; + if (oInfo.dictLookup(sName, &obj1)->isString()) + { + TextString* s = new TextString(obj1.getString()); + std::wstring sValue = NSStringExt::CConverter::GetUnicodeFromUTF32(s->getUnicode(), s->getLength()); + delete s; + NSStringExt::Replace(sValue, L"\\", L"\\\\"); + NSStringExt::Replace(sValue, L"\"", L"\\\""); + sValue.erase(std::remove_if(sValue.begin(), sValue.end(), [](const wchar_t& wc) { return wc < 0x20; }), sValue.end()); + if (!sValue.empty()) + { + sRes += L"\""; + sRes += wsName; + sRes += L"\":\""; + sRes += sValue; + sRes += L"\","; + } + } + obj1.free(); + return sRes; +} +std::wstring GetMetaDate(Object& oInfo, const char* sName, const wchar_t* wsName) +{ + std::wstring sRes; + Object obj1; + if (!oInfo.dictLookup(sName, &obj1)->isString() || !obj1.getString()->getLength()) + { + obj1.free(); + return sRes; + } + + TextString* s = new TextString(obj1.getString()); + std::wstring sNoDate = NSStringExt::CConverter::GetUnicodeFromUTF32(s->getUnicode(), s->getLength()); + delete s; + + if (sNoDate.length() > 16) + { + std::wstring sDate = sNoDate.substr(2, 4) + L'-' + sNoDate.substr(6, 2) + L'-' + sNoDate.substr(8, 2) + L'T' + + sNoDate.substr(10, 2) + L':' + sNoDate.substr(12, 2) + L':' + sNoDate.substr(14, 2); + if (sNoDate.length() > 21 && (sNoDate[16] == L'+' || sNoDate[16] == L'-')) + sDate += (L".000" + sNoDate.substr(16, 3) + L':' + sNoDate.substr(20, 2)); + else + sDate += L"Z"; + NSStringExt::Replace(sDate, L"\\", L"\\\\"); + NSStringExt::Replace(sDate, L"\"", L"\\\""); + sDate.erase(std::remove_if(sDate.begin(), sDate.end(), [](const wchar_t& wc) { return wc < 0x20; }), sDate.end()); + sRes += L"\""; + sRes += wsName; + sRes += L"\":\""; + sRes += sDate; + sRes += L"\","; + } + + obj1.free(); + return sRes; +} +std::wstring GetDocMetaFields(PDFDoc* pDoc) +{ + std::wstring sRes; + Object oInfo; + if (!pDoc->getDocInfo(&oInfo)->isDict()) + { + oInfo.free(); + return sRes; + } + + sRes += GetMetaString(oInfo, "Title", L"Title"); + sRes += GetMetaString(oInfo, "Author", L"Author"); + sRes += GetMetaString(oInfo, "Subject", L"Subject"); + sRes += GetMetaString(oInfo, "Keywords", L"Keywords"); + sRes += GetMetaString(oInfo, "Creator", L"Creator"); + sRes += GetMetaString(oInfo, "Producer", L"Producer"); + sRes += GetMetaDate (oInfo, "CreationDate", L"CreationDate"); + sRes += GetMetaDate (oInfo, "ModDate", L"ModDate"); + + oInfo.free(); + return sRes; +} +bool IsLinearized(PDFDoc* pDoc, XRef* xref, BaseStream* str, DWORD nFileLength) +{ + Object obj1, obj2, obj3, obj4, obj5, obj6; + obj1.initNull(); + Parser* parser = new Parser(xref, new Lexer(xref, str->makeSubStream(str->getStart(), gFalse, 0, &obj1)), gTrue); + parser->getObj(&obj1); + parser->getObj(&obj2); + parser->getObj(&obj3); + parser->getObj(&obj4); + + bool bLinearized = false; + if (obj1.isInt() && obj2.isInt() && obj3.isCmd("obj") && obj4.isDict()) + { + obj4.dictLookup("Linearized", &obj5); + if (obj5.isNum() && obj5.getNum() > 0 && obj4.dictLookup("L", &obj6)->isNum()) + { + unsigned long size = (unsigned long)obj6.getNum(); + bLinearized = size == nFileLength; + } + obj6.free(); + obj5.free(); + } + obj4.free(); + obj3.free(); + obj2.free(); + obj1.free(); + delete parser; + + return bLinearized; +} +bool IsTagged(XRef* xref) +{ + bool bTagged = false; + Object catDict, markInfoObj; + if (xref->getCatalog(&catDict)->isDict() && catDict.dictLookup("MarkInfo", &markInfoObj)->isDict()) + { + Object marked, suspects; + if (markInfoObj.dictLookup("Marked", &marked)->isBool() && marked.getBool() == gTrue) + { + bTagged = true; + if (markInfoObj.dictLookup("Suspects", &suspects)->isBool() && suspects.getBool() == gTrue) + bTagged = false; + } + marked.free(); + suspects.free(); + } + markInfoObj.free(); + catDict.free(); + + return bTagged; +} std::wstring CPdfReader::GetInfo() { std::wstring sRes; @@ -847,85 +1006,13 @@ std::wstring CPdfReader::GetInfo() return sRes; PDFDoc* pDoc = pPDFContext->m_pDocument; - XRef* xref = pDoc->getXRef(); + XRef* xref = pDoc->getXRef(); BaseStream* str = pDoc->getBaseStream(); if (!xref || !str) - return NULL; + return sRes; sRes = L"{"; - - Object oInfo; - if (pDoc->getDocInfo(&oInfo)->isDict()) - { - auto fDictLookup = [&oInfo](const char* sName, const wchar_t* wsName) - { - std::wstring sRes; - Object obj1; - if (oInfo.dictLookup(sName, &obj1)->isString()) - { - TextString* s = new TextString(obj1.getString()); - std::wstring sValue = NSStringExt::CConverter::GetUnicodeFromUTF32(s->getUnicode(), s->getLength()); - delete s; - NSStringExt::Replace(sValue, L"\\", L"\\\\"); - NSStringExt::Replace(sValue, L"\"", L"\\\""); - sValue.erase(std::remove_if(sValue.begin(), sValue.end(), [] (const wchar_t& wc) { return wc < 0x20; } ), sValue.end()); - if (!sValue.empty()) - { - sRes += L"\""; - sRes += wsName; - sRes += L"\":\""; - sRes += sValue; - sRes += L"\","; - } - } - obj1.free(); - return sRes; - }; - sRes += fDictLookup("Title", L"Title"); - sRes += fDictLookup("Author", L"Author"); - sRes += fDictLookup("Subject", L"Subject"); - sRes += fDictLookup("Keywords", L"Keywords"); - sRes += fDictLookup("Creator", L"Creator"); - sRes += fDictLookup("Producer", L"Producer"); - - auto fDictLookupDate = [&oInfo](const char* sName, const wchar_t* wsName) - { - std::wstring sRes; - Object obj1; - if (!oInfo.dictLookup(sName, &obj1)->isString() || !obj1.getString()->getLength()) - { - obj1.free(); - return sRes; - } - - TextString* s = new TextString(obj1.getString()); - std::wstring sNoDate = NSStringExt::CConverter::GetUnicodeFromUTF32(s->getUnicode(), s->getLength()); - if (sNoDate.length() > 16) - { - std::wstring sDate = sNoDate.substr(2, 4) + L'-' + sNoDate.substr(6, 2) + L'-' + sNoDate.substr(8, 2) + L'T' + - sNoDate.substr(10, 2) + L':' + sNoDate.substr(12, 2) + L':' + sNoDate.substr(14, 2); - if (sNoDate.length() > 21 && (sNoDate[16] == L'+' || sNoDate[16] == L'-')) - sDate += (L".000" + sNoDate.substr(16, 3) + L':' + sNoDate.substr(20, 2)); - else - sDate += L"Z"; - NSStringExt::Replace(sDate, L"\\", L"\\\\"); - NSStringExt::Replace(sDate, L"\"", L"\\\""); - sDate.erase(std::remove_if(sDate.begin(), sDate.end(), [] (const wchar_t& wc) { return wc < 0x20; } ), sDate.end()); - sRes += L"\""; - sRes += wsName; - sRes += L"\":\""; - sRes += sDate; - sRes += L"\","; - } - delete s; - - obj1.free(); - return sRes; - }; - sRes += fDictLookupDate("CreationDate", L"CreationDate"); - sRes += fDictLookupDate("ModDate", L"ModDate"); - } - oInfo.free(); + sRes += GetDocMetaFields(pDoc); std::wstring version = std::to_wstring(pDoc->getPDFVersion()); std::wstring::size_type posDot = version.find('.'); @@ -934,71 +1021,19 @@ std::wstring CPdfReader::GetInfo() if (!version.empty()) sRes += (L"\"Version\":" + version + L","); - double nW = 0; - double nH = 0; - double nDpi = 0; + double nW = 0, nH = 0, nDpi = 0; GetPageInfo(0, &nW, &nH, &nDpi, &nDpi); - sRes += L"\"PageWidth\":"; - sRes += std::to_wstring((int)(nW * 100)); - sRes += L",\"PageHeight\":"; - sRes += std::to_wstring((int)(nH * 100)); - sRes += L",\"NumberOfPages\":"; - sRes += std::to_wstring(GetNumPages()); - sRes += L",\"FastWebView\":"; + sRes += L"\"PageWidth\":" + std::to_wstring((int)(nW * 100)); + sRes += L",\"PageHeight\":" + std::to_wstring((int)(nH * 100)); + sRes += L",\"NumberOfPages\":" + std::to_wstring(GetNumPages()); - bool bLinearized = false; - if (m_vPDFContext.size() == 1) - { - Object obj1, obj2, obj3, obj4, obj5, obj6; - obj1.initNull(); - Parser* parser = new Parser(xref, new Lexer(xref, str->makeSubStream(str->getStart(), gFalse, 0, &obj1)), gTrue); - parser->getObj(&obj1); - parser->getObj(&obj2); - parser->getObj(&obj3); - parser->getObj(&obj4); - if (obj1.isInt() && obj2.isInt() && obj3.isCmd("obj") && obj4.isDict()) - { - obj4.dictLookup("Linearized", &obj5); - if (obj5.isNum() && obj5.getNum() > 0 && obj4.dictLookup("L", &obj6)->isNum()) - { - unsigned long size = (unsigned long)obj6.getNum(); - bLinearized = size == m_nFileLength; - } - obj6.free(); - obj5.free(); - } - obj4.free(); - obj3.free(); - obj2.free(); - obj1.free(); - delete parser; - } - - sRes += bLinearized ? L"true" : L"false"; - sRes += L",\"Tagged\":"; - - bool bTagged = false; - Object catDict, markInfoObj; - if (xref->getCatalog(&catDict)->isDict() && catDict.dictLookup("MarkInfo", &markInfoObj)->isDict()) - { - Object marked, suspects; - if (markInfoObj.dictLookup("Marked", &marked)->isBool() && marked.getBool() == gTrue) - { - bTagged = true; - // If Suspects is true, the document may not completely conform to Tagged PDF conventions. - if (markInfoObj.dictLookup("Suspects", &suspects)->isBool() && suspects.getBool() == gTrue) - bTagged = false; - } - marked.free(); - suspects.free(); - } - markInfoObj.free(); - catDict.free(); - - sRes += bTagged ? L"true}" : L"false}"; + bool bLinearized = (m_vPDFContext.size() == 1) && IsLinearized(pDoc, xref, str, m_nFileLength); + sRes += std::wstring(L",\"FastWebView\":") + (bLinearized ? L"true" : L"false"); + sRes += std::wstring(L",\"Tagged\":") + (IsTagged(xref) ? L"true}" : L"false}"); return sRes; } + BYTE* CPdfReader::GetGIDByUnicode(const std::wstring& wsFontName) { std::map::const_iterator oIter = m_mFonts.find(wsFontName); @@ -1049,8 +1084,8 @@ BYTE* CPdfReader::GetGIDByUnicode(const std::wstring& wsFontName) NSWasm::CData oRes; oRes.SkipLen(); - oRes.AddInt(mGIDbyUnicode.size()); + oRes.AddInt(mGIDbyUnicode.size()); for (std::map::const_iterator it = mGIDbyUnicode.begin(); it != mGIDbyUnicode.end(); ++it) { oRes.AddInt(it->first); @@ -1058,9 +1093,9 @@ BYTE* CPdfReader::GetGIDByUnicode(const std::wstring& wsFontName) } oRes.WriteLen(); - BYTE* bRes = oRes.GetBuffer(); + BYTE* pRes = oRes.GetBuffer(); oRes.ClearWithoutAttack(); - return bRes; + return pRes; } std::wstring CPdfReader::GetFontPath(const std::wstring& wsFontName, bool bSave) { @@ -1170,10 +1205,9 @@ BYTE* CPdfReader::GetStructure() } oRes.WriteLen(); - - BYTE* bRes = oRes.GetBuffer(); + BYTE* pRes = oRes.GetBuffer(); oRes.ClearWithoutAttack(); - return bRes; + return pRes; } BYTE* CPdfReader::GetLinks(int _nPageIndex) { @@ -1348,9 +1382,9 @@ BYTE* CPdfReader::GetWidgets() } oRes.WriteLen(); - BYTE* bRes = oRes.GetBuffer(); + BYTE* pRes = oRes.GetBuffer(); oRes.ClearWithoutAttack(); - return bRes; + return pRes; } void CPdfReader::SetFonts(PdfReader::CPdfFontList* pFontList) { @@ -1395,9 +1429,9 @@ BYTE* CPdfReader::GetFonts(bool bStandart) oRes.AddInt(nFonts, nFontsPos); oRes.WriteLen(); - BYTE* bRes = oRes.GetBuffer(); + BYTE* pRes = oRes.GetBuffer(); oRes.ClearWithoutAttack(); - return bRes; + return pRes; } BYTE* CPdfReader::VerifySign(const std::wstring& sFile, ICertificate* pCertificate, int nWidget) { @@ -1480,9 +1514,9 @@ BYTE* CPdfReader::VerifySign(const std::wstring& sFile, ICertificate* pCertifica } oRes.WriteLen(); - BYTE* bRes = oRes.GetBuffer(); + BYTE* pRes = oRes.GetBuffer(); oRes.ClearWithoutAttack(); - return bRes; + return pRes; } BYTE* CPdfReader::GetAPWidget(int nRasterW, int nRasterH, int nBackgroundColor, int _nPageIndex, int nWidget, const char* sView, const char* sButtonView) { @@ -1518,9 +1552,9 @@ BYTE* CPdfReader::GetAPWidget(int nRasterW, int nRasterH, int nBackgroundColor, } oRes.WriteLen(); - BYTE* bRes = oRes.GetBuffer(); + BYTE* pRes = oRes.GetBuffer(); oRes.ClearWithoutAttack(); - return bRes; + return pRes; } BYTE* CPdfReader::GetButtonIcon(int nBackgroundColor, int _nPageIndex, bool bBase64, int nButtonWidget, const char* sIconView) { @@ -1967,9 +2001,9 @@ BYTE* CPdfReader::GetButtonIcon(int nBackgroundColor, int _nPageIndex, bool bBas } oRes.WriteLen(); - BYTE* bRes = oRes.GetBuffer(); + BYTE* pRes = oRes.GetBuffer(); oRes.ClearWithoutAttack(); - return bRes; + return pRes; } BYTE* CPdfReader::StreamToCData(BYTE* pSteam, int nLength) { @@ -1979,7 +2013,6 @@ BYTE* CPdfReader::StreamToCData(BYTE* pSteam, int nLength) oRes.Write(pSteam, nLength); oRes.WriteLen(); - BYTE* bRes = oRes.GetBuffer(); oRes.ClearWithoutAttack(); return bRes; @@ -2140,9 +2173,9 @@ BYTE* CPdfReader::GetAnnots(int _nPageIndex) } oRes.WriteLen(); - BYTE* bRes = oRes.GetBuffer(); + BYTE* pRes = oRes.GetBuffer(); oRes.ClearWithoutAttack(); - return bRes; + return pRes; } BYTE* CPdfReader::GetAPAnnots(int nRasterW, int nRasterH, int nBackgroundColor, int _nPageIndex, int nAnnot, const char* sView) { @@ -2205,11 +2238,10 @@ BYTE* CPdfReader::GetAPAnnots(int nRasterW, int nRasterH, int nBackgroundColor, oAnnotRef.free(); } - oAnnots.free(); oRes.WriteLen(); - BYTE* bRes = oRes.GetBuffer(); + BYTE* pRes = oRes.GetBuffer(); oRes.ClearWithoutAttack(); - return bRes; + return pRes; } diff --git a/PdfFile/PdfReader.h b/PdfFile/PdfReader.h index c74c4706d6..a90b004f7c 100644 --- a/PdfFile/PdfReader.h +++ b/PdfFile/PdfReader.h @@ -37,6 +37,7 @@ #include "../DesktopEditor/graphics/pro/Fonts.h" #include "../DesktopEditor/graphics/pro/officedrawingfile.h" +#include "../DesktopEditor/graphics/pro/js/wasm/src/serialize.h" #include "../DesktopEditor/xmlsec/src/include/Certificate.h" #include "SrcReader/RendererOutputDev.h" @@ -92,6 +93,7 @@ public: int GetMaxRefID(); int GetNumPages(); bool ValidMetaData(); + // Takes ownership of malloc data memory bool MergePages(BYTE* pData, DWORD nLength, const wchar_t* wsPassword = NULL, int nMaxID = 0, const std::string& sPrefixForm = ""); bool MergePages(const std::wstring& wsFile, const wchar_t* wsPassword = NULL, int nMaxID = 0, const std::string& sPrefixForm = ""); @@ -135,13 +137,18 @@ public: private: void Clear(); + CPdfReaderContext* CreateContext(const std::string& sPrefixForm, int nMaxID); + bool FinalizeMerge(CPdfReaderContext* pContext); + CPdfReaderContext* FindContext(PDFDoc* pDoc) const; + +private: std::wstring m_wsTempFolder; NSFonts::IFontManager* m_pFontManager; DWORD m_nFileLength; int m_eError; - IOfficeDrawingFilePainter* m_pPainter; + IOfficeDrawingFilePainter* m_pPainter; std::vector m_vPDFContext; - std::vector m_vRedact; + std::vector m_vRedact; std::map m_mFonts; }; diff --git a/PdfFile/SrcReader/PdfAnnot.cpp b/PdfFile/SrcReader/PdfAnnot.cpp index 655e78b2c3..09e5103d19 100644 --- a/PdfFile/SrcReader/PdfAnnot.cpp +++ b/PdfFile/SrcReader/PdfAnnot.cpp @@ -49,7 +49,6 @@ #include "../../DesktopEditor/common/Types.h" #include "../../DesktopEditor/common/StringExt.h" -#include "../../DesktopEditor/xml/include/xmlutils.h" #include "../../DesktopEditor/fontengine/ApplicationFonts.h" #include "../../DesktopEditor/graphics/pro/Fonts.h" @@ -1857,7 +1856,7 @@ CAnnotFreeText::CAnnotFreeText(PDFDoc* pdfDoc, Object* oAnnotRef, int nPageIndex if (oAnnot.dictLookup("RC", &oObj2)->isNull() && oAnnot.dictLookup("Contents", &oObj)->isString() && oObj.getString()->getLength()) { - m_arrRC = CAnnotMarkup::ReadRC(GetRCFromDS(m_sDS, &oObj, m_arrCFromDA)); + m_arrRC = ReadRC(GetRCFromDS(m_sDS, &oObj, m_arrCFromDA)); if (m_arrRC.empty()) m_unFlags &= ~(1 << 3); else @@ -2749,7 +2748,7 @@ CAnnotMarkup::CAnnotMarkup(PDFDoc* pdfDoc, Object* oAnnotRef, int nPageIndex, in // std::cout << sRC << std::endl; // if (oAnnot.dictLookup("RC", &oObj)->isStream()) // TODO streamGetBlock - m_arrRC = CAnnotMarkup::ReadRC(sRC); + m_arrRC = ReadRC(sRC); if (m_arrRC.empty()) m_unFlags &= ~(1 << 3); else @@ -2786,166 +2785,6 @@ CAnnotMarkup::~CAnnotMarkup() for (int i = 0; i < m_arrRC.size(); ++i) RELEASEOBJECT(m_arrRC[i]); } -void ReadFontData(const std::string& sData, CAnnotMarkup::CFontData* pFont) -{ - size_t nSemicolon = 0; - size_t nColon = sData.find(':'); - while (nColon != std::string::npos && nColon > nSemicolon) - { - std::string sProperty = sData.substr(nSemicolon, nColon - nSemicolon); - nSemicolon = sData.find(';', nSemicolon); - nColon++; - std::string sValue = sData.substr(nColon, nSemicolon - nColon); - nColon = sData.find(':', nSemicolon); - nSemicolon++; - - if (sProperty == "font-size") - pFont->dFontSise = std::stod(sValue); - else if (sProperty == "text-align") - { - // 0 start / left - if (sValue == "center" || sValue == "middle") - pFont->nAlign = 1; - else if (sValue == "right" || sValue == "end") - pFont->nAlign = 2; - else if (sValue == "justify") - pFont->nAlign = 3; - } - else if (sProperty == "color") - { - if (sValue[0] == '#') - { - sValue = sValue.substr(1); - BYTE nColor1 = 0, nColor2 = 0, nColor3 = 0; - if (sValue.length() == 6) - sscanf(sValue.c_str(), "%2hhx%2hhx%2hhx", &nColor1, &nColor2, &nColor3); - else if (sValue.length() == 3) - { - sscanf(sValue.c_str(), "%1hhx%1hhx%1hhx", &nColor1, &nColor2, &nColor3); - nColor1 *= 17; - nColor2 *= 17; - nColor3 *= 17; - } - - pFont->dColor[0] = (double)nColor1 / 255.0; - pFont->dColor[1] = (double)nColor2 / 255.0; - pFont->dColor[2] = (double)nColor3 / 255.0; - } - } - else if (sProperty == "font-weight") - { - // 0 normal / 300 / 400 / 500 - if (sValue == "normal" || sValue == "300" || sValue == "400" || sValue == "500") - pFont->unFontFlags &= ~(1 << 0); - else if (sValue == "bold" || sValue == "bolder" || sValue == "600" || sValue == "700" || sValue == "800" || sValue == "900") - pFont->unFontFlags |= (1 << 0); - } - else if (sProperty == "font-style") - { - // 0 normal - if (sValue == "normal") - pFont->unFontFlags &= ~(1 << 1); - else if (sValue == "italic" || sValue.find("oblique") != std::string::npos) - pFont->unFontFlags |= (1 << 1); - } - else if (sProperty == "font-family") - pFont->sFontFamily = sValue[0] == '\'' ? sValue.substr(1, sValue.length() - 2) : sValue; - else if (sProperty == "text-decoration") - { - if (sValue.find("line-through") != std::string::npos) - pFont->unFontFlags |= (1 << 3); - if (sValue.find("word") != std::string::npos || sValue.find("underline") != std::string::npos) - pFont->unFontFlags |= (1 << 4); - if (sValue.find("none") != std::string::npos) - { - pFont->unFontFlags &= ~(1 << 3); - pFont->unFontFlags &= ~(1 << 4); - } - } - else if (sProperty == "vertical-align") - { - pFont->unFontFlags |= (1 << 5); - pFont->dVAlign = std::stod(sValue); - if (pFont->dVAlign == 0 && sValue[0] == '-') - pFont->dVAlign = -0.01; - } - // font-stretch - } -} -std::vector CAnnotMarkup::ReadRC(const std::string& sRC) -{ - std::vector arrRC; - - XmlUtils::CXmlLiteReader oLightReader; - if (sRC.empty() || !oLightReader.FromStringA(sRC) || !oLightReader.ReadNextNode() || oLightReader.GetNameA() != "body") - return arrRC; - - CAnnotMarkup::CFontData oFontBase; - while (oLightReader.MoveToNextAttribute()) - { - if (oLightReader.GetNameA() == "style") - { - ReadFontData(oLightReader.GetTextA(), &oFontBase); - break; - } - } - oLightReader.MoveToElement(); - - int nDepthP = oLightReader.GetDepth(); - while (oLightReader.ReadNextSiblingNode2(nDepthP)) - { - if (oLightReader.GetNameA() != "p") - continue; - - bool bRTL = false; - while (oLightReader.MoveToNextAttribute()) - { - if (oLightReader.GetNameA() == "dir" && oLightReader.GetTextA() == "rtl") - { - bRTL = true; - break; - } - } - oLightReader.MoveToElement(); - - int nDepthSpan = oLightReader.GetDepth(); - if (oLightReader.IsEmptyNode() || !oLightReader.ReadNextSiblingNode2(nDepthSpan)) - continue; - - do - { - std::string sName = oLightReader.GetNameA(); - if (sName == "span") - { - CAnnotMarkup::CFontData* pFont = new CAnnotMarkup::CFontData(oFontBase); - while (oLightReader.MoveToNextAttribute()) - { - if (oLightReader.GetNameA() == "style") - { - ReadFontData(oLightReader.GetTextA(), pFont); - break; - } - } - oLightReader.MoveToElement(); - - if (bRTL) - pFont->unFontFlags |= (1 << 7); - pFont->sText = oLightReader.GetText2A(); - arrRC.push_back(pFont); - } - else if (sName == "#text") - { - CAnnotMarkup::CFontData* pFont = new CAnnotMarkup::CFontData(oFontBase); - if (bRTL) - pFont->unFontFlags |= (1 << 7); - pFont->sText = oLightReader.GetTextA(); - arrRC.push_back(pFont); - } - } while (oLightReader.ReadNextSiblingNode2(nDepthSpan)); - } - - return arrRC; -} void CAnnotMarkup::SetFont(PDFDoc* pdfDoc, Object* oAnnotRef, NSFonts::IFontManager* pFontManager, CPdfFontList *pFontList) { GetFreeTextFont(pdfDoc, pFontManager, pFontList, oAnnotRef, m_arrRC); diff --git a/PdfFile/SrcReader/PdfAnnot.h b/PdfFile/SrcReader/PdfAnnot.h index 5f87c6b617..c138c640f0 100644 --- a/PdfFile/SrcReader/PdfAnnot.h +++ b/PdfFile/SrcReader/PdfAnnot.h @@ -46,6 +46,7 @@ #include "../../DesktopEditor/graphics/pro/js/wasm/src/serialize.h" #include "RendererOutputDev.h" +#include "PdfFont.h" namespace PdfReader { @@ -387,25 +388,7 @@ private: class CAnnotMarkup : public CAnnot { public: - struct CFontData final - { - bool bFind; - BYTE nAlign; - unsigned int unFontFlags; // 0 Bold, 1 Italic, 3 strikethrough, 4 underline, 5 vertical-align, 6 actual font, 7 RTL - double dFontSise; - double dVAlign; - double dColor[3]; - std::string sFontFamily; - std::string sActualFont; - std::string sText; - - CFontData() : bFind(false), nAlign(0), unFontFlags(4), dFontSise(10), dVAlign(0), dColor{0, 0, 0} {} - CFontData(const CFontData& oFont) : bFind(oFont.bFind), nAlign(oFont.nAlign), unFontFlags(oFont.unFontFlags), dFontSise(oFont.dFontSise), dVAlign(oFont.dVAlign), - dColor{oFont.dColor[0], oFont.dColor[1], oFont.dColor[2]}, sFontFamily(oFont.sFontFamily), sActualFont(oFont.sActualFont), sText(oFont.sText) {} - }; - void SetFont(PDFDoc* pdfDoc, Object* oAnnotRef, NSFonts::IFontManager* pFontManager, CPdfFontList *pFontList); - static std::vector ReadRC(const std::string& sRC); protected: CAnnotMarkup(PDFDoc* pdfDoc, Object* oAnnotRef, int nPageIndex, int nStartRefID); diff --git a/PdfFile/SrcReader/PdfFont.cpp b/PdfFile/SrcReader/PdfFont.cpp index f910748980..e6640aa374 100644 --- a/PdfFile/SrcReader/PdfFont.cpp +++ b/PdfFile/SrcReader/PdfFont.cpp @@ -40,12 +40,27 @@ #include "../lib/xpdf/GfxFont.h" #include "../lib/xpdf/Lexer.h" #include "../lib/xpdf/Parser.h" +#include "../lib/xpdf/CharCodeToUnicode.h" +#include "../lib/xpdf/Decrypt.h" +#include "../lib/fofi/FoFiTrueType.h" +#include "../lib/fofi/FoFiType1C.h" +#include "../lib/fofi/FoFiIdentifier.h" #include "../Resources/BaseFonts.h" #include "../../DesktopEditor/common/StringExt.h" #include "../../DesktopEditor/common/StringBuilder.h" +#include "../../DesktopEditor/common/Path.h" +#include "../../DesktopEditor/xml/include/xmlutils.h" #include "../../DesktopEditor/fontengine/ApplicationFonts.h" +#ifndef BUILDING_WASM_MODULE +#define FONTS_USE_AFM_SETTINGS +#else +#include "../../DesktopEditor/graphics/pro/js/wasm/src/serialize.h" +#include "FontsWasm.h" +#define FONTS_USE_ONLY_MEMORY_STREAMS +#endif + const std::vector arrCMap = {"GB-EUC-H", "GB-EUC-V", "GB-H", "GB-V", "GBpc-EUC-H", "GBpc-EUC-V", "GBK-EUC-H", "GBK-EUC-V", "GBKp-EUC-H", "GBKp-EUC-V", "GBK2K-H", "GBK2K-V", "GBT-H", "GBT-V", "GBTpc-EUC-H", "GBTpc-EUC-V", "UniGB-UCS2-H", "UniGB-UCS2-V", "UniGB-UTF8-H", "UniGB-UTF8-V", "UniGB-UTF16-H", "UniGB-UTF16-V", "UniGB-UTF32-H", @@ -249,9 +264,376 @@ std::wstring Normalize(const std::wstring& wsName) s.erase(std::remove_if(s.begin(), s.end(), [](wchar_t c){ return c == L' ' || c == L'-' || c == L'_'; }), s.end()); return s; }; +std::wstring ComputeFontHash(XRef* pXref, GfxFont* pFont) +{ + MD5State oMD5; + md5Start(&oMD5); + + Ref* pRef = pFont->getID(); + Object oRefObj, oFontObj; + oRefObj.initRef(pRef->num, pRef->gen); + oRefObj.fetch(pXref, &oFontObj); + oRefObj.free(); + + if (oFontObj.isDict()) + { + const char* aFontObjNames[] = { "Name", "Subtype", "BaseFont", "Encoding" }; + for (const char* sKey : aFontObjNames) + { + Object oItem; + oFontObj.dictLookup(sKey, &oItem); + if (oItem.isName()) + md5Append(&oMD5, (BYTE*)oItem.getName(), strlen(oItem.getName())); + oItem.free(); + } + + Object oDescObj, oDescendantFonts; + oFontObj.dictLookup("FontDescriptor", &oDescObj); + if (!oDescObj.isDict()) + { + oDescObj.free(); + if (oFontObj.dictLookup("DescendantFonts", &oDescendantFonts)->isArray()) + { + Object oDescendant; + if (oDescendantFonts.arrayGet(0, &oDescendant)->isDict()) + oDescendant.dictLookup("FontDescriptor", &oDescObj); + oDescendant.free(); + } + oDescendantFonts.free(); + } + + if (oDescObj.isDict()) + { + Object oItem; + + oDescObj.dictLookup("FontName", &oItem); + if (oItem.isName()) + md5Append(&oMD5, (BYTE*)oItem.getName(), strlen(oItem.getName())); + oItem.free(); + + const char* aMetricNames[] = { + "Flags", "ItalicAngle", "Ascent", "Descent", + "CapHeight", "XHeight", "StemV", "StemH" + }; + for (const char* sName : aMetricNames) + { + oDescObj.dictLookup(sName, &oItem); + if (oItem.isInt()) + { + int nVal = oItem.getInt(); + md5Append(&oMD5, (BYTE*)&nVal, sizeof(int)); + } + oItem.free(); + } + + oDescObj.dictLookup("FontBBox", &oItem); + if (oItem.isArray() && oItem.arrayGetLength() == 4) + { + for (int i = 0; i < 4; i++) + { + Object oCoord; + if (oItem.arrayGet(i, &oCoord)->isInt()) + { + int nVal = oCoord.getInt(); + md5Append(&oMD5, (BYTE*)&nVal, sizeof(int)); + } + oCoord.free(); + } + } + oItem.free(); + } + oDescObj.free(); + } + oFontObj.free(); + + Ref oEmbRef; + if (pFont->getEmbeddedFontID(&oEmbRef)) + { + Object oRefObj, oStreamObj; + oRefObj.initRef(oEmbRef.num, oEmbRef.gen); + oRefObj.fetch(pXref, &oStreamObj); + oRefObj.free(); + + if (oStreamObj.isStream()) + { + oStreamObj.streamReset(); + const int nMaxBytes = 512; + BYTE aBuf[nMaxBytes]; + int nRead = 0; + int nChar; + while (nRead < nMaxBytes && (nChar = oStreamObj.streamGetChar()) != EOF) + aBuf[nRead++] = (BYTE)nChar; + + oStreamObj.streamClose(); + md5Append(&oMD5, aBuf, nRead); + } + oStreamObj.free(); + } + + md5Finish(&oMD5); + + static const char aHexChars[] = "0123456789ABCDEF"; + std::string sHex; + sHex.reserve(32); + for (int i = 0; i < 16; i++) + { + sHex += aHexChars[(oMD5.digest[i] >> 4) & 0x0F]; + sHex += aHexChars[oMD5.digest[i] & 0x0F]; + } + + return UTF8_TO_U(sHex); +} +void ReadFontData(const std::string& sData, PdfReader::CFontData* pFont) +{ + size_t nSemicolon = 0; + size_t nColon = sData.find(':'); + while (nColon != std::string::npos && nColon > nSemicolon) + { + std::string sProperty = sData.substr(nSemicolon, nColon - nSemicolon); + nSemicolon = sData.find(';', nSemicolon); + nColon++; + std::string sValue = sData.substr(nColon, nSemicolon - nColon); + nColon = sData.find(':', nSemicolon); + nSemicolon++; + + if (sProperty == "font-size") + pFont->dFontSise = std::stod(sValue); + else if (sProperty == "text-align") + { + // 0 start / left + if (sValue == "center" || sValue == "middle") + pFont->nAlign = 1; + else if (sValue == "right" || sValue == "end") + pFont->nAlign = 2; + else if (sValue == "justify") + pFont->nAlign = 3; + } + else if (sProperty == "color") + { + if (sValue[0] == '#') + { + sValue = sValue.substr(1); + BYTE nColor1 = 0, nColor2 = 0, nColor3 = 0; + if (sValue.length() == 6) + sscanf(sValue.c_str(), "%2hhx%2hhx%2hhx", &nColor1, &nColor2, &nColor3); + else if (sValue.length() == 3) + { + sscanf(sValue.c_str(), "%1hhx%1hhx%1hhx", &nColor1, &nColor2, &nColor3); + nColor1 *= 17; + nColor2 *= 17; + nColor3 *= 17; + } + + pFont->dColor[0] = (double)nColor1 / 255.0; + pFont->dColor[1] = (double)nColor2 / 255.0; + pFont->dColor[2] = (double)nColor3 / 255.0; + } + } + else if (sProperty == "font-weight") + { + // 0 normal / 300 / 400 / 500 + if (sValue == "normal" || sValue == "300" || sValue == "400" || sValue == "500") + pFont->unFontFlags &= ~(1 << 0); + else if (sValue == "bold" || sValue == "bolder" || sValue == "600" || sValue == "700" || sValue == "800" || sValue == "900") + pFont->unFontFlags |= (1 << 0); + } + else if (sProperty == "font-style") + { + // 0 normal + if (sValue == "normal") + pFont->unFontFlags &= ~(1 << 1); + else if (sValue == "italic" || sValue.find("oblique") != std::string::npos) + pFont->unFontFlags |= (1 << 1); + } + else if (sProperty == "font-family") + pFont->sFontFamily = sValue[0] == '\'' ? sValue.substr(1, sValue.length() - 2) : sValue; + else if (sProperty == "text-decoration") + { + if (sValue.find("line-through") != std::string::npos) + pFont->unFontFlags |= (1 << 3); + if (sValue.find("word") != std::string::npos || sValue.find("underline") != std::string::npos) + pFont->unFontFlags |= (1 << 4); + if (sValue.find("none") != std::string::npos) + { + pFont->unFontFlags &= ~(1 << 3); + pFont->unFontFlags &= ~(1 << 4); + } + } + else if (sProperty == "vertical-align") + { + pFont->unFontFlags |= (1 << 5); + pFont->dVAlign = std::stod(sValue); + if (pFont->dVAlign == 0 && sValue[0] == '-') + pFont->dVAlign = -0.01; + } + // font-stretch + } +} + +class CMemoryFontStream +{ +public: + BYTE* m_pData; + int m_nSize; + int m_nPos; + bool m_bIsAttach; + + CMemoryFontStream() + { + m_pData = NULL; + m_nSize = 0; + m_nPos = 0; + m_bIsAttach = false; + } + ~CMemoryFontStream() + { + if (NULL != m_pData && !m_bIsAttach) + RELEASEARRAYOBJECTS(m_pData); + } + + void fromStream(std::wstring& sStreamName) + { + NSFonts::IFontStream* pStream = NSFonts::NSApplicationFontStream::GetGlobalMemoryStorage()->Get(sStreamName); + if (pStream) + { + LONG lSize = 0; + pStream->GetMemory(m_pData, lSize); + m_nSize = (int)lSize; + m_nPos = 0; + m_bIsAttach = true; + } + } + + void fromBuffer(BYTE* pData, int nSize) + { + if (pData) + { + m_pData = pData; + m_nSize = nSize; + m_nPos = 0; + m_bIsAttach = true; + } + } + + void load(Object& oStreamObject) + { + int nCurrentSize = 0xFFFF; + int nCurrentPos = 0; + BYTE* pStream = new BYTE[nCurrentSize]; + + int nChar; + while ((nChar = oStreamObject.streamGetChar()) != EOF) + { + if (nCurrentPos >= nCurrentSize) + { + int nNewSize = 2 * nCurrentSize; + BYTE* pNewBuffer = new BYTE[nNewSize]; + memcpy(pNewBuffer, pStream, nCurrentSize); + RELEASEARRAYOBJECTS(pStream); + pStream = pNewBuffer; + nCurrentSize = nNewSize; + } + pStream[nCurrentPos++] = nChar; + } + + m_pData = pStream; + m_nSize = nCurrentPos; + m_nPos = 0; + } + + int getChar() + { + if (m_nPos >= m_nSize) + return EOF; + return m_pData[m_nPos++]; + } + + void toStart() + { + m_nPos = 0; + } +}; +static int readFromMemoryStream(void* data) +{ + return ((CMemoryFontStream*)data)->getChar(); +} namespace PdfReader { +std::vector ReadRC(const std::string& sRC) +{ + std::vector arrRC; + + XmlUtils::CXmlLiteReader oLightReader; + if (sRC.empty() || !oLightReader.FromStringA(sRC) || !oLightReader.ReadNextNode() || oLightReader.GetNameA() != "body") + return arrRC; + + CFontData oFontBase; + while (oLightReader.MoveToNextAttribute()) + { + if (oLightReader.GetNameA() == "style") + { + ReadFontData(oLightReader.GetTextA(), &oFontBase); + break; + } + } + oLightReader.MoveToElement(); + + int nDepthP = oLightReader.GetDepth(); + while (oLightReader.ReadNextSiblingNode2(nDepthP)) + { + if (oLightReader.GetNameA() != "p") + continue; + + bool bRTL = false; + while (oLightReader.MoveToNextAttribute()) + { + if (oLightReader.GetNameA() == "dir" && oLightReader.GetTextA() == "rtl") + { + bRTL = true; + break; + } + } + oLightReader.MoveToElement(); + + int nDepthSpan = oLightReader.GetDepth(); + if (oLightReader.IsEmptyNode() || !oLightReader.ReadNextSiblingNode2(nDepthSpan)) + continue; + + do + { + std::string sName = oLightReader.GetNameA(); + if (sName == "span") + { + CFontData* pFont = new CFontData(oFontBase); + while (oLightReader.MoveToNextAttribute()) + { + if (oLightReader.GetNameA() == "style") + { + ReadFontData(oLightReader.GetTextA(), pFont); + break; + } + } + oLightReader.MoveToElement(); + + if (bRTL) + pFont->unFontFlags |= (1 << 7); + pFont->sText = oLightReader.GetText2A(); + arrRC.push_back(pFont); + } + else if (sName == "#text") + { + CFontData* pFont = new CFontData(oFontBase); + if (bRTL) + pFont->unFontFlags |= (1 << 7); + pFont->sText = oLightReader.GetTextA(); + arrRC.push_back(pFont); + } + } while (oLightReader.ReadNextSiblingNode2(nDepthSpan)); + } + + return arrRC; +} std::string GetRCFromDS(const std::string& sDS, Object* pContents, const std::vector& arrCFromDA) { NSStringUtils::CStringBuilder oRC; @@ -398,7 +780,7 @@ bool IsBaseFont(const std::wstring& wsName) wsName == L"Helvetica-Oblique" || wsName == L"Symbol" || wsName == L"Times-Bold" || wsName == L"Times-BoldItalic" || wsName == L"Times-Italic" || wsName == L"Times-Roman" || wsName == L"ZapfDingbats"; } -std::map GetAllFonts(PDFDoc* pdfDoc, NSFonts::IFontManager* pFontManager, CPdfFontList* pFontList, bool bIsNeedCMap) +std::map GetAllFonts(PDFDoc* pdfDoc, NSFonts::IFontManager* pFontManager, CPdfFontList* pFontList) { std::map mFonts; @@ -440,7 +822,7 @@ std::map GetAllFonts(PDFDoc* pdfDoc, NSFonts::IFontM std::string sActualFontName; std::wstring wsFileName; bool bBold = false, bItalic = false; - wsFileName = GetFontData(pdfDoc, pFontManager, pFontList, &oFontRef, sFontName, sActualFontName, bBold, bItalic, bIsNeedCMap); + wsFileName = GetFontData(pdfDoc, pFontManager, pFontList, &oFontRef, sFontName, sActualFontName, bBold, bItalic); if (!sActualFontName.empty()) { @@ -464,7 +846,7 @@ std::map GetAllFonts(PDFDoc* pdfDoc, NSFonts::IFontM std::string sFontKey; if (GetFontFromAP(pdfDoc, pField, &oFontRef, sFontKey) && std::find(arrUniqueFontsRef.begin(), arrUniqueFontsRef.end(), oFontRef.getRefNum()) == arrUniqueFontsRef.end()) { - wsFileName = GetFontData(pdfDoc, pFontManager, pFontList, &oFontRef, sFontName, sActualFontName, bBold, bItalic, bIsNeedCMap); + wsFileName = GetFontData(pdfDoc, pFontManager, pFontList, &oFontRef, sFontName, sActualFontName, bBold, bItalic); std::wstring wsFontName = UTF8_TO_U(sFontName); if (sActualFontName.empty() && mFonts.find(wsFontName) == mFonts.end()) @@ -548,7 +930,7 @@ std::map GetAllFonts(PDFDoc* pdfDoc, NSFonts::IFontM Object oAnnotRef; oAnnots.arrayGetNF(i, &oAnnotRef); - std::vector arrRC = CAnnotMarkup::ReadRC(sRC); + std::vector arrRC = ReadRC(sRC); std::map mFreeText = GetFreeTextFont(pdfDoc, pFontManager, pFontList, &oAnnotRef, arrRC); for (std::map::iterator it = mFreeText.begin(); it != mFreeText.end(); ++it) { @@ -565,7 +947,7 @@ std::map GetAllFonts(PDFDoc* pdfDoc, NSFonts::IFontM return mFonts; } -std::wstring GetFontData(PDFDoc* pdfDoc, NSFonts::IFontManager* pFontManager, CPdfFontList *pFontList, Object* oFontRef, std::string& sFontName, std::string& sActualFontName, bool& bBold, bool& bItalic, bool bIsNeedCMap) +std::wstring GetFontData(PDFDoc* pdfDoc, NSFonts::IFontManager* pFontManager, CPdfFontList *pFontList, Object* oFontRef, std::string& sFontName, std::string& sActualFontName, bool& bBold, bool& bItalic) { bBold = false, bItalic = false; XRef* xref = pdfDoc->getXRef(); @@ -589,7 +971,7 @@ std::wstring GetFontData(PDFDoc* pdfDoc, NSFonts::IFontManager* pFontManager, CP if (gfxFont->getEmbeddedFontID(&oEmbRef) || IsBaseFont(wsFontBaseName)) { std::wstring wsFontName; - RendererOutputDev::GetFont(xref, pFontManager, pFontList, gfxFont, wsFileName, wsFontName, false); + GetFont(xref, pFontManager, pFontList, gfxFont, wsFileName, wsFontName, false); sFontName = U_TO_UTF8(wsFontName); CheckFontStylePDF(wsFontName, bBold, bItalic); @@ -602,7 +984,7 @@ std::wstring GetFontData(PDFDoc* pdfDoc, NSFonts::IFontManager* pFontManager, CP { double dStretch = 1.0; std::wstring wsFBN = wsFontBaseName; - NSFonts::CFontInfo* pFontInfo = RendererOutputDev::GetFontByParams(xref, pFontManager, gfxFont, wsFBN, dStretch); + NSFonts::CFontInfo* pFontInfo = GetFontByParams(xref, pFontManager, gfxFont, wsFBN, dStretch); if (pFontInfo && !pFontInfo->m_wsFontPath.empty()) { EraseSubsetTag(wsFontBaseName); @@ -830,7 +1212,7 @@ const CAnnotFontInfo* FindMatchInAnnotFonts(const std::vector& a return pBestMatch; } -std::map GetFreeTextFont(PDFDoc* pdfDoc, NSFonts::IFontManager* pFontManager, CPdfFontList* pFontList, Object* oAnnotRef, std::vector& arrRC) +std::map GetFreeTextFont(PDFDoc* pdfDoc, NSFonts::IFontManager* pFontManager, CPdfFontList* pFontList, Object* oAnnotRef, std::vector& arrRC) { std::map mRes; @@ -957,7 +1339,7 @@ std::map GetFreeTextFont(PDFDoc* pdfDoc, NSFonts::IF return mRes; } -int CollectFontWidths(GfxFont* gfxFont, Dict* pFontDict, std::map& mGIDToWidth) +int CollectFontWidths(Dict* pFontDict, std::map& mGIDToWidth) { int nDefaultWidth = 1000; // Try to get widths from Widths dictionary @@ -1108,6 +1490,23 @@ double CheckFontStylePDF(std::wstring& sName, bool& bBold, bool& bItalic) return dStretch; } +double CheckFontNamePDF(std::wstring& sName, NSFonts::CFontSelectFormat* format) +{ + bool bBold = false; + bool bItalic = false; + + double dStretch = CheckFontStylePDF(sName, bBold, bItalic); + + if (format) + { + if (bBold) + format->bBold = new INT(1); + if (bItalic) + format->bItalic = new INT(1); + } + + return dStretch; +} bool EraseSubsetTag(std::wstring& sFontName) { bool bIsRemove = false; @@ -1129,6 +1528,886 @@ bool EraseSubsetTag(std::wstring& sFontName) return bIsRemove; } +USHORT StretchToWidthClass(double fStretch) +{ + if (fStretch <= 0.50) return 1; // Ultra-condensed + if (fStretch <= 0.625) return 2; // Extra-condensed + if (fStretch <= 0.75) return 3; // Condensed + if (fStretch <= 0.875) return 4; // Semi-condensed + if (fStretch <= 1.0) return 5; // Normal + if (fStretch <= 1.125) return 6; // Semi-expanded + if (fStretch <= 1.25) return 7; // Expanded + if (fStretch <= 1.50) return 8; // Extra-expanded + return 9; // Ultra-expanded +} +NSFonts::CFontInfo* GetFontByParams(XRef* pXref, NSFonts::IFontManager* pFontManager, GfxFont* pFont, std::wstring& wsFontBaseName, double& dStretch) +{ + NSFonts::CFontInfo* pFontInfo = NULL; + if (!pFontManager) + return pFontInfo; + + Ref* pRef = pFont->getID(); + Object oRefObject, oFontObject; + oRefObject.initRef(pRef->num, pRef->gen); + oRefObject.fetch(pXref, &oFontObject); + oRefObject.free(); + + NSFonts::CFontSelectFormat oFontSelect; + dStretch = CheckFontNamePDF(wsFontBaseName, &oFontSelect); + if (std::abs(dStretch - 1.0f) > 1e-5f) + oFontSelect.usWidth = new USHORT(StretchToWidthClass(dStretch)); + if (oFontObject.isDict()) + { + Dict* pFontDict = oFontObject.getDict(); + Object oFontDescriptor, oDescendantFonts; + pFontDict->lookup("FontDescriptor", &oFontDescriptor); + if (!oFontDescriptor.isDict() && pFontDict->lookup("DescendantFonts", &oDescendantFonts)->isArray()) + { + oFontDescriptor.free(); oFontObject.free(); + if (oDescendantFonts.arrayGet(0, &oFontObject)->isDict()) + oFontObject.dictLookup("FontDescriptor", &oFontDescriptor); + } + if (oFontDescriptor.isDict()) + { + Object oDictItem; + oFontDescriptor.dictLookup("FontName", &oDictItem); + if (oDictItem.isName()) + oFontSelect.wsName = AStringToPWString(oDictItem.getName()); + else + oFontSelect.wsName = new std::wstring(wsFontBaseName); + oDictItem.free(); + + oFontDescriptor.dictLookup("FontFamily", &oDictItem); + if (oDictItem.isString()) + { + TextString* s = new TextString(oDictItem.getString()); + oFontSelect.wsAltName = new std::wstring(NSStringExt::CConverter::GetUnicodeFromUTF32(s->getUnicode(), s->getLength())); + delete s; + } + oDictItem.free(); + + oFontDescriptor.dictLookup("FontStretch", &oDictItem); + oDictItem.free(); + + oFontDescriptor.dictLookup("FontWeight", &oDictItem); + oDictItem.free(); + + oFontDescriptor.dictLookup("FontBBox", &oDictItem); + oDictItem.free(); + + oFontDescriptor.dictLookup("Flags", &oDictItem); + if (oDictItem.isInt() && 0 != oDictItem.getInt()) + { + int nFlags = oDictItem.getInt(); + if (nFlags & 1) // monospaced + oFontSelect.bFixedWidth = new INT(1); + } + oDictItem.free(); + + oFontDescriptor.dictLookup("ItalicAngle", &oDictItem); + if (oDictItem.isInt() && 0 != oDictItem.getInt()) + { + if (oFontSelect.bItalic) RELEASEOBJECT(oFontSelect.bItalic); + oFontSelect.bItalic = new INT(1); + } + oDictItem.free(); + + oFontDescriptor.dictLookup("Ascent", &oDictItem); + if (oDictItem.isInt()) oFontSelect.shAscent = new SHORT(oDictItem.getInt()); + oDictItem.free(); + + oFontDescriptor.dictLookup("Leading", &oDictItem); + if (oDictItem.isInt()) oFontSelect.shLineGap = new SHORT(oDictItem.getInt()); + oDictItem.free(); + + oFontDescriptor.dictLookup("CapHeight", &oDictItem); + if (oDictItem.isInt()) oFontSelect.shCapHeight = new SHORT(oDictItem.getInt()); + oDictItem.free(); + + oFontDescriptor.dictLookup("XHeight", &oDictItem); + if (oDictItem.isInt()) oFontSelect.shXHeight = new SHORT(oDictItem.getInt()); + oDictItem.free(); + + oFontDescriptor.dictLookup("StemV", &oDictItem); + if (oDictItem.isNum() && !oFontSelect.usWidth) + { + double dStemV = oDictItem.getNum(); + if (dStemV > 50.5) + oFontSelect.usWeight = new USHORT(sqrt(oDictItem.getNum() - 50.5) * 65); + } + oDictItem.free(); + + oFontDescriptor.dictLookup("StemH", &oDictItem); + oDictItem.free(); + + oFontDescriptor.dictLookup("Descent", &oDictItem); + if (oDictItem.isInt()) oFontSelect.shDescent = new SHORT(oDictItem.getInt()); + oDictItem.free(); + + oFontDescriptor.dictLookup("AvgWidth", &oDictItem); + if (oDictItem.isInt()) oFontSelect.shAvgCharWidth = new SHORT(oDictItem.getInt()); + oDictItem.free(); + + oFontDescriptor.dictLookup("MaxWidth", &oDictItem); + oDictItem.free(); + + oFontDescriptor.dictLookup("MissingWidth", &oDictItem); + oDictItem.free(); + } + else + oFontSelect.wsName = new std::wstring(wsFontBaseName); + oFontDescriptor.free(); oDescendantFonts.free(); + } + else + oFontSelect.wsName = new std::wstring(wsFontBaseName); + oFontObject.free(); + + pFontInfo = pFontManager->GetFontInfoByParams(oFontSelect); + return pFontInfo; +} +void GetFont(XRef* pXref, NSFonts::IFontManager* pFontManager, CPdfFontList* pFontList, GfxFont* pFont, std::wstring& wsFileName, std::wstring& wsFontName, bool bNotFullName) +{ + wsFileName = L""; + wsFontName = L""; + TFontEntry* pEntry = NULL; + // MEMERR string dealocation pEntry + if (!pFontList->Find2((*pFont->getID()), &pEntry)) + { + GfxFontType eFontType = pFont->getType(); + if (fontType3 == eFontType) // FontType3 is handled by a separate command + { + pEntry->bAvailable = true; + return; + } + + std::wstring wsTempFileName = L""; + Ref oEmbRef; + bool bFontSubstitution = false, bFontBase14 = false; + std::wstring wsFontBaseName = NSStrings::GetStringFromUTF32(pFont->getName()); + if (wsFontBaseName.empty()) + wsFontBaseName = L"Helvetica"; + const BYTE* pData14 = NULL; + unsigned int nSize14 = 0; + double dStretch = 1.0; +#ifdef FONTS_USE_ONLY_MEMORY_STREAMS + CMemoryFontStream oMemoryFontStream; +#endif + // 1. If font is embedded, dump it to a temp file. + // 2. If font is outside pdf but pdf has a reference to it, use that reference. + // 3. Otherwise, select a font. + + if (pFont->getEmbeddedFontID(&oEmbRef)) + { + std::wstring wsExt; + switch (pFont->getType()) + { + case fontType1: wsExt = L".pfb_t1"; break; + case fontType1C: wsExt = L".pfb_t1c"; break; + case fontType1COT: wsExt = L".pfb_t1cot"; break; + case fontTrueType: wsExt = L".ttf"; break; + case fontTrueTypeOT: wsExt = L".otf"; break; + case fontCIDType0: wsExt = L".cid_0"; break; + case fontCIDType0C: wsExt = L".cid_0c"; break; + case fontCIDType0COT: wsExt = L".cid_0cot"; break; + case fontCIDType2: wsExt = L".cid_2"; break; + case fontCIDType2OT: wsExt = L".cid_2ot"; break; + } + +#ifdef FONTS_USE_ONLY_MEMORY_STREAMS + if (NSFonts::NSApplicationFontStream::GetGlobalMemoryStorage()) + { + wsTempFileName = NSFonts::NSApplicationFontStream::GetGlobalMemoryStorage()->GenerateId(); + } +#else + FILE* pTempFile = NULL; + if (!NSFile::CFileBinary::OpenTempFile(&wsTempFileName, &pTempFile, L"wb", (wchar_t*)wsExt.c_str(), + (wchar_t*)((GlobalParamsAdaptor*)globalParams)->GetTempFolder().c_str(), NULL)) + { + if (L"" != wsTempFileName) + NSFile::CFileBinary::Remove(wsTempFileName); + + pEntry->bAvailable = true; + return; + } + wsTempFileName = UTF8_TO_U(NSSystemPath::NormalizePath(U_TO_UTF8(wsTempFileName))); +#endif + + Object oReferenceObject, oStreamObject; + oReferenceObject.initRef(oEmbRef.num, oEmbRef.gen); + oReferenceObject.fetch(pXref, &oStreamObject); + oReferenceObject.free(); + if (!oStreamObject.isStream()) + { + // Embedded font is incorrectly written + oStreamObject.free(); + +#ifndef FONTS_USE_ONLY_MEMORY_STREAMS + fclose(pTempFile); + + if (L"" != wsTempFileName) + NSFile::CFileBinary::Remove(wsTempFileName); +#endif + + pEntry->bAvailable = true; + return; + } + oStreamObject.streamReset(); + +#ifdef FONTS_USE_ONLY_MEMORY_STREAMS + oMemoryFontStream.load(oStreamObject); + NSFonts::NSApplicationFontStream::GetGlobalMemoryStorage()->Add(wsTempFileName, oMemoryFontStream.m_pData, (LONG)oMemoryFontStream.m_nSize, true); +#else + int nChar; + while ((nChar = oStreamObject.streamGetChar()) != EOF) + { + fputc(nChar, pTempFile); + } + fclose(pTempFile); +#endif + + oStreamObject.streamClose(); + oStreamObject.free(); + wsFileName = wsTempFileName; + +#ifdef FONTS_USE_AFM_SETTINGS + // For Type1 fonts, need to write Afm file with metrics + if (fontType1 == pFont->getType() || fontType1C == pFont->getType() || fontType1COT == pFont->getType()) + { + std::wstring wsSplitFileName, wsSplitFileExt; + SpitPathExt(wsFileName, &wsSplitFileName, &wsSplitFileExt); + std::wstring wsAfmPath = wsSplitFileName + L".afm"; + + FILE* pFile = NSFile::CFileBinary::OpenFileNative(wsAfmPath, L"wb"); + if (pFile) + { + Ref* pRef = pFont->getID(); + Object oRefObject, oFontObject; + oRefObject.initRef(pRef->num, pRef->gen); + oRefObject.fetch(pXref, &oFontObject); + oRefObject.free(); + + if (oFontObject.isDict()) + { + std::string sFontName, sFontFamily; + int nFontWeight = 0, nItalicAngle = 0, nAscent = 0, nDescent = 0; + int nCapHeight = 0, nXHeight = 0, nStemV = 0, nStemH = 0, nMissingWidth = 0; + int arrBBox[4] = { 0, 0, 0, 0 }; + + Object oFontDescriptor; + if (oFontObject.dictLookup("FontDescriptor", &oFontDescriptor)->isDict()) + { + Object oDictItem; + oFontDescriptor.dictLookup("FontName", &oDictItem); + if (oDictItem.isName()) sFontName = oDictItem.getName(); + oDictItem.free(); + + oFontDescriptor.dictLookup("FontFamily", &oDictItem); + if (oDictItem.isName()) sFontFamily = oDictItem.getName(); + oDictItem.free(); + + oFontDescriptor.dictLookup("FontWeight", &oDictItem); + if (oDictItem.isInt()) nFontWeight = oDictItem.getInt(); + oDictItem.free(); + + if (oFontDescriptor.dictLookup("FontBBox", &oDictItem)->isArray() && oDictItem.arrayGetLength() == 4) + { + for (int nIndex = 0; nIndex < 4; nIndex++) + { + Object oArrayItem; + if (oDictItem.arrayGet(nIndex, &oArrayItem)->isInt()) + arrBBox[nIndex] = oArrayItem.getInt(); + oArrayItem.free(); + } + } + oDictItem.free(); + + oFontDescriptor.dictLookup("ItalicAngle", &oDictItem); + if (oDictItem.isInt()) nItalicAngle = oDictItem.getInt(); + oDictItem.free(); + + oFontDescriptor.dictLookup("Ascent", &oDictItem); + if (oDictItem.isInt()) nAscent = oDictItem.getInt(); + oDictItem.free(); + + oFontDescriptor.dictLookup("CapHeight", &oDictItem); + if (oDictItem.isInt()) nCapHeight = oDictItem.getInt(); + oDictItem.free(); + + oFontDescriptor.dictLookup("XHeight", &oDictItem); + if (oDictItem.isInt()) nXHeight = oDictItem.getInt(); + oDictItem.free(); + + oFontDescriptor.dictLookup("StemV", &oDictItem); + if (oDictItem.isInt()) nStemV = oDictItem.getInt(); + oDictItem.free(); + + oFontDescriptor.dictLookup("StemH", &oDictItem); + if (oDictItem.isInt()) nStemH = oDictItem.getInt(); + oDictItem.free(); + + oFontDescriptor.dictLookup("Descent", &oDictItem); + if (oDictItem.isInt()) nDescent = oDictItem.getInt(); + oDictItem.free(); + + oFontDescriptor.dictLookup("MissingWidth", &oDictItem); + if (oDictItem.isInt()) nMissingWidth = oDictItem.getInt(); + oDictItem.free(); + + } + oFontDescriptor.free(); + + fprintf(pFile, "StartFontMetrics 3.0\n"); + if (!sFontName.empty()) fprintf(pFile, "FontName %s\n", sFontName.c_str()); + if (!sFontFamily.empty()) fprintf(pFile, "FamilyName %s\n", sFontFamily.c_str()); + if (nFontWeight >= 550) fprintf(pFile, "Weight Bold\n"); + + fprintf(pFile, "ItalicAngle %d\n", nItalicAngle); + + fprintf(pFile, "FontBBox %d %d %d %d\n", arrBBox[0], arrBBox[1], arrBBox[2], arrBBox[3]); + + fprintf(pFile, "CapHeight %d\n", nCapHeight); + fprintf(pFile, "XHeight %d\n", nXHeight); + fprintf(pFile, "Ascender %d\n", nAscent); + fprintf(pFile, "Descender %d\n", nDescent); + fprintf(pFile, "StdHW %d\n", nStemH); + fprintf(pFile, "StdHV %d\n", nStemV); + + int nFirstChar = 0; + Object oDictItem; + if (oFontObject.dictLookup("FirstChar", &oDictItem)->isInt()) nFirstChar = oDictItem.getInt(); + oDictItem.free(); + + Gfx8BitFont* pT1Font = (Gfx8BitFont*)pFont; + if (oFontObject.dictLookup("Widths", &oDictItem)->isArray()) + { + int nWidthsCount = oDictItem.arrayGetLength(); + fprintf(pFile, "StartCharMetrics %d\n", nWidthsCount); + for (int nIndex = 0; nIndex < nWidthsCount; nIndex++) + { + int nWidth = nMissingWidth; + Object oArrayItem; + if (oDictItem.arrayGet(nIndex, &oArrayItem)->isInt()) nWidth = oArrayItem.getInt(); + oArrayItem.free(); + + char** ppEncoding = pT1Font->getEncoding(); + + if (ppEncoding && ppEncoding[nIndex]) + fprintf(pFile, "C %d ; WX %d ; N %s ;\n", nIndex + nFirstChar, nWidth, ppEncoding[nIndex]); + else + fprintf(pFile, "C %d ; WX %d ;\n", nIndex + nFirstChar, nWidth); + } + fprintf(pFile, "EndCharMetrics\n"); + } + oDictItem.free(); + } + oFontObject.free(); + } + fclose(pFile); + } +#endif + + // Load the font file itself to determine its exact type + if (!pFontManager->LoadFontFromFile(wsFileName, 0, 10, 72, 72)) + { + pEntry->bAvailable = true; + return; + } + + std::wstring wsFontType = pFontManager->GetFontType(); + if (L"TrueType" == wsFontType) + { + if (eFontType != fontType1COT && eFontType != fontTrueType + && eFontType != fontTrueTypeOT && eFontType != fontCIDType0COT + && eFontType != fontCIDType2 && eFontType != fontCIDType2OT) + { + if (eFontType == fontType1 || eFontType == fontType1C) + eFontType = fontType1COT; + else if (eFontType == fontCIDType0 || eFontType == fontCIDType0C) + eFontType = fontCIDType0COT; + } + } + else if (L"Type 1" == wsFontType) + { + if (eFontType != fontType1 && eFontType != fontType1C) + { + eFontType = fontType1; + } + } + else if (L"CID Type 1" == wsFontType) + { + if (eFontType != fontCIDType0 && eFontType != fontCIDType0C + && eFontType != fontCIDType2OT && eFontType != fontCIDType0COT) + { + eFontType = fontCIDType0; + } + } + else if (L"CFF" == wsFontType) + { + if (eFontType != fontType1C && eFontType != fontType1COT + && eFontType != fontTrueTypeOT && eFontType != fontCIDType0C + && eFontType != fontCIDType0COT && eFontType != fontCIDType2OT + && eFontType != fontCIDType2) + { + if (eFontType == fontType1 || eFontType == fontTrueType) + eFontType = fontType1C; + else if (eFontType == fontCIDType0) + eFontType = fontCIDType0C; + } + } + } +#ifndef FONTS_USE_ONLY_MEMORY_STREAMS + else if (PdfReader::GetBaseFont(wsFontBaseName, pData14, nSize14)) + { + FILE* pFile = NULL; + if (!NSFile::CFileBinary::OpenTempFile(&wsTempFileName, &pFile, L"wb", L".base", + (wchar_t*)((GlobalParamsAdaptor*)globalParams)->GetTempFolder().c_str(), NULL)) + { + if (!wsTempFileName.empty()) + NSFile::CFileBinary::Remove(wsTempFileName); + + pEntry->bAvailable = true; + return; + } + fclose(pFile); + NSFile::CFileBinary oFile; + oFile.CreateFileW(wsTempFileName); + oFile.WriteFile((BYTE*)pData14, nSize14); + oFile.CloseFile(); + wsFileName = wsTempFileName; + bFontBase14 = true; + + eFontType = fontTrueType; + } +#else + else if ([&oMemoryFontStream, wsFontBaseName]() + { + const BYTE* pData14 = NULL; + unsigned int nSize14 = 0; + if (PdfReader::GetBaseFont(wsFontBaseName, pData14, nSize14)) + { + oMemoryFontStream.fromBuffer((BYTE*)pData14, nSize14); + return true; + } + return false; + }()) + { + wsFileName = wsFontBaseName; + bFontBase14 = true; + NSFonts::NSApplicationFontStream::GetGlobalMemoryStorage()->Add(wsFileName, oMemoryFontStream.m_pData, (LONG)oMemoryFontStream.m_nSize, true); + } +#endif + else if (!pFont->locateFont(pXref, false) || + (wsFileName = NSStrings::GetStringFromUTF32(pFont->locateFont(pXref, false)->path)).length() == 0) + { + NSFonts::CFontInfo* pFontInfo = GetFontByParams(pXref, pFontManager, pFont, wsFontBaseName, dStretch); + + if (pFontInfo && L"" != pFontInfo->m_wsFontPath) + { + wsFileName = pFontInfo->m_wsFontPath; + eFontType = pFont->isCIDFont() ? fontCIDType2 : fontTrueType; + +#ifdef FONTS_USE_ONLY_MEMORY_STREAMS + if (NSWasm::IsJSEnv()) + wsFileName = pFontInfo->m_wsFontName; + + if (!wsFileName.empty()) + { + wsFileName = NSWasm::LoadFont(wsFileName, pFontInfo->m_bBold, pFontInfo->m_bItalic); + if (wsFileName.empty()) + { + pFontList->Remove(*pFont->getID()); + return; + } + } + oMemoryFontStream.fromStream(wsFileName); +#endif + + bFontSubstitution = true; + } + else // As a last resort, simply don't write anything with this font + { + pEntry->bAvailable = true; + return; + } + } + // Here we load encodings + int* pCodeToGID = NULL, *pCodeToUnicode = NULL; + int nLen = 0; + FoFiTrueType* pTTFontFile = NULL; +#ifdef FONTS_USE_ONLY_MEMORY_STREAMS + FoFiIdentifierType fofiType = FoFiIdentifier::identifyStream(&readFromMemoryStream, &oMemoryFontStream); + oMemoryFontStream.toStart(); +#else + FoFiIdentifierType fofiType = FoFiIdentifier::identifyFile((char*)U_TO_UTF8(wsFileName).c_str()); +#endif + + switch (eFontType) + { + case fontType1: + case fontType1C: + case fontType1COT: + { + Gfx8BitFont* pFont8bit = NULL; + if (fofiType == fofiIdTrueType) + { +#ifdef FONTS_USE_ONLY_MEMORY_STREAMS + pTTFontFile = FoFiTrueType::make((char*)oMemoryFontStream.m_pData, oMemoryFontStream.m_nSize, 0); +#else + pTTFontFile = FoFiTrueType::load((char*)U_TO_UTF8(wsFileName).c_str(), 0); +#endif + + if (pTTFontFile) + { + pCodeToGID = ((Gfx8BitFont*)pFont)->getCodeToGIDMap(pTTFontFile); + nLen = 256; + + delete pTTFontFile; + pTTFontFile = NULL; + } + else + { + pCodeToGID = NULL; + nLen = 0; + } + } + else if (L"" != wsFileName && (pFont8bit = dynamic_cast(pFont))) + { + char** ppEncoding = pFont8bit->getEncoding(); + if (!ppEncoding) + break; + + if (!pFontManager) + break; + + pFontManager->LoadFontFromFile(wsFileName, 0, 1, 72, 72); + pCodeToGID = (int*)MemUtilsMallocArray(256, sizeof(int)); + if (!pCodeToGID) + break; + + nLen = 256; + for (int nIndex = 0; nIndex < 256; ++nIndex) + { + pCodeToGID[nIndex] = 0; + char* sName = NULL; + if ((sName = ppEncoding[nIndex])) + { + unsigned short ushGID = pFontManager->GetNameIndex(AStringToWString(sName)); + pCodeToGID[nIndex] = ushGID; + } + } + } + break; + } + case fontTrueType: + case fontTrueTypeOT: + { + if (fofiType == fofiIdType1PFB) + { + Gfx8BitFont* pFont8bit = dynamic_cast(pFont); + if (L"" != wsFileName && pFont8bit && pFont8bit->getHasEncoding()) + { + char** ppEncoding = pFont8bit->getEncoding(); + if (!ppEncoding) + break; + + if (!pFontManager) + break; + + pFontManager->LoadFontFromFile(wsFileName, 0, 1, 72, 72); + pCodeToGID = (int*)MemUtilsMallocArray(256, sizeof(int)); + if (!pCodeToGID) + break; + + nLen = 256; + for (int nIndex = 0; nIndex < 256; ++nIndex) + { + pCodeToGID[nIndex] = 0; + char* sName = NULL; + if ((sName = ppEncoding[nIndex])) + { + unsigned short ushGID = pFontManager->GetNameIndex(AStringToWString(sName)); + pCodeToGID[nIndex] = ushGID; + } + } + } + break; + } + +#ifdef FONTS_USE_ONLY_MEMORY_STREAMS + pTTFontFile = FoFiTrueType::make((char*)oMemoryFontStream.m_pData, oMemoryFontStream.m_nSize, 0); +#else + pTTFontFile = FoFiTrueType::load((char*)U_TO_UTF8(wsFileName).c_str(), 0); +#endif + if (pTTFontFile) + { + pCodeToGID = ((Gfx8BitFont*)pFont)->getCodeToGIDMap(pTTFontFile); + nLen = 256; + + delete pTTFontFile; + pTTFontFile = NULL; + } + else + { + pCodeToGID = NULL; + nLen = 0; + + if (pFontManager->LoadFontFromFile(wsFileName, 0, 10, 72, 72)) + { + nLen = 256; + pCodeToGID = (int*)MemUtilsMallocArray(nLen, sizeof(int)); + for (int nCode = 0; nCode < nLen; ++nCode) + { + pCodeToGID[nCode] = pFontManager->GetGIDByUnicode(nCode); + } + } + } + break; + } + case fontCIDType0: + case fontCIDType0C: + { + GfxCIDFont* pFontCID = dynamic_cast(pFont); + if (!bFontSubstitution && pFontCID && pFontCID->getCIDToGID()) + { + nLen = pFontCID->getCIDToGIDLen(); + if (!nLen) + break; + pCodeToGID = (int*)MemUtilsMallocArray(nLen, sizeof(int)); + if (!pCodeToGID) + { + nLen = 0; + break; + } + memcpy(pCodeToGID, ((GfxCIDFont*)pFont)->getCIDToGID(), nLen * sizeof(int)); + break; + } + /* + FoFiType1C* pT1CFontFile = NULL; +#ifdef FONTS_USE_ONLY_MEMORY_STREAMS + pT1CFontFile = FoFiType1C::make((char*)oMemoryFontStream.m_pData, oMemoryFontStream.m_nSize); +#else + pT1CFontFile = FoFiType1C::load((char*)U_TO_UTF8(wsFileName).c_str()); +#endif + if (pT1CFontFile) + { + pCodeToGID = pT1CFontFile->getCIDToGIDMap(&nLen); + + delete pT1CFontFile; + pT1CFontFile = NULL; + } + else + { + pCodeToGID = NULL; + nLen = 0; + } + */ + pCodeToGID = NULL; + nLen = 0; + break; + } + case fontCIDType0COT: + { + GfxCIDFont* pFontCID = dynamic_cast(pFont); + if (!bFontSubstitution && pFontCID && pFontCID->getCIDToGID()) + { + nLen = pFontCID->getCIDToGIDLen(); + if (!nLen) + break; + pCodeToGID = (int*)MemUtilsMallocArray(nLen, sizeof(int)); + if (!pCodeToGID) + { + nLen = 0; + break; + } + memcpy(pCodeToGID, ((GfxCIDFont*)pFont)->getCIDToGID(), nLen * sizeof(int)); + break; + } +#ifdef FONTS_USE_ONLY_MEMORY_STREAMS + pTTFontFile = FoFiTrueType::make((char*)oMemoryFontStream.m_pData, oMemoryFontStream.m_nSize, 0); +#else + pTTFontFile = FoFiTrueType::load((char*)U_TO_UTF8(wsFileName).c_str(), 0); +#endif + + if (pTTFontFile) + { + if (pTTFontFile->isOpenTypeCFF()) + { + pCodeToGID = pTTFontFile->getCIDToGIDMap(&nLen); + } + else + { + pCodeToGID = NULL; + nLen = 0; + } + delete pTTFontFile; + pTTFontFile = NULL; + } + else + { + pCodeToGID = NULL; + nLen = 0; + } + break; + } + case fontCIDType2: + case fontCIDType2OT: + { + // Create CID-to-GID map + // If font was not embedded and was substituted and has ToUnicode map, read GIDs from file based on unicode values. + // For embedded fonts use CIDtoGID map + pCodeToGID = NULL; + nLen = 0; + if (L"" != wsFileName && bFontSubstitution) + { + CharCodeToUnicode* pCodeToUnicode = NULL; + if ((pCodeToUnicode = ((GfxCIDFont*)pFont)->getToUnicode())) + { +#ifdef FONTS_USE_ONLY_MEMORY_STREAMS + pTTFontFile = FoFiTrueType::make((char*)oMemoryFontStream.m_pData, oMemoryFontStream.m_nSize, 0); +#else + pTTFontFile = FoFiTrueType::load((char*)U_TO_UTF8(wsFileName).c_str(), 0); +#endif + if (pTTFontFile) + { + // Looking for Unicode Cmap + std::vector arrCMapIndex; + for (int nCMapIndex = 0; nCMapIndex < pTTFontFile->getNumCmaps(); ++nCMapIndex) + { + if ((pTTFontFile->getCmapPlatform(nCMapIndex) == 3 && pTTFontFile->getCmapEncoding(nCMapIndex) == 1) || pTTFontFile->getCmapPlatform(nCMapIndex) == 0) + { + arrCMapIndex.push_back(nCMapIndex); + } + } + if (arrCMapIndex.size() > 0) + { + // CID -> Unicode -> GID + nLen = pCodeToUnicode->getLength(); + pCodeToGID = (int*)MemUtilsMallocArray(nLen, sizeof(int)); + for (int nCode = 0; nCode < nLen; ++nCode) + { + Unicode arrUnicodeBuffer[8]; + if (pCodeToUnicode->mapToUnicode(nCode, arrUnicodeBuffer, 8) > 0) + { + pCodeToGID[nCode] = pTTFontFile->mapCodeToGID(arrCMapIndex[0], arrUnicodeBuffer[0]); + for (size_t nIndex = 1; nIndex < arrCMapIndex.size(); nIndex++) + { + if (0 == pCodeToGID[nCode]) + pCodeToGID[nCode] = pTTFontFile->mapCodeToGID(arrCMapIndex[nIndex], arrUnicodeBuffer[0]); + else + break; + } + } + else + { + pCodeToGID[nCode] = 0; + } + } + } + delete pTTFontFile; + pTTFontFile = NULL; + } + pCodeToUnicode->decRefCnt(); + } + } + else if (((GfxCIDFont*)pFont)->getCIDToGID()) + { + nLen = ((GfxCIDFont*)pFont)->getCIDToGIDLen(); + pCodeToGID = (int*)MemUtilsMallocArray(nLen, sizeof(int)); + if (!pCodeToGID) + break; + + memcpy(pCodeToGID, ((GfxCIDFont*)pFont)->getCIDToGID(), nLen * sizeof(int)); + } + + break; + } + default: + { + // This should not happen +#ifndef FONTS_USE_ONLY_MEMORY_STREAMS + if (L"" != wsTempFileName) + NSFile::CFileBinary::Remove(wsTempFileName); +#endif + break; + } + } + // Build Code -> Unicode table + int nToUnicodeLen = 0; + if (pFont->isCIDFont()) + { + GfxCIDFont* pCIDFont = (GfxCIDFont*)pFont; + CharCodeToUnicode* pToUnicode = pCIDFont->getToUnicode(); + if (NULL != pToUnicode) + { + nToUnicodeLen = pToUnicode->getLength(); + pCodeToUnicode = (int*)MemUtilsMallocArray(nToUnicodeLen, sizeof(int)); + + if (pCodeToUnicode) + { + for (int nIndex = 0; nIndex < nToUnicodeLen; ++nIndex) + { + Unicode aUnicode[2]; + if (pToUnicode->mapToUnicode(nIndex, aUnicode, 2)) + pCodeToUnicode[nIndex] = aUnicode[0]; + else + pCodeToUnicode[nIndex] = 0; + } + } + + pToUnicode->decRefCnt(); + } + } + else + { + // memory troubles here + + CharCodeToUnicode* pToUnicode = ((Gfx8BitFont*)pFont)->getToUnicode(); + if (NULL != pToUnicode) + { + nToUnicodeLen = pToUnicode->getLength(); + pCodeToUnicode = (int*)MemUtilsMallocArray(nToUnicodeLen, sizeof(int));//literally here + + if (pCodeToUnicode) + { + for (int nIndex = 0; nIndex < nToUnicodeLen; ++nIndex) + { + Unicode nUnicode = 0; + if (pToUnicode->mapToUnicode(nIndex, &nUnicode, 1)) + pCodeToUnicode[nIndex] = (unsigned short)nUnicode; + else + pCodeToUnicode[nIndex] = nIndex; + } + } + pToUnicode->decRefCnt(); + } + } + + // Trim index from FontName if present + if (wsFontName.empty()) + wsFontName = wsFontBaseName; + if (bNotFullName) + EraseSubsetTag(wsFontName); + else if (!bFontBase14 && !bFontSubstitution) + wsFontName += (L" " + ComputeFontHash(pXref, pFont)); + + pEntry->wsFilePath = wsFileName; + pEntry->wsFontName = wsFontName; + pEntry->pCodeToGID = pCodeToGID; + pEntry->pCodeToUnicode = pCodeToUnicode; + pEntry->unLenGID = (unsigned int)nLen; + pEntry->unLenUnicode = (unsigned int)nToUnicodeLen; + pEntry->bAvailable = true; + pEntry->dStretch = dStretch; + pEntry->bFontSubstitution = bFontSubstitution; + pEntry->bIsIdentity = pFont->isCIDFont() == gTrue ? ((GfxCIDFont*)pFont)->usesIdentityEncoding() || ((GfxCIDFont*)pFont)->usesIdentityCIDToGID() || ((GfxCIDFont*)pFont)->ctuUsesCharCodeToUnicode() || pFont->getType() == fontCIDType0C : false; + } + else if (NULL != pEntry) + { + wsFileName = pEntry->wsFilePath; + wsFontName = pEntry->wsFontName; + } +} + CType3FontMetrics* BuildType3FontMetrics(XRef* pXref, GfxFont* pFont) { CType3FontMetrics* pMetrics = new CType3FontMetrics(); diff --git a/PdfFile/SrcReader/PdfFont.h b/PdfFile/SrcReader/PdfFont.h index 670fee67c0..a763fed41b 100644 --- a/PdfFile/SrcReader/PdfFont.h +++ b/PdfFile/SrcReader/PdfFont.h @@ -45,7 +45,6 @@ #include "../../DesktopEditor/graphics/pro/Fonts.h" #include "RendererOutputDev.h" -#include "PdfAnnot.h" namespace PdfReader { @@ -84,20 +83,40 @@ struct CType3FontMetrics return dUnitsPerEm * 0.5; } }; +struct CFontData +{ + bool bFind; + BYTE nAlign; + unsigned int unFontFlags; // 0 Bold, 1 Italic, 3 strikethrough, 4 underline, 5 vertical-align, 6 actual font, 7 RTL + double dFontSise; + double dVAlign; + double dColor[3]; + std::string sFontFamily; + std::string sActualFont; + std::string sText; + CFontData() : bFind(false), nAlign(0), unFontFlags(4), dFontSise(10), dVAlign(0), dColor{0, 0, 0} {} + CFontData(const CFontData& oFont) : bFind(oFont.bFind), nAlign(oFont.nAlign), unFontFlags(oFont.unFontFlags), dFontSise(oFont.dFontSise), dVAlign(oFont.dVAlign), + dColor{oFont.dColor[0], oFont.dColor[1], oFont.dColor[2]}, sFontFamily(oFont.sFontFamily), sActualFont(oFont.sActualFont), sText(oFont.sText) {} +}; + +std::vector ReadRC(const std::string& sRC); std::string GetRCFromDS(const std::string& sDS, Object* pContents, const std::vector& arrCFromDA); bool IsNeedCMap(PDFDoc* pDoc); bool IsBaseFont(const std::wstring& wsName); -std::map GetAllFonts(PDFDoc* pdfDoc, NSFonts::IFontManager* pFontManager, CPdfFontList* pFontList, bool bIsNeedCMap); -std::wstring GetFontData(PDFDoc* pdfDoc, NSFonts::IFontManager* pFontManager, CPdfFontList *pFontList, Object* oFontRef, std::string& sFontName, std::string& sActualFontName, bool& bBold, bool& bItalic, bool bIsNeedCMap = false); +std::map GetAllFonts(PDFDoc* pdfDoc, NSFonts::IFontManager* pFontManager, CPdfFontList* pFontList); +std::wstring GetFontData(PDFDoc* pdfDoc, NSFonts::IFontManager* pFontManager, CPdfFontList *pFontList, Object* oFontRef, std::string& sFontName, std::string& sActualFontName, bool& bBold, bool& bItalic); bool GetFontFromAP(PDFDoc* pdfDoc, AcroFormField* pField, Object* oFontRef, std::string& sFontKey); std::vector GetAnnotFontInfos(PDFDoc* pdfDoc, NSFonts::IFontManager* pFontManager, CPdfFontList* pFontList, Object* oAnnotRef); -std::map GetFreeTextFont(PDFDoc* pdfDoc, NSFonts::IFontManager* pFontManager, CPdfFontList* pFontList, Object* oAnnotRef, std::vector& arrRC); +std::map GetFreeTextFont(PDFDoc* pdfDoc, NSFonts::IFontManager* pFontManager, CPdfFontList* pFontList, Object* oAnnotRef, std::vector& arrRC); bool FindFonts(Object* oStream, int nDepth, Object* oResFonts); -int CollectFontWidths(GfxFont* gfxFont, Dict* pFontDict, std::map& mGIDToWidth); +int CollectFontWidths(Dict* pFontDict, std::map& mGIDToWidth); double CheckFontStylePDF(std::wstring& sName, bool& bBold, bool& bItalic); bool EraseSubsetTag(std::wstring& sFontName); +NSFonts::CFontInfo* GetFontByParams(XRef* pXref, NSFonts::IFontManager* pFontManager, GfxFont* pFont, std::wstring& wsFontBaseName, double& dStretch); +void GetFont(XRef* pXref, NSFonts::IFontManager* pFontManager, CPdfFontList *pFontList, GfxFont* pFont, std::wstring& wsFileName, std::wstring& wsFontName, bool bNotFullName = true); + CType3FontMetrics* BuildType3FontMetrics(XRef* pXref, GfxFont* pFont); } diff --git a/PdfFile/SrcReader/RendererOutputDev.cpp b/PdfFile/SrcReader/RendererOutputDev.cpp index b40020523c..f3ff22b4ee 100644 --- a/PdfFile/SrcReader/RendererOutputDev.cpp +++ b/PdfFile/SrcReader/RendererOutputDev.cpp @@ -40,22 +40,16 @@ #include "../lib/xpdf/ErrorCodes.h" #include "../lib/xpdf/GfxState.h" #include "../lib/xpdf/GfxFont.h" -#include "../lib/fofi/FoFiTrueType.h" -#include "../lib/fofi/FoFiType1C.h" -#include "../lib/fofi/FoFiIdentifier.h" #include "../lib/xpdf/Page.h" #include "../lib/xpdf/Dict.h" #include "../lib/xpdf/Stream.h" #include "../lib/xpdf/PDFDoc.h" -#include "../lib/xpdf/CharCodeToUnicode.h" #include "../lib/xpdf/TextString.h" -#include "../lib/xpdf/Decrypt.h" #include "../../DesktopEditor/graphics/pro/Graphics.h" #include "../../DesktopEditor/graphics/Image.h" #include "../../DesktopEditor/graphics/pro/Fonts.h" #include "../../DesktopEditor/common/File.h" -#include "../../DesktopEditor/common/Path.h" #include "../../DesktopEditor/common/Array.h" #include "../../DesktopEditor/common/StringExt.h" #include "../../DesktopEditor/graphics/BaseThread.h" @@ -67,9 +61,7 @@ #ifndef BUILDING_WASM_MODULE #define FONTS_USE_AFM_SETTINGS #else -#include "../../DesktopEditor/graphics/pro/js/wasm/src/serialize.h" #include "FontsWasm.h" -#define FONTS_USE_ONLY_MEMORY_STREAMS #endif #if defined(_MSC_VER) @@ -80,36 +72,6 @@ namespace PdfReader { - double CheckFontNamePDF(std::wstring& sName, NSFonts::CFontSelectFormat* format) - { - bool bBold = false; - bool bItalic = false; - - double dStretch = CheckFontStylePDF(sName, bBold, bItalic); - - if (format) - { - if (bBold) - format->bBold = new INT(1); - if (bItalic) - format->bItalic = new INT(1); - } - - return dStretch; - } - USHORT StretchToWidthClass(double fStretch) - { - if (fStretch <= 0.50) return 1; // Ultra-condensed - if (fStretch <= 0.625) return 2; // Extra-condensed - if (fStretch <= 0.75) return 3; // Condensed - if (fStretch <= 0.875) return 4; // Semi-condensed - if (fStretch <= 1.0) return 5; // Normal - if (fStretch <= 1.125) return 6; // Semi-expanded - if (fStretch <= 1.25) return 7; // Expanded - if (fStretch <= 1.50) return 8; // Extra-expanded - return 9; // Ultra-expanded - } - void Transform(double* pMatrix, double dUserX, double dUserY, double* pdDeviceX, double* pdDeviceY) { *pdDeviceX = dUserX * pMatrix[0] + dUserY * pMatrix[2] + pMatrix[4]; @@ -119,214 +81,6 @@ namespace PdfReader { return (p[2]*77 + p[1]*150 + p[0]*29) >> 8; } - std::wstring ComputeFontHash(XRef* pXref, GfxFont* pFont) - { - MD5State oMD5; - md5Start(&oMD5); - - Ref* pRef = pFont->getID(); - Object oRefObj, oFontObj; - oRefObj.initRef(pRef->num, pRef->gen); - oRefObj.fetch(pXref, &oFontObj); - oRefObj.free(); - - if (oFontObj.isDict()) - { - const char* aFontObjNames[] = { "Name", "Subtype", "BaseFont", "Encoding" }; - for (const char* sKey : aFontObjNames) - { - Object oItem; - oFontObj.dictLookup(sKey, &oItem); - if (oItem.isName()) - md5Append(&oMD5, (BYTE*)oItem.getName(), strlen(oItem.getName())); - oItem.free(); - } - - Object oDescObj, oDescendantFonts; - oFontObj.dictLookup("FontDescriptor", &oDescObj); - if (!oDescObj.isDict()) - { - oDescObj.free(); - if (oFontObj.dictLookup("DescendantFonts", &oDescendantFonts)->isArray()) - { - Object oDescendant; - if (oDescendantFonts.arrayGet(0, &oDescendant)->isDict()) - oDescendant.dictLookup("FontDescriptor", &oDescObj); - oDescendant.free(); - } - oDescendantFonts.free(); - } - - if (oDescObj.isDict()) - { - Object oItem; - - oDescObj.dictLookup("FontName", &oItem); - if (oItem.isName()) - md5Append(&oMD5, (BYTE*)oItem.getName(), strlen(oItem.getName())); - oItem.free(); - - const char* aMetricNames[] = { - "Flags", "ItalicAngle", "Ascent", "Descent", - "CapHeight", "XHeight", "StemV", "StemH" - }; - for (const char* sName : aMetricNames) - { - oDescObj.dictLookup(sName, &oItem); - if (oItem.isInt()) - { - int nVal = oItem.getInt(); - md5Append(&oMD5, (BYTE*)&nVal, sizeof(int)); - } - oItem.free(); - } - - oDescObj.dictLookup("FontBBox", &oItem); - if (oItem.isArray() && oItem.arrayGetLength() == 4) - { - for (int i = 0; i < 4; i++) - { - Object oCoord; - if (oItem.arrayGet(i, &oCoord)->isInt()) - { - int nVal = oCoord.getInt(); - md5Append(&oMD5, (BYTE*)&nVal, sizeof(int)); - } - oCoord.free(); - } - } - oItem.free(); - } - oDescObj.free(); - } - oFontObj.free(); - - Ref oEmbRef; - if (pFont->getEmbeddedFontID(&oEmbRef)) - { - Object oRefObj, oStreamObj; - oRefObj.initRef(oEmbRef.num, oEmbRef.gen); - oRefObj.fetch(pXref, &oStreamObj); - oRefObj.free(); - - if (oStreamObj.isStream()) - { - oStreamObj.streamReset(); - const int nMaxBytes = 512; - BYTE aBuf[nMaxBytes]; - int nRead = 0; - int nChar; - while (nRead < nMaxBytes && (nChar = oStreamObj.streamGetChar()) != EOF) - aBuf[nRead++] = (BYTE)nChar; - - oStreamObj.streamClose(); - md5Append(&oMD5, aBuf, nRead); - } - oStreamObj.free(); - } - - md5Finish(&oMD5); - - static const char aHexChars[] = "0123456789ABCDEF"; - std::string sHex; - sHex.reserve(32); - for (int i = 0; i < 16; i++) - { - sHex += aHexChars[(oMD5.digest[i] >> 4) & 0x0F]; - sHex += aHexChars[oMD5.digest[i] & 0x0F]; - } - - return UTF8_TO_U(sHex); - } -} - -class CMemoryFontStream -{ -public: - BYTE* m_pData; - int m_nSize; - int m_nPos; - bool m_bIsAttach; - - CMemoryFontStream() - { - m_pData = NULL; - m_nSize = 0; - m_nPos = 0; - m_bIsAttach = false; - } - ~CMemoryFontStream() - { - if (NULL != m_pData && !m_bIsAttach) - RELEASEARRAYOBJECTS(m_pData); - } - - void fromStream(std::wstring& sStreamName) - { - NSFonts::IFontStream* pStream = NSFonts::NSApplicationFontStream::GetGlobalMemoryStorage()->Get(sStreamName); - if (pStream) - { - LONG lSize = 0; - pStream->GetMemory(m_pData, lSize); - m_nSize = (int)lSize; - m_nPos = 0; - m_bIsAttach = true; - } - } - - void fromBuffer(BYTE* pData, int nSize) - { - if (pData) - { - m_pData = pData; - m_nSize = nSize; - m_nPos = 0; - m_bIsAttach = true; - } - } - - void load(Object& oStreamObject) - { - int nCurrentSize = 0xFFFF; - int nCurrentPos = 0; - BYTE* pStream = new BYTE[nCurrentSize]; - - int nChar; - while ((nChar = oStreamObject.streamGetChar()) != EOF) - { - if (nCurrentPos >= nCurrentSize) - { - int nNewSize = 2 * nCurrentSize; - BYTE* pNewBuffer = new BYTE[nNewSize]; - memcpy(pNewBuffer, pStream, nCurrentSize); - RELEASEARRAYOBJECTS(pStream); - pStream = pNewBuffer; - nCurrentSize = nNewSize; - } - pStream[nCurrentPos++] = nChar; - } - - m_pData = pStream; - m_nSize = nCurrentPos; - m_nPos = 0; - } - - int getChar() - { - if (m_nPos >= m_nSize) - return EOF; - return m_pData[m_nPos++]; - } - - void toStart() - { - m_nPos = 0; - } -}; - -static int readFromMemoryStream(void* data) -{ - return ((CMemoryFontStream*)data)->getChar(); } // TODO: 1. Implement gradient fills properly (Axial and Radial) @@ -755,874 +509,7 @@ namespace PdfReader { } - NSFonts::CFontInfo* RendererOutputDev::GetFontByParams(XRef* pXref, NSFonts::IFontManager* pFontManager, GfxFont* pFont, std::wstring& wsFontBaseName, double& dStretch) - { - NSFonts::CFontInfo* pFontInfo = NULL; - if (!pFontManager) - return pFontInfo; - Ref* pRef = pFont->getID(); - Object oRefObject, oFontObject; - oRefObject.initRef(pRef->num, pRef->gen); - oRefObject.fetch(pXref, &oFontObject); - oRefObject.free(); - - NSFonts::CFontSelectFormat oFontSelect; - dStretch = CheckFontNamePDF(wsFontBaseName, &oFontSelect); - if (std::abs(dStretch - 1.0f) > 1e-5f) - oFontSelect.usWidth = new USHORT(StretchToWidthClass(dStretch)); - if (oFontObject.isDict()) - { - Dict* pFontDict = oFontObject.getDict(); - Object oFontDescriptor, oDescendantFonts; - pFontDict->lookup("FontDescriptor", &oFontDescriptor); - if (!oFontDescriptor.isDict() && pFontDict->lookup("DescendantFonts", &oDescendantFonts)->isArray()) - { - oFontDescriptor.free(); oFontObject.free(); - if (oDescendantFonts.arrayGet(0, &oFontObject)->isDict()) - oFontObject.dictLookup("FontDescriptor", &oFontDescriptor); - } - if (oFontDescriptor.isDict()) - { - Object oDictItem; - oFontDescriptor.dictLookup("FontName", &oDictItem); - if (oDictItem.isName()) - oFontSelect.wsName = AStringToPWString(oDictItem.getName()); - else - oFontSelect.wsName = new std::wstring(wsFontBaseName); - oDictItem.free(); - - oFontDescriptor.dictLookup("FontFamily", &oDictItem); - if (oDictItem.isString()) - { - TextString* s = new TextString(oDictItem.getString()); - oFontSelect.wsAltName = new std::wstring(NSStringExt::CConverter::GetUnicodeFromUTF32(s->getUnicode(), s->getLength())); - delete s; - } - oDictItem.free(); - - oFontDescriptor.dictLookup("FontStretch", &oDictItem); - oDictItem.free(); - - oFontDescriptor.dictLookup("FontWeight", &oDictItem); - oDictItem.free(); - - oFontDescriptor.dictLookup("FontBBox", &oDictItem); - oDictItem.free(); - - oFontDescriptor.dictLookup("Flags", &oDictItem); - if (oDictItem.isInt() && 0 != oDictItem.getInt()) - { - int nFlags = oDictItem.getInt(); - if (nFlags & 1) // monospaced - oFontSelect.bFixedWidth = new INT(1); - } - oDictItem.free(); - - oFontDescriptor.dictLookup("ItalicAngle", &oDictItem); - if (oDictItem.isInt() && 0 != oDictItem.getInt()) - { - if (oFontSelect.bItalic) RELEASEOBJECT(oFontSelect.bItalic); - oFontSelect.bItalic = new INT(1); - } - oDictItem.free(); - - oFontDescriptor.dictLookup("Ascent", &oDictItem); - if (oDictItem.isInt()) oFontSelect.shAscent = new SHORT(oDictItem.getInt()); - oDictItem.free(); - - oFontDescriptor.dictLookup("Leading", &oDictItem); - if (oDictItem.isInt()) oFontSelect.shLineGap = new SHORT(oDictItem.getInt()); - oDictItem.free(); - - oFontDescriptor.dictLookup("CapHeight", &oDictItem); - if (oDictItem.isInt()) oFontSelect.shCapHeight = new SHORT(oDictItem.getInt()); - oDictItem.free(); - - oFontDescriptor.dictLookup("XHeight", &oDictItem); - if (oDictItem.isInt()) oFontSelect.shXHeight = new SHORT(oDictItem.getInt()); - oDictItem.free(); - - oFontDescriptor.dictLookup("StemV", &oDictItem); - if (oDictItem.isNum() && !oFontSelect.usWidth) - { - double dStemV = oDictItem.getNum(); - if (dStemV > 50.5) - oFontSelect.usWeight = new USHORT(sqrt(oDictItem.getNum() - 50.5) * 65); - } - oDictItem.free(); - - oFontDescriptor.dictLookup("StemH", &oDictItem); - oDictItem.free(); - - oFontDescriptor.dictLookup("Descent", &oDictItem); - if (oDictItem.isInt()) oFontSelect.shDescent = new SHORT(oDictItem.getInt()); - oDictItem.free(); - - oFontDescriptor.dictLookup("AvgWidth", &oDictItem); - if (oDictItem.isInt()) oFontSelect.shAvgCharWidth = new SHORT(oDictItem.getInt()); - oDictItem.free(); - - oFontDescriptor.dictLookup("MaxWidth", &oDictItem); - oDictItem.free(); - - oFontDescriptor.dictLookup("MissingWidth", &oDictItem); - oDictItem.free(); - } - else - oFontSelect.wsName = new std::wstring(wsFontBaseName); - oFontDescriptor.free(); oDescendantFonts.free(); - } - else - oFontSelect.wsName = new std::wstring(wsFontBaseName); - oFontObject.free(); - - pFontInfo = pFontManager->GetFontInfoByParams(oFontSelect); - return pFontInfo; - } - void RendererOutputDev::GetFont(XRef* pXref, NSFonts::IFontManager* pFontManager, CPdfFontList* pFontList, GfxFont* pFont, std::wstring& wsFileName, std::wstring& wsFontName, bool bNotFullName) - { - wsFileName = L""; - wsFontName = L""; - TFontEntry* pEntry = NULL; - // MEMERR string dealocation pEntry - if (!pFontList->Find2((*pFont->getID()), &pEntry)) - { - GfxFontType eFontType = pFont->getType(); - if (fontType3 == eFontType) // FontType3 is handled by a separate command - { - pEntry->bAvailable = true; - return; - } - - std::wstring wsTempFileName = L""; - Ref oEmbRef; - bool bFontSubstitution = false, bFontBase14 = false; - std::wstring wsFontBaseName = NSStrings::GetStringFromUTF32(pFont->getName()); - if (wsFontBaseName.empty()) - wsFontBaseName = L"Helvetica"; - const BYTE* pData14 = NULL; - unsigned int nSize14 = 0; - double dStretch = 1.0; -#ifdef FONTS_USE_ONLY_MEMORY_STREAMS - CMemoryFontStream oMemoryFontStream; -#endif - // 1. If font is embedded, dump it to a temp file. - // 2. If font is outside pdf but pdf has a reference to it, use that reference. - // 3. Otherwise, select a font. - - if (pFont->getEmbeddedFontID(&oEmbRef)) - { - std::wstring wsExt; - switch (pFont->getType()) - { - case fontType1: wsExt = L".pfb_t1"; break; - case fontType1C: wsExt = L".pfb_t1c"; break; - case fontType1COT: wsExt = L".pfb_t1cot"; break; - case fontTrueType: wsExt = L".ttf"; break; - case fontTrueTypeOT: wsExt = L".otf"; break; - case fontCIDType0: wsExt = L".cid_0"; break; - case fontCIDType0C: wsExt = L".cid_0c"; break; - case fontCIDType0COT: wsExt = L".cid_0cot"; break; - case fontCIDType2: wsExt = L".cid_2"; break; - case fontCIDType2OT: wsExt = L".cid_2ot"; break; - } - -#ifdef FONTS_USE_ONLY_MEMORY_STREAMS - if (NSFonts::NSApplicationFontStream::GetGlobalMemoryStorage()) - { - wsTempFileName = NSFonts::NSApplicationFontStream::GetGlobalMemoryStorage()->GenerateId(); - } -#else - FILE* pTempFile = NULL; - if (!NSFile::CFileBinary::OpenTempFile(&wsTempFileName, &pTempFile, L"wb", (wchar_t*)wsExt.c_str(), - (wchar_t*)((GlobalParamsAdaptor*)globalParams)->GetTempFolder().c_str(), NULL)) - { - if (L"" != wsTempFileName) - NSFile::CFileBinary::Remove(wsTempFileName); - - pEntry->bAvailable = true; - return; - } - wsTempFileName = UTF8_TO_U(NSSystemPath::NormalizePath(U_TO_UTF8(wsTempFileName))); -#endif - - Object oReferenceObject, oStreamObject; - oReferenceObject.initRef(oEmbRef.num, oEmbRef.gen); - oReferenceObject.fetch(pXref, &oStreamObject); - oReferenceObject.free(); - if (!oStreamObject.isStream()) - { - // Embedded font is incorrectly written - oStreamObject.free(); - -#ifndef FONTS_USE_ONLY_MEMORY_STREAMS - fclose(pTempFile); - - if (L"" != wsTempFileName) - NSFile::CFileBinary::Remove(wsTempFileName); -#endif - - pEntry->bAvailable = true; - return; - } - oStreamObject.streamReset(); - -#ifdef FONTS_USE_ONLY_MEMORY_STREAMS - oMemoryFontStream.load(oStreamObject); - NSFonts::NSApplicationFontStream::GetGlobalMemoryStorage()->Add(wsTempFileName, oMemoryFontStream.m_pData, (LONG)oMemoryFontStream.m_nSize, true); -#else - int nChar; - while ((nChar = oStreamObject.streamGetChar()) != EOF) - { - fputc(nChar, pTempFile); - } - fclose(pTempFile); -#endif - - oStreamObject.streamClose(); - oStreamObject.free(); - wsFileName = wsTempFileName; - -#ifdef FONTS_USE_AFM_SETTINGS - // For Type1 fonts, need to write Afm file with metrics - if (fontType1 == pFont->getType() || fontType1C == pFont->getType() || fontType1COT == pFont->getType()) - { - std::wstring wsSplitFileName, wsSplitFileExt; - SpitPathExt(wsFileName, &wsSplitFileName, &wsSplitFileExt); - std::wstring wsAfmPath = wsSplitFileName + L".afm"; - - FILE* pFile = NSFile::CFileBinary::OpenFileNative(wsAfmPath, L"wb"); - if (pFile) - { - Ref* pRef = pFont->getID(); - Object oRefObject, oFontObject; - oRefObject.initRef(pRef->num, pRef->gen); - oRefObject.fetch(pXref, &oFontObject); - oRefObject.free(); - - if (oFontObject.isDict()) - { - std::string sFontName, sFontFamily; - int nFontWeight = 0, nItalicAngle = 0, nAscent = 0, nDescent = 0; - int nCapHeight = 0, nXHeight = 0, nStemV = 0, nStemH = 0, nMissingWidth = 0; - int arrBBox[4] = { 0, 0, 0, 0 }; - - Object oFontDescriptor; - if (oFontObject.dictLookup("FontDescriptor", &oFontDescriptor)->isDict()) - { - Object oDictItem; - oFontDescriptor.dictLookup("FontName", &oDictItem); - if (oDictItem.isName()) sFontName = oDictItem.getName(); - oDictItem.free(); - - oFontDescriptor.dictLookup("FontFamily", &oDictItem); - if (oDictItem.isName()) sFontFamily = oDictItem.getName(); - oDictItem.free(); - - oFontDescriptor.dictLookup("FontWeight", &oDictItem); - if (oDictItem.isInt()) nFontWeight = oDictItem.getInt(); - oDictItem.free(); - - if (oFontDescriptor.dictLookup("FontBBox", &oDictItem)->isArray() && oDictItem.arrayGetLength() == 4) - { - for (int nIndex = 0; nIndex < 4; nIndex++) - { - Object oArrayItem; - if (oDictItem.arrayGet(nIndex, &oArrayItem)->isInt()) - arrBBox[nIndex] = oArrayItem.getInt(); - oArrayItem.free(); - } - } - oDictItem.free(); - - oFontDescriptor.dictLookup("ItalicAngle", &oDictItem); - if (oDictItem.isInt()) nItalicAngle = oDictItem.getInt(); - oDictItem.free(); - - oFontDescriptor.dictLookup("Ascent", &oDictItem); - if (oDictItem.isInt()) nAscent = oDictItem.getInt(); - oDictItem.free(); - - oFontDescriptor.dictLookup("CapHeight", &oDictItem); - if (oDictItem.isInt()) nCapHeight = oDictItem.getInt(); - oDictItem.free(); - - oFontDescriptor.dictLookup("XHeight", &oDictItem); - if (oDictItem.isInt()) nXHeight = oDictItem.getInt(); - oDictItem.free(); - - oFontDescriptor.dictLookup("StemV", &oDictItem); - if (oDictItem.isInt()) nStemV = oDictItem.getInt(); - oDictItem.free(); - - oFontDescriptor.dictLookup("StemH", &oDictItem); - if (oDictItem.isInt()) nStemH = oDictItem.getInt(); - oDictItem.free(); - - oFontDescriptor.dictLookup("Descent", &oDictItem); - if (oDictItem.isInt()) nDescent = oDictItem.getInt(); - oDictItem.free(); - - oFontDescriptor.dictLookup("MissingWidth", &oDictItem); - if (oDictItem.isInt()) nMissingWidth = oDictItem.getInt(); - oDictItem.free(); - - } - oFontDescriptor.free(); - - fprintf(pFile, "StartFontMetrics 3.0\n"); - if (!sFontName.empty()) fprintf(pFile, "FontName %s\n", sFontName.c_str()); - if (!sFontFamily.empty()) fprintf(pFile, "FamilyName %s\n", sFontFamily.c_str()); - if (nFontWeight >= 550) fprintf(pFile, "Weight Bold\n"); - - fprintf(pFile, "ItalicAngle %d\n", nItalicAngle); - - fprintf(pFile, "FontBBox %d %d %d %d\n", arrBBox[0], arrBBox[1], arrBBox[2], arrBBox[3]); - - fprintf(pFile, "CapHeight %d\n", nCapHeight); - fprintf(pFile, "XHeight %d\n", nXHeight); - fprintf(pFile, "Ascender %d\n", nAscent); - fprintf(pFile, "Descender %d\n", nDescent); - fprintf(pFile, "StdHW %d\n", nStemH); - fprintf(pFile, "StdHV %d\n", nStemV); - - int nFirstChar = 0; - Object oDictItem; - if (oFontObject.dictLookup("FirstChar", &oDictItem)->isInt()) nFirstChar = oDictItem.getInt(); - oDictItem.free(); - - Gfx8BitFont* pT1Font = (Gfx8BitFont*)pFont; - if (oFontObject.dictLookup("Widths", &oDictItem)->isArray()) - { - int nWidthsCount = oDictItem.arrayGetLength(); - fprintf(pFile, "StartCharMetrics %d\n", nWidthsCount); - for (int nIndex = 0; nIndex < nWidthsCount; nIndex++) - { - int nWidth = nMissingWidth; - Object oArrayItem; - if (oDictItem.arrayGet(nIndex, &oArrayItem)->isInt()) nWidth = oArrayItem.getInt(); - oArrayItem.free(); - - char** ppEncoding = pT1Font->getEncoding(); - - if (ppEncoding && ppEncoding[nIndex]) - fprintf(pFile, "C %d ; WX %d ; N %s ;\n", nIndex + nFirstChar, nWidth, ppEncoding[nIndex]); - else - fprintf(pFile, "C %d ; WX %d ;\n", nIndex + nFirstChar, nWidth); - } - fprintf(pFile, "EndCharMetrics\n"); - } - oDictItem.free(); - } - oFontObject.free(); - } - fclose(pFile); - } -#endif - - // Load the font file itself to determine its exact type - if (!pFontManager->LoadFontFromFile(wsFileName, 0, 10, 72, 72)) - { - pEntry->bAvailable = true; - return; - } - - std::wstring wsFontType = pFontManager->GetFontType(); - if (L"TrueType" == wsFontType) - { - if (eFontType != fontType1COT && eFontType != fontTrueType - && eFontType != fontTrueTypeOT && eFontType != fontCIDType0COT - && eFontType != fontCIDType2 && eFontType != fontCIDType2OT) - { - if (eFontType == fontType1 || eFontType == fontType1C) - eFontType = fontType1COT; - else if (eFontType == fontCIDType0 || eFontType == fontCIDType0C) - eFontType = fontCIDType0COT; - } - } - else if (L"Type 1" == wsFontType) - { - if (eFontType != fontType1 && eFontType != fontType1C) - { - eFontType = fontType1; - } - } - else if (L"CID Type 1" == wsFontType) - { - if (eFontType != fontCIDType0 && eFontType != fontCIDType0C - && eFontType != fontCIDType2OT && eFontType != fontCIDType0COT) - { - eFontType = fontCIDType0; - } - } - else if (L"CFF" == wsFontType) - { - if (eFontType != fontType1C && eFontType != fontType1COT - && eFontType != fontTrueTypeOT && eFontType != fontCIDType0C - && eFontType != fontCIDType0COT && eFontType != fontCIDType2OT - && eFontType != fontCIDType2) - { - if (eFontType == fontType1 || eFontType == fontTrueType) - eFontType = fontType1C; - else if (eFontType == fontCIDType0) - eFontType = fontCIDType0C; - } - } - } -#ifndef FONTS_USE_ONLY_MEMORY_STREAMS - else if (PdfReader::GetBaseFont(wsFontBaseName, pData14, nSize14)) - { - FILE* pFile = NULL; - if (!NSFile::CFileBinary::OpenTempFile(&wsTempFileName, &pFile, L"wb", L".base", - (wchar_t*)((GlobalParamsAdaptor*)globalParams)->GetTempFolder().c_str(), NULL)) - { - if (!wsTempFileName.empty()) - NSFile::CFileBinary::Remove(wsTempFileName); - - pEntry->bAvailable = true; - return; - } - fclose(pFile); - NSFile::CFileBinary oFile; - oFile.CreateFileW(wsTempFileName); - oFile.WriteFile((BYTE*)pData14, nSize14); - oFile.CloseFile(); - wsFileName = wsTempFileName; - bFontBase14 = true; - - eFontType = fontTrueType; - } -#else - else if ([&oMemoryFontStream, wsFontBaseName]() - { - const BYTE* pData14 = NULL; - unsigned int nSize14 = 0; - if (PdfReader::GetBaseFont(wsFontBaseName, pData14, nSize14)) - { - oMemoryFontStream.fromBuffer((BYTE*)pData14, nSize14); - return true; - } - return false; - }()) - { - wsFileName = wsFontBaseName; - bFontBase14 = true; - NSFonts::NSApplicationFontStream::GetGlobalMemoryStorage()->Add(wsFileName, oMemoryFontStream.m_pData, (LONG)oMemoryFontStream.m_nSize, true); - } -#endif - else if (!pFont->locateFont(pXref, false) || - (wsFileName = NSStrings::GetStringFromUTF32(pFont->locateFont(pXref, false)->path)).length() == 0) - { - NSFonts::CFontInfo* pFontInfo = GetFontByParams(pXref, pFontManager, pFont, wsFontBaseName, dStretch); - - if (pFontInfo && L"" != pFontInfo->m_wsFontPath) - { - wsFileName = pFontInfo->m_wsFontPath; - eFontType = pFont->isCIDFont() ? fontCIDType2 : fontTrueType; - -#ifdef FONTS_USE_ONLY_MEMORY_STREAMS - if (NSWasm::IsJSEnv()) - wsFileName = pFontInfo->m_wsFontName; - - if (!wsFileName.empty()) - { - wsFileName = NSWasm::LoadFont(wsFileName, pFontInfo->m_bBold, pFontInfo->m_bItalic); - if (wsFileName.empty()) - { - pFontList->Remove(*pFont->getID()); - return; - } - } - oMemoryFontStream.fromStream(wsFileName); -#endif - - bFontSubstitution = true; - } - else // As a last resort, simply don't write anything with this font - { - pEntry->bAvailable = true; - return; - } - } - // Here we load encodings - int* pCodeToGID = NULL, *pCodeToUnicode = NULL; - int nLen = 0; - FoFiTrueType* pTTFontFile = NULL; - FoFiType1C* pT1CFontFile = NULL; -#ifdef FONTS_USE_ONLY_MEMORY_STREAMS - FoFiIdentifierType fofiType = FoFiIdentifier::identifyStream(&readFromMemoryStream, &oMemoryFontStream); - oMemoryFontStream.toStart(); -#else - FoFiIdentifierType fofiType = FoFiIdentifier::identifyFile((char*)U_TO_UTF8(wsFileName).c_str()); -#endif - - switch (eFontType) - { - case fontType1: - case fontType1C: - case fontType1COT: - { - Gfx8BitFont* pFont8bit = NULL; - if (fofiType == fofiIdTrueType) - { -#ifdef FONTS_USE_ONLY_MEMORY_STREAMS - pTTFontFile = FoFiTrueType::make((char*)oMemoryFontStream.m_pData, oMemoryFontStream.m_nSize, 0); -#else - pTTFontFile = FoFiTrueType::load((char*)U_TO_UTF8(wsFileName).c_str(), 0); -#endif - - if (pTTFontFile) - { - pCodeToGID = ((Gfx8BitFont*)pFont)->getCodeToGIDMap(pTTFontFile); - nLen = 256; - - delete pTTFontFile; - pTTFontFile = NULL; - } - else - { - pCodeToGID = NULL; - nLen = 0; - } - } - else if (L"" != wsFileName && (pFont8bit = dynamic_cast(pFont))) - { - char** ppEncoding = pFont8bit->getEncoding(); - if (!ppEncoding) - break; - - if (!pFontManager) - break; - - pFontManager->LoadFontFromFile(wsFileName, 0, 1, 72, 72); - pCodeToGID = (int*)MemUtilsMallocArray(256, sizeof(int)); - if (!pCodeToGID) - break; - - nLen = 256; - for (int nIndex = 0; nIndex < 256; ++nIndex) - { - pCodeToGID[nIndex] = 0; - char* sName = NULL; - if ((sName = ppEncoding[nIndex])) - { - unsigned short ushGID = pFontManager->GetNameIndex(AStringToWString(sName)); - pCodeToGID[nIndex] = ushGID; - } - } - } - break; - } - case fontTrueType: - case fontTrueTypeOT: - { - if (fofiType == fofiIdType1PFB) - { - Gfx8BitFont* pFont8bit = dynamic_cast(pFont); - if (L"" != wsFileName && pFont8bit && pFont8bit->getHasEncoding()) - { - char** ppEncoding = pFont8bit->getEncoding(); - if (!ppEncoding) - break; - - if (!pFontManager) - break; - - pFontManager->LoadFontFromFile(wsFileName, 0, 1, 72, 72); - pCodeToGID = (int*)MemUtilsMallocArray(256, sizeof(int)); - if (!pCodeToGID) - break; - - nLen = 256; - for (int nIndex = 0; nIndex < 256; ++nIndex) - { - pCodeToGID[nIndex] = 0; - char* sName = NULL; - if ((sName = ppEncoding[nIndex])) - { - unsigned short ushGID = pFontManager->GetNameIndex(AStringToWString(sName)); - pCodeToGID[nIndex] = ushGID; - } - } - } - break; - } - -#ifdef FONTS_USE_ONLY_MEMORY_STREAMS - pTTFontFile = FoFiTrueType::make((char*)oMemoryFontStream.m_pData, oMemoryFontStream.m_nSize, 0); -#else - pTTFontFile = FoFiTrueType::load((char*)U_TO_UTF8(wsFileName).c_str(), 0); -#endif - if (pTTFontFile) - { - pCodeToGID = ((Gfx8BitFont*)pFont)->getCodeToGIDMap(pTTFontFile); - nLen = 256; - - delete pTTFontFile; - pTTFontFile = NULL; - } - else - { - pCodeToGID = NULL; - nLen = 0; - - if (pFontManager->LoadFontFromFile(wsFileName, 0, 10, 72, 72)) - { - INT* pCodes = NULL; - nLen = 256; - pCodeToGID = (int*)MemUtilsMallocArray(nLen, sizeof(int)); - for (int nCode = 0; nCode < nLen; ++nCode) - { - pCodeToGID[nCode] = pFontManager->GetGIDByUnicode(nCode); - } - } - } - break; - } - case fontCIDType0: - case fontCIDType0C: - { - GfxCIDFont* pFontCID = dynamic_cast(pFont); - if (!bFontSubstitution && pFontCID && pFontCID->getCIDToGID()) - { - nLen = pFontCID->getCIDToGIDLen(); - if (!nLen) - break; - pCodeToGID = (int*)MemUtilsMallocArray(nLen, sizeof(int)); - if (!pCodeToGID) - { - nLen = 0; - break; - } - memcpy(pCodeToGID, ((GfxCIDFont*)pFont)->getCIDToGID(), nLen * sizeof(int)); - break; - } - /* -#ifdef FONTS_USE_ONLY_MEMORY_STREAMS - pT1CFontFile = FoFiType1C::make((char*)oMemoryFontStream.m_pData, oMemoryFontStream.m_nSize); -#else - pT1CFontFile = FoFiType1C::load((char*)U_TO_UTF8(wsFileName).c_str()); -#endif - if (pT1CFontFile) - { - pCodeToGID = pT1CFontFile->getCIDToGIDMap(&nLen); - - delete pT1CFontFile; - pT1CFontFile = NULL; - } - else - { - pCodeToGID = NULL; - nLen = 0; - } - */ - pCodeToGID = NULL; - nLen = 0; - break; - } - case fontCIDType0COT: - { - GfxCIDFont* pFontCID = dynamic_cast(pFont); - if (!bFontSubstitution && pFontCID && pFontCID->getCIDToGID()) - { - nLen = pFontCID->getCIDToGIDLen(); - if (!nLen) - break; - pCodeToGID = (int*)MemUtilsMallocArray(nLen, sizeof(int)); - if (!pCodeToGID) - { - nLen = 0; - break; - } - memcpy(pCodeToGID, ((GfxCIDFont*)pFont)->getCIDToGID(), nLen * sizeof(int)); - break; - } -#ifdef FONTS_USE_ONLY_MEMORY_STREAMS - pTTFontFile = FoFiTrueType::make((char*)oMemoryFontStream.m_pData, oMemoryFontStream.m_nSize, 0); -#else - pTTFontFile = FoFiTrueType::load((char*)U_TO_UTF8(wsFileName).c_str(), 0); -#endif - - if (pTTFontFile) - { - if (pTTFontFile->isOpenTypeCFF()) - { - pCodeToGID = pTTFontFile->getCIDToGIDMap(&nLen); - } - else - { - pCodeToGID = NULL; - nLen = 0; - } - delete pTTFontFile; - pTTFontFile = NULL; - } - else - { - pCodeToGID = NULL; - nLen = 0; - } - break; - } - case fontCIDType2: - case fontCIDType2OT: - { - // Create CID-to-GID map - // If font was not embedded and was substituted and has ToUnicode map, read GIDs from file based on unicode values. - // For embedded fonts use CIDtoGID map - pCodeToGID = NULL; - nLen = 0; - if (L"" != wsFileName && bFontSubstitution) - { - CharCodeToUnicode* pCodeToUnicode = NULL; - if ((pCodeToUnicode = ((GfxCIDFont*)pFont)->getToUnicode())) - { -#ifdef FONTS_USE_ONLY_MEMORY_STREAMS - pTTFontFile = FoFiTrueType::make((char*)oMemoryFontStream.m_pData, oMemoryFontStream.m_nSize, 0); -#else - pTTFontFile = FoFiTrueType::load((char*)U_TO_UTF8(wsFileName).c_str(), 0); -#endif - if (pTTFontFile) - { - // Looking for Unicode Cmap - std::vector arrCMapIndex; - for (int nCMapIndex = 0; nCMapIndex < pTTFontFile->getNumCmaps(); ++nCMapIndex) - { - if ((pTTFontFile->getCmapPlatform(nCMapIndex) == 3 && pTTFontFile->getCmapEncoding(nCMapIndex) == 1) || pTTFontFile->getCmapPlatform(nCMapIndex) == 0) - { - arrCMapIndex.push_back(nCMapIndex); - } - } - if (arrCMapIndex.size() > 0) - { - // CID -> Unicode -> GID - nLen = pCodeToUnicode->getLength(); - pCodeToGID = (int*)MemUtilsMallocArray(nLen, sizeof(int)); - for (int nCode = 0; nCode < nLen; ++nCode) - { - Unicode arrUnicodeBuffer[8]; - if (pCodeToUnicode->mapToUnicode(nCode, arrUnicodeBuffer, 8) > 0) - { - pCodeToGID[nCode] = pTTFontFile->mapCodeToGID(arrCMapIndex[0], arrUnicodeBuffer[0]); - for (size_t nIndex = 1; nIndex < arrCMapIndex.size(); nIndex++) - { - if (0 == pCodeToGID[nCode]) - pCodeToGID[nCode] = pTTFontFile->mapCodeToGID(arrCMapIndex[nIndex], arrUnicodeBuffer[0]); - else - break; - } - } - else - { - pCodeToGID[nCode] = 0; - } - } - } - delete pTTFontFile; - pTTFontFile = NULL; - } - pCodeToUnicode->decRefCnt(); - } - } - else if (((GfxCIDFont*)pFont)->getCIDToGID()) - { - nLen = ((GfxCIDFont*)pFont)->getCIDToGIDLen(); - pCodeToGID = (int*)MemUtilsMallocArray(nLen, sizeof(int)); - if (!pCodeToGID) - break; - - memcpy(pCodeToGID, ((GfxCIDFont*)pFont)->getCIDToGID(), nLen * sizeof(int)); - } - - break; - } - default: - { - // This should not happen -#ifndef FONTS_USE_ONLY_MEMORY_STREAMS - if (L"" != wsTempFileName) - NSFile::CFileBinary::Remove(wsTempFileName); -#endif - break; - } - } - // Build Code -> Unicode table - int nToUnicodeLen = 0; - if (pFont->isCIDFont()) - { - GfxCIDFont* pCIDFont = (GfxCIDFont*)pFont; - CharCodeToUnicode* pToUnicode = pCIDFont->getToUnicode(); - if (NULL != pToUnicode) - { - nToUnicodeLen = pToUnicode->getLength(); - pCodeToUnicode = (int*)MemUtilsMallocArray(nToUnicodeLen, sizeof(int)); - - if (pCodeToUnicode) - { - for (int nIndex = 0; nIndex < nToUnicodeLen; ++nIndex) - { - Unicode aUnicode[2]; - if (pToUnicode->mapToUnicode(nIndex, aUnicode, 2)) - pCodeToUnicode[nIndex] = aUnicode[0]; - else - pCodeToUnicode[nIndex] = 0; - } - } - - pToUnicode->decRefCnt(); - } - } - else - { - // memory troubles here - - CharCodeToUnicode* pToUnicode = ((Gfx8BitFont*)pFont)->getToUnicode(); - if (NULL != pToUnicode) - { - nToUnicodeLen = pToUnicode->getLength(); - pCodeToUnicode = (int*)MemUtilsMallocArray(nToUnicodeLen, sizeof(int));//literally here - - if (pCodeToUnicode) - { - for (int nIndex = 0; nIndex < nToUnicodeLen; ++nIndex) - { - Unicode nUnicode = 0; - if (pToUnicode->mapToUnicode(nIndex, &nUnicode, 1)) - pCodeToUnicode[nIndex] = (unsigned short)nUnicode; - else - pCodeToUnicode[nIndex] = nIndex; - } - } - pToUnicode->decRefCnt(); - } - } - - // Trim index from FontName if present - if (wsFontName.empty()) - wsFontName = wsFontBaseName; - if (bNotFullName) - EraseSubsetTag(wsFontName); - else if (!bFontBase14 && !bFontSubstitution) - wsFontName += (L" " + ComputeFontHash(pXref, pFont)); - - pEntry->wsFilePath = wsFileName; - pEntry->wsFontName = wsFontName; - pEntry->pCodeToGID = pCodeToGID; - pEntry->pCodeToUnicode = pCodeToUnicode; - pEntry->unLenGID = (unsigned int)nLen; - pEntry->unLenUnicode = (unsigned int)nToUnicodeLen; - pEntry->bAvailable = true; - pEntry->dStretch = dStretch; - pEntry->bFontSubstitution = bFontSubstitution; - pEntry->bIsIdentity = pFont->isCIDFont() == gTrue ? ((GfxCIDFont*)pFont)->usesIdentityEncoding() || ((GfxCIDFont*)pFont)->usesIdentityCIDToGID() || ((GfxCIDFont*)pFont)->ctuUsesCharCodeToUnicode() || pFont->getType() == fontCIDType0C : false; - } - else if (NULL != pEntry) - { - wsFileName = pEntry->wsFilePath; - wsFontName = pEntry->wsFontName; - } - } void RendererOutputDev::updateFont(GfxState* pGState) { // Check for font list presence diff --git a/PdfFile/SrcReader/RendererOutputDev.h b/PdfFile/SrcReader/RendererOutputDev.h index ee9937ec75..9250b2e0a6 100644 --- a/PdfFile/SrcReader/RendererOutputDev.h +++ b/PdfFile/SrcReader/RendererOutputDev.h @@ -249,8 +249,6 @@ namespace PdfReader { m_pbBreak = pbBreak; } - static NSFonts::CFontInfo* GetFontByParams(XRef* pXref, NSFonts::IFontManager* pFontManager, GfxFont* pFont, std::wstring& wsFontBaseName, double& dStretch); - static void GetFont(XRef* pXref, NSFonts::IFontManager* pFontManager, CPdfFontList *pFontList, GfxFont* pFont, std::wstring& wsFileName, std::wstring& wsFontName, bool bNotFullName = true); private: struct GfxOutputState diff --git a/PdfFile/lib/xpdf/Object.h b/PdfFile/lib/xpdf/Object.h index cb63651014..a141567c38 100644 --- a/PdfFile/lib/xpdf/Object.h +++ b/PdfFile/lib/xpdf/Object.h @@ -146,7 +146,7 @@ public: GBool isName(const char *nameA) { return type == objName && !strcmp(name, nameA); } GBool isDict(const char *dictType); - GBool isStream(char *dictType); + GBool isStream(const char *dictType); GBool isCmd(const char *cmdA) { return type == objCmd && !strcmp(cmd, cmdA); } @@ -182,7 +182,7 @@ public: Object *dictGetValNF(int i, Object *obj); // Stream accessors. - GBool streamIs(char *dictType); + GBool streamIs(const char *dictType); void streamReset(); void streamClose(); int streamGetChar(); @@ -284,10 +284,10 @@ inline Object *Object::dictGetValNF(int i, Object *obj) #include "Stream.h" -inline GBool Object::streamIs(char *dictType) +inline GBool Object::streamIs(const char *dictType) { return stream->getDict()->is(dictType); } -inline GBool Object::isStream(char *dictType) +inline GBool Object::isStream(const char *dictType) { return type == objStream && streamIs(dictType); } inline void Object::streamReset()