[poppler] qt6/src

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Fri Dec 18 12:50:06 UTC 2020


 qt6/src/poppler-annotation-private.h      |    4 
 qt6/src/poppler-annotation-private.h.orig |  115 ---------------
 qt6/src/poppler-annotation.cc             |   18 +-
 qt6/src/poppler-annotation.h              |    2 
 qt6/src/poppler-document.cc               |    2 
 qt6/src/poppler-form.cc                   |  119 +++++++++++++++-
 qt6/src/poppler-form.h                    |   55 +++++++
 qt6/src/poppler-pdf-converter.cc          |  220 +++++++++++++++++++++++++++++-
 qt6/src/poppler-qt6.h                     |   83 +++++++++++
 9 files changed, 489 insertions(+), 129 deletions(-)

New commits:
commit fbc4d13d075ff30d6fccb5b81d8f3b8b19d673cb
Author: Albert Astals Cid <aacid at kde.org>
Date:   Fri Dec 18 13:40:49 2020 +0100

    qt6: Port the signing code from qt5

diff --git a/qt6/src/poppler-annotation-private.h b/qt6/src/poppler-annotation-private.h
index 288ab6f1..1e8b6d32 100644
--- a/qt6/src/poppler-annotation-private.h
+++ b/qt6/src/poppler-annotation-private.h
@@ -3,6 +3,7 @@
  * Copyright (C) 2012, Tobias Koenig <tokoe at kdab.com>
  * Copyright (C) 2012, 2013 Fabio D'Urso <fabiodurso at hotmail.it>
  * Copyright (C) 2012, 2014, 2018-2020, Albert Astals Cid <aacid at kde.org>
