sinc with TL rev. 38618.
[luatex.git] / source / libs / poppler / poppler-0.37.0 / poppler / Link.cc
blob4ab5f52cedabe1174830ced237b0cb7a3ac0caa4
1 //========================================================================
2 //
3 // Link.cc
4 //
5 // Copyright 1996-2003 Glyph & Cog, LLC
6 //
7 //========================================================================
9 //========================================================================
11 // Modified under the Poppler project - http://poppler.freedesktop.org
13 // All changes made under the Poppler project to this file are licensed
14 // under GPL version 2 or later
16 // Copyright (C) 2006, 2008 Pino Toscano <pino@kde.org>
17 // Copyright (C) 2007, 2010, 2011 Carlos Garcia Campos <carlosgc@gnome.org>
18 // Copyright (C) 2008 Hugo Mercier <hmercier31@gmail.com>
19 // Copyright (C) 2008-2010, 2012-2014 Albert Astals Cid <aacid@kde.org>
20 // Copyright (C) 2009 Kovid Goyal <kovid@kovidgoyal.net>
21 // Copyright (C) 2009 Ilya Gorenbein <igorenbein@finjan.com>
22 // Copyright (C) 2012 Tobias Koening <tobias.koenig@kdab.com>
24 // To see a description of the changes please see the Changelog file that
25 // came with your tarball or type make ChangeLog if you are building from git
27 //========================================================================
29 #include <config.h>
31 #ifdef USE_GCC_PRAGMAS
32 #pragma implementation
33 #endif
35 #include <stddef.h>
36 #include <string.h>
37 #include "goo/gmem.h"
38 #include "goo/GooString.h"
39 #include "goo/GooList.h"
40 #include "Error.h"
41 #include "Object.h"
42 #include "Array.h"
43 #include "Dict.h"
44 #include "Link.h"
45 #include "Sound.h"
46 #include "FileSpec.h"
47 #include "Rendition.h"
48 #include "Annot.h"
50 //------------------------------------------------------------------------
51 // LinkAction
52 //------------------------------------------------------------------------
54 LinkAction *LinkAction::parseDest(Object *obj) {
55 LinkAction *action;
57 action = new LinkGoTo(obj);
58 if (!action->isOk()) {
59 delete action;
60 return NULL;
62 return action;
65 LinkAction *LinkAction::parseAction(Object *obj, GooString *baseURI) {
66 LinkAction *action;
67 Object obj2, obj3, obj4;
69 if (!obj->isDict()) {
70 error(errSyntaxWarning, -1, "parseAction: Bad annotation action for URI '{0:s}'",
71 baseURI ? baseURI->getCString() : "NULL");
72 return NULL;
75 obj->dictLookup("S", &obj2);
77 // GoTo action
78 if (obj2.isName("GoTo")) {
79 obj->dictLookup("D", &obj3);
80 action = new LinkGoTo(&obj3);
81 obj3.free();
83 // GoToR action
84 } else if (obj2.isName("GoToR")) {
85 obj->dictLookup("F", &obj3);
86 obj->dictLookup("D", &obj4);
87 action = new LinkGoToR(&obj3, &obj4);
88 obj3.free();
89 obj4.free();
91 // Launch action
92 } else if (obj2.isName("Launch")) {
93 action = new LinkLaunch(obj);
95 // URI action
96 } else if (obj2.isName("URI")) {
97 obj->dictLookup("URI", &obj3);
98 action = new LinkURI(&obj3, baseURI);
99 obj3.free();
101 // Named action
102 } else if (obj2.isName("Named")) {
103 obj->dictLookup("N", &obj3);
104 action = new LinkNamed(&obj3);
105 obj3.free();
107 // Movie action
108 } else if (obj2.isName("Movie")) {
109 action = new LinkMovie(obj);
111 // Rendition action
112 } else if (obj2.isName("Rendition")) {
113 action = new LinkRendition(obj);
115 // Sound action
116 } else if (obj2.isName("Sound")) {
117 action = new LinkSound(obj);
119 // JavaScript action
120 } else if (obj2.isName("JavaScript")) {
121 obj->dictLookup("JS", &obj3);
122 action = new LinkJavaScript(&obj3);
123 obj3.free();
125 // Set-OCG-State action
126 } else if (obj2.isName("SetOCGState")) {
127 action = new LinkOCGState(obj);
129 // unknown action
130 } else if (obj2.isName()) {
131 action = new LinkUnknown(obj2.getName());
133 // action is missing or wrong type
134 } else {
135 error(errSyntaxWarning, -1, "parseAction: Unknown annotation action object: URI = '{0:s}'",
136 baseURI ? baseURI->getCString() : "NULL");
137 action = NULL;
140 obj2.free();
142 if (action && !action->isOk()) {
143 delete action;
144 return NULL;
146 return action;
149 //------------------------------------------------------------------------
150 // LinkDest
151 //------------------------------------------------------------------------
153 LinkDest::LinkDest(Array *a) {
154 Object obj1, obj2;
156 // initialize fields
157 left = bottom = right = top = zoom = 0;
158 changeLeft = changeTop = changeZoom = gFalse;
159 ok = gFalse;
161 // get page
162 if (a->getLength() < 2) {
163 error(errSyntaxWarning, -1, "Annotation destination array is too short");
164 return;
166 a->getNF(0, &obj1);
167 if (obj1.isInt()) {
168 pageNum = obj1.getInt() + 1;
169 pageIsRef = gFalse;
170 } else if (obj1.isRef()) {
171 pageRef.num = obj1.getRefNum();
172 pageRef.gen = obj1.getRefGen();
173 pageIsRef = gTrue;
174 } else {
175 error(errSyntaxWarning, -1, "Bad annotation destination");
176 goto err2;
178 obj1.free();
180 // get destination type
181 a->get(1, &obj1);
183 // XYZ link
184 if (obj1.isName("XYZ")) {
185 kind = destXYZ;
186 if (a->getLength() < 3) {
187 changeLeft = gFalse;
188 } else {
189 a->get(2, &obj2);
190 if (obj2.isNull()) {
191 changeLeft = gFalse;
192 } else if (obj2.isNum()) {
193 changeLeft = gTrue;
194 left = obj2.getNum();
195 } else {
196 error(errSyntaxWarning, -1, "Bad annotation destination position");
197 goto err1;
199 obj2.free();
201 if (a->getLength() < 4) {
202 changeTop = gFalse;
203 } else {
204 a->get(3, &obj2);
205 if (obj2.isNull()) {
206 changeTop = gFalse;
207 } else if (obj2.isNum()) {
208 changeTop = gTrue;
209 top = obj2.getNum();
210 } else {
211 error(errSyntaxWarning, -1, "Bad annotation destination position");
212 goto err1;
214 obj2.free();
216 if (a->getLength() < 5) {
217 changeZoom = gFalse;
218 } else {
219 a->get(4, &obj2);
220 if (obj2.isNull()) {
221 changeZoom = gFalse;
222 } else if (obj2.isNum()) {
223 zoom = obj2.getNum();
224 changeZoom = (zoom == 0) ? gFalse : gTrue;
225 } else {
226 error(errSyntaxWarning, -1, "Bad annotation destination position");
227 goto err1;
229 obj2.free();
232 // Fit link
233 } else if (obj1.isName("Fit")) {
234 if (a->getLength() < 2) {
235 error(errSyntaxWarning, -1, "Annotation destination array is too short");
236 goto err2;
238 kind = destFit;
240 // FitH link
241 } else if (obj1.isName("FitH")) {
242 if (a->getLength() < 3) {
243 error(errSyntaxWarning, -1, "Annotation destination array is too short");
244 goto err2;
246 kind = destFitH;
247 a->get(2, &obj2);
248 if (obj2.isNull()) {
249 changeTop = gFalse;
250 } else if (obj2.isNum()) {
251 changeTop = gTrue;
252 top = obj2.getNum();
253 } else {
254 error(errSyntaxWarning, -1, "Bad annotation destination position");
255 kind = destFit;
257 obj2.free();
259 // FitV link
260 } else if (obj1.isName("FitV")) {
261 if (a->getLength() < 3) {
262 error(errSyntaxWarning, -1, "Annotation destination array is too short");
263 goto err2;
265 kind = destFitV;
266 a->get(2, &obj2);
267 if (obj2.isNull()) {
268 changeLeft = gFalse;
269 } else if (obj2.isNum()) {
270 changeLeft = gTrue;
271 left = obj2.getNum();
272 } else {
273 error(errSyntaxWarning, -1, "Bad annotation destination position");
274 kind = destFit;
276 obj2.free();
278 // FitR link
279 } else if (obj1.isName("FitR")) {
280 if (a->getLength() < 6) {
281 error(errSyntaxWarning, -1, "Annotation destination array is too short");
282 goto err2;
284 kind = destFitR;
285 if (a->get(2, &obj2)->isNum()) {
286 left = obj2.getNum();
287 } else {
288 error(errSyntaxWarning, -1, "Bad annotation destination position");
289 kind = destFit;
291 obj2.free();
292 if (a->get(3, &obj2)->isNum()) {
293 bottom = obj2.getNum();
294 } else {
295 error(errSyntaxWarning, -1, "Bad annotation destination position");
296 kind = destFit;
298 obj2.free();
299 if (a->get(4, &obj2)->isNum()) {
300 right = obj2.getNum();
301 } else {
302 error(errSyntaxWarning, -1, "Bad annotation destination position");
303 kind = destFit;
305 obj2.free();
306 if (a->get(5, &obj2)->isNum()) {
307 top = obj2.getNum();
308 } else {
309 error(errSyntaxWarning, -1, "Bad annotation destination position");
310 kind = destFit;
312 obj2.free();
314 // FitB link
315 } else if (obj1.isName("FitB")) {
316 if (a->getLength() < 2) {
317 error(errSyntaxWarning, -1, "Annotation destination array is too short");
318 goto err2;
320 kind = destFitB;
322 // FitBH link
323 } else if (obj1.isName("FitBH")) {
324 if (a->getLength() < 3) {
325 error(errSyntaxWarning, -1, "Annotation destination array is too short");
326 goto err2;
328 kind = destFitBH;
329 a->get(2, &obj2);
330 if (obj2.isNull()) {
331 changeTop = gFalse;
332 } else if (obj2.isNum()) {
333 changeTop = gTrue;
334 top = obj2.getNum();
335 } else {
336 error(errSyntaxWarning, -1, "Bad annotation destination position");
337 kind = destFit;
339 obj2.free();
341 // FitBV link
342 } else if (obj1.isName("FitBV")) {
343 if (a->getLength() < 3) {
344 error(errSyntaxWarning, -1, "Annotation destination array is too short");
345 goto err2;
347 kind = destFitBV;
348 a->get(2, &obj2);
349 if (obj2.isNull()) {
350 changeLeft = gFalse;
351 } else if (obj2.isNum()) {
352 changeLeft = gTrue;
353 left = obj2.getNum();
354 } else {
355 error(errSyntaxWarning, -1, "Bad annotation destination position");
356 kind = destFit;
358 obj2.free();
360 // unknown link kind
361 } else {
362 error(errSyntaxWarning, -1, "Unknown annotation destination type");
363 goto err2;
366 obj1.free();
367 ok = gTrue;
368 return;
370 err1:
371 obj2.free();
372 err2:
373 obj1.free();
376 LinkDest::LinkDest(LinkDest *dest) {
377 kind = dest->kind;
378 pageIsRef = dest->pageIsRef;
379 if (pageIsRef)
380 pageRef = dest->pageRef;
381 else
382 pageNum = dest->pageNum;
383 left = dest->left;
384 bottom = dest->bottom;
385 right = dest->right;
386 top = dest->top;
387 zoom = dest->zoom;
388 changeLeft = dest->changeLeft;
389 changeTop = dest->changeTop;
390 changeZoom = dest->changeZoom;
391 ok = gTrue;
394 //------------------------------------------------------------------------
395 // LinkGoTo
396 //------------------------------------------------------------------------
398 LinkGoTo::LinkGoTo(Object *destObj) {
399 dest = NULL;
400 namedDest = NULL;
402 // named destination
403 if (destObj->isName()) {
404 namedDest = new GooString(destObj->getName());
405 } else if (destObj->isString()) {
406 namedDest = destObj->getString()->copy();
408 // destination dictionary
409 } else if (destObj->isArray()) {
410 dest = new LinkDest(destObj->getArray());
411 if (!dest->isOk()) {
412 delete dest;
413 dest = NULL;
416 // error
417 } else {
418 error(errSyntaxWarning, -1, "Illegal annotation destination");
422 LinkGoTo::~LinkGoTo() {
423 if (dest)
424 delete dest;
425 if (namedDest)
426 delete namedDest;
429 //------------------------------------------------------------------------
430 // LinkGoToR
431 //------------------------------------------------------------------------
433 LinkGoToR::LinkGoToR(Object *fileSpecObj, Object *destObj) {
434 fileName = NULL;
435 dest = NULL;
436 namedDest = NULL;
438 // get file name
439 Object obj1;
440 if (getFileSpecNameForPlatform (fileSpecObj, &obj1)) {
441 fileName = obj1.getString()->copy();
442 obj1.free();
445 // named destination
446 if (destObj->isName()) {
447 namedDest = new GooString(destObj->getName());
448 } else if (destObj->isString()) {
449 namedDest = destObj->getString()->copy();
451 // destination dictionary
452 } else if (destObj->isArray()) {
453 dest = new LinkDest(destObj->getArray());
454 if (!dest->isOk()) {
455 delete dest;
456 dest = NULL;
459 // error
460 } else {
461 error(errSyntaxWarning, -1, "Illegal annotation destination");
465 LinkGoToR::~LinkGoToR() {
466 if (fileName)
467 delete fileName;
468 if (dest)
469 delete dest;
470 if (namedDest)
471 delete namedDest;
475 //------------------------------------------------------------------------
476 // LinkLaunch
477 //------------------------------------------------------------------------
479 LinkLaunch::LinkLaunch(Object *actionObj) {
480 Object obj1, obj2, obj3;
482 fileName = NULL;
483 params = NULL;
485 if (actionObj->isDict()) {
486 if (!actionObj->dictLookup("F", &obj1)->isNull()) {
487 if (getFileSpecNameForPlatform (&obj1, &obj3)) {
488 fileName = obj3.getString()->copy();
489 obj3.free();
491 } else {
492 obj1.free();
493 #ifdef _WIN32
494 if (actionObj->dictLookup("Win", &obj1)->isDict()) {
495 obj1.dictLookup("F", &obj2);
496 if (getFileSpecNameForPlatform (&obj2, &obj3)) {
497 fileName = obj3.getString()->copy();
498 obj3.free();
500 obj2.free();
501 if (obj1.dictLookup("P", &obj2)->isString()) {
502 params = obj2.getString()->copy();
504 obj2.free();
505 } else {
506 error(errSyntaxWarning, -1, "Bad launch-type link action");
508 #else
509 //~ This hasn't been defined by Adobe yet, so assume it looks
510 //~ just like the Win dictionary until they say otherwise.
511 if (actionObj->dictLookup("Unix", &obj1)->isDict()) {
512 obj1.dictLookup("F", &obj2);
513 if (getFileSpecNameForPlatform (&obj2, &obj3)) {
514 fileName = obj3.getString()->copy();
515 obj3.free();
517 obj2.free();
518 if (obj1.dictLookup("P", &obj2)->isString()) {
519 params = obj2.getString()->copy();
521 obj2.free();
522 } else {
523 error(errSyntaxWarning, -1, "Bad launch-type link action");
525 #endif
527 obj1.free();
531 LinkLaunch::~LinkLaunch() {
532 if (fileName)
533 delete fileName;
534 if (params)
535 delete params;
538 //------------------------------------------------------------------------
539 // LinkURI
540 //------------------------------------------------------------------------
542 LinkURI::LinkURI(Object *uriObj, GooString *baseURI) {
543 GooString *uri2;
544 int n;
545 char c;
547 uri = NULL;
548 if (uriObj->isString()) {
549 uri2 = uriObj->getString();
550 n = (int)strcspn(uri2->getCString(), "/:");
551 if (n < uri2->getLength() && uri2->getChar(n) == ':') {
552 // "http:..." etc.
553 uri = uri2->copy();
554 } else if (!uri2->cmpN("www.", 4)) {
555 // "www.[...]" without the leading "http://"
556 uri = new GooString("http://");
557 uri->append(uri2);
558 } else {
559 // relative URI
560 if (baseURI) {
561 uri = baseURI->copy();
562 if (uri->getLength() > 0) {
563 c = uri->getChar(uri->getLength() - 1);
564 if (c != '/' && c != '?') {
565 uri->append('/');
568 if (uri2->getChar(0) == '/') {
569 uri->append(uri2->getCString() + 1, uri2->getLength() - 1);
570 } else {
571 uri->append(uri2);
573 } else {
574 uri = uri2->copy();
577 } else {
578 error(errSyntaxWarning, -1, "Illegal URI-type link");
582 LinkURI::~LinkURI() {
583 if (uri)
584 delete uri;
587 //------------------------------------------------------------------------
588 // LinkNamed
589 //------------------------------------------------------------------------
591 LinkNamed::LinkNamed(Object *nameObj) {
592 name = NULL;
593 if (nameObj->isName()) {
594 name = new GooString(nameObj->getName());
598 LinkNamed::~LinkNamed() {
599 if (name) {
600 delete name;
604 //------------------------------------------------------------------------
605 // LinkMovie
606 //------------------------------------------------------------------------
608 LinkMovie::LinkMovie(Object *obj) {
609 annotRef.num = -1;
610 annotTitle = NULL;
612 Object tmp;
613 if (obj->dictLookupNF("Annotation", &tmp)->isRef()) {
614 annotRef = tmp.getRef();
616 tmp.free();
618 if (obj->dictLookup("T", &tmp)->isString()) {
619 annotTitle = tmp.getString()->copy();
621 tmp.free();
623 if ((annotTitle == NULL) && (annotRef.num == -1)) {
624 error(errSyntaxError, -1,
625 "Movie action is missing both the Annot and T keys");
628 if (obj->dictLookup("Operation", &tmp)->isName()) {
629 char *name = tmp.getName();
631 if (!strcmp(name, "Play")) {
632 operation = operationTypePlay;
634 else if (!strcmp(name, "Stop")) {
635 operation = operationTypeStop;
637 else if (!strcmp(name, "Pause")) {
638 operation = operationTypePause;
640 else if (!strcmp(name, "Resume")) {
641 operation = operationTypeResume;
644 tmp.free();
647 LinkMovie::~LinkMovie() {
648 if (annotTitle) {
649 delete annotTitle;
653 //------------------------------------------------------------------------
654 // LinkSound
655 //------------------------------------------------------------------------
657 LinkSound::LinkSound(Object *soundObj) {
658 volume = 1.0;
659 sync = gFalse;
660 repeat = gFalse;
661 mix = gFalse;
662 sound = NULL;
663 if (soundObj->isDict())
665 Object tmp;
666 // volume
667 soundObj->dictLookup("Volume", &tmp);
668 if (tmp.isNum()) {
669 volume = tmp.getNum();
671 tmp.free();
672 // sync
673 soundObj->dictLookup("Synchronous", &tmp);
674 if (tmp.isBool()) {
675 sync = tmp.getBool();
677 tmp.free();
678 // repeat
679 soundObj->dictLookup("Repeat", &tmp);
680 if (tmp.isBool()) {
681 repeat = tmp.getBool();
683 tmp.free();
684 // mix
685 soundObj->dictLookup("Mix", &tmp);
686 if (tmp.isBool()) {
687 mix = tmp.getBool();
689 tmp.free();
690 // 'Sound' object
691 soundObj->dictLookup("Sound", &tmp);
692 sound = Sound::parseSound(&tmp);
693 tmp.free();
697 LinkSound::~LinkSound() {
698 delete sound;
701 //------------------------------------------------------------------------
702 // LinkRendition
703 //------------------------------------------------------------------------
705 LinkRendition::LinkRendition(Object *obj) {
706 operation = NoRendition;
707 media = NULL;
708 js = NULL;
709 int operationCode = -1;
711 if (obj->isDict()) {
712 Object tmp;
714 if (!obj->dictLookup("JS", &tmp)->isNull()) {
715 if (tmp.isString()) {
716 js = new GooString(tmp.getString());
717 } else if (tmp.isStream()) {
718 Stream *stream = tmp.getStream();
719 js = new GooString();
720 stream->fillGooString(js);
721 } else {
722 error(errSyntaxWarning, -1, "Invalid Rendition Action: JS not string or stream");
725 tmp.free();
727 if (obj->dictLookup("OP", &tmp)->isInt()) {
728 operationCode = tmp.getInt();
729 if (!js && (operationCode < 0 || operationCode > 4)) {
730 error(errSyntaxWarning, -1, "Invalid Rendition Action: unrecognized operation valued: {0:d}", operationCode);
731 } else {
732 Object obj1;
734 // retrieve rendition object
735 if (obj->dictLookup("R", &renditionObj)->isDict()) {
736 media = new MediaRendition(&renditionObj);
737 } else if (operationCode == 0 || operationCode == 4) {
738 error(errSyntaxWarning, -1, "Invalid Rendition Action: no R field with op = {0:d}", operationCode);
739 renditionObj.free();
742 if (!obj->dictLookupNF("AN", &screenRef)->isRef() && operation >= 0 && operation <= 4) {
743 error(errSyntaxWarning, -1, "Invalid Rendition Action: no AN field with op = {0:d}", operationCode);
744 screenRef.free();
748 switch (operationCode) {
749 case 0:
750 operation = PlayRendition;
751 break;
752 case 1:
753 operation = StopRendition;
754 break;
755 case 2:
756 operation = PauseRendition;
757 break;
758 case 3:
759 operation = ResumeRendition;
760 break;
761 case 4:
762 operation = PlayRendition;
763 break;
765 } else if (!js) {
766 error(errSyntaxWarning, -1, "Invalid Rendition action: no OP or JS field defined");
768 tmp.free();
772 LinkRendition::~LinkRendition() {
773 renditionObj.free();
774 screenRef.free();
776 if (js)
777 delete js;
778 if (media)
779 delete media;
783 //------------------------------------------------------------------------
784 // LinkJavaScript
785 //------------------------------------------------------------------------
787 LinkJavaScript::LinkJavaScript(Object *jsObj) {
788 js = NULL;
790 if (jsObj->isString()) {
791 js = new GooString(jsObj->getString());
793 else if (jsObj->isStream()) {
794 Stream *stream = jsObj->getStream();
795 js = new GooString();
796 stream->fillGooString(js);
800 LinkJavaScript::~LinkJavaScript() {
801 if (js) {
802 delete js;
806 //------------------------------------------------------------------------
807 // LinkOCGState
808 //------------------------------------------------------------------------
809 LinkOCGState::LinkOCGState(Object *obj) {
810 Object obj1;
812 stateList = new GooList();
813 preserveRB = gTrue;
815 if (obj->dictLookup("State", &obj1)->isArray()) {
816 StateList *stList = NULL;
818 for (int i = 0; i < obj1.arrayGetLength(); ++i) {
819 Object obj2;
821 obj1.arrayGetNF(i, &obj2);
822 if (obj2.isName()) {
823 if (stList)
824 stateList->append(stList);
826 char *name = obj2.getName();
827 stList = new StateList();
828 stList->list = new GooList();
829 if (!strcmp (name, "ON")) {
830 stList->st = On;
831 } else if (!strcmp (name, "OFF")) {
832 stList->st = Off;
833 } else if (!strcmp (name, "Toggle")) {
834 stList->st = Toggle;
835 } else {
836 error(errSyntaxWarning, -1, "Invalid name '{0:s}' in OCG Action state array", name);
837 delete stList;
838 stList = NULL;
840 } else if (obj2.isRef()) {
841 if (stList) {
842 Ref ocgRef = obj2.getRef();
843 Ref *item = new Ref();
844 item->num = ocgRef.num;
845 item->gen = ocgRef.gen;
846 stList->list->append(item);
847 } else {
848 error(errSyntaxWarning, -1, "Invalid OCG Action State array, expected name instead of ref");
850 } else {
851 error(errSyntaxWarning, -1, "Invalid item in OCG Action State array");
853 obj2.free();
855 // Add the last group
856 if (stList)
857 stateList->append(stList);
858 } else {
859 error(errSyntaxWarning, -1, "Invalid OCGState action");
860 delete stateList;
861 stateList = NULL;
863 obj1.free();
865 if (obj->dictLookup("PreserveRB", &obj1)->isBool()) {
866 preserveRB = obj1.getBool();
868 obj1.free();
871 LinkOCGState::~LinkOCGState() {
872 if (stateList)
873 deleteGooList(stateList, StateList);
876 LinkOCGState::StateList::~StateList() {
877 if (list)
878 deleteGooList(list, Ref);
881 //------------------------------------------------------------------------
882 // LinkUnknown
883 //------------------------------------------------------------------------
885 LinkUnknown::LinkUnknown(char *actionA) {
886 action = new GooString(actionA);
889 LinkUnknown::~LinkUnknown() {
890 delete action;
893 //------------------------------------------------------------------------
894 // Links
895 //------------------------------------------------------------------------
897 Links::Links(Annots *annots) {
898 int size;
899 int i;
901 links = NULL;
902 size = 0;
903 numLinks = 0;
905 if (!annots)
906 return;
908 for (i = 0; i < annots->getNumAnnots(); ++i) {
909 Annot *annot = annots->getAnnot(i);
911 if (annot->getType() != Annot::typeLink)
912 continue;
914 if (numLinks >= size) {
915 size += 16;
916 links = (AnnotLink **)greallocn(links, size, sizeof(AnnotLink *));
918 annot->incRefCnt();
919 links[numLinks++] = static_cast<AnnotLink *>(annot);
923 Links::~Links() {
924 int i;
926 for (i = 0; i < numLinks; ++i)
927 links[i]->decRefCnt();
929 gfree(links);
932 LinkAction *Links::find(double x, double y) const {
933 int i;
935 for (i = numLinks - 1; i >= 0; --i) {
936 if (links[i]->inRect(x, y)) {
937 return links[i]->getAction();
940 return NULL;
943 GBool Links::onLink(double x, double y) const {
944 int i;
946 for (i = 0; i < numLinks; ++i) {
947 if (links[i]->inRect(x, y))
948 return gTrue;
950 return gFalse;