1 | //======================================================================== |
2 | // |
3 | // Page.h |
4 | // |
5 | // Copyright 1996-2003 Glyph & Cog, LLC |
6 | // |
7 | //======================================================================== |
8 | |
9 | //======================================================================== |
10 | // |
11 | // Modified under the Poppler project - http://poppler.freedesktop.org |
12 | // |
13 | // All changes made under the Poppler project to this file are licensed |
14 | // under GPL version 2 or later |
15 | // |
16 | // Copyright (C) 2005 Kristian Høgsberg <krh@redhat.com> |
17 | // Copyright (C) 2005 Jeff Muizelaar <jeff@infidigm.net> |
18 | // Copyright (C) 2006 Pino Toscano <pino@kde.org> |
19 | // Copyright (C) 2006, 2011 Carlos Garcia Campos <carlosgc@gnome.org> |
20 | // Copyright (C) 2007 Julien Rebetez <julienr@svn.gnome.org> |
21 | // Copyright (C) 2008 Iñigo Martínez <inigomartinez@gmail.com> |
22 | // Copyright (C) 2012 Fabio D'Urso <fabiodurso@hotmail.it> |
23 | // Copyright (C) 2012, 2017, 2018, 2020, 2021, 2023 Albert Astals Cid <aacid@kde.org> |
24 | // Copyright (C) 2013 Thomas Freitag <Thomas.Freitag@alfa.de> |
25 | // Copyright (C) 2013, 2017, 2023 Adrian Johnson <ajohnson@redneon.com> |
26 | // Copyright (C) 2018 Adam Reichold <adam.reichold@t-online.de> |
27 | // Copyright (C) 2020 Oliver Sander <oliver.sander@tu-dresden.de> |
28 | // Copyright (C) 2020, 2021 Nelson Benítez León <nbenitezl@gmail.com> |
29 | // |
30 | // To see a description of the changes please see the Changelog file that |
31 | // came with your tarball or type make ChangeLog if you are building from git |
32 | // |
33 | //======================================================================== |
34 | |
35 | #ifndef PAGE_H |
36 | #define PAGE_H |
37 | |
38 | #include <memory> |
39 | #include <mutex> |
40 | |
41 | #include "poppler-config.h" |
42 | #include "Object.h" |
43 | #include "poppler_private_export.h" |
44 | |
45 | class Dict; |
46 | class PDFDoc; |
47 | class XRef; |
48 | class OutputDev; |
49 | class Links; |
50 | class LinkAction; |
51 | class Annots; |
52 | class Annot; |
53 | class Gfx; |
54 | class FormPageWidgets; |
55 | class Form; |
56 | class FormField; |
57 | |
58 | //------------------------------------------------------------------------ |
59 | |
60 | class PDFRectangle |
61 | { |
62 | public: |
63 | double x1, y1, x2, y2; |
64 | |
65 | PDFRectangle() { x1 = y1 = x2 = y2 = 0; } |
66 | PDFRectangle(double x1A, double y1A, double x2A, double y2A) |
67 | { |
68 | x1 = x1A; |
69 | y1 = y1A; |
70 | x2 = x2A; |
71 | y2 = y2A; |
72 | } |
73 | bool isValid() const { return x1 != 0 || y1 != 0 || x2 != 0 || y2 != 0; } |
74 | bool contains(double x, double y) const { return x1 <= x && x <= x2 && y1 <= y && y <= y2; } |
75 | void clipTo(PDFRectangle *rect); |
76 | |
77 | bool operator==(const PDFRectangle &rect) const { return x1 == rect.x1 && y1 == rect.y1 && x2 == rect.x2 && y2 == rect.y2; } |
78 | }; |
79 | |
80 | //------------------------------------------------------------------------ |
81 | // PageAttrs |
82 | //------------------------------------------------------------------------ |
83 | |
84 | class PageAttrs |
85 | { |
86 | public: |
87 | // Construct a new PageAttrs object by merging a dictionary |
88 | // (of type Pages or Page) into another PageAttrs object. If |
89 | // <attrs> is nullptr, uses defaults. |
90 | PageAttrs(PageAttrs *attrs, Dict *dict); |
91 | |
92 | // Destructor. |
93 | ~PageAttrs(); |
94 | |
95 | // Accessors. |
96 | const PDFRectangle *getMediaBox() const { return &mediaBox; } |
97 | const PDFRectangle *getCropBox() const { return &cropBox; } |
98 | bool isCropped() const { return haveCropBox; } |
99 | const PDFRectangle *getBleedBox() const { return &bleedBox; } |
100 | const PDFRectangle *getTrimBox() const { return &trimBox; } |
101 | const PDFRectangle *getArtBox() const { return &artBox; } |
102 | int getRotate() const { return rotate; } |
103 | const GooString *getLastModified() const { return lastModified.isString() ? lastModified.getString() : nullptr; } |
104 | Dict *getBoxColorInfo() { return boxColorInfo.isDict() ? boxColorInfo.getDict() : nullptr; } |
105 | Dict *getGroup() { return group.isDict() ? group.getDict() : nullptr; } |
106 | Stream *getMetadata() { return metadata.isStream() ? metadata.getStream() : nullptr; } |
107 | Dict *getPieceInfo() { return pieceInfo.isDict() ? pieceInfo.getDict() : nullptr; } |
108 | Dict *getSeparationInfo() { return separationInfo.isDict() ? separationInfo.getDict() : nullptr; } |
109 | Dict *getResourceDict() { return resources.isDict() ? resources.getDict() : nullptr; } |
110 | Object *getResourceDictObject() { return &resources; } |
111 | void replaceResource(Object &&obj1) { resources = std::move(obj1); } |
112 | |
113 | // Clip all other boxes to the MediaBox. |
114 | void clipBoxes(); |
115 | |
116 | private: |
117 | bool readBox(Dict *dict, const char *key, PDFRectangle *box); |
118 | |
119 | PDFRectangle mediaBox; |
120 | PDFRectangle cropBox; |
121 | bool haveCropBox; |
122 | PDFRectangle bleedBox; |
123 | PDFRectangle trimBox; |
124 | PDFRectangle artBox; |
125 | int rotate; |
126 | Object lastModified; |
127 | Object boxColorInfo; |
128 | Object group; |
129 | Object metadata; |
130 | Object pieceInfo; |
131 | Object separationInfo; |
132 | Object resources; |
133 | }; |
134 | |
135 | //------------------------------------------------------------------------ |
136 | // Page |
137 | //------------------------------------------------------------------------ |
138 | |
139 | class POPPLER_PRIVATE_EXPORT Page |
140 | { |
141 | public: |
142 | // Constructor. |
143 | Page(PDFDoc *docA, int numA, Object &&pageDict, Ref , PageAttrs *attrsA, Form *form); |
144 | |
145 | // Destructor. |
146 | ~Page(); |
147 | |
148 | Page(const Page &) = delete; |
149 | Page &operator=(const Page &) = delete; |
150 | |
151 | // Is page valid? |
152 | bool isOk() const { return ok; } |
153 | |
154 | // Get page parameters. |
155 | int getNum() const { return num; } |
156 | const PDFRectangle *getMediaBox() const { return attrs->getMediaBox(); } |
157 | const PDFRectangle *getCropBox() const { return attrs->getCropBox(); } |
158 | bool isCropped() const { return attrs->isCropped(); } |
159 | double getMediaWidth() const { return attrs->getMediaBox()->x2 - attrs->getMediaBox()->x1; } |
160 | double getMediaHeight() const { return attrs->getMediaBox()->y2 - attrs->getMediaBox()->y1; } |
161 | double getCropWidth() const { return attrs->getCropBox()->x2 - attrs->getCropBox()->x1; } |
162 | double getCropHeight() const { return attrs->getCropBox()->y2 - attrs->getCropBox()->y1; } |
163 | const PDFRectangle *getBleedBox() const { return attrs->getBleedBox(); } |
164 | const PDFRectangle *getTrimBox() const { return attrs->getTrimBox(); } |
165 | const PDFRectangle *getArtBox() const { return attrs->getArtBox(); } |
166 | int getRotate() const { return attrs->getRotate(); } |
167 | const GooString *getLastModified() const { return attrs->getLastModified(); } |
168 | Dict *getBoxColorInfo() { return attrs->getBoxColorInfo(); } |
169 | Dict *getGroup() { return attrs->getGroup(); } |
170 | Stream *getMetadata() { return attrs->getMetadata(); } |
171 | Dict *getPieceInfo() { return attrs->getPieceInfo(); } |
172 | Dict *getSeparationInfo() { return attrs->getSeparationInfo(); } |
173 | PDFDoc *getDoc() { return doc; } |
174 | Ref getRef() { return pageRef; } |
175 | |
176 | // Get resource dictionary. |
177 | Dict *getResourceDict(); |
178 | Object *getResourceDictObject(); |
179 | Dict *getResourceDictCopy(XRef *xrefA); |
180 | |
181 | // Get annotations array. |
182 | Object getAnnotsObject(XRef *xrefA = nullptr) { return annotsObj.fetch(xref: xrefA ? xrefA : xref); } |
183 | // Add a new annotation to the page |
184 | bool addAnnot(Annot *annot); |
185 | // Remove an existing annotation from the page |
186 | void removeAnnot(Annot *annot); |
187 | |
188 | // Return a list of links. |
189 | std::unique_ptr<Links> getLinks(); |
190 | |
191 | // Return a list of annots. It will be valid until the page is destroyed |
192 | Annots *getAnnots(XRef *xrefA = nullptr); |
193 | |
194 | // Get contents. |
195 | Object getContents() { return contents.fetch(xref); } |
196 | |
197 | // Get thumb. |
198 | Object getThumb() { return thumb.fetch(xref); } |
199 | bool loadThumb(unsigned char **data, int *width, int *height, int *rowstride); |
200 | |
201 | // Get transition. |
202 | Object getTrans() { return trans.fetch(xref); } |
203 | |
204 | // Get form. |
205 | std::unique_ptr<FormPageWidgets> getFormWidgets(); |
206 | |
207 | // Get duration, the maximum length of time, in seconds, |
208 | // that the page is displayed before the presentation automatically |
209 | // advances to the next page |
210 | double getDuration() { return duration; } |
211 | |
212 | // Get actions |
213 | Object getActions() { return actions.fetch(xref); } |
214 | |
215 | enum PageAdditionalActionsType |
216 | { |
217 | actionOpenPage, ///< Performed when opening the page |
218 | actionClosePage, ///< Performed when closing the page |
219 | }; |
220 | |
221 | std::unique_ptr<LinkAction> getAdditionalAction(PageAdditionalActionsType type); |
222 | |
223 | Gfx *createGfx(OutputDev *out, double hDPI, double vDPI, int rotate, bool useMediaBox, bool crop, int sliceX, int sliceY, int sliceW, int sliceH, bool printing, bool (*abortCheckCbk)(void *data), void *abortCheckCbkData, |
224 | XRef *xrefA = nullptr); |
225 | |
226 | // Display a page. |
227 | void display(OutputDev *out, double hDPI, double vDPI, int rotate, bool useMediaBox, bool crop, bool printing, bool (*abortCheckCbk)(void *data) = nullptr, void *abortCheckCbkData = nullptr, |
228 | bool (*annotDisplayDecideCbk)(Annot *annot, void *user_data) = nullptr, void *annotDisplayDecideCbkData = nullptr, bool copyXRef = false); |
229 | |
230 | // Display part of a page. |
231 | void displaySlice(OutputDev *out, double hDPI, double vDPI, int rotate, bool useMediaBox, bool crop, int sliceX, int sliceY, int sliceW, int sliceH, bool printing, bool (*abortCheckCbk)(void *data) = nullptr, |
232 | void *abortCheckCbkData = nullptr, bool (*annotDisplayDecideCbk)(Annot *annot, void *user_data) = nullptr, void *annotDisplayDecideCbkData = nullptr, bool copyXRef = false); |
233 | |
234 | void display(Gfx *gfx); |
235 | |
236 | void makeBox(double hDPI, double vDPI, int rotate, bool useMediaBox, bool upsideDown, double sliceX, double sliceY, double sliceW, double sliceH, PDFRectangle *box, bool *crop); |
237 | |
238 | void processLinks(OutputDev *out); |
239 | |
240 | // Get the page's default CTM. |
241 | void getDefaultCTM(double *ctm, double hDPI, double vDPI, int rotate, bool useMediaBox, bool upsideDown); |
242 | |
243 | bool hasStandaloneFields() const { return !standaloneFields.empty(); } |
244 | |
245 | // Get the integer key of the page's entry in the structural parent tree. |
246 | // Returns -1 if the page dict does not contain a StructParents key. |
247 | int getStructParents() const { return structParents; } |
248 | |
249 | private: |
250 | // replace xref |
251 | void replaceXRef(XRef *xrefA); |
252 | |
253 | PDFDoc *doc; |
254 | XRef *xref; // the xref table for this PDF file |
255 | Object pageObj; // page dictionary |
256 | const Ref ; // page reference |
257 | int num; // page number |
258 | PageAttrs *attrs; // page attributes |
259 | Annots *annots; // annotations |
260 | Object annotsObj; // annotations array |
261 | Object contents; // page contents |
262 | Object thumb; // page thumbnail |
263 | Object trans; // page transition |
264 | Object actions; // page additional actions |
265 | double duration; // page duration |
266 | int structParents; // integer key of page in structure parent tree |
267 | bool ok; // true if page is valid |
268 | mutable std::recursive_mutex mutex; |
269 | // standalone widgets are special FormWidget's inside a Page that *are not* |
270 | // referenced from the Catalog's Field array. That means they are standlone, |
271 | // i.e. the PDF document does not have a FormField associated with them. We |
272 | // create standalone FormFields to contain those special FormWidgets, as |
273 | // they are 'de facto' being used to implement tooltips. See #34 |
274 | std::vector<FormField *> standaloneFields; |
275 | void loadStandaloneFields(Annots *annotations, Form *form); |
276 | }; |
277 | |
278 | #endif |
279 | |