source: trunk/poppler/mypoppler/poppler/Link.cc @ 277

Last change on this file since 277 was 277, checked in by rbri, 12 years ago

PDF plugin: Poppler library updated to version 0.12.3

File size: 20.3 KB
Line 
1//========================================================================
2//
3// Link.cc
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) 2007 Carlos Garcia Campos <carlosgc@gnome.org>
18// Copyright (C) 2008 Hugo Mercier <hmercier31@gmail.com>
19// Copyright (C) 2008, 2009 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//
23// To see a description of the changes please see the Changelog file that
24// came with your tarball or type make ChangeLog if you are building from git
25//
26//========================================================================
27
28#include <config.h>
29
30#ifdef USE_GCC_PRAGMAS
31#pragma implementation
32#endif
33
34#include <stddef.h>
35#include <string.h>
36#include "goo/gmem.h"
37#include "goo/GooString.h"
38#include "Error.h"
39#include "Object.h"
40#include "Array.h"
41#include "Dict.h"
42#include "Link.h"
43#include "Sound.h"
44#include "Movie.h"
45#include "FileSpec.h"
46
47//------------------------------------------------------------------------
48// LinkAction
49//------------------------------------------------------------------------
50
51LinkAction *LinkAction::parseDest(Object *obj) {
52  LinkAction *action;
53
54  action = new LinkGoTo(obj);
55  if (!action->isOk()) {
56    delete action;
57    return NULL;
58  }
59  return action;
60}
61
62LinkAction *LinkAction::parseAction(Object *obj, GooString *baseURI) {
63  LinkAction *action;
64  Object obj2, obj3, obj4;
65
66  if (!obj->isDict()) {
67      error(-1, "parseAction: Bad annotation action for URI '%s'",
68            baseURI ? baseURI->getCString() : "NULL");
69      return NULL;
70  }
71
72  obj->dictLookup("S", &obj2);
73
74  // GoTo action
75  if (obj2.isName("GoTo")) {
76    obj->dictLookup("D", &obj3);
77    action = new LinkGoTo(&obj3);
78    obj3.free();
79
80  // GoToR action
81  } else if (obj2.isName("GoToR")) {
82    obj->dictLookup("F", &obj3);
83    obj->dictLookup("D", &obj4);
84    action = new LinkGoToR(&obj3, &obj4);
85    obj3.free();
86    obj4.free();
87
88  // Launch action
89  } else if (obj2.isName("Launch")) {
90    action = new LinkLaunch(obj);
91
92  // URI action
93  } else if (obj2.isName("URI")) {
94    obj->dictLookup("URI", &obj3);
95    action = new LinkURI(&obj3, baseURI);
96    obj3.free();
97
98  // Named action
99  } else if (obj2.isName("Named")) {
100    obj->dictLookup("N", &obj3);
101    action = new LinkNamed(&obj3);
102    obj3.free();
103
104  // Movie action
105  } else if (obj2.isName("Movie")) {
106    action = new LinkMovie(obj);
107
108  // Rendition action
109  } else if (obj2.isName("Rendition")) {
110    action = new LinkRendition(obj);
111
112  // Sound action
113  } else if (obj2.isName("Sound")) {
114    action = new LinkSound(obj);
115
116  // JavaScript action
117  } else if (obj2.isName("JavaScript")) {
118    obj->dictLookup("JS", &obj3);
119    action = new LinkJavaScript(&obj3);
120    obj3.free();
121
122  // unknown action
123  } else if (obj2.isName()) {
124    action = new LinkUnknown(obj2.getName());
125
126  // action is missing or wrong type
127  } else {
128    error(-1, "parseAction: Unknown annotation action object: URI = '%s'",
129          baseURI ? baseURI->getCString() : "NULL");
130    action = NULL;
131  }
132
133  obj2.free();
134
135  if (action && !action->isOk()) {
136    delete action;
137    return NULL;
138  }
139  return action;
140}
141
142//------------------------------------------------------------------------
143// LinkDest
144//------------------------------------------------------------------------
145
146LinkDest::LinkDest(Array *a) {
147  Object obj1, obj2;
148
149  // initialize fields
150  left = bottom = right = top = zoom = 0;
151  changeLeft = changeTop = changeZoom = gFalse;
152  ok = gFalse;
153
154  // get page
155  if (a->getLength() < 2) {
156    error(-1, "Annotation destination array is too short");
157    return;
158  }
159  a->getNF(0, &obj1);
160  if (obj1.isInt()) {
161    pageNum = obj1.getInt() + 1;
162    pageIsRef = gFalse;
163  } else if (obj1.isRef()) {
164    pageRef.num = obj1.getRefNum();
165    pageRef.gen = obj1.getRefGen();
166    pageIsRef = gTrue;
167  } else {
168    error(-1, "Bad annotation destination");
169    goto err2;
170  }
171  obj1.free();
172
173  // get destination type
174  a->get(1, &obj1);
175
176  // XYZ link
177  if (obj1.isName("XYZ")) {
178    kind = destXYZ;
179    if (a->getLength() < 3) {
180      changeLeft = gFalse;
181    } else {
182      a->get(2, &obj2);
183      if (obj2.isNull()) {
184        changeLeft = gFalse;
185      } else if (obj2.isNum()) {
186        changeLeft = gTrue;
187        left = obj2.getNum();
188      } else {
189        error(-1, "Bad annotation destination position");
190        goto err1;
191      }
192      obj2.free();
193    }
194    if (a->getLength() < 4) {
195      changeTop = gFalse;
196    } else {
197      a->get(3, &obj2);
198      if (obj2.isNull()) {
199        changeTop = gFalse;
200      } else if (obj2.isNum()) {
201        changeTop = gTrue;
202        top = obj2.getNum();
203      } else {
204        error(-1, "Bad annotation destination position");
205        goto err1;
206      }
207      obj2.free();
208    }
209    if (a->getLength() < 5) {
210      changeZoom = gFalse;
211    } else {
212      a->get(4, &obj2);
213      if (obj2.isNull()) {
214        changeZoom = gFalse;
215      } else if (obj2.isNum()) {
216        changeZoom = gTrue;
217        zoom = obj2.getNum();
218      } else {
219        error(-1, "Bad annotation destination position");
220        goto err1;
221      }
222      obj2.free();
223    }
224
225  // Fit link
226  } else if (obj1.isName("Fit")) {
227    if (a->getLength() < 2) {
228      error(-1, "Annotation destination array is too short");
229      goto err2;
230    }
231    kind = destFit;
232
233  // FitH link
234  } else if (obj1.isName("FitH")) {
235    if (a->getLength() < 3) {
236      error(-1, "Annotation destination array is too short");
237      goto err2;
238    }
239    kind = destFitH;
240    a->get(2, &obj2);
241    if (obj2.isNull()) {
242      changeTop = gFalse;
243    } else if (obj2.isNum()) {
244      changeTop = gTrue;
245      top = obj2.getNum();
246    } else {
247      error(-1, "Bad annotation destination position");
248      kind = destFit;
249    }
250    obj2.free();
251
252  // FitV link
253  } else if (obj1.isName("FitV")) {
254    if (a->getLength() < 3) {
255      error(-1, "Annotation destination array is too short");
256      goto err2;
257    }
258    kind = destFitV;
259    a->get(2, &obj2);
260    if (obj2.isNull()) {
261      changeLeft = gFalse;
262    } else if (obj2.isNum()) {
263      changeLeft = gTrue;
264      left = obj2.getNum();
265    } else {
266      error(-1, "Bad annotation destination position");
267      kind = destFit;
268    }
269    obj2.free();
270
271  // FitR link
272  } else if (obj1.isName("FitR")) {
273    if (a->getLength() < 6) {
274      error(-1, "Annotation destination array is too short");
275      goto err2;
276    }
277    kind = destFitR;
278    if (!a->get(2, &obj2)->isNum()) {
279      error(-1, "Bad annotation destination position");
280      kind = destFit;
281    }
282    left = obj2.getNum();
283    obj2.free();
284    if (!a->get(3, &obj2)->isNum()) {
285      error(-1, "Bad annotation destination position");
286      kind = destFit;
287    }
288    bottom = obj2.getNum();
289    obj2.free();
290    if (!a->get(4, &obj2)->isNum()) {
291      error(-1, "Bad annotation destination position");
292      kind = destFit;
293    }
294    right = obj2.getNum();
295    obj2.free();
296    if (!a->get(5, &obj2)->isNum()) {
297      error(-1, "Bad annotation destination position");
298      kind = destFit;
299    }
300    top = obj2.getNum();
301    obj2.free();
302
303  // FitB link
304  } else if (obj1.isName("FitB")) {
305    if (a->getLength() < 2) {
306      error(-1, "Annotation destination array is too short");
307      goto err2;
308    }
309    kind = destFitB;
310
311  // FitBH link
312  } else if (obj1.isName("FitBH")) {
313    if (a->getLength() < 3) {
314      error(-1, "Annotation destination array is too short");
315      goto err2;
316    }
317    kind = destFitBH;
318    a->get(2, &obj2);
319    if (obj2.isNull()) {
320      changeTop = gFalse;
321    } else if (obj2.isNum()) {
322      changeTop = gTrue;
323      top = obj2.getNum();
324    } else {
325      error(-1, "Bad annotation destination position");
326      kind = destFit;
327    }
328    obj2.free();
329
330  // FitBV link
331  } else if (obj1.isName("FitBV")) {
332    if (a->getLength() < 3) {
333      error(-1, "Annotation destination array is too short");
334      goto err2;
335    }
336    kind = destFitBV;
337    a->get(2, &obj2);
338    if (obj2.isNull()) {
339      changeLeft = gFalse;
340    } else if (obj2.isNum()) {
341      changeLeft = gTrue;
342      left = obj2.getNum();
343    } else {
344      error(-1, "Bad annotation destination position");
345      kind = destFit;
346    }
347    obj2.free();
348
349  // unknown link kind
350  } else {
351    error(-1, "Unknown annotation destination type");
352    goto err2;
353  }
354
355  obj1.free();
356  ok = gTrue;
357  return;
358
359 err1:
360  obj2.free();
361 err2:
362  obj1.free();
363}
364
365LinkDest::LinkDest(LinkDest *dest) {
366  kind = dest->kind;
367  pageIsRef = dest->pageIsRef;
368  if (pageIsRef)
369    pageRef = dest->pageRef;
370  else
371    pageNum = dest->pageNum;
372  left = dest->left;
373  bottom = dest->bottom;
374  right = dest->right;
375  top = dest->top;
376  zoom = dest->zoom;
377  changeLeft = dest->changeLeft;
378  changeTop = dest->changeTop;
379  changeZoom = dest->changeZoom;
380  ok = gTrue;
381}
382
383//------------------------------------------------------------------------
384// LinkGoTo
385//------------------------------------------------------------------------
386
387LinkGoTo::LinkGoTo(Object *destObj) {
388  dest = NULL;
389  namedDest = NULL;
390
391  // named destination
392  if (destObj->isName()) {
393    namedDest = new GooString(destObj->getName());
394  } else if (destObj->isString()) {
395    namedDest = destObj->getString()->copy();
396
397  // destination dictionary
398  } else if (destObj->isArray()) {
399    dest = new LinkDest(destObj->getArray());
400    if (!dest->isOk()) {
401      delete dest;
402      dest = NULL;
403    }
404
405  // error
406  } else {
407    error(-1, "Illegal annotation destination");
408  }
409}
410
411LinkGoTo::~LinkGoTo() {
412  if (dest)
413    delete dest;
414  if (namedDest)
415    delete namedDest;
416}
417
418//------------------------------------------------------------------------
419// LinkGoToR
420//------------------------------------------------------------------------
421
422LinkGoToR::LinkGoToR(Object *fileSpecObj, Object *destObj) {
423  fileName = NULL;
424  dest = NULL;
425  namedDest = NULL;
426
427  // get file name
428  Object obj1;
429  if (getFileSpecNameForPlatform (fileSpecObj, &obj1)) {
430    fileName = obj1.getString()->copy();
431    obj1.free();
432  }
433
434  // named destination
435  if (destObj->isName()) {
436    namedDest = new GooString(destObj->getName());
437  } else if (destObj->isString()) {
438    namedDest = destObj->getString()->copy();
439
440  // destination dictionary
441  } else if (destObj->isArray()) {
442    dest = new LinkDest(destObj->getArray());
443    if (!dest->isOk()) {
444      delete dest;
445      dest = NULL;
446    }
447
448  // error
449  } else {
450    error(-1, "Illegal annotation destination");
451  }
452}
453
454LinkGoToR::~LinkGoToR() {
455  if (fileName)
456    delete fileName;
457  if (dest)
458    delete dest;
459  if (namedDest)
460    delete namedDest;
461}
462
463
464//------------------------------------------------------------------------
465// LinkLaunch
466//------------------------------------------------------------------------
467
468LinkLaunch::LinkLaunch(Object *actionObj) {
469  Object obj1, obj2, obj3;
470
471  fileName = NULL;
472  params = NULL;
473
474  if (actionObj->isDict()) {
475    if (!actionObj->dictLookup("F", &obj1)->isNull()) {
476      if (getFileSpecNameForPlatform (&obj1, &obj3)) {
477        fileName = obj3.getString()->copy();
478        obj3.free();
479      }
480    } else {
481      obj1.free();
482#ifdef _WIN32
483      if (actionObj->dictLookup("Win", &obj1)->isDict()) {
484        obj1.dictLookup("F", &obj2);
485        if (getFileSpecNameForPlatform (&obj2, &obj3)) {
486          fileName = obj3.getString()->copy();
487          obj3.free();
488        }
489        obj2.free();
490        if (obj1.dictLookup("P", &obj2)->isString()) {
491          params = obj2.getString()->copy();
492        }
493        obj2.free();
494      } else {
495        error(-1, "Bad launch-type link action");
496      }
497#else
498      //~ This hasn't been defined by Adobe yet, so assume it looks
499      //~ just like the Win dictionary until they say otherwise.
500      if (actionObj->dictLookup("Unix", &obj1)->isDict()) {
501        obj1.dictLookup("F", &obj2);
502        if (getFileSpecNameForPlatform (&obj2, &obj3)) {
503          fileName = obj3.getString()->copy();
504          obj3.free();
505        }
506        obj2.free();
507        if (obj1.dictLookup("P", &obj2)->isString()) {
508          params = obj2.getString()->copy();
509        }
510        obj2.free();
511      } else {
512        error(-1, "Bad launch-type link action");
513      }
514#endif
515    }
516    obj1.free();
517  }
518}
519
520LinkLaunch::~LinkLaunch() {
521  if (fileName)
522    delete fileName;
523  if (params)
524    delete params;
525}
526
527//------------------------------------------------------------------------
528// LinkURI
529//------------------------------------------------------------------------
530
531LinkURI::LinkURI(Object *uriObj, GooString *baseURI) {
532  GooString *uri2;
533  int n;
534  char c;
535
536  uri = NULL;
537  if (uriObj->isString()) {
538    uri2 = uriObj->getString()->copy();
539    if (baseURI && baseURI->getLength() > 0) {
540      n = strcspn(uri2->getCString(), "/:");
541      if (n == uri2->getLength() || uri2->getChar(n) == '/') {
542        uri = baseURI->copy();
543        c = uri->getChar(uri->getLength() - 1);
544        if (c == '/' || c == '?') {
545          if (uri2->getChar(0) == '/') {
546            uri2->del(0);
547          }
548        } else {
549          if (uri2->getChar(0) != '/') {
550            uri->append('/');
551          }
552        }
553        uri->append(uri2);
554        delete uri2;
555      } else {
556        uri = uri2;
557      }
558    } else {
559      uri = uri2;
560    }
561  } else {
562    error(-1, "Illegal URI-type link");
563  }
564}
565
566LinkURI::~LinkURI() {
567  if (uri)
568    delete uri;
569}
570
571//------------------------------------------------------------------------
572// LinkNamed
573//------------------------------------------------------------------------
574
575LinkNamed::LinkNamed(Object *nameObj) {
576  name = NULL;
577  if (nameObj->isName()) {
578    name = new GooString(nameObj->getName());
579  }
580}
581
582LinkNamed::~LinkNamed() {
583  if (name) {
584    delete name;
585  }
586}
587
588//------------------------------------------------------------------------
589// LinkMovie
590//------------------------------------------------------------------------
591
592LinkMovie::LinkMovie(Object *obj) {
593  annotRef.num = -1;
594  annotTitle = NULL;
595
596  Object tmp;
597  if (obj->dictLookupNF("Annotation", &tmp)->isRef()) {
598    annotRef = tmp.getRef();
599  }
600  tmp.free();
601
602  if (obj->dictLookup("T", &tmp)->isString()) {
603    annotTitle = tmp.getString()->copy();
604  }
605  tmp.free();
606
607  if ((annotTitle == NULL) && (annotRef.num == -1)) {
608    error(-1, "Movie action is missing both the Annot and T keys");
609  }
610
611  if (obj->dictLookup("Operation", &tmp)->isName()) {
612    char *name = tmp.getName();
613   
614    if (!strcmp(name, "Play")) {
615      operation = operationTypePlay;
616    }
617    else if (!strcmp(name, "Stop")) {
618      operation = operationTypeStop;
619    }
620    else if (!strcmp(name, "Pause")) {
621      operation = operationTypePause;
622    }
623    else if (!strcmp(name, "Resume")) {
624      operation = operationTypeResume;
625    }
626  }
627  tmp.free();
628}
629
630LinkMovie::~LinkMovie() {
631  if (annotTitle) {
632    delete annotTitle;
633  }
634}
635
636//------------------------------------------------------------------------
637// LinkSound
638//------------------------------------------------------------------------
639
640LinkSound::LinkSound(Object *soundObj) {
641  volume = 1.0;
642  sync = gFalse;
643  repeat = gFalse;
644  mix = gFalse;
645  sound = NULL;
646  if (soundObj->isDict())
647  {
648    Object tmp;
649    // volume
650    soundObj->dictLookup("Volume", &tmp);
651    if (tmp.isNum()) {
652      volume = tmp.getNum();
653    }
654    tmp.free();
655    // sync
656    soundObj->dictLookup("Synchronous", &tmp);
657    if (tmp.isBool()) {
658      sync = tmp.getBool();
659    }
660    tmp.free();
661    // repeat
662    soundObj->dictLookup("Repeat", &tmp);
663    if (tmp.isBool()) {
664      repeat = tmp.getBool();
665    }
666    tmp.free();
667    // mix
668    soundObj->dictLookup("Mix", &tmp);
669    if (tmp.isBool()) {
670      mix = tmp.getBool();
671    }
672    tmp.free();
673    // 'Sound' object
674    soundObj->dictLookup("Sound", &tmp);
675    sound = Sound::parseSound(&tmp);
676    tmp.free();
677  }
678}
679
680LinkSound::~LinkSound() {
681  delete sound;
682}
683
684//------------------------------------------------------------------------
685// LinkRendition
686//------------------------------------------------------------------------
687
688LinkRendition::LinkRendition(Object *Obj) {
689  operation = -1;
690  movie = NULL;
691  screenRef.num = -1;
692
693  if (Obj->isDict())
694  {
695    Object tmp;
696
697    if (Obj->dictLookup("OP", &tmp)->isNull()) {
698      error(-1, "Rendition action : no /OP field defined");
699      tmp.free();
700    } else {
701   
702      operation = tmp.getInt();
703      tmp.free();
704
705      // screen annotation reference
706      Obj->dictLookupNF("AN", &tmp);
707      if (tmp.isRef()) {
708        screenRef = tmp.getRef();
709      }
710      tmp.free();
711
712      // retrieve rendition object
713      Obj->dictLookup("R", &renditionObj);
714      if (renditionObj.isDict()) {
715
716        movie = new Movie();
717        movie->parseMediaRendition(&renditionObj);
718       
719        if (screenRef.num == -1) {
720          error(-1, "Action Rendition : Rendition without Screen Annotation !");
721        }
722      }     
723
724    }
725  }
726
727}
728
729LinkRendition::~LinkRendition() {
730  renditionObj.free();
731
732  if (movie)
733    delete movie;
734}
735
736
737//------------------------------------------------------------------------
738// LinkJavaScript
739//------------------------------------------------------------------------
740
741LinkJavaScript::LinkJavaScript(Object *jsObj) {
742  js = NULL;
743
744  if (jsObj->isString()) {
745    js = new GooString(jsObj->getString());
746  }
747  else if (jsObj->isStream()) {
748    Stream *stream = jsObj->getStream();
749    js = new GooString();
750    stream->reset();
751    int i;
752    while ((i = stream->getChar()) != EOF) {
753      js->append((char)i);
754    }
755  }
756}
757
758LinkJavaScript::~LinkJavaScript() {
759  if (js) {
760    delete js;
761  }
762}
763
764//------------------------------------------------------------------------
765// LinkUnknown
766//------------------------------------------------------------------------
767
768LinkUnknown::LinkUnknown(char *actionA) {
769  action = new GooString(actionA);
770}
771
772LinkUnknown::~LinkUnknown() {
773  delete action;
774}
775
776//------------------------------------------------------------------------
777// Link
778//------------------------------------------------------------------------
779
780Link::Link(Dict *dict, GooString *baseURI) {
781  Object obj1, obj2;
782  double t;
783
784  action = NULL;
785  ok = gFalse;
786
787  // get rectangle
788  if (!dict->lookup("Rect", &obj1)->isArray()) {
789    error(-1, "Annotation rectangle is wrong type");
790    goto err2;
791  }
792  if (!obj1.arrayGet(0, &obj2)->isNum()) {
793    error(-1, "Bad annotation rectangle");
794    goto err1;
795  }
796  x1 = obj2.getNum();
797  obj2.free();
798  if (!obj1.arrayGet(1, &obj2)->isNum()) {
799    error(-1, "Bad annotation rectangle");
800    goto err1;
801  }
802  y1 = obj2.getNum();
803  obj2.free();
804  if (!obj1.arrayGet(2, &obj2)->isNum()) {
805    error(-1, "Bad annotation rectangle");
806    goto err1;
807  }
808  x2 = obj2.getNum();
809  obj2.free();
810  if (!obj1.arrayGet(3, &obj2)->isNum()) {
811    error(-1, "Bad annotation rectangle");
812    goto err1;
813  }
814  y2 = obj2.getNum();
815  obj2.free();
816  obj1.free();
817  if (x1 > x2) {
818    t = x1;
819    x1 = x2;
820    x2 = t;
821  }
822  if (y1 > y2) {
823    t = y1;
824    y1 = y2;
825    y2 = t;
826  }
827
828  // look for destination
829  if (!dict->lookup("Dest", &obj1)->isNull()) {
830    action = LinkAction::parseDest(&obj1);
831
832  // look for action
833  } else {
834    obj1.free();
835    if (dict->lookup("A", &obj1)->isDict()) {
836      action = LinkAction::parseAction(&obj1, baseURI);
837    }
838  }
839  obj1.free();
840
841  // check for bad action
842  if (action) {
843    ok = gTrue;
844  }
845
846  return;
847
848 err1:
849  obj2.free();
850 err2:
851  obj1.free();
852}
853
854Link::~Link() {
855  if (action) {
856    delete action;
857  }
858}
859
860//------------------------------------------------------------------------
861// Links
862//------------------------------------------------------------------------
863
864Links::Links(Object *annots, GooString *baseURI) {
865  Link *link;
866  Object obj1, obj2;
867  int size;
868  int i;
869
870  links = NULL;
871  size = 0;
872  numLinks = 0;
873
874  if (annots->isArray()) {
875    for (i = 0; i < annots->arrayGetLength(); ++i) {
876      if (annots->arrayGet(i, &obj1)->isDict()) {
877        if (obj1.dictLookup("Subtype", &obj2)->isName("Link")) {
878          link = new Link(obj1.getDict(), baseURI);
879          if (link->isOk()) {
880            if (numLinks >= size) {
881              size += 16;
882              links = (Link **)greallocn(links, size, sizeof(Link *));
883            }
884            links[numLinks++] = link;
885          } else {
886            delete link;
887          }
888        }
889        obj2.free();
890      }
891      obj1.free();
892    }
893  }
894}
895
896Links::~Links() {
897  int i;
898
899  for (i = 0; i < numLinks; ++i)
900    delete links[i];
901  gfree(links);
902}
903
904LinkAction *Links::find(double x, double y) const {
905  int i;
906
907  for (i = numLinks - 1; i >= 0; --i) {
908    if (links[i]->inRect(x, y)) {
909      return links[i]->getAction();
910    }
911  }
912  return NULL;
913}
914
915GBool Links::onLink(double x, double y) const {
916  int i;
917
918  for (i = 0; i < numLinks; ++i) {
919    if (links[i]->inRect(x, y))
920      return gTrue;
921  }
922  return gFalse;
923}
Note: See TracBrowser for help on using the repository browser.