1 /**
2  * Copyright (C) 2011-2012  Charlie Sharpsteen, Stefan Löffler
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License as published by the Free
6  * Software Foundation; either version 3, or (at your option) any later
7  * version.
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
12  * more details.
13  */
14 
15 // NOTE:
16 //
17 // ** THIS HEADER IS NOT MENT TO BE INCLUDED DIRECTLY **
18 //
19 // Instead, include `PDFBackend.h` which defines classes that this header
20 // relies on.
21 #ifndef MuPDFBackend_H
22 #define MuPDFBackend_H
23 
24 #include "PDFBackend.h"
25 
26 extern "C"
27 {
28 #include <fitz.h>
29 #include <mupdf.h>
30 }
31 
32 namespace QtPDF {
33 
34 namespace Backend {
35 
36 namespace MuPDF {
37 
38 class Document;
39 class Page;
40 
41 class Document: public Backend::Document
42 {
43   typedef Backend::Document Super;
44   friend class Page;
45 
46   void recursiveConvertToC(QList<PDFToCItem> & items, pdf_outline * node) const;
47 
48 protected:
49   // The pdf_xref is the main MuPDF object that represents a Document. Calls
50   // that use it may have to be protected by a mutex.
51   pdf_xref *_mupdf_data;
52   fz_glyph_cache *_glyph_cache;
53 
54   void loadMetaData();
55 
56   // The following two methods are not thread-safe because they don't acquire a
57   // read lock. This is to enable methods that have a write lock to use them.
_isValid()58   bool _isValid() const { return (_mupdf_data != NULL); }
_isLocked()59   bool _isLocked() const { return (_isValid() && _permissionLevel == PermissionLevel_Locked); }
60 
61 public:
62   Document(QString fileName);
63   ~Document();
64 
isValid()65   bool isValid() const { QReadLocker docLocker(_docLock.data()); return _isValid(); }
isLocked()66   bool isLocked() const { QReadLocker docLocker(_docLock.data()); return _isLocked(); }
67 
68   bool unlock(const QString password);
69   void reload();
70 
71   QWeakPointer<Backend::Page> page(int at);
72   QWeakPointer<Backend::Page> page(int at) const;
73   PDFDestination resolveDestination(const PDFDestination & namedDestination) const;
74 
75   PDFToC toc() const;
76   QList<PDFFontInfo> fonts() const;
77 
78 private:
79   enum PermissionLevel { PermissionLevel_Locked, PermissionLevel_User, PermissionLevel_Owner };
80   QString _password;
81   // NOTE: the MuPDF function pdf_needs_password actually tries to authenticate
82   // with an empty password under certain circumstances. This can effectively
83   // relock _mupdf_data, so we have to cache to `locked` state.
84   PermissionLevel _permissionLevel;
85 };
86 
87 
88 class Page: public Backend::Page
89 {
90   friend class Document;
91   typedef Backend::Page Super;
92 
93   // The `fz_display_list` is the main MuPDF object that represents the parsed
94   // contents of a Page.
95   fz_display_list *_mupdf_page;
96 
97   // Keep as a Fitz object rather than QRect as it is used in rendering ops.
98   fz_rect _bbox;
99   QSizeF _size;
100   qreal _rotate;
101 
102   QList< QSharedPointer<Annotation::AbstractAnnotation> > _annotations;
103   QList< QSharedPointer<Annotation::Link> > _links;
104   bool _annotationsLoaded;
105   bool _linksLoaded;
106 
107   // requires a doc-lock and a page-write-lock
108   void loadTransitionData();
109 
110 protected:
111   Page(Document *parent, int at, QSharedPointer<QReadWriteLock> docLock);
112 
113 public:
114   ~Page();
115 
116   QSizeF pageSizeF() const;
117 
118   QImage renderToImage(double xres, double yres, QRect render_box = QRect(), bool cache = false);
119 
120   QList< QSharedPointer<Annotation::Link> > loadLinks();
121   QList< QSharedPointer<Annotation::AbstractAnnotation> > loadAnnotations();
122 
123   QList<SearchResult> search(QString searchText, SearchFlags flags);
124   virtual QList<Backend::Page::Box> boxes();
125   virtual QString selectedText(const QList<QPolygonF> & selection, QMap<int, QRectF> * wordBoxes = NULL, QMap<int, QRectF> * charBoxes = NULL);
126 };
127 
128 } // namespace MuPDF
129 
130 } // namespace Backend
131 
132 class MuPDFBackend : public BackendInterface
133 {
134   Q_OBJECT
Q_INTERFACES(QtPDF::BackendInterface)135   Q_INTERFACES(QtPDF::BackendInterface)
136 public:
137   MuPDFBackend() { }
~MuPDFBackend()138   virtual ~MuPDFBackend() { }
139 
newDocument(const QString & fileName)140   virtual QSharedPointer<Backend::Document> newDocument(const QString & fileName) {
141     return QSharedPointer<Backend::Document>(new Backend::MuPDF::Document(fileName));
142   }
143 
name()144   virtual QString name() const { return QString::fromAscii("mupdf"); }
canHandleFile(const QString & fileName)145   virtual bool canHandleFile(const QString & fileName) { return QFileInfo(fileName).suffix() == QString::fromAscii("pdf"); }
146 };
147 
148 } // namespace QtPDF
149 
150 #endif // End header guard
151 // vim: set sw=2 ts=2 et
152 
153