qt5/src/ArthurOutputDev.cc | 355 +++++++++++++++++++-------------------------- qt5/src/ArthurOutputDev.h | 15 + qt5/src/CMakeLists.txt | 2 splash/SplashFTFontFile.cc | 4 splash/SplashFTFontFile.h | 3 5 files changed, 167 insertions(+), 212 deletions(-)
New commits: commit 230652c1af3c1b3b91e10d94ab79339135dc6ca3 Author: Oliver Sander <[email protected]> Date: Tue Dec 11 22:50:07 2018 +0100 Fix memory handling bug The CIDToGID map is an array of ints. The code properly allocated a number N of ints, but then used memcpy for N unsigned shorts. That left the upper half of the array uninitialized. diff --git a/qt5/src/ArthurOutputDev.cc b/qt5/src/ArthurOutputDev.cc index 1d3ae77f..750dc1df 100644 --- a/qt5/src/ArthurOutputDev.cc +++ b/qt5/src/ArthurOutputDev.cc @@ -673,7 +673,7 @@ void ArthurOutputDev::updateFont(GfxState *state) if (codeToGIDLen) { codeToGID = (int *)gmallocn(codeToGIDLen, sizeof(int)); memcpy(codeToGID, ((GfxCIDFont *)gfxFont)->getCIDToGID(), - codeToGIDLen * sizeof(unsigned short)); + codeToGIDLen * sizeof(int)); } } else { auto ff = (fontLoc->locType != gfxFontLocEmbedded) commit 13ed70184e125a20a5bdbfbf73456de741c81d9f Author: Oliver Sander <[email protected]> Date: Fri Nov 9 22:28:21 2018 +0100 Remove method SplashFTFontFile::getCodeToGID This method was added in cc43c720e857548175a9e35b0686a1a7a8957f50 for the use in the ArturOutputDev::updateFont. It is not use there anymore, and can therefore be removed again. diff --git a/splash/SplashFTFontFile.cc b/splash/SplashFTFontFile.cc index 91c5e864..7e3c34fc 100644 --- a/splash/SplashFTFontFile.cc +++ b/splash/SplashFTFontFile.cc @@ -140,7 +140,3 @@ SplashFont *SplashFTFontFile::makeFont(SplashCoord *mat, font->initCache(); return font; } - -int *SplashFTFontFile::getCodeToGID() { - return codeToGID; -} diff --git a/splash/SplashFTFontFile.h b/splash/SplashFTFontFile.h index a73c671a..e5e0e940 100644 --- a/splash/SplashFTFontFile.h +++ b/splash/SplashFTFontFile.h @@ -58,9 +58,6 @@ public: SplashFont *makeFont(SplashCoord *mat, const SplashCoord *textMat) override; - // Provide access to the code-to-GID map - int* getCodeToGID(); - private: SplashFTFontFile(SplashFTFontEngine *engineA, commit 3c56110469b86a7665c18ce165d4ad0e5870ebb3 Author: Oliver Sander <[email protected]> Date: Sat Sep 15 13:58:37 2018 +0200 Remove all Splash code from the Arthur backend Previously, Splash code was used to get the codeToGID mapping for font rendering (which you apparently cannot get from Qt). This patch reimplements the same functionality using only FoFi and FreeType. This makes the code easier to understand, because it removes several layers of redirection. diff --git a/qt5/src/ArthurOutputDev.cc b/qt5/src/ArthurOutputDev.cc index b837973d..1d3ae77f 100644 --- a/qt5/src/ArthurOutputDev.cc +++ b/qt5/src/ArthurOutputDev.cc @@ -49,6 +49,7 @@ #include "Link.h" #include "FontEncodingTables.h" #include <fofi/FoFiTrueType.h> +#include <fofi/FoFiType1C.h> #include "ArthurOutputDev.h" #include "Page.h" #include "Gfx.h" @@ -60,34 +61,6 @@ #include <QtGui/QPainterPath> #include <QPicture> -//------------------------------------------------------------------------ - -#ifdef HAVE_SPLASH -#include "splash/SplashFontFileID.h" -#include "splash/SplashFTFontFile.h" -#include "splash/SplashFontEngine.h" -//------------------------------------------------------------------------ -// SplashOutFontFileID -//------------------------------------------------------------------------ - -class SplashOutFontFileID: public SplashFontFileID { -public: - - SplashOutFontFileID(const Ref *rA) { r = *rA; } - - ~SplashOutFontFileID() {} - - bool matches(SplashFontFileID *id) override { - return ((SplashOutFontFileID *)id)->r.num == r.num && - ((SplashOutFontFileID *)id)->r.gen == r.gen; - } - -private: - - Ref r; -}; - -#endif class ArthurType3Font { @@ -181,31 +154,41 @@ ArthurOutputDev::ArthurOutputDev(QPainter *painter): { m_painter.push(painter); m_currentBrush = QBrush(Qt::SolidPattern); - m_fontEngine = nullptr; + + auto error = FT_Init_FreeType(&m_ftLibrary); + if (error) + { + qCritical() << "An error occurred will initializing the FreeType library"; + } + + // as of FT 2.1.8, CID fonts are indexed by CID instead of GID + FT_Int major, minor, patch; + FT_Library_Version(m_ftLibrary, &major, &minor, &patch); + m_useCIDs = major > 2 || + (major == 2 && (minor > 1 || (minor == 1 && patch > 7))); } ArthurOutputDev::~ArthurOutputDev() { -#ifdef HAVE_SPLASH - delete m_fontEngine; -#endif + for (auto& codeToGID : m_codeToGIDCache) { + gfree(const_cast<int*>(codeToGID.second)); + } + + FT_Done_FreeType(m_ftLibrary); } void ArthurOutputDev::startDoc(PDFDoc* doc) { xref = doc->getXRef(); m_doc = doc; -#ifdef HAVE_SPLASH - delete m_fontEngine; - - const bool isHintingEnabled = m_fontHinting != NoHinting; - const bool isSlightHinting = m_fontHinting == SlightHinting; - - m_fontEngine = new SplashFontEngine( - globalParams->getEnableFreeType(), - isHintingEnabled, - isSlightHinting, - m_painter.top()->testRenderHint(QPainter::TextAntialiasing)); -#endif + + if (!globalParams->getEnableFreeType()) { + qCritical() << "Arthur backend will not render text without FreeType, but it is disabled!"; + } + + for (auto& codeToGID : m_codeToGIDCache) { + gfree(const_cast<int*>(codeToGID.second)); + } + m_codeToGIDCache.clear(); } void ArthurOutputDev::startPage(int pageNum, GfxState *state, XRef *) @@ -529,216 +512,190 @@ void ArthurOutputDev::updateFont(GfxState *state) // We have now successfully loaded the font into a QRawFont object. This // allows us to draw all the glyphs in the font. However, what is missing is // the charcode-to-glyph-index mapping. Apparently, Qt does not provide this - // information at all. We therefore now load the font again, this time into - // a Splash font object. This is wasteful, but I see no other way to access - // the important glyph-index mapping. + // information at all. Therefore, we need to figure it ourselves, using + // FoFi and FreeType. // ***************************************************************************** -#ifdef HAVE_SPLASH - GfxFontType fontType; - SplashFontFile *fontFile; - SplashFontSrc *fontsrc = nullptr; - FoFiTrueType *ff; - GooString *fileName; - char *tmpBuf; - int tmpBufLen = 0; - int *codeToGID; - SplashCoord mat[4] = {0,0,0,0}; - int n; - int faceIndex = 0; - SplashCoord matrix[6] = {1,0,0,1,0,0}; - SplashFTFontFile* ftFontFile; - m_needFontUpdate = false; - fileName = nullptr; - tmpBuf = nullptr; - fontType = gfxFont->getType(); - if (fontType == fontType3) { - return; - } + GfxFontType fontType = gfxFont->getType(); // Default: no codeToGID table m_codeToGID = nullptr; // check the font file cache - SplashOutFontFileID *id = new SplashOutFontFileID(gfxFont->getID()); - if ((fontFile = m_fontEngine->getFontFile(id))) { - delete id; + Ref id = *gfxFont->getID(); + + auto codeToGIDIt = m_codeToGIDCache.find(id); + + if (codeToGIDIt != m_codeToGIDCache.end()) { + + m_codeToGID = codeToGIDIt->second; } else { + std::unique_ptr<char[], void(*)(char*)> tmpBuf(nullptr, [](char* b){ free(b); }); + int tmpBufLen = 0; + std::unique_ptr<GfxFontLoc> fontLoc(gfxFont->locateFont(xref, nullptr)); if (!fontLoc) { error(errSyntaxError, -1, "Couldn't find a font for '{0:s}'", gfxFont->getName() ? gfxFont->getName()->c_str() : "(unnamed)"); - goto err2; + return; } // embedded font if (fontLoc->locType == gfxFontLocEmbedded) { // if there is an embedded font, read it to memory - tmpBuf = gfxFont->readEmbFontFile(xref, &tmpBufLen); - if (! tmpBuf) - goto err2; + tmpBuf.reset(gfxFont->readEmbFontFile(xref, &tmpBufLen)); + if (! tmpBuf) { + return; + } // external font } else { // gfxFontLocExternal - fileName = fontLoc->path; + // Hmm, fontType has already been set to gfxFont->getType() above. + // Can it really assume a different value here? fontType = fontLoc->fontType; } - fontsrc = new SplashFontSrc; - if (fileName) - fontsrc->setFile(fileName, false); - else - fontsrc->setBuf(tmpBuf, tmpBufLen, true); - - // load the font file switch (fontType) { case fontType1: - if (!(fontFile = m_fontEngine->loadType1Font( - id, - fontsrc, - (const char **)((Gfx8BitFont *)gfxFont)->getEncoding()))) { - error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'", - gfxFont->getName() ? gfxFont->getName()->c_str() - : "(unnamed)"); - goto err2; - } - break; case fontType1C: - if (!(fontFile = m_fontEngine->loadType1CFont( - id, - fontsrc, - (const char **)((Gfx8BitFont *)gfxFont)->getEncoding()))) { - error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'", - gfxFont->getName() ? gfxFont->getName()->c_str() - : "(unnamed)"); - goto err2; - } - break; case fontType1COT: - if (!(fontFile = m_fontEngine->loadOpenTypeT1CFont( - id, - fontsrc, - (const char **)((Gfx8BitFont *)gfxFont)->getEncoding()))) { - error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'", - gfxFont->getName() ? gfxFont->getName()->c_str() - : "(unnamed)"); - goto err2; + { + // Load the font face using FreeType + const int faceIndex = 0; // We always load the zero-th face from a font + FT_Face freeTypeFace; + + if (fontLoc->locType != gfxFontLocEmbedded) { + if (FT_New_Face(m_ftLibrary, fontLoc->path->c_str(), faceIndex, &freeTypeFace)) { + error(errSyntaxError, -1, "Couldn't create a FreeType face for '{0:s}'", + gfxFont->getName() ? gfxFont->getName()->c_str() : "(unnamed)"); + return; + } + } else { + if (FT_New_Memory_Face(m_ftLibrary, (const FT_Byte *)tmpBuf.get(), tmpBufLen, faceIndex, &freeTypeFace)) { + error(errSyntaxError, -1, "Couldn't create a FreeType face for '{0:s}'", + gfxFont->getName() ? gfxFont->getName()->c_str() : "(unnamed)"); + return; + } } + + const char *name; + + int *codeToGID = (int *)gmallocn(256, sizeof(int)); + for (int i = 0; i < 256; ++i) { + codeToGID[i] = 0; + if ((name = ((const char **)((Gfx8BitFont *)gfxFont)->getEncoding())[i])) { + codeToGID[i] = (int)FT_Get_Name_Index(freeTypeFace, (char *)name); + if (codeToGID[i] == 0) { + name = GfxFont::getAlternateName(name); + if (name) { + codeToGID[i] = FT_Get_Name_Index(freeTypeFace, (char *)name); + } + } + } + } + + FT_Done_Face(freeTypeFace); + + m_codeToGIDCache[id] = codeToGID; + break; + } case fontTrueType: case fontTrueTypeOT: - if (fileName) - ff = FoFiTrueType::load(fileName->c_str()); - else - ff = FoFiTrueType::make(tmpBuf, tmpBufLen); - if (ff) { - codeToGID = ((Gfx8BitFont *)gfxFont)->getCodeToGIDMap(ff); - n = 256; - delete ff; - } else { - codeToGID = nullptr; - n = 0; - } - if (!(fontFile = m_fontEngine->loadTrueTypeFont( - id, - fontsrc, - codeToGID, n))) { - error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'", - gfxFont->getName() ? gfxFont->getName()->c_str() - : "(unnamed)"); - goto err2; - } + { + auto ff = (fontLoc->locType != gfxFontLocEmbedded) + ? std::unique_ptr<FoFiTrueType>(FoFiTrueType::load(fontLoc->path->c_str())) + : std::unique_ptr<FoFiTrueType>(FoFiTrueType::make(tmpBuf.get(), tmpBufLen)); + + m_codeToGIDCache[id] = (ff) ? ((Gfx8BitFont *)gfxFont)->getCodeToGIDMap(ff.get()) : nullptr; + break; + } case fontCIDType0: case fontCIDType0C: - if (!(fontFile = m_fontEngine->loadCIDFont( - id, - fontsrc))) { - error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'", - gfxFont->getName() ? gfxFont->getName()->c_str() - : "(unnamed)"); - goto err2; + { + int *cidToGIDMap = nullptr; + int nCIDs = 0; + + // check for a CFF font + if (!m_useCIDs) { + auto ff = (fontLoc->locType != gfxFontLocEmbedded) + ? std::unique_ptr<FoFiType1C>(FoFiType1C::load(fontLoc->path->c_str())) + : std::unique_ptr<FoFiType1C>(FoFiType1C::make(tmpBuf.get(), tmpBufLen)); + + cidToGIDMap = (ff) ? ff->getCIDToGIDMap(&nCIDs) : nullptr; } + + m_codeToGIDCache[id] = cidToGIDMap; + break; + } case fontCIDType0COT: + { + int* codeToGID = nullptr; + if (((GfxCIDFont *)gfxFont)->getCIDToGID()) { - n = ((GfxCIDFont *)gfxFont)->getCIDToGIDLen(); - codeToGID = (int *)gmallocn(n, sizeof(int)); - memcpy(codeToGID, ((GfxCIDFont *)gfxFont)->getCIDToGID(), - n * sizeof(int)); - } else { - codeToGID = nullptr; - n = 0; - } - if (!(fontFile = m_fontEngine->loadOpenTypeCFFFont( - id, - fontsrc, - codeToGID, n))) { - error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'", - gfxFont->getName() ? gfxFont->getName()->c_str() - : "(unnamed)"); - goto err2; + int codeToGIDLen = ((GfxCIDFont *)gfxFont)->getCIDToGIDLen(); + codeToGID = (int *)gmallocn(codeToGIDLen, sizeof(int)); + memcpy(codeToGID, ((GfxCIDFont *)gfxFont)->getCIDToGID(), + codeToGIDLen * sizeof(int)); } + + int *cidToGIDMap = nullptr; + int nCIDs = 0; + + if (!codeToGID && !m_useCIDs) { + auto ff = (fontLoc->locType != gfxFontLocEmbedded) + ? std::unique_ptr<FoFiTrueType>(FoFiTrueType::load(fontLoc->path->c_str())) + : std::unique_ptr<FoFiTrueType>(FoFiTrueType::make(tmpBuf.get(), tmpBufLen)); + + if (ff && ff->isOpenTypeCFF()) { + cidToGIDMap = ff->getCIDToGIDMap(&nCIDs); + } + } + + m_codeToGIDCache[id] = codeToGID ? codeToGID : cidToGIDMap; + break; + } case fontCIDType2: case fontCIDType2OT: - codeToGID = nullptr; - n = 0; + { + int* codeToGID = nullptr; + int codeToGIDLen = 0; if (((GfxCIDFont *)gfxFont)->getCIDToGID()) { - n = ((GfxCIDFont *)gfxFont)->getCIDToGIDLen(); - if (n) { - codeToGID = (int *)gmallocn(n, sizeof(int)); - memcpy(codeToGID, ((GfxCIDFont *)gfxFont)->getCIDToGID(), - n * sizeof(unsigned short)); - } + codeToGIDLen = ((GfxCIDFont *)gfxFont)->getCIDToGIDLen(); + if (codeToGIDLen) { + codeToGID = (int *)gmallocn(codeToGIDLen, sizeof(int)); + memcpy(codeToGID, ((GfxCIDFont *)gfxFont)->getCIDToGID(), + codeToGIDLen * sizeof(unsigned short)); + } } else { - if (fileName) - ff = FoFiTrueType::load(fileName->c_str()); - else - ff = FoFiTrueType::make(tmpBuf, tmpBufLen); - if (! ff) - goto err2; - codeToGID = ((GfxCIDFont *)gfxFont)->getCodeToGIDMap(ff, &n); - delete ff; - } - if (!(fontFile = m_fontEngine->loadTrueTypeFont( - id, - fontsrc, - codeToGID, n, faceIndex))) { - error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'", - gfxFont->getName() ? gfxFont->getName()->c_str() - : "(unnamed)"); - goto err2; + auto ff = (fontLoc->locType != gfxFontLocEmbedded) + ? std::unique_ptr<FoFiTrueType>(FoFiTrueType::load(fontLoc->path->c_str())) + : std::unique_ptr<FoFiTrueType>(FoFiTrueType::make(tmpBuf.get(), tmpBufLen)); + if (! ff) { + return; + } + codeToGID = ((GfxCIDFont *)gfxFont)->getCodeToGIDMap(ff.get(), &codeToGIDLen); } + + m_codeToGIDCache[id] = codeToGID; + break; + } default: // this shouldn't happen - goto err2; + return; } - } - - ftFontFile = dynamic_cast<SplashFTFontFile*>(fontFile); - if (ftFontFile) - m_codeToGID = ftFontFile->getCodeToGID(); - - // create dummy font - // The font matrices are bogus, but we will never use the glyphs anyway. - // However we need to call m_fontEngine->getFont, in order to have the - // font in the Splash font cache. Otherwise we'd load it again and again. - m_fontEngine->getFont(fontFile, mat, matrix); - if (fontsrc && !fontsrc->isFile) - fontsrc->unref(); - return; - - err2: - delete id; -#endif + m_codeToGID = m_codeToGIDCache[id]; + } } static QPainterPath convertPath(GfxState *state, GfxPath *path, Qt::FillRule fillRule) diff --git a/qt5/src/ArthurOutputDev.h b/qt5/src/ArthurOutputDev.h index dae55637..396ce578 100644 --- a/qt5/src/ArthurOutputDev.h +++ b/qt5/src/ArthurOutputDev.h @@ -37,13 +37,14 @@ #include "OutputDev.h" #include "GfxState.h" +#include <ft2build.h> +#include FT_FREETYPE_H + #include <QtGui/QPainter> class GfxState; class PDFDoc; -class SplashFontEngine; - class QRawFont; class ArthurType3Font; @@ -204,7 +205,6 @@ private: std::stack<QBrush> m_currentBrushStack; bool m_needFontUpdate; // set when the font needs to be updated - SplashFontEngine *m_fontEngine; PDFDoc* m_doc; XRef *xref; // xref table for current document @@ -219,10 +219,15 @@ private: using ArthurFontID = std::pair<Ref,double>; std::map<ArthurFontID,std::unique_ptr<QRawFont> > m_rawFontCache; std::map<ArthurFontID,std::unique_ptr<ArthurType3Font> > m_type3FontCache; + std::map<Ref,const int*> m_codeToGIDCache; // The table that maps character codes to glyph indexes - int* m_codeToGID; - std::stack<int*> m_codeToGIDStack; + const int* m_codeToGID; + std::stack<const int*> m_codeToGIDStack; + + FT_Library m_ftLibrary; + // as of FT 2.1.8, CID fonts are indexed by CID instead of GID + bool m_useCIDs; }; #endif diff --git a/qt5/src/CMakeLists.txt b/qt5/src/CMakeLists.txt index 5269d620..4da5e57c 100644 --- a/qt5/src/CMakeLists.txt +++ b/qt5/src/CMakeLists.txt @@ -43,7 +43,7 @@ if(MINGW) get_target_property(POPPLER_QT5_SOVERSION poppler-qt5 SOVERSION) set_target_properties(poppler-qt5 PROPERTIES SUFFIX "-${POPPLER_QT5_SOVERSION}${CMAKE_SHARED_LIBRARY_SUFFIX}") endif() -target_link_libraries(poppler-qt5 poppler ${Qt5Core_LIBRARIES} ${Qt5Gui_LIBRARIES} ${Qt5Xml_LIBRARIES}) +target_link_libraries(poppler-qt5 poppler ${Qt5Core_LIBRARIES} ${Qt5Gui_LIBRARIES} ${Qt5Xml_LIBRARIES} ${FREETYPE_LIBRARIES}) if(MSVC) target_link_libraries(poppler-qt5 poppler ${poppler_LIBS}) endif() _______________________________________________ poppler mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/poppler
