1 | /* poppler-private.h: qt interface to poppler |
2 | * Copyright (C) 2005, Net Integration Technologies, Inc. |
3 | * Copyright (C) 2005, 2008, Brad Hards <bradh@frogmouth.net> |
4 | * Copyright (C) 2006-2009, 2011, 2012, 2017-2022 by Albert Astals Cid <aacid@kde.org> |
5 | * Copyright (C) 2007-2009, 2011, 2014 by Pino Toscano <pino@kde.org> |
6 | * Copyright (C) 2011 Andreas Hartmetz <ahartmetz@gmail.com> |
7 | * Copyright (C) 2011 Hib Eris <hib@hiberis.nl> |
8 | * Copyright (C) 2012, 2013 Thomas Freitag <Thomas.Freitag@alfa.de> |
9 | * Copyright (C) 2013 Anthony Granger <grangeranthony@gmail.com> |
10 | * Copyright (C) 2014 Bogdan Cristea <cristeab@gmail.com> |
11 | * Copyright (C) 2014 Aki Koskinen <freedesktop@akikoskinen.info> |
12 | * Copyright (C) 2016 Jakub Alba <jakubalba@gmail.com> |
13 | * Copyright (C) 2017 Christoph Cullmann <cullmann@kde.org> |
14 | * Copyright (C) 2018 Klarälvdalens Datakonsult AB, a KDAB Group company, <info@kdab.com>. Work sponsored by the LiMux project of the city of Munich |
15 | * Copyright (C) 2018, 2020 Adam Reichold <adam.reichold@t-online.de> |
16 | * Copyright (C) 2019-2021 Oliver Sander <oliver.sander@tu-dresden.de> |
17 | * Copyright (C) 2019 João Netto <joaonetto901@gmail.com> |
18 | * Copyright (C) 2019 Jan Grulich <jgrulich@redhat.com> |
19 | * Copyright (C) 2019 Alexander Volkov <a.volkov@rusbitech.ru> |
20 | * Copyright (C) 2020 Philipp Knechtges <philipp-dev@knechtges.com> |
21 | * Copyright (C) 2021 Mahmoud Khalil <mahmoudkhalil11@gmail.com> |
22 | * Copyright (C) 2021 Hubert Figuiere <hub@figuiere.net> |
23 | * Copyright (C) 2021 Georgiy Sgibnev <georgiy@sgibnev.com>. Work sponsored by lab50.net. |
24 | * Copyright (C) 2024 g10 Code GmbH, Author: Sune Stolborg Vuorela <sune@vuorela.dk> |
25 | * Inspired on code by |
26 | * Copyright (C) 2004 by Albert Astals Cid <tsdgeos@terra.es> |
27 | * Copyright (C) 2004 by Enrico Ros <eros.kde@email.it> |
28 | * |
29 | * This program is free software; you can redistribute it and/or modify |
30 | * it under the terms of the GNU General Public License as published by |
31 | * the Free Software Foundation; either version 2, or (at your option) |
32 | * any later version. |
33 | * |
34 | * This program is distributed in the hope that it will be useful, |
35 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
36 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
37 | * GNU General Public License for more details. |
38 | * |
39 | * You should have received a copy of the GNU General Public License |
40 | * along with this program; if not, write to the Free Software |
41 | * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. |
42 | */ |
43 | |
44 | #ifndef _POPPLER_PRIVATE_H_ |
45 | #define _POPPLER_PRIVATE_H_ |
46 | |
47 | #include <QtCore/QFile> |
48 | #include <QtCore/QMutex> |
49 | #include <QtCore/QPointer> |
50 | #include <QtCore/QVector> |
51 | |
52 | #include <functional> |
53 | #include <config.h> |
54 | #include <poppler-config.h> |
55 | #include <GfxState.h> |
56 | #include <GlobalParams.h> |
57 | #include <FileSpec.h> |
58 | #include <Form.h> |
59 | #include <PDFDoc.h> |
60 | #include <FontInfo.h> |
61 | #include <OutputDev.h> |
62 | #include <Error.h> |
63 | #include <SplashOutputDev.h> |
64 | |
65 | #include "poppler-qt6.h" |
66 | #include "poppler-embeddedfile-private.h" |
67 | #include "poppler-qiodeviceinstream-private.h" |
68 | |
69 | class LinkDest; |
70 | class FormWidget; |
71 | |
72 | namespace Poppler { |
73 | |
74 | /* borrowed from kpdf */ |
75 | POPPLER_QT6_EXPORT QString unicodeToQString(const Unicode *u, int len); |
76 | POPPLER_QT6_EXPORT QString unicodeToQString(const std::vector<Unicode> &u); |
77 | |
78 | POPPLER_QT6_EXPORT QString UnicodeParsedString(const GooString *s1); |
79 | |
80 | POPPLER_QT6_EXPORT QString UnicodeParsedString(const std::string &s1); |
81 | |
82 | POPPLER_QT6_EXPORT GooString *QStringToUnicodeGooString(const QString &s); |
83 | |
84 | // Returns a big endian UTF-16 string with BOM or an empty string without BOM. |
85 | // The caller owns the returned pointer. |
86 | POPPLER_QT6_EXPORT GooString *QStringToGooString(const QString &s); |
87 | |
88 | GooString *QDateTimeToUnicodeGooString(const QDateTime &dt); |
89 | |
90 | void qt6ErrorFunction(ErrorCategory /*category*/, Goffset pos, const char *msg); |
91 | |
92 | Annot::AdditionalActionsType toPopplerAdditionalActionType(Annotation::AdditionalActionType type); |
93 | |
94 | class LinkDestinationData |
95 | { |
96 | public: |
97 | LinkDestinationData(const LinkDest *l, const GooString *nd, Poppler::DocumentData *pdfdoc, bool external) : ld(l), namedDest(nd), doc(pdfdoc), externalDest(external) { } |
98 | |
99 | const LinkDest *ld; |
100 | const GooString *namedDest; |
101 | Poppler::DocumentData *doc; |
102 | bool externalDest; |
103 | }; |
104 | |
105 | class DocumentData : private GlobalParamsIniter |
106 | { |
107 | public: |
108 | DocumentData(const QString &filePath, const std::optional<GooString> &ownerPassword, const std::optional<GooString> &userPassword) : GlobalParamsIniter(qt6ErrorFunction) |
109 | { |
110 | init(); |
111 | m_device = nullptr; |
112 | m_filePath = filePath; |
113 | |
114 | #ifdef _WIN32 |
115 | doc = new PDFDoc((wchar_t *)filePath.utf16(), filePath.length(), ownerPassword, userPassword, nullptr, std::bind(&DocumentData::noitfyXRefReconstructed, this)); |
116 | #else |
117 | doc = new PDFDoc(std::make_unique<GooString>(args: QFile::encodeName(fileName: filePath).constData()), ownerPassword, userPassword, nullptr, std::bind(f: &DocumentData::noitfyXRefReconstructed, args: this)); |
118 | #endif |
119 | } |
120 | |
121 | DocumentData(QIODevice *device, const std::optional<GooString> &ownerPassword, const std::optional<GooString> &userPassword) : GlobalParamsIniter(qt6ErrorFunction) |
122 | { |
123 | m_device = device; |
124 | QIODeviceInStream *str = new QIODeviceInStream(device, 0, false, device->size(), Object(objNull)); |
125 | init(); |
126 | doc = new PDFDoc(str, ownerPassword, userPassword, nullptr, std::bind(f: &DocumentData::noitfyXRefReconstructed, args: this)); |
127 | } |
128 | |
129 | DocumentData(const QByteArray &data, const std::optional<GooString> &ownerPassword, const std::optional<GooString> &userPassword) : GlobalParamsIniter(qt6ErrorFunction) |
130 | { |
131 | m_device = nullptr; |
132 | fileContents = data; |
133 | MemStream *str = new MemStream((char *)fileContents.data(), 0, fileContents.length(), Object(objNull)); |
134 | init(); |
135 | doc = new PDFDoc(str, ownerPassword, userPassword, nullptr, std::bind(f: &DocumentData::noitfyXRefReconstructed, args: this)); |
136 | } |
137 | |
138 | void init(); |
139 | |
140 | ~DocumentData(); |
141 | |
142 | DocumentData(const DocumentData &) = delete; |
143 | DocumentData &operator=(const DocumentData &) = delete; |
144 | |
145 | void setPaperColor(const QColor &color) { paperColor = color; } |
146 | |
147 | void fillMembers() |
148 | { |
149 | int numEmb = doc->getCatalog()->numEmbeddedFiles(); |
150 | if (!(0 == numEmb)) { |
151 | // we have some embedded documents, build the list |
152 | for (int yalv = 0; yalv < numEmb; ++yalv) { |
153 | std::unique_ptr<FileSpec> fs = doc->getCatalog()->embeddedFile(i: yalv); |
154 | m_embeddedFiles.append(t: new EmbeddedFile(*new EmbeddedFileData(std::move(fs)))); |
155 | } |
156 | } |
157 | } |
158 | |
159 | /** |
160 | * a method that is being called whenever PDFDoc's XRef is reconstructed |
161 | * where we'll set xrefReconstructed flag and notify users of the |
162 | * reconstruction event |
163 | */ |
164 | void noitfyXRefReconstructed(); |
165 | |
166 | static std::unique_ptr<Document> checkDocument(DocumentData *doc); |
167 | |
168 | PDFDoc *doc; |
169 | QString m_filePath; |
170 | QIODevice *m_device; |
171 | QByteArray fileContents; |
172 | bool locked; |
173 | Document::RenderBackend m_backend; |
174 | QList<EmbeddedFile *> m_embeddedFiles; |
175 | QPointer<OptContentModel> m_optContentModel; |
176 | QColor paperColor; |
177 | int m_hints; |
178 | #ifdef USE_CMS |
179 | GfxLCMSProfilePtr m_sRGBProfile; |
180 | GfxLCMSProfilePtr m_displayProfile; |
181 | #endif |
182 | bool xrefReconstructed; |
183 | // notifies the user whenever the backend's PDFDoc XRef is reconstructed |
184 | std::function<void()> xrefReconstructedCallback; |
185 | }; |
186 | |
187 | class FontInfoData |
188 | { |
189 | public: |
190 | FontInfoData() |
191 | { |
192 | isEmbedded = false; |
193 | isSubset = false; |
194 | type = FontInfo::unknown; |
195 | } |
196 | |
197 | explicit FontInfoData(::FontInfo *fi) |
198 | { |
199 | if (fi->getName()) { |
200 | fontName = fi->getName()->c_str(); |
201 | } |
202 | if (fi->getFile()) { |
203 | fontFile = fi->getFile()->c_str(); |
204 | } |
205 | if (fi->getSubstituteName()) { |
206 | fontSubstituteName = fi->getSubstituteName()->c_str(); |
207 | } |
208 | isEmbedded = fi->getEmbedded(); |
209 | isSubset = fi->getSubset(); |
210 | type = (Poppler::FontInfo::Type)fi->getType(); |
211 | embRef = fi->getEmbRef(); |
212 | } |
213 | |
214 | FontInfoData(const FontInfoData &fid) = default; |
215 | FontInfoData &operator=(const FontInfoData &) = default; |
216 | |
217 | QString fontName; |
218 | QString fontSubstituteName; |
219 | QString fontFile; |
220 | bool isEmbedded : 1; |
221 | bool isSubset : 1; |
222 | FontInfo::Type type; |
223 | Ref embRef; |
224 | }; |
225 | |
226 | class FontIteratorData |
227 | { |
228 | public: |
229 | FontIteratorData(int startPage, DocumentData *dd) : fontInfoScanner(dd->doc, startPage), totalPages(dd->doc->getNumPages()), currentPage(qMax(a: startPage, b: 0) - 1) { } |
230 | |
231 | ~FontIteratorData() { } |
232 | |
233 | FontInfoScanner fontInfoScanner; |
234 | int totalPages; |
235 | int currentPage; |
236 | }; |
237 | |
238 | class TextBoxData |
239 | { |
240 | public: |
241 | TextBoxData() : nextWord(nullptr), hasSpaceAfter(false) { } |
242 | |
243 | QString text; |
244 | QRectF bBox; |
245 | TextBox *nextWord; |
246 | QVector<QRectF> charBBoxes; // the boundingRect of each character |
247 | bool hasSpaceAfter; |
248 | }; |
249 | |
250 | class FormFieldData |
251 | { |
252 | public: |
253 | FormFieldData(DocumentData *_doc, ::Page *p, ::FormWidget *w) : doc(_doc), page(p), fm(w) { } |
254 | |
255 | DocumentData *doc; |
256 | ::Page *page; // Note for some signatures it can be null since there's signatures that don't belong to a given page |
257 | ::FormWidget *fm; |
258 | QRectF box; |
259 | static POPPLER_QT6_EXPORT ::FormWidget *getFormWidget(const FormField *f); |
260 | }; |
261 | |
262 | class FormFieldIcon; |
263 | class FormFieldIconData |
264 | { |
265 | public: |
266 | static POPPLER_QT6_EXPORT FormFieldIconData *getData(const FormFieldIcon &f); |
267 | Dict *icon; |
268 | }; |
269 | |
270 | } |
271 | |
272 | #endif |
273 | |