1 //========================================================================
5 // Copyright 1996-2003 Glyph & Cog, LLC
7 //========================================================================
11 #ifdef USE_GCC_PRAGMAS
12 #pragma implementation
25 //------------------------------------------------------------------------
27 //------------------------------------------------------------------------
29 LinkAction
*LinkAction::parseDest(Object
*obj
) {
32 action
= new LinkGoTo(obj
);
33 if (!action
->isOk()) {
40 LinkAction
*LinkAction::parseAction(Object
*obj
, GString
*baseURI
) {
42 Object obj2
, obj3
, obj4
;
45 error(-1, "Bad annotation action");
49 obj
->dictLookup("S", &obj2
);
52 if (obj2
.isName("GoTo")) {
53 obj
->dictLookup("D", &obj3
);
54 action
= new LinkGoTo(&obj3
);
58 } else if (obj2
.isName("GoToR")) {
59 obj
->dictLookup("F", &obj3
);
60 obj
->dictLookup("D", &obj4
);
61 action
= new LinkGoToR(&obj3
, &obj4
);
66 } else if (obj2
.isName("Launch")) {
67 action
= new LinkLaunch(obj
);
70 } else if (obj2
.isName("URI")) {
71 obj
->dictLookup("URI", &obj3
);
72 action
= new LinkURI(&obj3
, baseURI
);
76 } else if (obj2
.isName("Named")) {
77 obj
->dictLookup("N", &obj3
);
78 action
= new LinkNamed(&obj3
);
82 } else if (obj2
.isName("Movie")) {
83 obj
->dictLookupNF("Annot", &obj3
);
84 obj
->dictLookup("T", &obj4
);
85 action
= new LinkMovie(&obj3
, &obj4
);
90 } else if (obj2
.isName()) {
91 action
= new LinkUnknown(obj2
.getName());
93 // action is missing or wrong type
95 error(-1, "Bad annotation action");
101 if (action
&& !action
->isOk()) {
108 GString
*LinkAction::getFileSpecName(Object
*fileSpecObj
) {
115 if (fileSpecObj
->isString()) {
116 name
= fileSpecObj
->getString()->copy();
119 } else if (fileSpecObj
->isDict()) {
120 if (!fileSpecObj
->dictLookup("Unix", &obj1
)->isString()) {
122 fileSpecObj
->dictLookup("F", &obj1
);
125 name
= obj1
.getString()->copy();
127 error(-1, "Illegal file spec in link");
132 error(-1, "Illegal file spec in link");
138 //------------------------------------------------------------------------
140 //------------------------------------------------------------------------
142 LinkDest::LinkDest(Array
*a
) {
146 left
= bottom
= right
= top
= zoom
= 0;
150 if (a
->getLength() < 2) {
151 error(-1, "Annotation destination array is too short");
156 pageNum
= obj1
.getInt() + 1;
158 } else if (obj1
.isRef()) {
159 pageRef
.num
= obj1
.getRefNum();
160 pageRef
.gen
= obj1
.getRefGen();
163 error(-1, "Bad annotation destination");
168 // get destination type
172 if (obj1
.isName("XYZ")) {
174 if (a
->getLength() < 3) {
180 } else if (obj2
.isNum()) {
182 left
= obj2
.getNum();
184 error(-1, "Bad annotation destination position");
189 if (a
->getLength() < 4) {
195 } else if (obj2
.isNum()) {
199 error(-1, "Bad annotation destination position");
204 if (a
->getLength() < 5) {
210 } else if (obj2
.isNum()) {
212 zoom
= obj2
.getNum();
214 error(-1, "Bad annotation destination position");
221 } else if (obj1
.isName("Fit")) {
222 if (a
->getLength() < 2) {
223 error(-1, "Annotation destination array is too short");
229 } else if (obj1
.isName("FitH")) {
230 if (a
->getLength() < 3) {
231 error(-1, "Annotation destination array is too short");
235 if (!a
->get(2, &obj2
)->isNum()) {
236 error(-1, "Bad annotation destination position");
243 } else if (obj1
.isName("FitV")) {
244 if (a
->getLength() < 3) {
245 error(-1, "Annotation destination array is too short");
249 if (!a
->get(2, &obj2
)->isNum()) {
250 error(-1, "Bad annotation destination position");
253 left
= obj2
.getNum();
257 } else if (obj1
.isName("FitR")) {
258 if (a
->getLength() < 6) {
259 error(-1, "Annotation destination array is too short");
263 if (!a
->get(2, &obj2
)->isNum()) {
264 error(-1, "Bad annotation destination position");
267 left
= obj2
.getNum();
269 if (!a
->get(3, &obj2
)->isNum()) {
270 error(-1, "Bad annotation destination position");
273 bottom
= obj2
.getNum();
275 if (!a
->get(4, &obj2
)->isNum()) {
276 error(-1, "Bad annotation destination position");
279 right
= obj2
.getNum();
281 if (!a
->get(5, &obj2
)->isNum()) {
282 error(-1, "Bad annotation destination position");
289 } else if (obj1
.isName("FitB")) {
290 if (a
->getLength() < 2) {
291 error(-1, "Annotation destination array is too short");
297 } else if (obj1
.isName("FitBH")) {
298 if (a
->getLength() < 3) {
299 error(-1, "Annotation destination array is too short");
303 if (!a
->get(2, &obj2
)->isNum()) {
304 error(-1, "Bad annotation destination position");
311 } else if (obj1
.isName("FitBV")) {
312 if (a
->getLength() < 3) {
313 error(-1, "Annotation destination array is too short");
317 if (!a
->get(2, &obj2
)->isNum()) {
318 error(-1, "Bad annotation destination position");
321 left
= obj2
.getNum();
326 error(-1, "Unknown annotation destination type");
340 LinkDest::LinkDest(LinkDest
*dest
) {
342 pageIsRef
= dest
->pageIsRef
;
344 pageRef
= dest
->pageRef
;
346 pageNum
= dest
->pageNum
;
348 bottom
= dest
->bottom
;
352 changeLeft
= dest
->changeLeft
;
353 changeTop
= dest
->changeTop
;
354 changeZoom
= dest
->changeZoom
;
358 //------------------------------------------------------------------------
360 //------------------------------------------------------------------------
362 LinkGoTo::LinkGoTo(Object
*destObj
) {
367 if (destObj
->isName()) {
368 namedDest
= new GString(destObj
->getName());
369 } else if (destObj
->isString()) {
370 namedDest
= destObj
->getString()->copy();
372 // destination dictionary
373 } else if (destObj
->isArray()) {
374 dest
= new LinkDest(destObj
->getArray());
382 error(-1, "Illegal annotation destination");
386 LinkGoTo::~LinkGoTo() {
393 //------------------------------------------------------------------------
395 //------------------------------------------------------------------------
397 LinkGoToR::LinkGoToR(Object
*fileSpecObj
, Object
*destObj
) {
402 fileName
= getFileSpecName(fileSpecObj
);
405 if (destObj
->isName()) {
406 namedDest
= new GString(destObj
->getName());
407 } else if (destObj
->isString()) {
408 namedDest
= destObj
->getString()->copy();
410 // destination dictionary
411 } else if (destObj
->isArray()) {
412 dest
= new LinkDest(destObj
->getArray());
420 error(-1, "Illegal annotation destination");
424 LinkGoToR::~LinkGoToR() {
434 //------------------------------------------------------------------------
436 //------------------------------------------------------------------------
438 LinkLaunch::LinkLaunch(Object
*actionObj
) {
444 if (actionObj
->isDict()) {
445 if (!actionObj
->dictLookup("F", &obj1
)->isNull()) {
446 fileName
= getFileSpecName(&obj1
);
450 if (actionObj
->dictLookup("Win", &obj1
)->isDict()) {
451 obj1
.dictLookup("F", &obj2
);
452 fileName
= getFileSpecName(&obj2
);
454 if (obj1
.dictLookup("P", &obj2
)->isString()) {
455 params
= obj2
.getString()->copy();
459 error(-1, "Bad launch-type link action");
462 //~ This hasn't been defined by Adobe yet, so assume it looks
463 //~ just like the Win dictionary until they say otherwise.
464 if (actionObj
->dictLookup("Unix", &obj1
)->isDict()) {
465 obj1
.dictLookup("F", &obj2
);
466 fileName
= getFileSpecName(&obj2
);
468 if (obj1
.dictLookup("P", &obj2
)->isString()) {
469 params
= obj2
.getString()->copy();
473 error(-1, "Bad launch-type link action");
481 LinkLaunch::~LinkLaunch() {
488 //------------------------------------------------------------------------
490 //------------------------------------------------------------------------
492 LinkURI::LinkURI(Object
*uriObj
, GString
*baseURI
) {
498 if (uriObj
->isString()) {
499 uri2
= uriObj
->getString()->copy();
501 n
= strcspn(uri2
->getCString(), "/:");
502 if (n
== uri2
->getLength() || uri2
->getChar(n
) == '/') {
503 uri
= baseURI
->copy();
504 c
= uri
->getChar(uri
->getLength() - 1);
505 if (c
== '/' || c
== '?') {
506 if (uri2
->getChar(0) == '/') {
510 if (uri2
->getChar(0) != '/') {
523 error(-1, "Illegal URI-type link");
527 LinkURI::~LinkURI() {
532 //------------------------------------------------------------------------
534 //------------------------------------------------------------------------
536 LinkNamed::LinkNamed(Object
*nameObj
) {
538 if (nameObj
->isName()) {
539 name
= new GString(nameObj
->getName());
543 LinkNamed::~LinkNamed() {
549 //------------------------------------------------------------------------
551 //------------------------------------------------------------------------
553 LinkMovie::LinkMovie(Object
*annotObj
, Object
*titleObj
) {
556 if (annotObj
->isRef()) {
557 annotRef
= annotObj
->getRef();
558 } else if (titleObj
->isString()) {
559 title
= titleObj
->getString()->copy();
561 error(-1, "Movie action is missing both the Annot and T keys");
565 LinkMovie::~LinkMovie() {
571 //------------------------------------------------------------------------
573 //------------------------------------------------------------------------
575 LinkUnknown::LinkUnknown(char *actionA
) {
576 action
= new GString(actionA
);
579 LinkUnknown::~LinkUnknown() {
583 //------------------------------------------------------------------------
585 //------------------------------------------------------------------------
587 LinkBorderStyle::LinkBorderStyle(LinkBorderType typeA
, double widthA
,
588 double *dashA
, int dashLengthA
,
589 double rA
, double gA
, double bA
) {
593 dashLength
= dashLengthA
;
599 LinkBorderStyle::~LinkBorderStyle() {
605 //------------------------------------------------------------------------
607 //------------------------------------------------------------------------
609 Link::Link(Dict
*dict
, GString
*baseURI
) {
610 Object obj1
, obj2
, obj3
;
611 LinkBorderType borderType
;
614 int borderDashLength
;
615 double borderR
, borderG
, borderB
;
624 if (!dict
->lookup("Rect", &obj1
)->isArray()) {
625 error(-1, "Annotation rectangle is wrong type");
628 if (!obj1
.arrayGet(0, &obj2
)->isNum()) {
629 error(-1, "Bad annotation rectangle");
634 if (!obj1
.arrayGet(1, &obj2
)->isNum()) {
635 error(-1, "Bad annotation rectangle");
640 if (!obj1
.arrayGet(2, &obj2
)->isNum()) {
641 error(-1, "Bad annotation rectangle");
646 if (!obj1
.arrayGet(3, &obj2
)->isNum()) {
647 error(-1, "Bad annotation rectangle");
664 // get the border style info
665 borderType
= linkBorderSolid
;
668 borderDashLength
= 0;
672 if (dict
->lookup("BS", &obj1
)->isDict()) {
673 if (obj1
.dictLookup("S", &obj2
)->isName()) {
674 if (obj2
.isName("S")) {
675 borderType
= linkBorderSolid
;
676 } else if (obj2
.isName("D")) {
677 borderType
= linkBorderDashed
;
678 } else if (obj2
.isName("B")) {
679 borderType
= linkBorderEmbossed
;
680 } else if (obj2
.isName("I")) {
681 borderType
= linkBorderEngraved
;
682 } else if (obj2
.isName("U")) {
683 borderType
= linkBorderUnderlined
;
687 if (obj1
.dictLookup("W", &obj2
)->isNum()) {
688 borderWidth
= obj2
.getNum();
691 if (obj1
.dictLookup("D", &obj2
)->isArray()) {
692 borderDashLength
= obj2
.arrayGetLength();
693 borderDash
= (double *)gmalloc(borderDashLength
* sizeof(double));
694 for (i
= 0; i
< borderDashLength
; ++i
) {
695 if (obj2
.arrayGet(i
, &obj3
)->isNum()) {
696 borderDash
[i
] = obj3
.getNum();
706 if (dict
->lookup("Border", &obj1
)->isArray()) {
707 if (obj1
.arrayGetLength() >= 3) {
708 if (obj1
.arrayGet(2, &obj2
)->isNum()) {
709 borderWidth
= obj2
.getNum();
712 if (obj1
.arrayGetLength() >= 4) {
713 if (obj1
.arrayGet(3, &obj2
)->isArray()) {
714 borderType
= linkBorderDashed
;
715 borderDashLength
= obj2
.arrayGetLength();
716 borderDash
= (double *)gmalloc(borderDashLength
* sizeof(double));
717 for (i
= 0; i
< borderDashLength
; ++i
) {
718 if (obj2
.arrayGet(i
, &obj3
)->isNum()) {
719 borderDash
[i
] = obj3
.getNum();
732 if (dict
->lookup("C", &obj1
)->isArray() && obj1
.arrayGetLength() == 3) {
733 if (obj1
.arrayGet(0, &obj2
)->isNum()) {
734 borderR
= obj2
.getNum();
737 if (obj1
.arrayGet(1, &obj2
)->isNum()) {
738 borderG
= obj2
.getNum();
741 if (obj1
.arrayGet(2, &obj2
)->isNum()) {
742 borderB
= obj2
.getNum();
747 borderStyle
= new LinkBorderStyle(borderType
, borderWidth
,
748 borderDash
, borderDashLength
,
749 borderR
, borderG
, borderB
);
751 // look for destination
752 if (!dict
->lookup("Dest", &obj1
)->isNull()) {
753 action
= LinkAction::parseDest(&obj1
);
758 if (dict
->lookup("A", &obj1
)->isDict()) {
759 action
= LinkAction::parseAction(&obj1
, baseURI
);
764 // check for bad action
786 //------------------------------------------------------------------------
788 //------------------------------------------------------------------------
790 Links::Links(Object
*annots
, GString
*baseURI
) {
800 if (annots
->isArray()) {
801 for (i
= 0; i
< annots
->arrayGetLength(); ++i
) {
802 if (annots
->arrayGet(i
, &obj1
)->isDict()) {
803 if (obj1
.dictLookup("Subtype", &obj2
)->isName("Link")) {
804 link
= new Link(obj1
.getDict(), baseURI
);
806 if (numLinks
>= size
) {
808 links
= (Link
**)grealloc(links
, size
* sizeof(Link
*));
810 links
[numLinks
++] = link
;
825 for (i
= 0; i
< numLinks
; ++i
)
830 LinkAction
*Links::find(double x
, double y
) {
833 for (i
= numLinks
- 1; i
>= 0; --i
) {
834 if (links
[i
]->inRect(x
, y
)) {
835 return links
[i
]->getAction();
841 GBool
Links::onLink(double x
, double y
) {
844 for (i
= 0; i
< numLinks
; ++i
) {
845 if (links
[i
]->inRect(x
, y
))