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

Last change on this file since 250 was 250, checked in by Eugene Romanenko, 13 years ago

PDF plugin: poppler library updated to version 0.8.3

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