From 003a7c0aa38524e51ebc9c14ea4a46e49d4b6bb8 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 3 Jul 2015 15:18:03 +0530 Subject: [PATCH] PDF Output: Fix crash when running with the latest release of PyQt/SIP. See #1471083 (Error in convert epub to pdf on archlinux) Apparently, direct attribute access of mapped C++ classes does not work anymore (regression in PyQt/SIP?). So we change the code to return Python objects directly. Makes it a bit longer, but also faster, since the conversion to python is now hand coded instead of relying on SIP. --- src/calibre/ebooks/pdf/render/engine.py | 15 +++---- src/calibre/ebooks/pdf/render/qt_hack.cpp | 48 ++++++++++++++--------- src/calibre/ebooks/pdf/render/qt_hack.h | 23 ++--------- src/calibre/ebooks/pdf/render/qt_hack.sip | 21 ++-------- 4 files changed, 43 insertions(+), 64 deletions(-) diff --git a/src/calibre/ebooks/pdf/render/engine.py b/src/calibre/ebooks/pdf/render/engine.py index 967c121656..c54b05707c 100644 --- a/src/calibre/ebooks/pdf/render/engine.py +++ b/src/calibre/ebooks/pdf/render/engine.py @@ -10,9 +10,8 @@ __docformat__ = 'restructuredtext en' import sys, traceback, math from collections import namedtuple from functools import wraps, partial -from future_builtins import map +from future_builtins import map, zip -import sip from PyQt5.Qt import (QPaintEngine, QPaintDevice, Qt, QTransform, QBrush) from calibre.constants import plugins @@ -24,6 +23,7 @@ from calibre.utils.fonts.sfnt.metrics import FontMetrics Point = namedtuple('Point', 'x y') ColorState = namedtuple('ColorState', 'color opacity do') +GlyphInfo = namedtuple('GlyphInfo', 'name size stretch positions indices') def repr_transform(t): vals = map(fmtnum, (t.m11(), t.m12(), t.m21(), t.m22(), t.dx(), t.dy())) @@ -242,11 +242,10 @@ class PdfEngine(QPaintEngine): def drawTextItem(self, point, text_item): # return super(PdfEngine, self).drawTextItem(point, text_item) self.apply_graphics_state() - gi = self.qt_hack.get_glyphs(point, text_item) + gi = GlyphInfo(*self.qt_hack.get_glyphs(point, text_item)) if not gi.indices: - sip.delete(gi) return - name = hash(bytes(gi.name)) + name = hash(gi.name) if name not in self.fonts: try: self.fonts[name] = self.create_sfnt(text_item) @@ -260,14 +259,12 @@ class PdfEngine(QPaintEngine): pass glyphs = [] last_x = last_y = 0 - for i, pos in enumerate(gi.positions): - x, y = pos.x(), pos.y() - glyphs.append((x-last_x, last_y - y, gi.indices[i])) + for glyph_index, (x, y) in zip(gi.indices, gi.positions): + glyphs.append((x-last_x, last_y - y, glyph_index)) last_x, last_y = x, y self.pdf.draw_glyph_run([gi.stretch, 0, 0, -1, 0, 0], gi.size, metrics, glyphs) - sip.delete(gi) @store_error def drawPolygon(self, points, mode): diff --git a/src/calibre/ebooks/pdf/render/qt_hack.cpp b/src/calibre/ebooks/pdf/render/qt_hack.cpp index 7ec7eb0877..4bb65421cf 100644 --- a/src/calibre/ebooks/pdf/render/qt_hack.cpp +++ b/src/calibre/ebooks/pdf/render/qt_hack.cpp @@ -12,7 +12,8 @@ #include "private/qtextengine_p.h" #include "private/qfontengine_p.h" -GlyphInfo* get_glyphs(QPointF &p, const QTextItem &text_item) { +PyObject* get_glyphs(const QPointF &p, const QTextItem &text_item) { + const quint32 *tag = reinterpret_cast("name"); QTextItemInt ti = static_cast(text_item); QFontEngine *fe = ti.fontEngine; qreal size = ti.fontEngine->fontDef.pixelSize; @@ -33,40 +34,49 @@ GlyphInfo* get_glyphs(QPointF &p, const QTextItem &text_item) { QVarLengthArray positions; QTransform m = QTransform::fromTranslate(p.x(), p.y()); fe->getGlyphPositions(ti.glyphs, m, ti.flags, glyphs, positions); - QVector points = QVector(positions.count()); + + PyObject *points = NULL, *indices = NULL, *temp = NULL; + + points = PyTuple_New(positions.count()); + if (points == NULL) return PyErr_NoMemory(); for (int i = 0; i < positions.count(); i++) { - points[i].setX(positions[i].x.toReal()/stretch); - points[i].setY(positions[i].y.toReal()); + temp = Py_BuildValue("dd", positions[i].x.toReal()/stretch, positions[i].y.toReal()); + if (temp == NULL) { Py_DECREF(points); return NULL; } + PyTuple_SET_ITEM(points, i, temp); temp = NULL; } - QVector indices = QVector(glyphs.count()); - for (int i = 0; i < glyphs.count(); i++) - indices[i] = (quint32)glyphs[i]; - - const quint32 *tag = reinterpret_cast("name"); - - return new GlyphInfo(fe->getSfntTable(qToBigEndian(*tag)), size, stretch, points, indices); + indices = PyTuple_New(glyphs.count()); + if (indices == NULL) { Py_DECREF(points); return PyErr_NoMemory(); } + for (int i = 0; i < glyphs.count(); i++) { + temp = PyInt_FromLong((long)glyphs[i]); + if (temp == NULL) { Py_DECREF(indices); Py_DECREF(points); return PyErr_NoMemory(); } + PyTuple_SET_ITEM(indices, i, temp); temp = NULL; + } + const QByteArray table(fe->getSfntTable(qToBigEndian(*tag))); + return Py_BuildValue("s#ffOO", table.constData(), table.size(), size, stretch, points, indices); } -GlyphInfo::GlyphInfo(const QByteArray& name, qreal size, qreal stretch, const QVector &positions, const QVector &indices) :name(name), positions(positions), size(size), stretch(stretch), indices(indices) { -} - -QByteArray get_sfnt_table(const QTextItem &text_item, const char* tag_name) { +PyObject* get_sfnt_table(const QTextItem &text_item, const char* tag_name) { QTextItemInt ti = static_cast(text_item); const quint32 *tag = reinterpret_cast(tag_name); - return ti.fontEngine->getSfntTable(qToBigEndian(*tag)); + const QByteArray table(ti.fontEngine->getSfntTable(qToBigEndian(*tag))); + return Py_BuildValue("s#", table.constData()); } -QVector* get_glyph_map(const QTextItem &text_item) { +PyObject* get_glyph_map(const QTextItem &text_item) { QTextItemInt ti = static_cast(text_item); - QVector *ans = new QVector(0x10000); QGlyphLayoutArray<10> glyphs; int nglyphs = 10; + PyObject *t = NULL, *ans = PyTuple_New(0x10000); + + if (ans == NULL) return PyErr_NoMemory(); for (uint uc = 0; uc < 0x10000; ++uc) { QChar ch(uc); ti.fontEngine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly); - (*ans)[uc] = glyphs.glyphs[0]; + t = PyInt_FromLong(glyphs.glyphs[0]); + if (t == NULL) { Py_DECREF(ans); return PyErr_NoMemory(); } + PyTuple_SET_ITEM(ans, uc, t); t = NULL; } return ans; } diff --git a/src/calibre/ebooks/pdf/render/qt_hack.h b/src/calibre/ebooks/pdf/render/qt_hack.h index b2cc64e7b6..43a638bfba 100644 --- a/src/calibre/ebooks/pdf/render/qt_hack.h +++ b/src/calibre/ebooks/pdf/render/qt_hack.h @@ -10,26 +10,11 @@ #include #include #include +#include +PyObject* get_glyphs(const QPointF &p, const QTextItem &text_item); -class GlyphInfo { - public: - QByteArray name; - QVector positions; - qreal size; - qreal stretch; - QVector indices; +PyObject* get_sfnt_table(const QTextItem &text_item, const char* tag_name); - GlyphInfo(const QByteArray &name, qreal size, qreal stretch, const QVector &positions, const QVector &indices); - - private: - GlyphInfo(const GlyphInfo&); - GlyphInfo &operator=(const GlyphInfo&); -}; - -GlyphInfo* get_glyphs(QPointF &p, const QTextItem &text_item); - -QByteArray get_sfnt_table(const QTextItem &text_item, const char* tag_name); - -QVector* get_glyph_map(const QTextItem &text_item); +PyObject* get_glyph_map(const QTextItem &text_item); diff --git a/src/calibre/ebooks/pdf/render/qt_hack.sip b/src/calibre/ebooks/pdf/render/qt_hack.sip index b3815ef50e..9ea15cd191 100644 --- a/src/calibre/ebooks/pdf/render/qt_hack.sip +++ b/src/calibre/ebooks/pdf/render/qt_hack.sip @@ -5,25 +5,12 @@ %Import QtCore/QtCoremod.sip %Import QtGui/QtGuimod.sip - -class GlyphInfo { -%TypeHeaderCode +%ModuleCode #include %End -public: - QByteArray name; - qreal size; - qreal stretch; - QVector &positions; - QVector indices; - GlyphInfo(const QByteArray &name, qreal size, qreal stretch, const QVector &positions, const QVector &indices); -private: - GlyphInfo(const GlyphInfo& g); -}; +PyObject* get_glyphs(const QPointF &p, const QTextItem &text_item); -GlyphInfo* get_glyphs(QPointF &p, const QTextItem &text_item); +PyObject* get_sfnt_table(const QTextItem &text_item, const char* tag_name); -QByteArray get_sfnt_table(const QTextItem &text_item, const char* tag_name); - -QVector* get_glyph_map(const QTextItem &text_item); +PyObject* get_glyph_map(const QTextItem &text_item);