File indexing completed on 2024-05-12 16:06:50

0001 /*
0002     SPDX-FileCopyrightText: 2006 Brad Hards <bradh@frogmouth.net>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #ifndef _OKULAR_GENERATOR_XPS_H_
0008 #define _OKULAR_GENERATOR_XPS_H_
0009 
0010 #include <core/generator.h>
0011 #include <core/textpage.h>
0012 
0013 #include <QColor>
0014 #include <QDomDocument>
0015 #include <QFontDatabase>
0016 #include <QImage>
0017 #include <QLoggingCategory>
0018 #include <QStack>
0019 #include <QVariant>
0020 #include <QXmlStreamReader>
0021 
0022 #include <kzip.h>
0023 
0024 typedef enum { abtCommand, abtNumber, abtComma, abtEOF } AbbPathTokenType;
0025 
0026 class AbbPathToken
0027 {
0028 public:
0029     QString data;
0030     int curPos;
0031 
0032     AbbPathTokenType type;
0033     char command;
0034     double number;
0035 };
0036 
0037 /**
0038     Holds information about xml element during SAX parsing of page
0039 */
0040 class XpsRenderNode
0041 {
0042 public:
0043     QString name;
0044     QVector<XpsRenderNode> children;
0045     QXmlStreamAttributes attributes;
0046     QVariant data;
0047 
0048     const XpsRenderNode *findChild(const QString &name) const;
0049     QVariant getRequiredChildData(const QString &name) const;
0050     QVariant getChildData(const QString &name) const;
0051 };
0052 
0053 struct XpsGradient {
0054     XpsGradient(double o, const QColor &c)
0055         : offset(o)
0056         , color(c)
0057     {
0058     }
0059 
0060     double offset;
0061     QColor color;
0062 };
0063 
0064 /**
0065     Types of data in XpsRenderNode::data. Name of each type consist of Xps and
0066     name of xml element which data it holds
0067 */
0068 typedef QTransform XpsMatrixTransform;
0069 typedef QTransform XpsRenderTransform;
0070 typedef QBrush XpsFill;
0071 struct XpsPathFigure {
0072     XpsPathFigure(const QPainterPath &_path, bool filled)
0073         : path(_path)
0074         , isFilled(filled)
0075     {
0076     }
0077 
0078     QPainterPath path;
0079     bool isFilled;
0080 };
0081 
0082 struct XpsPathGeometry {
0083     XpsPathGeometry()
0084         : fillRule(Qt::OddEvenFill)
0085     {
0086     }
0087     ~XpsPathGeometry()
0088     {
0089         qDeleteAll(paths);
0090     }
0091 
0092     XpsPathGeometry(const XpsPathGeometry &) = delete;
0093     XpsPathGeometry &operator=(const XpsPathGeometry &) = delete;
0094 
0095     QList<XpsPathFigure *> paths;
0096     Qt::FillRule fillRule;
0097     XpsMatrixTransform transform;
0098 };
0099 
0100 class XpsPage;
0101 class XpsFile;
0102 
0103 class XpsPage
0104 {
0105 public:
0106     XpsPage(XpsFile *file, const QString &fileName);
0107     ~XpsPage();
0108 
0109     XpsPage(const XpsPage &) = delete;
0110     XpsPage &operator=(const XpsPage &) = delete;
0111 
0112     QSizeF size() const;
0113     bool renderToImage(QImage *p);
0114     bool renderToPainter(QPainter *painter);
0115     Okular::TextPage *textPage();
0116 
0117     QImage loadImageFromFile(const QString &filename);
0118     QString fileName() const
0119     {
0120         return m_fileName;
0121     }
0122 
0123 private:
0124     // Methods for processing of different xml elements
0125     void processStartElement(QPainter *painter, XpsRenderNode &node);
0126     void processEndElement(QPainter *painter, XpsRenderNode &node);
0127     void processGlyph(QPainter *painter, XpsRenderNode &node);
0128     void processPath(QPainter *painter, XpsRenderNode &node);
0129     void processPathData(XpsRenderNode &node);
0130     void processFill(XpsRenderNode &node);
0131     void processStroke(XpsRenderNode &node);
0132     void processImageBrush(XpsRenderNode &node);
0133     void processPathGeometry(XpsRenderNode &node);
0134     void processPathFigure(XpsRenderNode &node);
0135 
0136     XpsFile *m_file;
0137     const QString m_fileName;
0138     QStack<XpsRenderNode> m_nodes;
0139 
0140     QSizeF m_pageSize;
0141 
0142     QString m_thumbnailFileName;
0143     bool m_thumbnailMightBeAvailable;
0144     QImage m_thumbnail;
0145     bool m_thumbnailIsLoaded;
0146 
0147     QImage *m_pageImage;
0148     bool m_pageIsRendered;
0149 
0150     friend class XpsHandler;
0151     friend class XpsTextExtractionHandler;
0152 };
0153 
0154 /**
0155    Represents one of the (perhaps the only) documents in an XpsFile
0156 */
0157 class XpsDocument
0158 {
0159 public:
0160     XpsDocument(XpsFile *file, const QString &fileName);
0161     ~XpsDocument();
0162 
0163     XpsDocument(const XpsDocument &) = delete;
0164     XpsDocument &operator=(const XpsDocument &) = delete;
0165 
0166     /**
0167        the total number of pages in this document
0168     */
0169     int numPages() const;
0170 
0171     /**
0172        obtain a certain page from this document
0173 
0174        \param pageNum the number of the page to return
0175 
0176        \note page numbers are zero based - they run from 0 to
0177        numPages() - 1
0178     */
0179     XpsPage *page(int pageNum) const;
0180 
0181     /**
0182       whether this document has a Document Structure
0183     */
0184     bool hasDocumentStructure();
0185 
0186     /**
0187       the document structure for this document, if available
0188     */
0189     const Okular::DocumentSynopsis *documentStructure();
0190 
0191 private:
0192     void parseDocumentStructure(const QString &documentStructureFileName);
0193 
0194     std::vector<std::unique_ptr<XpsPage>> m_pages;
0195     XpsFile *m_file;
0196     bool m_haveDocumentStructure;
0197     std::unique_ptr<Okular::DocumentSynopsis> m_docStructure;
0198     QMap<QString, int> m_docStructurePageMap;
0199 };
0200 
0201 /**
0202    Represents the contents of a Microsoft XML Paper Specification
0203    format document.
0204 */
0205 class XpsFile
0206 {
0207 public:
0208     XpsFile();
0209     ~XpsFile();
0210 
0211     XpsFile(const XpsFile &) = delete;
0212     XpsFile &operator=(const XpsFile &) = delete;
0213 
0214     bool loadDocument(const QString &fileName);
0215     bool closeDocument();
0216 
0217     Okular::DocumentInfo generateDocumentInfo() const;
0218 
0219     QImage thumbnail();
0220 
0221     /**
0222        the total number of XpsDocuments with this file
0223     */
0224     int numDocuments() const;
0225 
0226     /**
0227        the total number of pages in all the XpsDocuments within this
0228        file
0229     */
0230     int numPages() const;
0231 
0232     /**
0233        a page from the file
0234 
0235         \param pageNum the page number of the page to return
0236 
0237         \note page numbers are zero based - they run from 0 to
0238         numPages() - 1
0239     */
0240     XpsPage *page(int pageNum) const;
0241 
0242     /**
0243        obtain a certain document from this file
0244 
0245        \param documentNum the number of the document to return
0246 
0247        \note document numbers are zero based - they run from 0 to
0248        numDocuments() - 1
0249     */
0250     XpsDocument *document(int documentNum) const;
0251 
0252     QFont getFontByName(const QString &absoluteFileName, float size);
0253 
0254     KZip *xpsArchive();
0255 
0256 private:
0257     int loadFontByName(const QString &absoluteFileName);
0258 
0259     std::vector<std::unique_ptr<XpsDocument>> m_documents;
0260     QList<XpsPage *> m_pages;
0261 
0262     QString m_thumbnailFileName;
0263     bool m_thumbnailMightBeAvailable;
0264     QImage m_thumbnail;
0265     bool m_thumbnailIsLoaded;
0266 
0267     QString m_corePropertiesFileName;
0268 
0269     QString m_signatureOrigin;
0270 
0271     std::unique_ptr<KZip> m_xpsArchive;
0272 
0273     QMap<QString, int> m_fontCache;
0274     QFontDatabase m_fontDatabase;
0275 };
0276 
0277 class XpsGenerator : public Okular::Generator
0278 {
0279     Q_OBJECT
0280     Q_INTERFACES(Okular::Generator)
0281 public:
0282     XpsGenerator(QObject *parent, const QVariantList &args);
0283     ~XpsGenerator() override;
0284 
0285     bool loadDocument(const QString &fileName, QVector<Okular::Page *> &pagesVector) override;
0286 
0287     Okular::DocumentInfo generateDocumentInfo(const QSet<Okular::DocumentInfo::Key> &keys) const override;
0288     const Okular::DocumentSynopsis *generateDocumentSynopsis() override;
0289 
0290     Okular::ExportFormat::List exportFormats() const override;
0291     bool exportTo(const QString &fileName, const Okular::ExportFormat &format) override;
0292 
0293     Okular::Document::PrintError print(QPrinter &printer) override;
0294 
0295 protected:
0296     bool doCloseDocument() override;
0297     QImage image(Okular::PixmapRequest *request) override;
0298     Okular::TextPage *textPage(Okular::TextRequest *request) override;
0299 
0300 private:
0301     std::unique_ptr<XpsFile> m_xpsFile;
0302 };
0303 
0304 Q_DECLARE_LOGGING_CATEGORY(OkularXpsDebug)
0305 
0306 #endif