1 | //======================================================================== |
2 | // |
3 | // Link.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) 2006, 2008 Pino Toscano <pino@kde.org> |
17 | // Copyright (C) 2008 Hugo Mercier <hmercier31@gmail.com> |
18 | // Copyright (C) 2010, 2011 Carlos Garcia Campos <carlosgc@gnome.org> |
19 | // Copyright (C) 2012 Tobias Koening <tobias.koenig@kdab.com> |
20 | // Copyright (C) 2018-2023 Albert Astals Cid <aacid@kde.org> |
21 | // 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 |
22 | // Copyright (C) 2018 Intevation GmbH <intevation@intevation.de> |
23 | // Copyright (C) 2019, 2020 Oliver Sander <oliver.sander@tu-dresden.de> |
24 | // Copyright (C) 2020 Adam Reichold <adam.reichold@t-online.de> |
25 | // Copyright (C) 2020 Marek Kasik <mkasik@redhat.com> |
26 | // |
27 | // To see a description of the changes please see the Changelog file that |
28 | // came with your tarball or type make ChangeLog if you are building from git |
29 | // |
30 | //======================================================================== |
31 | |
32 | #ifndef LINK_H |
33 | #define LINK_H |
34 | |
35 | #include "Object.h" |
36 | #include "poppler_private_export.h" |
37 | #include <memory> |
38 | #include <optional> |
39 | #include <set> |
40 | |
41 | class GooString; |
42 | class Array; |
43 | class Dict; |
44 | class Sound; |
45 | class MediaRendition; |
46 | class AnnotLink; |
47 | class Annots; |
48 | |
49 | //------------------------------------------------------------------------ |
50 | // LinkAction |
51 | //------------------------------------------------------------------------ |
52 | |
53 | enum LinkActionKind |
54 | { |
55 | actionGoTo, // go to destination |
56 | actionGoToR, // go to destination in new file |
57 | actionLaunch, // launch app (or open document) |
58 | actionURI, // URI |
59 | actionNamed, // named action |
60 | actionMovie, // movie action |
61 | actionRendition, // rendition action |
62 | actionSound, // sound action |
63 | actionJavaScript, // JavaScript action |
64 | actionOCGState, // Set-OCG-State action |
65 | actionHide, // Hide action |
66 | actionResetForm, // ResetForm action |
67 | actionUnknown // anything else |
68 | }; |
69 | |
70 | class POPPLER_PRIVATE_EXPORT LinkAction |
71 | { |
72 | public: |
73 | LinkAction(); |
74 | LinkAction(const LinkAction &) = delete; |
75 | LinkAction &operator=(const LinkAction &other) = delete; |
76 | |
77 | // Destructor. |
78 | virtual ~LinkAction(); |
79 | |
80 | // Was the LinkAction created successfully? |
81 | virtual bool isOk() const = 0; |
82 | |
83 | // Check link action type. |
84 | virtual LinkActionKind getKind() const = 0; |
85 | |
86 | // Parse a destination (old-style action) name, string, or array. |
87 | static std::unique_ptr<LinkAction> parseDest(const Object *obj); |
88 | |
89 | // Parse an action dictionary. |
90 | static std::unique_ptr<LinkAction> parseAction(const Object *obj, const std::optional<std::string> &baseURI = {}); |
91 | |
92 | // A List of the next actions to execute in order. |
93 | const std::vector<std::unique_ptr<LinkAction>> &nextActions() const; |
94 | |
95 | private: |
96 | static std::unique_ptr<LinkAction> parseAction(const Object *obj, const std::optional<std::string> &baseURI, std::set<int> *seenNextActions); |
97 | |
98 | std::vector<std::unique_ptr<LinkAction>> nextActionList; |
99 | }; |
100 | |
101 | //------------------------------------------------------------------------ |
102 | // LinkDest |
103 | //------------------------------------------------------------------------ |
104 | |
105 | enum LinkDestKind |
106 | { |
107 | destXYZ, |
108 | destFit, |
109 | destFitH, |
110 | destFitV, |
111 | destFitR, |
112 | destFitB, |
113 | destFitBH, |
114 | destFitBV |
115 | }; |
116 | |
117 | class POPPLER_PRIVATE_EXPORT LinkDest |
118 | { |
119 | public: |
120 | // Build a LinkDest from the array. |
121 | explicit LinkDest(const Array *a); |
122 | |
123 | // Was the LinkDest created successfully? |
124 | bool isOk() const { return ok; } |
125 | |
126 | // Accessors. |
127 | LinkDestKind getKind() const { return kind; } |
128 | bool () const { return pageIsRef; } |
129 | int getPageNum() const { return pageNum; } |
130 | Ref () const { return pageRef; } |
131 | double getLeft() const { return left; } |
132 | double getBottom() const { return bottom; } |
133 | double getRight() const { return right; } |
134 | double getTop() const { return top; } |
135 | double getZoom() const { return zoom; } |
136 | bool getChangeLeft() const { return changeLeft; } |
137 | bool getChangeTop() const { return changeTop; } |
138 | bool getChangeZoom() const { return changeZoom; } |
139 | |
140 | private: |
141 | LinkDestKind kind; // destination type |
142 | bool pageIsRef; // is the page a reference or number? |
143 | union { |
144 | Ref ; // reference to page |
145 | int pageNum; // one-relative page number |
146 | }; |
147 | double left, bottom; // position |
148 | double right, top; |
149 | double zoom; // zoom factor |
150 | bool changeLeft, changeTop; // which position components to change: |
151 | bool changeZoom; // destXYZ uses all three; |
152 | // destFitH/BH use changeTop; |
153 | // destFitV/BV use changeLeft |
154 | bool ok; // set if created successfully |
155 | }; |
156 | |
157 | //------------------------------------------------------------------------ |
158 | // LinkGoTo |
159 | //------------------------------------------------------------------------ |
160 | |
161 | class POPPLER_PRIVATE_EXPORT LinkGoTo : public LinkAction |
162 | { |
163 | public: |
164 | // Build a LinkGoTo from a destination (dictionary, name, or string). |
165 | explicit LinkGoTo(const Object *destObj); |
166 | |
167 | ~LinkGoTo() override; |
168 | |
169 | // Was the LinkGoTo created successfully? |
170 | bool isOk() const override { return dest || namedDest; } |
171 | |
172 | // Accessors. |
173 | LinkActionKind getKind() const override { return actionGoTo; } |
174 | const LinkDest *getDest() const { return dest.get(); } |
175 | const GooString *getNamedDest() const { return namedDest.get(); } |
176 | |
177 | private: |
178 | std::unique_ptr<LinkDest> dest; // regular destination (nullptr for remote |
179 | // link with bad destination) |
180 | std::unique_ptr<GooString> namedDest; // named destination (only one of dest and |
181 | // and namedDest may be non-nullptr) |
182 | }; |
183 | |
184 | //------------------------------------------------------------------------ |
185 | // LinkGoToR |
186 | //------------------------------------------------------------------------ |
187 | |
188 | class LinkGoToR : public LinkAction |
189 | { |
190 | public: |
191 | // Build a LinkGoToR from a file spec (dictionary) and destination |
192 | // (dictionary, name, or string). |
193 | LinkGoToR(Object *fileSpecObj, Object *destObj); |
194 | |
195 | ~LinkGoToR() override; |
196 | |
197 | // Was the LinkGoToR created successfully? |
198 | bool isOk() const override { return fileName && (dest || namedDest); } |
199 | |
200 | // Accessors. |
201 | LinkActionKind getKind() const override { return actionGoToR; } |
202 | const GooString *getFileName() const { return fileName.get(); } |
203 | const LinkDest *getDest() const { return dest.get(); } |
204 | const GooString *getNamedDest() const { return namedDest.get(); } |
205 | |
206 | private: |
207 | std::unique_ptr<GooString> fileName; // file name |
208 | std::unique_ptr<LinkDest> dest; // regular destination (nullptr for remote |
209 | // link with bad destination) |
210 | std::unique_ptr<GooString> namedDest; // named destination (only one of dest and |
211 | // and namedDest may be non-nullptr) |
212 | }; |
213 | |
214 | //------------------------------------------------------------------------ |
215 | // LinkLaunch |
216 | //------------------------------------------------------------------------ |
217 | |
218 | class LinkLaunch : public LinkAction |
219 | { |
220 | public: |
221 | // Build a LinkLaunch from an action dictionary. |
222 | explicit LinkLaunch(const Object *actionObj); |
223 | ~LinkLaunch() override; |
224 | |
225 | // Was the LinkLaunch created successfully? |
226 | bool isOk() const override { return fileName != nullptr; } |
227 | |
228 | // Accessors. |
229 | LinkActionKind getKind() const override { return actionLaunch; } |
230 | const GooString *getFileName() const { return fileName.get(); } |
231 | const GooString *getParams() const { return params.get(); } |
232 | |
233 | private: |
234 | std::unique_ptr<GooString> fileName; // file name |
235 | std::unique_ptr<GooString> params; // parameters |
236 | }; |
237 | |
238 | //------------------------------------------------------------------------ |
239 | // LinkURI |
240 | //------------------------------------------------------------------------ |
241 | |
242 | class POPPLER_PRIVATE_EXPORT LinkURI : public LinkAction |
243 | { |
244 | public: |
245 | // Build a LinkURI given the URI (string) and base URI. |
246 | LinkURI(const Object *uriObj, const std::optional<std::string> &baseURI); |
247 | |
248 | ~LinkURI() override; |
249 | |
250 | // Was the LinkURI created successfully? |
251 | bool isOk() const override { return hasURIFlag; } |
252 | |
253 | // Accessors. |
254 | LinkActionKind getKind() const override { return actionURI; } |
255 | const std::string &getURI() const { return uri; } |
256 | |
257 | private: |
258 | std::string uri; // the URI |
259 | bool hasURIFlag; |
260 | }; |
261 | |
262 | //------------------------------------------------------------------------ |
263 | // LinkNamed |
264 | //------------------------------------------------------------------------ |
265 | |
266 | class LinkNamed : public LinkAction |
267 | { |
268 | public: |
269 | // Build a LinkNamed given the action name. |
270 | explicit LinkNamed(const Object *nameObj); |
271 | |
272 | ~LinkNamed() override; |
273 | |
274 | bool isOk() const override { return hasNameFlag; } |
275 | |
276 | LinkActionKind getKind() const override { return actionNamed; } |
277 | const std::string &getName() const { return name; } |
278 | |
279 | private: |
280 | std::string name; |
281 | bool hasNameFlag; |
282 | }; |
283 | |
284 | //------------------------------------------------------------------------ |
285 | // LinkMovie |
286 | //------------------------------------------------------------------------ |
287 | |
288 | class LinkMovie : public LinkAction |
289 | { |
290 | public: |
291 | enum OperationType |
292 | { |
293 | operationTypePlay, |
294 | operationTypePause, |
295 | operationTypeResume, |
296 | operationTypeStop |
297 | }; |
298 | |
299 | explicit LinkMovie(const Object *obj); |
300 | |
301 | ~LinkMovie() override; |
302 | |
303 | bool isOk() const override { return hasAnnotRef() || hasAnnotTitleFlag; } |
304 | LinkActionKind getKind() const override { return actionMovie; } |
305 | |
306 | // a movie action stores either an indirect reference to a movie annotation |
307 | // or the movie annotation title |
308 | |
309 | bool hasAnnotRef() const { return annotRef != Ref::INVALID(); } |
310 | bool hasAnnotTitle() const { return hasAnnotTitleFlag; } |
311 | const Ref *getAnnotRef() const { return &annotRef; } |
312 | const std::string &getAnnotTitle() const { return annotTitle; } |
313 | |
314 | OperationType getOperation() const { return operation; } |
315 | |
316 | private: |
317 | Ref annotRef; // Annotation |
318 | std::string annotTitle; // T |
319 | bool hasAnnotTitleFlag; |
320 | |
321 | OperationType operation; // Operation |
322 | }; |
323 | |
324 | //------------------------------------------------------------------------ |
325 | // LinkRendition |
326 | //------------------------------------------------------------------------ |
327 | |
328 | class LinkRendition : public LinkAction |
329 | { |
330 | public: |
331 | /** |
332 | * Describes the possible rendition operations. |
333 | */ |
334 | enum RenditionOperation |
335 | { |
336 | NoRendition, |
337 | PlayRendition, |
338 | StopRendition, |
339 | PauseRendition, |
340 | ResumeRendition |
341 | }; |
342 | |
343 | explicit LinkRendition(const Object *Obj); |
344 | |
345 | ~LinkRendition() override; |
346 | |
347 | bool isOk() const override { return true; } |
348 | |
349 | LinkActionKind getKind() const override { return actionRendition; } |
350 | |
351 | bool hasScreenAnnot() const { return screenRef != Ref::INVALID(); } |
352 | Ref getScreenAnnot() const { return screenRef; } |
353 | |
354 | RenditionOperation getOperation() const { return operation; } |
355 | |
356 | const MediaRendition *getMedia() const { return media; } |
357 | |
358 | const std::string &getScript() const { return js; } |
359 | |
360 | private: |
361 | Ref screenRef; |
362 | RenditionOperation operation; |
363 | |
364 | MediaRendition *media; |
365 | |
366 | std::string js; |
367 | }; |
368 | |
369 | //------------------------------------------------------------------------ |
370 | // LinkSound |
371 | //------------------------------------------------------------------------ |
372 | |
373 | class LinkSound : public LinkAction |
374 | { |
375 | public: |
376 | explicit LinkSound(const Object *soundObj); |
377 | |
378 | ~LinkSound() override; |
379 | |
380 | bool isOk() const override { return sound != nullptr; } |
381 | |
382 | LinkActionKind getKind() const override { return actionSound; } |
383 | |
384 | double getVolume() const { return volume; } |
385 | bool getSynchronous() const { return sync; } |
386 | bool getRepeat() const { return repeat; } |
387 | bool getMix() const { return mix; } |
388 | Sound *getSound() const { return sound.get(); } |
389 | |
390 | private: |
391 | double volume; |
392 | bool sync; |
393 | bool repeat; |
394 | bool mix; |
395 | std::unique_ptr<Sound> sound; |
396 | }; |
397 | |
398 | //------------------------------------------------------------------------ |
399 | // LinkJavaScript |
400 | //------------------------------------------------------------------------ |
401 | |
402 | class LinkJavaScript : public LinkAction |
403 | { |
404 | public: |
405 | // Build a LinkJavaScript given the action name. |
406 | explicit LinkJavaScript(Object *jsObj); |
407 | |
408 | ~LinkJavaScript() override; |
409 | |
410 | bool isOk() const override { return isValid; } |
411 | |
412 | LinkActionKind getKind() const override { return actionJavaScript; } |
413 | const std::string &getScript() const { return js; } |
414 | |
415 | static Object createObject(XRef *xref, const std::string &js); |
416 | |
417 | private: |
418 | std::string js; |
419 | bool isValid; |
420 | }; |
421 | |
422 | //------------------------------------------------------------------------ |
423 | // LinkOCGState |
424 | //------------------------------------------------------------------------ |
425 | class LinkOCGState : public LinkAction |
426 | { |
427 | public: |
428 | explicit LinkOCGState(const Object *obj); |
429 | |
430 | ~LinkOCGState() override; |
431 | |
432 | bool isOk() const override { return isValid; } |
433 | |
434 | LinkActionKind getKind() const override { return actionOCGState; } |
435 | |
436 | enum State |
437 | { |
438 | On, |
439 | Off, |
440 | Toggle |
441 | }; |
442 | struct StateList |
443 | { |
444 | StateList() = default; |
445 | ~StateList() = default; |
446 | State st; |
447 | std::vector<Ref> list; |
448 | }; |
449 | |
450 | const std::vector<StateList> &getStateList() const { return stateList; } |
451 | bool getPreserveRB() const { return preserveRB; } |
452 | |
453 | private: |
454 | std::vector<StateList> stateList; |
455 | bool isValid; |
456 | bool preserveRB; |
457 | }; |
458 | |
459 | //------------------------------------------------------------------------ |
460 | // LinkHide |
461 | //------------------------------------------------------------------------ |
462 | |
463 | class LinkHide : public LinkAction |
464 | { |
465 | public: |
466 | explicit LinkHide(const Object *hideObj); |
467 | |
468 | ~LinkHide() override; |
469 | |
470 | bool isOk() const override { return hasTargetNameFlag; } |
471 | LinkActionKind getKind() const override { return actionHide; } |
472 | |
473 | // According to spec the target can be either: |
474 | // a) A text string containing the fully qualified name of the target |
475 | // field. |
476 | // b) An indirect reference to an annotation dictionary. |
477 | // c) An array of "such dictionaries or text strings". |
478 | // |
479 | // While b / c appear to be very uncommon and can't easily be |
480 | // created with Adobe Acrobat DC. So only support hide |
481 | // actions with named targets (yet). |
482 | bool hasTargetName() const { return hasTargetNameFlag; } |
483 | const std::string &getTargetName() const { return targetName; } |
484 | |
485 | // Should this action show or hide. |
486 | bool isShowAction() const { return show; } |
487 | |
488 | private: |
489 | bool hasTargetNameFlag; |
490 | std::string targetName; |
491 | bool show; |
492 | }; |
493 | |
494 | //------------------------------------------------------------------------ |
495 | // LinkResetForm |
496 | //------------------------------------------------------------------------ |
497 | |
498 | class POPPLER_PRIVATE_EXPORT LinkResetForm : public LinkAction |
499 | { |
500 | public: |
501 | // Build a LinkResetForm. |
502 | explicit LinkResetForm(const Object *nameObj); |
503 | |
504 | ~LinkResetForm() override; |
505 | |
506 | bool isOk() const override { return true; } |
507 | |
508 | LinkActionKind getKind() const override { return actionResetForm; } |
509 | |
510 | const std::vector<std::string> &getFields() const { return fields; } |
511 | bool getExclude() const { return exclude; } |
512 | |
513 | private: |
514 | std::vector<std::string> fields; |
515 | bool exclude; |
516 | }; |
517 | |
518 | //------------------------------------------------------------------------ |
519 | // LinkUnknown |
520 | //------------------------------------------------------------------------ |
521 | |
522 | class LinkUnknown : public LinkAction |
523 | { |
524 | public: |
525 | // Build a LinkUnknown with the specified action type. |
526 | explicit LinkUnknown(const char *actionA); |
527 | |
528 | ~LinkUnknown() override; |
529 | |
530 | // Was the LinkUnknown create successfully? |
531 | // Yes: nothing can go wrong when creating LinkUnknown objects |
532 | bool isOk() const override { return true; } |
533 | |
534 | // Accessors. |
535 | LinkActionKind getKind() const override { return actionUnknown; } |
536 | const std::string &getAction() const { return action; } |
537 | |
538 | private: |
539 | std::string action; // action subtype |
540 | }; |
541 | |
542 | //------------------------------------------------------------------------ |
543 | // Links |
544 | //------------------------------------------------------------------------ |
545 | |
546 | class POPPLER_PRIVATE_EXPORT Links |
547 | { |
548 | public: |
549 | // Extract links from array of annotations. |
550 | explicit Links(Annots *annots); |
551 | |
552 | // Destructor. |
553 | ~Links(); |
554 | |
555 | Links(const Links &) = delete; |
556 | Links &operator=(const Links &) = delete; |
557 | |
558 | const std::vector<AnnotLink *> &getLinks() const { return links; } |
559 | |
560 | private: |
561 | std::vector<AnnotLink *> links; |
562 | }; |
563 | |
564 | #endif |
565 | |