1 //========================================================================
2 //
3 // Page.cc
4 //
5 // Copyright 1996-2007 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) 2005 Kristian Høgsberg <krh@redhat.com>
17 // Copyright (C) 2005 Jeff Muizelaar <jeff@infidigm.net>
18 // Copyright (C) 2005-2010 Albert Astals Cid <aacid@kde.org>
19 // Copyright (C) 2006-2008 Pino Toscano <pino@kde.org>
20 // Copyright (C) 2006 Nickolay V. Shmyrev <nshmyrev@yandex.ru>
21 // Copyright (C) 2006 Scott Turner <scotty1024@mac.com>
22 // Copyright (C) 2006-2010 Carlos Garcia Campos <carlosgc@gnome.org>
23 // Copyright (C) 2007 Julien Rebetez <julienr@svn.gnome.org>
24 // Copyright (C) 2008 Iñigo Martínez <inigomartinez@gmail.com>
25 // Copyright (C) 2008 Brad Hards <bradh@kde.org>
26 // Copyright (C) 2008 Ilya Gorenbein <igorenbein@finjan.com>
27 //
28 // To see a description of the changes please see the Changelog file that
29 // came with your tarball or type make ChangeLog if you are building from git
30 //
31 //========================================================================
32 
33 #include <config.h>
34 
35 #ifdef USE_GCC_PRAGMAS
36 #pragma implementation
37 #endif
38 
39 #include <stddef.h>
40 #include <limits.h>
41 #include "GlobalParams.h"
42 #include "Object.h"
43 #include "Array.h"
44 #include "Dict.h"
45 #include "XRef.h"
46 #include "Link.h"
47 #include "OutputDev.h"
48 #ifndef PDF_PARSER_ONLY
49 #include "Gfx.h"
50 #include "GfxState.h"
51 #include "Annot.h"
52 #include "TextOutputDev.h"
53 #include "Form.h"
54 #endif
55 #include "Error.h"
56 #include "Page.h"
57 #include "Catalog.h"
58 #include "Form.h"
59 
60 //------------------------------------------------------------------------
61 // PDFRectangle
62 //------------------------------------------------------------------------
63 
clipTo(PDFRectangle * rect)64 void PDFRectangle::clipTo(PDFRectangle *rect) {
65   if (x1 < rect->x1) {
66     x1 = rect->x1;
67   } else if (x1 > rect->x2) {
68     x1 = rect->x2;
69   }
70   if (x2 < rect->x1) {
71     x2 = rect->x1;
72   } else if (x2 > rect->x2) {
73     x2 = rect->x2;
74   }
75   if (y1 < rect->y1) {
76     y1 = rect->y1;
77   } else if (y1 > rect->y2) {
78     y1 = rect->y2;
79   }
80   if (y2 < rect->y1) {
81     y2 = rect->y1;
82   } else if (y2 > rect->y2) {
83     y2 = rect->y2;
84   }
85 }
86 
87 //------------------------------------------------------------------------
88 // PageAttrs
89 //------------------------------------------------------------------------
90 
PageAttrs(PageAttrs * attrs,Dict * dict)91 PageAttrs::PageAttrs(PageAttrs *attrs, Dict *dict) {
92   Object obj1;
93   PDFRectangle mBox;
94   const GBool isPage = dict->is("Page");
95 
96   // get old/default values
97   if (attrs) {
98     mediaBox = attrs->mediaBox;
99     cropBox = attrs->cropBox;
100     haveCropBox = attrs->haveCropBox;
101     rotate = attrs->rotate;
102     attrs->resources.copy(&resources);
103   } else {
104     // set default MediaBox to 8.5" x 11" -- this shouldn't be necessary
105     // but some (non-compliant) PDF files don't specify a MediaBox
106     mediaBox.x1 = 0;
107     mediaBox.y1 = 0;
108     mediaBox.x2 = 612;
109     mediaBox.y2 = 792;
110     cropBox.x1 = cropBox.y1 = cropBox.x2 = cropBox.y2 = 0;
111     haveCropBox = gFalse;
112     rotate = 0;
113     resources.initNull();
114   }
115 
116   // media box
117   if (readBox(dict, "MediaBox", &mBox)) {
118     mediaBox = mBox;
119   }
120 
121   // crop box
122   if (readBox(dict, "CropBox", &cropBox)) {
123     haveCropBox = gTrue;
124   }
125   if (!haveCropBox) {
126     cropBox = mediaBox;
127   }
128 
129   if (isPage) {
130     // cropBox can not be bigger than mediaBox
131     if (cropBox.x2 - cropBox.x1 > mediaBox.x2 - mediaBox.x1)
132     {
133       cropBox.x1 = mediaBox.x1;
134       cropBox.x2 = mediaBox.x2;
135     }
136     if (cropBox.y2 - cropBox.y1 > mediaBox.y2 - mediaBox.y1)
137     {
138       cropBox.y1 = mediaBox.y1;
139       cropBox.y2 = mediaBox.y2;
140     }
141   }
142 
143   // other boxes
144   bleedBox = cropBox;
145   readBox(dict, "BleedBox", &bleedBox);
146   trimBox = cropBox;
147   readBox(dict, "TrimBox", &trimBox);
148   artBox = cropBox;
149   readBox(dict, "ArtBox", &artBox);
150 
151   if (isPage) {
152     // clip all other boxes to the media box
153     cropBox.clipTo(&mediaBox);
154     bleedBox.clipTo(&mediaBox);
155     trimBox.clipTo(&mediaBox);
156     artBox.clipTo(&mediaBox);
157   }
158 
159   // rotate
160   dict->lookup("Rotate", &obj1);
161   if (obj1.isInt()) {
162     rotate = obj1.getInt();
163   }
164   obj1.free();
165   while (rotate < 0) {
166     rotate += 360;
167   }
168   while (rotate >= 360) {
169     rotate -= 360;
170   }
171 
172   // misc attributes
173   dict->lookup("LastModified", &lastModified);
174   dict->lookup("BoxColorInfo", &boxColorInfo);
175   dict->lookup("Group", &group);
176   dict->lookup("Metadata", &metadata);
177   dict->lookup("PieceInfo", &pieceInfo);
178   dict->lookup("SeparationInfo", &separationInfo);
179 
180   // resource dictionary
181   dict->lookup("Resources", &obj1);
182   if (obj1.isDict()) {
183     resources.free();
184     obj1.copy(&resources);
185   }
186   obj1.free();
187 }
188 
~PageAttrs()189 PageAttrs::~PageAttrs() {
190   lastModified.free();
191   boxColorInfo.free();
192   group.free();
193   metadata.free();
194   pieceInfo.free();
195   separationInfo.free();
196   resources.free();
197 }
198 
readBox(Dict * dict,char * key,PDFRectangle * box)199 GBool PageAttrs::readBox(Dict *dict, char *key, PDFRectangle *box) {
200   PDFRectangle tmp;
201   double t;
202   Object obj1, obj2;
203   GBool ok;
204 
205   dict->lookup(key, &obj1);
206   if (obj1.isArray() && obj1.arrayGetLength() == 4) {
207     ok = gTrue;
208     obj1.arrayGet(0, &obj2);
209     if (obj2.isNum()) {
210       tmp.x1 = obj2.getNum();
211     } else {
212       ok = gFalse;
213     }
214     obj2.free();
215     obj1.arrayGet(1, &obj2);
216     if (obj2.isNum()) {
217       tmp.y1 = obj2.getNum();
218     } else {
219       ok = gFalse;
220     }
221     obj2.free();
222     obj1.arrayGet(2, &obj2);
223     if (obj2.isNum()) {
224       tmp.x2 = obj2.getNum();
225     } else {
226       ok = gFalse;
227     }
228     obj2.free();
229     obj1.arrayGet(3, &obj2);
230     if (obj2.isNum()) {
231       tmp.y2 = obj2.getNum();
232     } else {
233       ok = gFalse;
234     }
235     obj2.free();
236     if (tmp.x1 == 0 && tmp.x2 == 0 && tmp.y1 == 0 && tmp.y2 == 0)
237       ok = gFalse;
238     if (ok) {
239       if (tmp.x1 > tmp.x2) {
240 	t = tmp.x1; tmp.x1 = tmp.x2; tmp.x2 = t;
241       }
242       if (tmp.y1 > tmp.y2) {
243 	t = tmp.y1; tmp.y1 = tmp.y2; tmp.y2 = t;
244       }
245       *box = tmp;
246     }
247   } else {
248     ok = gFalse;
249   }
250   obj1.free();
251   return ok;
252 }
253 
254 //------------------------------------------------------------------------
255 // Page
256 //------------------------------------------------------------------------
257 
Page(XRef * xrefA,int numA,Dict * pageDict,Ref pageRefA,PageAttrs * attrsA,Form * form)258 Page::Page(XRef *xrefA, int numA, Dict *pageDict, Ref pageRefA, PageAttrs *attrsA, Form *form) {
259   Object tmp;
260 
261   ok = gTrue;
262   xref = xrefA;
263   num = numA;
264   duration = -1;
265   pageWidgets = NULL;
266 
267   pageObj.initDict(pageDict);
268   pageRef = pageRefA;
269 
270   // get attributes
271   attrs = attrsA;
272 
273   // transtion
274   pageDict->lookupNF("Trans", &trans);
275   if (!(trans.isRef() || trans.isDict() || trans.isNull())) {
276     error(-1, "Page transition object (page %d) is wrong type (%s)",
277 	  num, trans.getTypeName());
278     trans.free();
279   }
280 
281   // duration
282   pageDict->lookupNF("Dur", &tmp);
283   if (!(tmp.isNum() || tmp.isNull())) {
284     error(-1, "Page duration object (page %d) is wrong type (%s)",
285 	  num, tmp.getTypeName());
286   } else if (tmp.isNum()) {
287     duration = tmp.getNum();
288   }
289   tmp.free();
290 
291   // annotations
292   pageDict->lookupNF("Annots", &annots);
293   if (!(annots.isRef() || annots.isArray() || annots.isNull())) {
294     error(-1, "Page annotations object (page %d) is wrong type (%s)",
295 	  num, annots.getTypeName());
296     annots.free();
297     goto err2;
298   }
299 
300   // forms
301   pageWidgets = new FormPageWidgets(xrefA, this->getAnnots(&tmp),num,form);
302   tmp.free();
303 
304   // contents
305   pageDict->lookupNF("Contents", &contents);
306   if (!(contents.isRef() || contents.isArray() ||
307 	contents.isNull())) {
308     error(-1, "Page contents object (page %d) is wrong type (%s)",
309 	  num, contents.getTypeName());
310     contents.free();
311     goto err1;
312   }
313 
314   // thumb
315   pageDict->lookupNF("Thumb", &thumb);
316   if (!(thumb.isStream() || thumb.isNull() || thumb.isRef())) {
317       error(-1, "Page thumb object (page %d) is wrong type (%s)",
318             num, thumb.getTypeName());
319       thumb.initNull();
320   }
321 
322   // actions
323   pageDict->lookupNF("AA", &actions);
324   if (!(actions.isDict() || actions.isNull())) {
325       error(-1, "Page additional action object (page %d) is wrong type (%s)",
326             num, actions.getTypeName());
327       actions.initNull();
328   }
329 
330   return;
331 
332   trans.initNull();
333  err2:
334   annots.initNull();
335  err1:
336   contents.initNull();
337   ok = gFalse;
338 }
339 
~Page()340 Page::~Page() {
341   delete pageWidgets;
342   delete attrs;
343   pageObj.free();
344   annots.free();
345   contents.free();
346   trans.free();
347   thumb.free();
348   actions.free();
349 }
350 
getAnnots(Catalog * catalog)351 Annots *Page::getAnnots(Catalog *catalog) {
352   Annots *annots;
353   Object obj;
354 
355   annots = new Annots(xref, catalog, getAnnots(&obj));
356   obj.free();
357   return annots;
358 }
359 
addAnnot(Annot * annot)360 void Page::addAnnot(Annot *annot) {
361   Object obj1;
362   Object tmp;
363   Ref annotRef = annot->getRef ();
364 
365   if (annots.isNull()) {
366     Ref annotsRef;
367     // page doesn't have annots array,
368     // we have to create it
369 
370     obj1.initArray(xref);
371     obj1.arrayAdd(tmp.initRef (annotRef.num, annotRef.gen));
372     tmp.free();
373 
374     annotsRef = xref->addIndirectObject (&obj1);
375     annots.initRef(annotsRef.num, annotsRef.gen);
376     pageObj.dictSet ("Annots", &annots);
377     xref->setModifiedObject (&pageObj, pageRef);
378   } else {
379     getAnnots(&obj1);
380     if (obj1.isArray()) {
381       obj1.arrayAdd (tmp.initRef (annotRef.num, annotRef.gen));
382       if (annots.isRef())
383         xref->setModifiedObject (&obj1, annots.getRef());
384       else
385         xref->setModifiedObject (&pageObj, pageRef);
386     }
387     obj1.free();
388   }
389 
390   annot->setPage(&pageRef, num);
391 }
392 
getLinks(Catalog * catalog)393 Links *Page::getLinks(Catalog *catalog) {
394   Links *links;
395   Object obj;
396 
397   links = new Links(getAnnots(&obj), catalog->getBaseURI());
398   obj.free();
399   return links;
400 }
401 
display(OutputDev * out,double hDPI,double vDPI,int rotate,GBool useMediaBox,GBool crop,GBool printing,Catalog * catalog,GBool (* abortCheckCbk)(void * data),void * abortCheckCbkData,GBool (* annotDisplayDecideCbk)(Annot * annot,void * user_data),void * annotDisplayDecideCbkData)402 void Page::display(OutputDev *out, double hDPI, double vDPI,
403 		   int rotate, GBool useMediaBox, GBool crop,
404 		   GBool printing, Catalog *catalog,
405 		   GBool (*abortCheckCbk)(void *data),
406 		   void *abortCheckCbkData,
407                    GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data),
408                    void *annotDisplayDecideCbkData) {
409   displaySlice(out, hDPI, vDPI, rotate, useMediaBox, crop, -1, -1, -1, -1, printing, catalog,
410 	       abortCheckCbk, abortCheckCbkData,
411                annotDisplayDecideCbk, annotDisplayDecideCbkData);
412 }
413 
createGfx(OutputDev * out,double hDPI,double vDPI,int rotate,GBool useMediaBox,GBool crop,int sliceX,int sliceY,int sliceW,int sliceH,GBool printing,Catalog * catalog,GBool (* abortCheckCbk)(void * data),void * abortCheckCbkData,GBool (* annotDisplayDecideCbk)(Annot * annot,void * user_data),void * annotDisplayDecideCbkData)414 Gfx *Page::createGfx(OutputDev *out, double hDPI, double vDPI,
415 		     int rotate, GBool useMediaBox, GBool crop,
416 		     int sliceX, int sliceY, int sliceW, int sliceH,
417 		     GBool printing, Catalog *catalog,
418 		     GBool (*abortCheckCbk)(void *data),
419 		     void *abortCheckCbkData,
420 		     GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data),
421 		     void *annotDisplayDecideCbkData) {
422   PDFRectangle *mediaBox, *cropBox;
423   PDFRectangle box;
424   Gfx *gfx;
425 
426   rotate += getRotate();
427   if (rotate >= 360) {
428     rotate -= 360;
429   } else if (rotate < 0) {
430     rotate += 360;
431   }
432 
433   makeBox(hDPI, vDPI, rotate, useMediaBox, out->upsideDown(),
434 	  sliceX, sliceY, sliceW, sliceH, &box, &crop);
435   cropBox = getCropBox();
436   mediaBox = getMediaBox();
437 
438   if (globalParams->getPrintCommands()) {
439     printf("***** MediaBox = ll:%g,%g ur:%g,%g\n",
440 	    mediaBox->x1, mediaBox->y1, mediaBox->x2, mediaBox->y2);
441       printf("***** CropBox = ll:%g,%g ur:%g,%g\n",
442 	     cropBox->x1, cropBox->y1, cropBox->x2, cropBox->y2);
443     printf("***** Rotate = %d\n", attrs->getRotate());
444   }
445 
446   gfx = new Gfx(xref, out, num, attrs->getResourceDict(), catalog,
447 		hDPI, vDPI, &box, crop ? cropBox : (PDFRectangle *)NULL,
448 		rotate, abortCheckCbk, abortCheckCbkData);
449 
450   return gfx;
451 }
452 
displaySlice(OutputDev * out,double hDPI,double vDPI,int rotate,GBool useMediaBox,GBool crop,int sliceX,int sliceY,int sliceW,int sliceH,GBool printing,Catalog * catalog,GBool (* abortCheckCbk)(void * data),void * abortCheckCbkData,GBool (* annotDisplayDecideCbk)(Annot * annot,void * user_data),void * annotDisplayDecideCbkData)453 void Page::displaySlice(OutputDev *out, double hDPI, double vDPI,
454 			int rotate, GBool useMediaBox, GBool crop,
455 			int sliceX, int sliceY, int sliceW, int sliceH,
456 			GBool printing, Catalog *catalog,
457 			GBool (*abortCheckCbk)(void *data),
458 			void *abortCheckCbkData,
459                         GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data),
460                         void *annotDisplayDecideCbkData) {
461   Gfx *gfx;
462   Object obj;
463   Annots *annotList;
464   int i;
465 
466   if (!out->checkPageSlice(this, hDPI, vDPI, rotate, useMediaBox, crop,
467 			   sliceX, sliceY, sliceW, sliceH,
468 			   printing, catalog,
469 			   abortCheckCbk, abortCheckCbkData)) {
470     return;
471   }
472 
473   gfx = createGfx(out, hDPI, vDPI, rotate, useMediaBox, crop,
474 		  sliceX, sliceY, sliceW, sliceH,
475 		  printing, catalog,
476 		  abortCheckCbk, abortCheckCbkData,
477 		  annotDisplayDecideCbk, annotDisplayDecideCbkData);
478 
479   contents.fetch(xref, &obj);
480   if (!obj.isNull()) {
481     gfx->saveState();
482     gfx->display(&obj);
483     gfx->restoreState();
484   }
485   obj.free();
486 
487   // draw annotations
488   annotList = new Annots(xref, catalog, getAnnots(&obj));
489   obj.free();
490 
491   if (annotList->getNumAnnots() > 0) {
492     if (globalParams->getPrintCommands()) {
493       printf("***** Annotations\n");
494     }
495     for (i = 0; i < annotList->getNumAnnots(); ++i) {
496         Annot *annot = annotList->getAnnot(i);
497         if ((annotDisplayDecideCbk &&
498              (*annotDisplayDecideCbk)(annot, annotDisplayDecideCbkData)) ||
499             !annotDisplayDecideCbk) {
500              annotList->getAnnot(i)->draw(gfx, printing);
501 	}
502     }
503     out->dump();
504   }
505   delete annotList;
506 
507   delete gfx;
508 }
509 
display(Gfx * gfx)510 void Page::display(Gfx *gfx) {
511   Object obj;
512 
513   contents.fetch(xref, &obj);
514   if (!obj.isNull()) {
515     gfx->saveState();
516     gfx->display(&obj);
517     gfx->restoreState();
518   }
519   obj.free();
520 }
521 
loadThumb(unsigned char ** data_out,int * width_out,int * height_out,int * rowstride_out)522 GBool Page::loadThumb(unsigned char **data_out,
523 		      int *width_out, int *height_out,
524 		      int *rowstride_out)
525 {
526   unsigned int pixbufdatasize;
527   int width, height, bits;
528   Object obj1, fetched_thumb;
529   Dict *dict;
530   GfxColorSpace *colorSpace;
531   GBool success = gFalse;
532   Stream *str;
533   GfxImageColorMap *colorMap;
534 
535   /* Get stream dict */
536   thumb.fetch(xref, &fetched_thumb);
537   if (!fetched_thumb.isStream()) {
538     fetched_thumb.free();
539     return gFalse;
540   }
541 
542   dict = fetched_thumb.streamGetDict();
543   str = fetched_thumb.getStream();
544 
545   if (!dict->lookupInt("Width", "W", &width))
546     goto fail1;
547   if (!dict->lookupInt("Height", "H", &height))
548     goto fail1;
549   if (!dict->lookupInt("BitsPerComponent", "BPC", &bits))
550     goto fail1;
551 
552   /* Check for invalid dimensions and integer overflow. */
553   if (width <= 0 || height <= 0)
554     goto fail1;
555   if (width > INT_MAX / 3 / height)
556     goto fail1;
557   pixbufdatasize = width * height * 3;
558 
559   /* Get color space */
560   dict->lookup ("ColorSpace", &obj1);
561   if (obj1.isNull ()) {
562     obj1.free ();
563     dict->lookup ("CS", &obj1);
564   }
565   colorSpace = GfxColorSpace::parse(&obj1, NULL);
566   obj1.free();
567   if (!colorSpace) {
568     fprintf (stderr, "Error: Cannot parse color space\n");
569     goto fail1;
570   }
571 
572   dict->lookup("Decode", &obj1);
573   if (obj1.isNull()) {
574     obj1.free();
575     dict->lookup("D", &obj1);
576   }
577   colorMap = new GfxImageColorMap(bits, &obj1, colorSpace);
578   obj1.free();
579   if (!colorMap->isOk()) {
580     fprintf (stderr, "Error: invalid colormap\n");
581     delete colorMap;
582     goto fail1;
583   }
584 
585   if (data_out) {
586     unsigned char *pixbufdata = (unsigned char *) gmalloc(pixbufdatasize);
587     unsigned char *p = pixbufdata;
588     ImageStream *imgstr = new ImageStream(str, width,
589 			   colorMap->getNumPixelComps(),
590 			   colorMap->getBits());
591     imgstr->reset();
592     for (int row = 0; row < height; ++row) {
593       for (int col = 0; col < width; ++col) {
594         Guchar pix[gfxColorMaxComps];
595         GfxRGB rgb;
596 
597         imgstr->getPixel(pix);
598         colorMap->getRGB(pix, &rgb);
599 
600         *p++ = colToByte(rgb.r);
601         *p++ = colToByte(rgb.g);
602         *p++ = colToByte(rgb.b);
603       }
604     }
605     *data_out = pixbufdata;
606     imgstr->close();
607     delete imgstr;
608   }
609 
610   success = gTrue;
611 
612   if (width_out)
613     *width_out = width;
614   if (height_out)
615     *height_out = height;
616   if (rowstride_out)
617     *rowstride_out = width * 3;
618 
619   delete colorMap;
620  fail1:
621   fetched_thumb.free();
622 
623   return success;
624 }
625 
makeBox(double hDPI,double vDPI,int rotate,GBool useMediaBox,GBool upsideDown,double sliceX,double sliceY,double sliceW,double sliceH,PDFRectangle * box,GBool * crop)626 void Page::makeBox(double hDPI, double vDPI, int rotate,
627 		   GBool useMediaBox, GBool upsideDown,
628 		   double sliceX, double sliceY, double sliceW, double sliceH,
629 		   PDFRectangle *box, GBool *crop) {
630   PDFRectangle *mediaBox, *cropBox, *baseBox;
631   double kx, ky;
632 
633   mediaBox = getMediaBox();
634   cropBox = getCropBox();
635   if (sliceW >= 0 && sliceH >= 0) {
636     baseBox = useMediaBox ? mediaBox : cropBox;
637     kx = 72.0 / hDPI;
638     ky = 72.0 / vDPI;
639     if (rotate == 90) {
640       if (upsideDown) {
641 	box->x1 = baseBox->x1 + ky * sliceY;
642 	box->x2 = baseBox->x1 + ky * (sliceY + sliceH);
643       } else {
644 	box->x1 = baseBox->x2 - ky * (sliceY + sliceH);
645 	box->x2 = baseBox->x2 - ky * sliceY;
646       }
647       box->y1 = baseBox->y1 + kx * sliceX;
648       box->y2 = baseBox->y1 + kx * (sliceX + sliceW);
649     } else if (rotate == 180) {
650       box->x1 = baseBox->x2 - kx * (sliceX + sliceW);
651       box->x2 = baseBox->x2 - kx * sliceX;
652       if (upsideDown) {
653 	box->y1 = baseBox->y1 + ky * sliceY;
654 	box->y2 = baseBox->y1 + ky * (sliceY + sliceH);
655       } else {
656 	box->y1 = baseBox->y2 - ky * (sliceY + sliceH);
657 	box->y2 = baseBox->y2 - ky * sliceY;
658       }
659     } else if (rotate == 270) {
660       if (upsideDown) {
661 	box->x1 = baseBox->x2 - ky * (sliceY + sliceH);
662 	box->x2 = baseBox->x2 - ky * sliceY;
663       } else {
664 	box->x1 = baseBox->x1 + ky * sliceY;
665 	box->x2 = baseBox->x1 + ky * (sliceY + sliceH);
666       }
667       box->y1 = baseBox->y2 - kx * (sliceX + sliceW);
668       box->y2 = baseBox->y2 - kx * sliceX;
669     } else {
670       box->x1 = baseBox->x1 + kx * sliceX;
671       box->x2 = baseBox->x1 + kx * (sliceX + sliceW);
672       if (upsideDown) {
673 	box->y1 = baseBox->y2 - ky * (sliceY + sliceH);
674 	box->y2 = baseBox->y2 - ky * sliceY;
675       } else {
676 	box->y1 = baseBox->y1 + ky * sliceY;
677 	box->y2 = baseBox->y1 + ky * (sliceY + sliceH);
678       }
679     }
680   } else if (useMediaBox) {
681     *box = *mediaBox;
682   } else {
683     *box = *cropBox;
684     *crop = gFalse;
685   }
686 }
687 
processLinks(OutputDev * out,Catalog * catalog)688 void Page::processLinks(OutputDev *out, Catalog *catalog) {
689   Links *links;
690   int i;
691 
692   links = getLinks(catalog);
693   for (i = 0; i < links->getNumLinks(); ++i) {
694     out->processLink(links->getLink(i), catalog);
695   }
696   delete links;
697 }
698 
getDefaultCTM(double * ctm,double hDPI,double vDPI,int rotate,GBool useMediaBox,GBool upsideDown)699 void Page::getDefaultCTM(double *ctm, double hDPI, double vDPI,
700 			 int rotate, GBool useMediaBox, GBool upsideDown) {
701   GfxState *state;
702   int i;
703   rotate += getRotate();
704   if (rotate >= 360) {
705     rotate -= 360;
706   } else if (rotate < 0) {
707     rotate += 360;
708   }
709   state = new GfxState(hDPI, vDPI,
710 		       useMediaBox ? getMediaBox() : getCropBox(),
711 		       rotate, upsideDown);
712   for (i = 0; i < 6; ++i) {
713     ctm[i] = state->getCTM()[i];
714   }
715  delete state;
716 }
717