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.
This commit is contained in:
Kovid Goyal 2015-07-03 15:18:03 +05:30
parent 589a9022f1
commit 003a7c0aa3
4 changed files with 43 additions and 64 deletions

View File

@ -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):

View File

@ -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<const quint32 *>("name");
QTextItemInt ti = static_cast<const QTextItemInt &>(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<QFixedPoint> positions;
QTransform m = QTransform::fromTranslate(p.x(), p.y());
fe->getGlyphPositions(ti.glyphs, m, ti.flags, glyphs, positions);
QVector<QPointF> points = QVector<QPointF>(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<quint32> indices = QVector<quint32>(glyphs.count());
for (int i = 0; i < glyphs.count(); i++)
indices[i] = (quint32)glyphs[i];
const quint32 *tag = reinterpret_cast<const quint32 *>("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<QPointF> &positions, const QVector<quint32> &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<const QTextItemInt &>(text_item);
const quint32 *tag = reinterpret_cast<const quint32 *>(tag_name);
return ti.fontEngine->getSfntTable(qToBigEndian(*tag));
const QByteArray table(ti.fontEngine->getSfntTable(qToBigEndian(*tag)));
return Py_BuildValue("s#", table.constData());
}
QVector<quint32>* get_glyph_map(const QTextItem &text_item) {
PyObject* get_glyph_map(const QTextItem &text_item) {
QTextItemInt ti = static_cast<const QTextItemInt &>(text_item);
QVector<quint32> *ans = new QVector<quint32>(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;
}

View File

@ -10,26 +10,11 @@
#include <QGlyphRun>
#include <QTextItem>
#include <QPointF>
#include <Python.h>
PyObject* get_glyphs(const QPointF &p, const QTextItem &text_item);
class GlyphInfo {
public:
QByteArray name;
QVector<QPointF> positions;
qreal size;
qreal stretch;
QVector<quint32> indices;
PyObject* get_sfnt_table(const QTextItem &text_item, const char* tag_name);
GlyphInfo(const QByteArray &name, qreal size, qreal stretch, const QVector<QPointF> &positions, const QVector<quint32> &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<quint32>* get_glyph_map(const QTextItem &text_item);
PyObject* get_glyph_map(const QTextItem &text_item);

View File

@ -5,25 +5,12 @@
%Import QtCore/QtCoremod.sip
%Import QtGui/QtGuimod.sip
class GlyphInfo {
%TypeHeaderCode
%ModuleCode
#include <qt_hack.h>
%End
public:
QByteArray name;
qreal size;
qreal stretch;
QVector<QPointF> &positions;
QVector<quint32> indices;
GlyphInfo(const QByteArray &name, qreal size, qreal stretch, const QVector<QPointF> &positions, const QVector<quint32> &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<quint32>* get_glyph_map(const QTextItem &text_item);
PyObject* get_glyph_map(const QTextItem &text_item);