Commit 3c561104 authored by Oliver Sander's avatar Oliver Sander Committed by Albert Astals Cid
Browse files

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.
parent 7477b71e
......@@ -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)
......
......@@ -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
......@@ -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()
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment