[poppler] 3 commits - qt5/src splash/SplashFTFontFile.cc splash/SplashFTFontFile.h

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Fri Dec 21 19:55:37 UTC 2018


 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 <oliver.sander at tu-dresden.de>
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 <oliver.sander at tu-dresden.de>
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 <oliver.sander at tu-dresden.de>
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()


More information about the poppler mailing list