+ * Copyright (C) 2020, Klarälvdalens Datakonsult AB, a KDAB Group company, <info at kdab.com>. Work sponsored by Technische Universität Dresden
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -37,6 +38,8 @@ class PDFRectangle;
 namespace Poppler {
 class DocumentData;
 
+PDFRectangle boundaryToPdfRectangle(::Page *pdfPage, const QRectF &r, int flags);
+
 class AnnotationPrivate : public QSharedData
 {
 public:
@@ -87,7 +90,6 @@ public:
 
     /* The following helpers only work if pdfPage is set */
     void flushBaseAnnotationProperties();
-    void fillNormalizationMTX(double MTX[6], int pageRotation) const;
     void fillTransformationMTX(double MTX[6]) const;
     QRectF fromPdfRectangle(const PDFRectangle &r) const;
     PDFRectangle boundaryToPdfRectangle(const QRectF &r, int flags) const;
diff --git a/qt6/src/poppler-annotation-private.h.orig b/qt6/src/poppler-annotation-private.h.orig
deleted file mode 100644
index 937edad4..00000000
--- a/qt6/src/poppler-annotation-private.h.orig
+++ /dev/null
@@ -1,115 +0,0 @@
-/* poppler-annotation-private.h: qt interface to poppler
- * Copyright (C) 2007, Pino Toscano <pino at kde.org>
- * Copyright (C) 2012, Tobias Koenig <tokoe at kdab.com>
- * Copyright (C) 2012, 2013 Fabio D'Urso <fabiodurso at hotmail.it>
- * Copyright (C) 2012, 2014, 2018, Albert Astals Cid <aacid at kde.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#ifndef _POPPLER_ANNOTATION_PRIVATE_H_
-#define _POPPLER_ANNOTATION_PRIVATE_H_
-
-#include <QtCore/QLinkedList>
-#include <QtCore/QPointF>
-#include <QtCore/QSharedDataPointer>
-
-#include "poppler-annotation.h"
-
-#include <Object.h>
-
-class Annot;
-class AnnotPath;
-class Link;
-class Page;
-class PDFRectangle;
-
-namespace Poppler
-{
-class DocumentData;
-
-class AnnotationPrivate : public QSharedData
-{
-    public:
-        AnnotationPrivate();
-        virtual ~AnnotationPrivate();
-
-        AnnotationPrivate(const AnnotationPrivate &) = delete;
-        AnnotationPrivate& operator=(const AnnotationPrivate &) = delete;
-
-        void addRevision(Annotation *ann, Annotation::RevScope scope, Annotation::RevType type);
-
-        /* Returns an Annotation of the right subclass whose d_ptr points to
-         * this AnnotationPrivate */
-        virtual Annotation * makeAlias() = 0;
-
-        /* properties: contents related */
-        QString author;
-        QString contents;
-        QString uniqueName;
-        QDateTime modDate;       // before or equal to currentDateTime()
-        QDateTime creationDate;  // before or equal to modifyDate
-
-        /* properties: look/interaction related */
-        int flags;
-        QRectF boundary;
-
-        /* style and popup */
-        Annotation::Style style;
-        Annotation::Popup popup;
-
-        /* revisions */
-        Annotation::RevScope revisionScope;
-        Annotation::RevType revisionType;
-        QList<Annotation*> revisions;
-
-        /* After this call, the Annotation object will behave like a wrapper for
-         * the specified Annot object. All cached values are discarded */
-        void tieToNativeAnnot(Annot *ann, ::Page *page, DocumentData *doc);
-
-        /* Creates a new Annot object on the specified page, flushes current
-         * values to that object and ties this Annotation to that object */
-        virtual Annot* createNativeAnnot(::Page *destPage, DocumentData *doc) = 0;
-
-        /* Inited to 0 (i.e. untied annotation) */
-        Annot *pdfAnnot;
-        ::Page *pdfPage;
-        DocumentData * parentDoc;
-
-        /* The following helpers only work if pdfPage is set */
-        void flushBaseAnnotationProperties();
-        void fillNormalizationMTX(double MTX[6], int pageRotation) const;
-        void fillTransformationMTX(double MTX[6]) const;
-        QRectF fromPdfRectangle(const PDFRectangle &r) const;
-        PDFRectangle boundaryToPdfRectangle(const QRectF &r, int flags) const;
-        AnnotPath * toAnnotPath(const QLinkedList<QPointF> &l) const;
-
-        /* Scan page for annotations, parentId=0 searches for root annotations, subtypes empty means all subtypes */
-        static QList<Annotation*> findAnnotations(::Page *pdfPage, DocumentData *doc, const QSet<Annotation::SubType> &subtypes, int parentId = -1);
-
-        /* Add given annotation to given page */
-        static void addAnnotationToPage(::Page *pdfPage, DocumentData *doc, const Annotation * ann);
-
-        /* Remove annotation from page and destroy ann */
-        static void removeAnnotationFromPage(::Page *pdfPage, const Annotation * ann);
-
-        Ref pdfObjectReference() const;
-
-        Link* additionalAction( Annotation::AdditionalActionType type ) const;
-};
-
-}
-
-#endif
diff --git a/qt6/src/poppler-annotation.cc b/qt6/src/poppler-annotation.cc
index 9724e2df..609130b6 100644
--- a/qt6/src/poppler-annotation.cc
+++ b/qt6/src/poppler-annotation.cc
@@ -11,6 +11,9 @@
  * Copyright (C) 2018, 2019 Tobias Deiminger <haxtibal at posteo.de>
  * Copyright (C) 2018 Carlos Garcia Campos <carlosgc at gnome.org>
  * Copyright (C) 2020 Oliver Sander <oliver.sander at tu-dresden.de>
+ * Copyright (C) 2020 Katarina Behrens <Katarina.Behrens at cib.de>
+ * Copyright (C) 2020 Thorsten Behrens <Thorsten.Behrens at CIB.de>
+ * Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, <info at kdab.com>. Work sponsored by Technische Universität Dresden
  * Adapting code from
  *   Copyright (C) 2004 by Enrico Ros <eros.kde at email.it>
  *
@@ -133,7 +136,7 @@ void AnnotationPrivate::flushBaseAnnotationProperties()
 
 // Returns matrix to convert from user space coords (oriented according to the
 // specified rotation) to normalized coords
