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

Last change on this file since 2 was 2, checked in by Eugene Romanenko, 16 years ago

First import

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