-void AnnotationPrivate::fillNormalizationMTX(double MTX[6], int pageRotation) const
+void fillNormalizationMTX(::Page *pdfPage, double MTX[6], int pageRotation)
 {
     Q_ASSERT(pdfPage);
 
@@ -171,7 +174,7 @@ void AnnotationPrivate::fillTransformationMTX(double MTX[6]) const
 
     if (pageRotate == 0 || (pdfAnnot->getFlags() & Annot::flagNoRotate) == 0) {
         // Use the normalization matrix for this page's rotation
-        fillNormalizationMTX(MTX, pageRotate);
+        fillNormalizationMTX(pdfPage, MTX, pageRotate);
     } else {
         // Clients expect coordinates relative to this page's rotation, but
         // FixedRotation annotations internally use unrotated coordinates:
@@ -179,7 +182,7 @@ void AnnotationPrivate::fillTransformationMTX(double MTX[6]) const
         // top-left corner as rotation pivot
 
         double MTXnorm[6];
-        fillNormalizationMTX(MTXnorm, pageRotate);
+        fillNormalizationMTX(pdfPage, MTXnorm, pageRotate);
 
         QTransform transform(MTXnorm[0], MTXnorm[1], MTXnorm[2], MTXnorm[3], MTXnorm[4], MTXnorm[5]);
         transform.translate(+pdfAnnot->getXMin(), +pdfAnnot->getYMax());
@@ -230,14 +233,14 @@ QRectF AnnotationPrivate::fromPdfRectangle(const PDFRectangle &r) const
 // the transformation produced by fillTransformationMTX, but we can't use
 // fillTransformationMTX here because it relies on the native annotation
 // object's boundary rect to be already set up.
-PDFRectangle AnnotationPrivate::boundaryToPdfRectangle(const QRectF &r, int rFlags) const
+PDFRectangle boundaryToPdfRectangle(::Page *pdfPage, const QRectF &r, int rFlags)
 {
     Q_ASSERT(pdfPage);
 
     const int pageRotate = pdfPage->getRotate();
 
     double MTX[6];
-    fillNormalizationMTX(MTX, pageRotate);
+    fillNormalizationMTX(pdfPage, MTX, pageRotate);
 
     double tl_x, tl_y, br_x, br_y, swp;
     XPDFReader::invTransform(MTX, r.topLeft(), tl_x, tl_y);
@@ -269,6 +272,11 @@ PDFRectangle AnnotationPrivate::boundaryToPdfRectangle(const QRectF &r, int rFla
         return PDFRectangle(br_x, br_y - width, br_x + height, br_y);
 }
 
+PDFRectangle AnnotationPrivate::boundaryToPdfRectangle(const QRectF &r, int rFlags) const
+{
+    return Poppler::boundaryToPdfRectangle(pdfPage, r, rFlags);
+}
+
 AnnotPath *AnnotationPrivate::toAnnotPath(const QVector<QPointF> &list) const
 {
     const int count = list.size();
diff --git a/qt6/src/poppler-annotation.h b/qt6/src/poppler-annotation.h
index 6fad7e3e..857b0f19 100644
--- a/qt6/src/poppler-annotation.h
+++ b/qt6/src/poppler-annotation.h
@@ -8,6 +8,8 @@
  * Copyright (C) 2012, 2013 Fabio D'Urso <fabiodurso at hotmail.it>
  * Copyright (C) 2013, Anthony Granger <grangeranthony at gmail.com>
  * Copyright (C) 2018, Dileep Sankhla <sankhla.dileep96 at gmail.com>
+ * Copyright (C) 2020, Katarina Behrens <Katarina.Behrens at cib.de>
+ * Copyright (C) 2020, Klarälvdalens Datakonsult AB, a KDAB Group company, <info at kdab.com>. Work sponsored by Technische Universität Dresden
  * Adapting code from
  *   Copyright (C) 2004 by Enrico Ros <eros.kde at email.it>
  *
diff --git a/qt6/src/poppler-document.cc b/qt6/src/poppler-document.cc
index 65077e6f..9b5edc62 100644
--- a/qt6/src/poppler-document.cc
+++ b/qt6/src/poppler-document.cc
@@ -16,6 +16,8 @@
  * Copyright (C) 2019, 2020 Oliver Sander <oliver.sander at tu-dresden.de>
  * Copyright (C) 2019 Alexander Volkov <a.volkov at rusbitech.ru>
  * Copyright (C) 2020 Philipp Knechtges <philipp-dev at knechtges.com>
+ * Copyright (C) 2020 Katarina Behrens <Katarina.Behrens at cib.de>
+ * Copyright (C) 2020 Thorsten Behrens <Thorsten.Behrens at CIB.de>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
diff --git a/qt6/src/poppler-form.cc b/qt6/src/poppler-form.cc
index de0b540c..f70cea84 100644
--- a/qt6/src/poppler-form.cc
+++ b/qt6/src/poppler-form.cc
@@ -11,6 +11,8 @@
  * Copyright (C) 2018, 2020 Oliver Sander <oliver.sander at tu-dresden.de>
  * Copyright (C) 2019 João Netto <joaonetto901 at gmail.com>
  * Copyright (C) 2020 David García Garzón <voki at canvoki.net>
+ * Copyright (C) 2020 Thorsten Behrens <Thorsten.Behrens at CIB.de>
+ * Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, <info at kdab.com>. Work sponsored by Technische Universität Dresden
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -29,13 +31,19 @@
 
 #include "poppler-qt6.h"
 
+#include <config.h>
+
 #include <QtCore/QSizeF>
+#include <QUrl>
 
 #include <Form.h>
 #include <Object.h>
 #include <Link.h>
 #include <SignatureInfo.h>
 #include <CertificateInfo.h>
+#ifdef ENABLE_NSS3
+#    include <SignatureHandler.h>
+#endif
 
 #include "poppler-form.h"
 #include "poppler-page-private.h"
@@ -571,6 +579,7 @@ public:
 
     EntityInfo issuer_info;
     EntityInfo subject_info;
+    QString nick_name;
     QByteArray certificate_der;
     QByteArray serial_number;
     QByteArray public_key;
@@ -584,6 +593,11 @@ public:
     bool is_null;
 };
 
+CertificateInfo::CertificateInfo() : d_ptr(new CertificateInfoPrivate())
+{
+    d_ptr->is_null = true;
+}
+
 CertificateInfo::CertificateInfo(CertificateInfoPrivate *priv) : d_ptr(priv) { }
 
 CertificateInfo::CertificateInfo(const CertificateInfo &other) : d_ptr(other.d_ptr) { }
@@ -650,6 +664,12 @@ QString CertificateInfo::subjectInfo(EntityInfoKey key) const
     }
 }
 
+QString CertificateInfo::nickName() const
+{
+    Q_D(const CertificateInfo);
+    return d->nick_name;
+}
+
 QDateTime CertificateInfo::validityStart() const
 {
     Q_D(const CertificateInfo);
@@ -726,6 +746,21 @@ QByteArray CertificateInfo::certificateData() const
     return d->certificate_der;
 }
 
+bool CertificateInfo::checkPassword(const QString &password) const
+{
+#ifdef ENABLE_NSS3
+    Q_D(const CertificateInfo);
+    SignatureHandler sigHandler(d->nick_name.toUtf8().constData(), SEC_OID_SHA256);
+    unsigned char buffer[5];
+    memcpy(buffer, "test", 5);
+    sigHandler.updateHash(buffer, 5);
+    std::unique_ptr<GooString> tmpSignature = sigHandler.signDetached(password.toUtf8().constData());
+    return tmpSignature.get() != nullptr;
+#else
+    return false;
+#endif
+}
+
 class SignatureValidationInfoPrivate
 {
 public:
@@ -897,14 +932,8 @@ SignatureValidationInfo FormFieldSignature::validate(ValidateOptions opt) const
     return validate(opt, QDateTime());
 }
 
-SignatureValidationInfo FormFieldSignature::validate(int opt, const QDateTime &validationTime) const
+static CertificateInfoPrivate *createCertificateInfoPrivate(const X509CertificateInfo *ci)
 {
-    FormWidgetSignature *fws = static_cast<FormWidgetSignature *>(m_formData->fm);
-    const time_t validationTimeT = validationTime.isValid() ? validationTime.toSecsSinceEpoch() : -1;
-    SignatureInfo *si = fws->validateSignature(opt & ValidateVerifyCertificate, opt & ValidateForceRevalidation, validationTimeT);
-
-    // get certificate info
-    const X509CertificateInfo *ci = si->getCertificateInfo();
     CertificateInfoPrivate *certPriv = new CertificateInfoPrivate;
     certPriv->is_null = true;
     if (ci) {
@@ -926,6 +955,8 @@ SignatureValidationInfo FormFieldSignature::validate(int opt, const QDateTime &v
         certPriv->subject_info.email_address = subjectInfo.email.c_str();
         certPriv->subject_info.org_name = subjectInfo.organization.c_str();
 
+        certPriv->nick_name = ci->getNickName().c_str();
+
         X509CertificateInfo::Validity certValidity = ci->getValidity();
         certPriv->validity_start = QDateTime::fromSecsSinceEpoch(certValidity.notBefore, Qt::UTC);
         certPriv->validity_end = QDateTime::fromSecsSinceEpoch(certValidity.notAfter, Qt::UTC);
@@ -941,6 +972,19 @@ SignatureValidationInfo FormFieldSignature::validate(int opt, const QDateTime &v
         certPriv->is_null = false;
     }
 
+    return certPriv;
+}
+
+SignatureValidationInfo FormFieldSignature::validate(int opt, const QDateTime &validationTime) const
+{
+    FormWidgetSignature *fws = static_cast<FormWidgetSignature *>(m_formData->fm);
+    const time_t validationTimeT = validationTime.isValid() ? validationTime.toSecsSinceEpoch() : -1;
+    SignatureInfo *si = fws->validateSignature(opt & ValidateVerifyCertificate, opt & ValidateForceRevalidation, validationTimeT);
+
+    // get certificate info
+    const X509CertificateInfo *ci = si->getCertificateInfo();
+    CertificateInfoPrivate *certPriv = createCertificateInfoPrivate(ci);
+
     SignatureValidationInfoPrivate *priv = new SignatureValidationInfoPrivate(CertificateInfo(certPriv));
     switch (si->getSignatureValStatus()) {
     case SIGNATURE_VALID:
@@ -1012,4 +1056,65 @@ SignatureValidationInfo FormFieldSignature::validate(int opt, const QDateTime &v
     return SignatureValidationInfo(priv);
 }
 
+bool hasNSSSupport()
+{
+#ifdef ENABLE_NSS3
+    return true;
+#else
+    return false;
+#endif
+}
+
+QVector<CertificateInfo> getAvailableSigningCertificates()
+{
+    QVector<CertificateInfo> vReturnCerts;
+
+#ifdef ENABLE_NSS3
+    std::vector<std::unique_ptr<X509CertificateInfo>> vCerts = SignatureHandler::getAvailableSigningCertificates();
+
+    for (auto &cert : vCerts) {
+        CertificateInfoPrivate *certPriv = createCertificateInfoPrivate(cert.get());
+        vReturnCerts.append(CertificateInfo(certPriv));
+    }
+#endif
+
+    return vReturnCerts;
+}
+
+QString POPPLER_QT6_EXPORT getNSSDir()
+{
+#ifdef ENABLE_NSS3
+    return QString::fromLocal8Bit(SignatureHandler::getNSSDir().c_str());
+#else
+    return QString();
+#endif
+}
+
+void setNSSDir(const QString &path)
+{
+#ifdef ENABLE_NSS3
+    if (path.isEmpty())
+        return;
+
+    GooString *goo = QStringToGooString(path);
+    SignatureHandler::setNSSDir(*goo);
+    delete goo;
+#else
+    (void)path;
+#endif
+}
+
+namespace {
+std::function<QString(const QString &)> nssPasswordCall;
+}
+
+void setNSSPasswordCallback(const std::function<char *(const char *)> &f)
+{
+#ifdef ENABLE_NSS3
+    SignatureHandler::setNSSPasswordCallback(f);
+#else
+    qWarning() << "setNSSPasswordCallback called but this poppler is built without NSS support";
+    (void)f;
+#endif
+}
 }
diff --git a/qt6/src/poppler-form.h b/qt6/src/poppler-form.h
index cfb72d9b..dfc8142a 100644
--- a/qt6/src/poppler-form.h
+++ b/qt6/src/poppler-form.h
@@ -9,6 +9,9 @@
  * Copyright (C) 2018, Chinmoy Ranjan Pradhan <chinmoyrp65 at protonmail.com>
  * Copyright (C) 2018, Oliver Sander <oliver.sander at tu-dresden.de>
  * Copyright (C) 2019 João Netto <joaonetto901 at gmail.com>
+ * Copyright (C) 2019, Adrian Johnson <ajohnson at redneon.com>
+ * Copyright (C) 2020, Thorsten Behrens <Thorsten.Behrens at CIB.de>
+ * Copyright (C) 2020, Klarälvdalens Datakonsult AB, a KDAB Group company, <info at kdab.com>. Work sponsored by Technische Universität Dresden
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -28,9 +31,11 @@
 #ifndef _POPPLER_QT6_FORM_H_
 #define _POPPLER_QT6_FORM_H_
 
+#include <functional>
 #include <memory>
 #include <ctime>
 #include <QtCore/QDateTime>
+#include <QtCore/QVector>
 #include <QtCore/QList>
 #include <QtCore/QRectF>
 #include <QtCore/QStringList>
@@ -38,6 +43,7 @@
 #include "poppler-export.h"
 #include "poppler-annotation.h"
 
+class Object;
 class Page;
 class FormWidget;
 class FormWidgetButton;
@@ -491,6 +497,7 @@ public:
         Organization,
     };
 
+    CertificateInfo();
     CertificateInfo(CertificateInfoPrivate *priv);
     ~CertificateInfo();
 
@@ -519,6 +526,13 @@ public:
      */
     QString subjectInfo(EntityInfoKey key) const;
 
+    /**
+      The certificate internal database nickname
+
+      \since 20.12
+     */
+    QString nickName() const;
+
     /**
       The date-time when certificate becomes valid.
      */
@@ -559,6 +573,13 @@ public:
      */
     QByteArray certificateData() const;
 
+    /**
+      Checks if the given password is the correct one for this certificate
+
+      \since 20.12
+     */
+    bool checkPassword(const QString &password) const;
+
     CertificateInfo(const CertificateInfo &other);
     CertificateInfo &operator=(const CertificateInfo &other);
 
@@ -750,6 +771,40 @@ private:
     Q_DISABLE_COPY(FormFieldSignature)
 };
 
+/**
+  Returns is poppler was compiled with NSS support
+
+  \since 20.12
+*/
+bool POPPLER_QT6_EXPORT hasNSSSupport();
+
+/**
+  Return vector of suitable signing certificates
+
+  \since 20.12
+*/
+QVector<CertificateInfo> POPPLER_QT6_EXPORT getAvailableSigningCertificates();
+
+/**
+  Gets the current NSS CertDB directory
+
+  \since 20.12
+*/
+QString POPPLER_QT6_EXPORT getNSSDir();
+
+/**
+  Set a custom NSS CertDB directory. Needs to be called before doing any other signature operation
+
+  \since 20.12
+*/
+void POPPLER_QT6_EXPORT setNSSDir(const QString &pathURL);
+
+/**
+  Sets the callback for NSS password requests
+
+  \since 20.12
+*/
+void POPPLER_QT6_EXPORT setNSSPasswordCallback(const std::function<char *(const char *)> &f);
 }
 
 #endif
diff --git a/qt6/src/poppler-pdf-converter.cc b/qt6/src/poppler-pdf-converter.cc
index fe6ac4e2..91705f6e 100644
--- a/qt6/src/poppler-pdf-converter.cc
+++ b/qt6/src/poppler-pdf-converter.cc
@@ -1,6 +1,8 @@
 /* poppler-pdf-converter.cc: qt interface to poppler
  * Copyright (C) 2008, Pino Toscano <pino at kde.org>
  * Copyright (C) 2008, 2009, 2020, Albert Astals Cid <aacid at kde.org>
+ * Copyright (C) 2020, Thorsten Behrens <Thorsten.Behrens at CIB.de>
+ * Copyright (C) 2020, Klarälvdalens Datakonsult AB, a KDAB Group company, <info at kdab.com>. Work sponsored by Technische Universität Dresden
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -19,12 +21,17 @@
 
 #include "poppler-qt6.h"
 
+#include "poppler-annotation-helper.h"
+#include "poppler-annotation-private.h"
 #include "poppler-private.h"
 #include "poppler-converter-private.h"
 #include "poppler-qiodeviceoutstream-private.h"
 
-#include <QtCore/QFile>
+#include <QFile>
+#include <QUuid>
 
+#include "Array.h"
+#include "Form.h"
 #include <ErrorCodes.h>
 
 namespace Poppler {
@@ -103,4 +110,215 @@ bool PDFConverter::convert()
     return (errorCode == errNone);
 }
 
+bool PDFConverter::sign(const NewSignatureData &data)
+{
+    Q_D(PDFConverter);
+    d->lastError = NoError;
+
+    if (d->document->locked) {
+        d->lastError = FileLockedError;
+        return false;
+    }
+
+    if (data.signatureText().isEmpty()) {
+        qWarning() << "No signature text given";
+        return false;
+    }
+
+    ::PDFDoc *doc = d->document->doc;
+    ::Page *destPage = doc->getPage(data.page() + 1);
+
+    const DefaultAppearance da { { objName, "SigFont" }, data.fontSize(), std::unique_ptr<AnnotColor> { convertQColor(data.fontColor()) } };
+    const PDFRectangle rect = boundaryToPdfRectangle(destPage, data.boundingRectangle(), 0 /* no flags */);
+
+    Object annotObj = Object(new Dict(doc->getXRef()));
+    annotObj.dictSet("Type", Object(objName, "Annot"));
+    annotObj.dictSet("Subtype", Object(objName, "Widget"));
+    annotObj.dictSet("FT", Object(objName, "Sig"));
+    annotObj.dictSet("T", Object(QStringToGooString(data.fieldPartialName())));
+    Array *rectArray = new Array(doc->getXRef());
+    rectArray->add(Object(rect.x1));
+    rectArray->add(Object(rect.y1));
+    rectArray->add(Object(rect.x2));
+    rectArray->add(Object(rect.y2));
+    annotObj.dictSet("Rect", Object(rectArray));
+
+    GooString *daStr = da.toAppearanceString();
+    annotObj.dictSet("DA", Object(daStr));
+
+    const Ref ref = doc->getXRef()->addIndirectObject(&annotObj);
+    Catalog *catalog = doc->getCatalog();
+    catalog->addFormToAcroForm(ref);
+
+    std::unique_ptr<::FormFieldSignature> field = std::make_unique<::FormFieldSignature>(doc, Object(annotObj.getDict()), ref, nullptr, nullptr);
+
+    std::unique_ptr<GooString> gSignatureText = std::unique_ptr<GooString>(QStringToUnicodeGooString(data.signatureText()));
+    field->setCustomAppearanceContent(*gSignatureText);
+
+    Object refObj(ref);
+    AnnotWidget *signatureAnnot = new AnnotWidget(doc, &annotObj, &refObj, field.get());
+    signatureAnnot->setFlags(signatureAnnot->getFlags() | Annot::flagPrint | Annot::flagLocked);
+    Dict dummy(doc->getXRef());
+    auto appearCharacs = std::make_unique<AnnotAppearanceCharacs>(&dummy);
+    appearCharacs->setBorderColor(std::unique_ptr<AnnotColor> { convertQColor(data.borderColor()) });
+    appearCharacs->setBackColor(std::unique_ptr<AnnotColor> { convertQColor(data.backgroundColor()) });
+    signatureAnnot->setAppearCharacs(std::move(appearCharacs));
+
+    bool dummyAddDingbatsResource = false; // This is only update so if we didn't need to add
+                                           // the dingbats resource we should not need it now
+    signatureAnnot->generateFieldAppearance(&dummyAddDingbatsResource);
+    signatureAnnot->updateAppearanceStream();
+
+    FormWidget *formWidget = field->getWidget(field->getNumWidgets() - 1);
+    formWidget->setWidgetAnnotation(signatureAnnot);
+
+    destPage->addAnnot(signatureAnnot);
+
+    std::unique_ptr<AnnotBorder> border(new AnnotBorderArray());
+    border->setWidth(1.5);
+    signatureAnnot->setBorder(std::move(border));
+
+    FormWidgetSignature *fws = dynamic_cast<FormWidgetSignature *>(formWidget);
+    if (fws) {
+        const bool res = fws->signDocument(d->outputFileName.toUtf8().constData(), data.certNickname().toUtf8().constData(), "SHA256", data.password().toUtf8().constData());
+
+        // Now remove the signature stuff in case the user wants to continue editing stuff
+        // So the document object is clean
+        const Object &vRefObj = annotObj.dictLookupNF("V");
+        if (vRefObj.isRef()) {
+            doc->getXRef()->removeIndirectObject(vRefObj.getRef());
+        }
+        destPage->removeAnnot(signatureAnnot);
+        catalog->removeFormFromAcroForm(ref);
+        doc->getXRef()->removeIndirectObject(ref);
+
+        return res;
+    }
+
+    return false;
+}
+
+struct PDFConverter::NewSignatureData::NewSignatureDataPrivate
+{
+    NewSignatureDataPrivate() = default;
+
+    QString certNickname;
+    QString password;
+    int page;
+    QRectF boundingRectangle;
+    QString signatureText;
+    double fontSize = 10.0;
+    QColor fontColor = Qt::red;
+    QColor borderColor = Qt::red;
+    QColor backgroundColor = QColor(240, 240, 240);
+
+    QString partialName = QUuid::createUuid().toString();
+};
+
+PDFConverter::NewSignatureData::NewSignatureData() : d(new NewSignatureDataPrivate()) { }
+
+PDFConverter::NewSignatureData::~NewSignatureData()
+{
+    delete d;
+}
+
+QString PDFConverter::NewSignatureData::certNickname() const
+{
+    return d->certNickname;
+}
+
+void PDFConverter::NewSignatureData::setCertNickname(const QString &certNickname)
+{
+    d->certNickname = certNickname;
+}
+
+QString PDFConverter::NewSignatureData::password() const
+{
+    return d->password;
+}
+
+void PDFConverter::NewSignatureData::setPassword(const QString &password)
+{
+    d->password = password;
+}
+
+int PDFConverter::NewSignatureData::page() const
+{
+    return d->page;
+}
+
+void PDFConverter::NewSignatureData::setPage(int page)
+{
+    d->page = page;
+}
+
+QRectF PDFConverter::NewSignatureData::boundingRectangle() const
+{
+    return d->boundingRectangle;
+}
+
+void PDFConverter::NewSignatureData::setBoundingRectangle(const QRectF &rect)
+{
+    d->boundingRectangle = rect;
+}
+
+QString PDFConverter::NewSignatureData::signatureText() const
+{
+    return d->signatureText;
+}
+
+void PDFConverter::NewSignatureData::setSignatureText(const QString &text)
+{
+    d->signatureText = text;
+}
+
+double PDFConverter::NewSignatureData::fontSize() const
+{
+    return d->fontSize;
+}
+
+void PDFConverter::NewSignatureData::setFontSize(double fontSize)
+{
+    d->fontSize = fontSize;
+}
+
+QColor PDFConverter::NewSignatureData::fontColor() const
+{
+    return d->fontColor;
+}
+
+void PDFConverter::NewSignatureData::setFontColor(const QColor &color)
+{
+    d->fontColor = color;
+}
+
+QColor PDFConverter::NewSignatureData::borderColor() const
+{
+    return d->borderColor;
+}
+
+void PDFConverter::NewSignatureData::setBorderColor(const QColor &color)
+{
+    d->borderColor = color;
+}
+
+QColor PDFConverter::NewSignatureData::backgroundColor() const
+{
+    return d->backgroundColor;
+}
+
+void PDFConverter::NewSignatureData::setBackgroundColor(const QColor &color)
+{
+    d->backgroundColor = color;
+}
+
+QString PDFConverter::NewSignatureData::fieldPartialName() const
+{
+    return d->partialName;
+}
+
+void PDFConverter::NewSignatureData::setFieldPartialName(const QString &name)
+{
+    d->partialName = name;
+}
 }
diff --git a/qt6/src/poppler-qt6.h b/qt6/src/poppler-qt6.h
index c3c3f631..229f6c93 100644
--- a/qt6/src/poppler-qt6.h
+++ b/qt6/src/poppler-qt6.h
@@ -22,6 +22,9 @@
  * Copyright (C) 2019 Jan Grulich <jgrulich at redhat.com>
  * Copyright (C) 2019 Alexander Volkov <a.volkov at rusbitech.ru>
  * Copyright (C) 2020 Philipp Knechtges <philipp-dev at knechtges.com>
+ * Copyright (C) 2020 Katarina Behrens <Katarina.Behrens at cib.de>
+ * Copyright (C) 2020 Thorsten Behrens <Thorsten.Behrens at CIB.de>
+ * Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, <info at kdab.com>. Work sponsored by Technische Universität Dresden
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -1944,6 +1947,86 @@ public:
      */
     PDFOptions pdfOptions() const;
 
+    /**
+     * Holds data for a new signature
+     *  - Common Name of cert to sign (aka nickname)
+     *  - password for the cert
+     *  - page where to add the signature
+     *  - rect for the signature annotation
+     *  - text that will be shown inside the rect
+     *  - font size and color
+     *  - border and background color
+     * \since 20.12
+     */
+    class NewSignatureData
+    {
+    public:
+        NewSignatureData();
+        ~NewSignatureData();
+        NewSignatureData(const NewSignatureData &) = delete;
+        NewSignatureData &operator=(const NewSignatureData &) = delete;
+
+        QString certNickname() const;
+        void setCertNickname(const QString &certNickname);
+
+        QString password() const;
+        void setPassword(const QString &password);
+
+        int page() const;
+        void setPage(int page);
+
+        QRectF boundingRectangle() const;
+        void setBoundingRectangle(const QRectF &rect);
+
+        QString signatureText() const;
+        void setSignatureText(const QString &text);
+
+        /**
+         * Default: 10
+         */
+        double fontSize() const;
+        void setFontSize(double fontSize);
+
+        /**
+         * Default: red
+         */
+        QColor fontColor() const;
+        void setFontColor(const QColor &color);
+
+        /**
+         * Default: red
+         */
+        QColor borderColor() const;
+        void setBorderColor(const QColor &color);
+
+        /**
+         * Default: QColor(240, 240, 240)
+         */
+        QColor backgroundColor() const;
+        void setBackgroundColor(const QColor &color);
+
+        /**
+         * Default: QUuid::createUuid().toString()
+         */
+        QString fieldPartialName() const;
+        void setFieldPartialName(const QString &name);
+
+    private:
+        struct NewSignatureDataPrivate;
+        NewSignatureDataPrivate *const d;
+    };
+
+    /**
+        Sign PDF at given Annotation / signature form
+
+        \param data new signature data
+
+        \return whether the signing succeeded
+
+        \since 20.12
+    */
+    bool sign(const NewSignatureData &data);
+
     bool convert() override;
 
 private:


More information about the poppler mailing list