synch wiht TL 37823
[luatex.git] / source / libs / poppler / poppler-0.34.0 / poppler / Page.cc
bloba4af3405b926d46a0d58b9664c729a78d5db46db
1 //========================================================================
2 //
3 // Page.cc
4 //
5 // Copyright 1996-2007 Glyph & Cog, LLC
6 //
7 //========================================================================
9 //========================================================================
11 // Modified under the Poppler project - http://poppler.freedesktop.org
13 // All changes made under the Poppler project to this file are licensed
14 // under GPL version 2 or later
16 // Copyright (C) 2005 Kristian Høgsberg <krh@redhat.com>
17 // Copyright (C) 2005 Jeff Muizelaar <jeff@infidigm.net>
18 // Copyright (C) 2005-2013 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-2011, 2015 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 // Copyright (C) 2012, 2013 Fabio D'Urso <fabiodurso@hotmail.it>
28 // Copyright (C) 2013, 2014 Thomas Freitag <Thomas.Freitag@alfa.de>
29 // Copyright (C) 2013 Jason Crain <jason@aquaticape.us>
30 // Copyright (C) 2013 Adrian Johnson <ajohnson@redneon.com>
31 // Copyright (C) 2015 Philipp Reinkemeier <philipp.reinkemeier@offis.de>
33 // To see a description of the changes please see the Changelog file that
34 // came with your tarball or type make ChangeLog if you are building from git
36 //========================================================================
38 #include <config.h>
40 #ifdef USE_GCC_PRAGMAS
41 #pragma implementation
42 #endif
44 #include <stddef.h>
45 #include <limits.h>
46 #include "GlobalParams.h"
47 #include "Object.h"
48 #include "Array.h"
49 #include "Dict.h"
50 #include "PDFDoc.h"
51 #include "XRef.h"
52 #include "Link.h"
53 #include "OutputDev.h"
54 #include "Gfx.h"
55 #include "GfxState.h"
56 #include "Annot.h"
57 #include "TextOutputDev.h"
58 #include "Form.h"
59 #include "Error.h"
60 #include "Page.h"
61 #include "Catalog.h"
62 #include "Form.h"
64 #if MULTITHREADED
65 # define pageLocker() MutexLocker locker(&mutex)
66 #else
67 # define pageLocker()
68 #endif
69 //------------------------------------------------------------------------
70 // PDFRectangle
71 //------------------------------------------------------------------------
73 void PDFRectangle::clipTo(PDFRectangle *rect) {
74 if (x1 < rect->x1) {
75 x1 = rect->x1;
76 } else if (x1 > rect->x2) {
77 x1 = rect->x2;
79 if (x2 < rect->x1) {
80 x2 = rect->x1;
81 } else if (x2 > rect->x2) {
82 x2 = rect->x2;
84 if (y1 < rect->y1) {
85 y1 = rect->y1;
86 } else if (y1 > rect->y2) {
87 y1 = rect->y2;
89 if (y2 < rect->y1) {
90 y2 = rect->y1;
91 } else if (y2 > rect->y2) {
92 y2 = rect->y2;
96 //------------------------------------------------------------------------
97 // PageAttrs
98 //------------------------------------------------------------------------
100 PageAttrs::PageAttrs(PageAttrs *attrs, Dict *dict) {
101 Object obj1;
102 PDFRectangle mBox;
103 const GBool isPage = dict->is("Page");
105 // get old/default values
106 if (attrs) {
107 mediaBox = attrs->mediaBox;
108 cropBox = attrs->cropBox;
109 haveCropBox = attrs->haveCropBox;
110 rotate = attrs->rotate;
111 attrs->resources.copy(&resources);
112 } else {
113 // set default MediaBox to 8.5" x 11" -- this shouldn't be necessary
114 // but some (non-compliant) PDF files don't specify a MediaBox
115 mediaBox.x1 = 0;
116 mediaBox.y1 = 0;
117 mediaBox.x2 = 612;
118 mediaBox.y2 = 792;
119 cropBox.x1 = cropBox.y1 = cropBox.x2 = cropBox.y2 = 0;
120 haveCropBox = gFalse;
121 rotate = 0;
122 resources.initNull();
125 // media box
126 if (readBox(dict, "MediaBox", &mBox)) {
127 mediaBox = mBox;
130 // crop box
131 if (readBox(dict, "CropBox", &cropBox)) {
132 haveCropBox = gTrue;
134 if (!haveCropBox) {
135 cropBox = mediaBox;
138 if (isPage) {
139 // cropBox can not be bigger than mediaBox
140 if (cropBox.x2 - cropBox.x1 > mediaBox.x2 - mediaBox.x1)
142 cropBox.x1 = mediaBox.x1;
143 cropBox.x2 = mediaBox.x2;
145 if (cropBox.y2 - cropBox.y1 > mediaBox.y2 - mediaBox.y1)
147 cropBox.y1 = mediaBox.y1;
148 cropBox.y2 = mediaBox.y2;
152 // other boxes
153 bleedBox = cropBox;
154 readBox(dict, "BleedBox", &bleedBox);
155 trimBox = cropBox;
156 readBox(dict, "TrimBox", &trimBox);
157 artBox = cropBox;
158 readBox(dict, "ArtBox", &artBox);
160 // rotate
161 dict->lookup("Rotate", &obj1);
162 if (obj1.isInt()) {
163 rotate = obj1.getInt();
165 obj1.free();
166 while (rotate < 0) {
167 rotate += 360;
169 while (rotate >= 360) {
170 rotate -= 360;
173 // misc attributes
174 dict->lookup("LastModified", &lastModified);
175 dict->lookup("BoxColorInfo", &boxColorInfo);
176 dict->lookup("Group", &group);
177 dict->lookup("Metadata", &metadata);
178 dict->lookup("PieceInfo", &pieceInfo);
179 dict->lookup("SeparationInfo", &separationInfo);
181 // resource dictionary
182 dict->lookup("Resources", &obj1);
183 if (obj1.isDict()) {
184 resources.free();
185 obj1.copy(&resources);
187 obj1.free();
190 PageAttrs::~PageAttrs() {
191 lastModified.free();
192 boxColorInfo.free();
193 group.free();
194 metadata.free();
195 pieceInfo.free();
196 separationInfo.free();
197 resources.free();
200 void PageAttrs::clipBoxes() {
201 cropBox.clipTo(&mediaBox);
202 bleedBox.clipTo(&mediaBox);
203 trimBox.clipTo(&mediaBox);
204 artBox.clipTo(&mediaBox);
207 GBool PageAttrs::readBox(Dict *dict, const char *key, PDFRectangle *box) {
208 PDFRectangle tmp;
209 double t;
210 Object obj1, obj2;
211 GBool ok;
213 dict->lookup(key, &obj1);
214 if (obj1.isArray() && obj1.arrayGetLength() == 4) {
215 ok = gTrue;
216 obj1.arrayGet(0, &obj2);
217 if (obj2.isNum()) {
218 tmp.x1 = obj2.getNum();
219 } else {
220 ok = gFalse;
222 obj2.free();
223 obj1.arrayGet(1, &obj2);
224 if (obj2.isNum()) {
225 tmp.y1 = obj2.getNum();
226 } else {
227 ok = gFalse;
229 obj2.free();
230 obj1.arrayGet(2, &obj2);
231 if (obj2.isNum()) {
232 tmp.x2 = obj2.getNum();
233 } else {
234 ok = gFalse;
236 obj2.free();
237 obj1.arrayGet(3, &obj2);
238 if (obj2.isNum()) {
239 tmp.y2 = obj2.getNum();
240 } else {
241 ok = gFalse;
243 obj2.free();
244 if (tmp.x1 == 0 && tmp.x2 == 0 && tmp.y1 == 0 && tmp.y2 == 0)
245 ok = gFalse;
246 if (ok) {
247 if (tmp.x1 > tmp.x2) {
248 t = tmp.x1; tmp.x1 = tmp.x2; tmp.x2 = t;
250 if (tmp.y1 > tmp.y2) {
251 t = tmp.y1; tmp.y1 = tmp.y2; tmp.y2 = t;
253 *box = tmp;
255 } else {
256 ok = gFalse;
258 obj1.free();
259 return ok;
262 //------------------------------------------------------------------------
263 // Page
264 //------------------------------------------------------------------------
266 Page::Page(PDFDoc *docA, int numA, Dict *pageDict, Ref pageRefA, PageAttrs *attrsA, Form *form) {
267 Object tmp;
269 #if MULTITHREADED
270 gInitMutex(&mutex);
271 #endif
272 ok = gTrue;
273 doc = docA;
274 xref = doc->getXRef();
275 num = numA;
276 duration = -1;
277 annots = NULL;
279 pageObj.initDict(pageDict);
280 pageRef = pageRefA;
282 // get attributes
283 attrs = attrsA;
284 attrs->clipBoxes();
286 // transtion
287 pageDict->lookupNF("Trans", &trans);
288 if (!(trans.isRef() || trans.isDict() || trans.isNull())) {
289 error(errSyntaxError, -1, "Page transition object (page {0:d}) is wrong type ({1:s})",
290 num, trans.getTypeName());
291 trans.free();
294 // duration
295 pageDict->lookupNF("Dur", &tmp);
296 if (!(tmp.isNum() || tmp.isNull())) {
297 error(errSyntaxError, -1, "Page duration object (page {0:d}) is wrong type ({1:s})",
298 num, tmp.getTypeName());
299 } else if (tmp.isNum()) {
300 duration = tmp.getNum();
302 tmp.free();
304 // annotations
305 pageDict->lookupNF("Annots", &annotsObj);
306 if (!(annotsObj.isRef() || annotsObj.isArray() || annotsObj.isNull())) {
307 error(errSyntaxError, -1, "Page annotations object (page {0:d}) is wrong type ({1:s})",
308 num, annotsObj.getTypeName());
309 annotsObj.free();
310 goto err2;
313 // contents
314 pageDict->lookupNF("Contents", &contents);
315 if (!(contents.isRef() || contents.isArray() ||
316 contents.isNull())) {
317 error(errSyntaxError, -1, "Page contents object (page {0:d}) is wrong type ({1:s})",
318 num, contents.getTypeName());
319 contents.free();
320 goto err1;
323 // thumb
324 pageDict->lookupNF("Thumb", &thumb);
325 if (!(thumb.isStream() || thumb.isNull() || thumb.isRef())) {
326 error(errSyntaxError, -1, "Page thumb object (page {0:d}) is wrong type ({1:s})",
327 num, thumb.getTypeName());
328 thumb.initNull();
331 // actions
332 pageDict->lookupNF("AA", &actions);
333 if (!(actions.isDict() || actions.isNull())) {
334 error(errSyntaxError, -1, "Page additional action object (page {0:d}) is wrong type ({1:s})",
335 num, actions.getTypeName());
336 actions.initNull();
339 return;
341 trans.initNull();
342 err2:
343 annotsObj.initNull();
344 err1:
345 contents.initNull();
346 ok = gFalse;
349 Page::~Page() {
350 delete attrs;
351 delete annots;
352 pageObj.free();
353 annotsObj.free();
354 contents.free();
355 trans.free();
356 thumb.free();
357 actions.free();
358 #if MULTITHREADED
359 gDestroyMutex(&mutex);
360 #endif
363 Dict *Page::getResourceDict() {
364 return attrs->getResourceDict();
367 Dict *Page::getResourceDictCopy(XRef *xrefA) {
368 pageLocker();
369 Dict *dict = attrs->getResourceDict();
370 return dict ? dict->copy(xrefA) : NULL;
373 void Page::replaceXRef(XRef *xrefA) {
374 Object obj1;
375 Dict *pageDict = pageObj.getDict()->copy(xrefA);
376 xref = xrefA;
377 trans.free();
378 pageDict->lookupNF("Trans", &trans);
379 annotsObj.free();
380 pageDict->lookupNF("Annots", &annotsObj);
381 contents.free();
382 pageDict->lookupNF("Contents", &contents);
383 if (contents.isArray()) {
384 contents.free();
385 pageDict->lookupNF("Contents", &obj1)->getArray()->copy(xrefA, &contents);
386 obj1.free();
388 thumb.free();
389 pageDict->lookupNF("Thumb", &thumb);
390 actions.free();
391 pageDict->lookupNF("AA", &actions);
392 pageDict->lookup("Resources", &obj1);
393 if (obj1.isDict()) {
394 attrs->replaceResource(obj1);
396 obj1.free();
397 delete pageDict;
400 Annots *Page::getAnnots(XRef *xrefA) {
401 if (!annots) {
402 Object obj;
403 annots = new Annots(doc, num, getAnnots(&obj, (xrefA == NULL) ? xref : xrefA));
404 obj.free();
407 return annots;
410 void Page::addAnnot(Annot *annot) {
411 Object obj1;
412 Object tmp;
413 Ref annotRef = annot->getRef ();
415 // Make sure we have annots before adding the new one
416 // even if it's an empty list so that we can safely
417 // call annots->appendAnnot(annot)
418 pageLocker();
419 getAnnots();
421 if (annotsObj.isNull()) {
422 Ref annotsRef;
423 // page doesn't have annots array,
424 // we have to create it
426 obj1.initArray(xref);
427 obj1.arrayAdd(tmp.initRef (annotRef.num, annotRef.gen));
428 tmp.free();
430 annotsRef = xref->addIndirectObject (&obj1);
431 annotsObj.initRef(annotsRef.num, annotsRef.gen);
432 pageObj.dictSet ("Annots", &annotsObj);
433 xref->setModifiedObject (&pageObj, pageRef);
434 } else {
435 getAnnots(&obj1);
436 if (obj1.isArray()) {
437 obj1.arrayAdd (tmp.initRef (annotRef.num, annotRef.gen));
438 if (annotsObj.isRef())
439 xref->setModifiedObject (&obj1, annotsObj.getRef());
440 else
441 xref->setModifiedObject (&pageObj, pageRef);
443 obj1.free();
446 // Popup annots are already handled by markup annots,
447 // so add to the list only Popup annots without a
448 // markup annotation associated.
449 if (annot->getType() != Annot::typePopup ||
450 static_cast<AnnotPopup*>(annot)->getParentNF()->isNull()) {
451 annots->appendAnnot(annot);
453 annot->setPage(num, gTrue);
455 AnnotMarkup *annotMarkup = dynamic_cast<AnnotMarkup*>(annot);
456 if (annotMarkup) {
457 AnnotPopup *annotPopup = annotMarkup->getPopup();
458 if (annotPopup)
459 addAnnot(annotPopup);
463 void Page::removeAnnot(Annot *annot) {
464 Ref annotRef = annot->getRef();
465 Object annArray;
467 pageLocker();
468 getAnnots(&annArray);
469 if (annArray.isArray()) {
470 int idx = -1;
471 // Get annotation position
472 for (int i = 0; idx == -1 && i < annArray.arrayGetLength(); ++i) {
473 Object tmp;
474 if (annArray.arrayGetNF(i, &tmp)->isRef()) {
475 Ref currAnnot = tmp.getRef();
476 if (currAnnot.num == annotRef.num && currAnnot.gen == annotRef.gen) {
477 idx = i;
480 tmp.free();
483 if (idx == -1) {
484 error(errInternal, -1, "Annotation doesn't belong to this page");
485 annArray.free();
486 return;
488 annots->removeAnnot(annot); // Gracefully fails on popup windows
489 annArray.arrayRemove(idx);
490 xref->removeIndirectObject(annotRef);
492 if (annotsObj.isRef()) {
493 xref->setModifiedObject (&annArray, annotsObj.getRef());
494 } else {
495 xref->setModifiedObject (&pageObj, pageRef);
498 annArray.free();
499 annot->removeReferencedObjects(); // Note: Might recurse in removeAnnot again
500 annot->setPage(0, gFalse);
503 Links *Page::getLinks() {
504 return new Links(getAnnots());
507 FormPageWidgets *Page::getFormWidgets() {
508 return new FormPageWidgets(getAnnots(), num, doc->getCatalog()->getForm());
511 void Page::display(OutputDev *out, double hDPI, double vDPI,
512 int rotate, GBool useMediaBox, GBool crop,
513 GBool printing,
514 GBool (*abortCheckCbk)(void *data),
515 void *abortCheckCbkData,
516 GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data),
517 void *annotDisplayDecideCbkData,
518 GBool copyXRef) {
519 displaySlice(out, hDPI, vDPI, rotate, useMediaBox, crop, -1, -1, -1, -1, printing,
520 abortCheckCbk, abortCheckCbkData,
521 annotDisplayDecideCbk, annotDisplayDecideCbkData, copyXRef);
524 Gfx *Page::createGfx(OutputDev *out, double hDPI, double vDPI,
525 int rotate, GBool useMediaBox, GBool crop,
526 int sliceX, int sliceY, int sliceW, int sliceH,
527 GBool printing,
528 GBool (*abortCheckCbk)(void *data),
529 void *abortCheckCbkData, XRef *xrefA) {
530 PDFRectangle *mediaBox, *cropBox;
531 PDFRectangle box;
532 Gfx *gfx;
534 rotate += getRotate();
535 if (rotate >= 360) {
536 rotate -= 360;
537 } else if (rotate < 0) {
538 rotate += 360;
541 makeBox(hDPI, vDPI, rotate, useMediaBox, out->upsideDown(),
542 sliceX, sliceY, sliceW, sliceH, &box, &crop);
543 cropBox = getCropBox();
544 mediaBox = getMediaBox();
546 if (globalParams->getPrintCommands()) {
547 printf("***** MediaBox = ll:%g,%g ur:%g,%g\n",
548 mediaBox->x1, mediaBox->y1, mediaBox->x2, mediaBox->y2);
549 printf("***** CropBox = ll:%g,%g ur:%g,%g\n",
550 cropBox->x1, cropBox->y1, cropBox->x2, cropBox->y2);
551 printf("***** Rotate = %d\n", attrs->getRotate());
554 if (!crop) {
555 crop = (box == *cropBox) && out->needClipToCropBox();
557 gfx = new Gfx(doc, out, num, attrs->getResourceDict(),
558 hDPI, vDPI, &box, crop ? cropBox : (PDFRectangle *)NULL,
559 rotate, abortCheckCbk, abortCheckCbkData, xrefA);
561 return gfx;
564 void Page::displaySlice(OutputDev *out, double hDPI, double vDPI,
565 int rotate, GBool useMediaBox, GBool crop,
566 int sliceX, int sliceY, int sliceW, int sliceH,
567 GBool printing,
568 GBool (*abortCheckCbk)(void *data),
569 void *abortCheckCbkData,
570 GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data),
571 void *annotDisplayDecideCbkData,
572 GBool copyXRef) {
573 Gfx *gfx;
574 Object obj;
575 Annots *annotList;
576 int i;
578 if (!out->checkPageSlice(this, hDPI, vDPI, rotate, useMediaBox, crop,
579 sliceX, sliceY, sliceW, sliceH,
580 printing,
581 abortCheckCbk, abortCheckCbkData,
582 annotDisplayDecideCbk, annotDisplayDecideCbkData)) {
583 return;
585 pageLocker();
586 XRef *localXRef = (copyXRef) ? xref->copy() : xref;
587 if (copyXRef) {
588 replaceXRef(localXRef);
591 gfx = createGfx(out, hDPI, vDPI, rotate, useMediaBox, crop,
592 sliceX, sliceY, sliceW, sliceH,
593 printing,
594 abortCheckCbk, abortCheckCbkData, localXRef);
596 contents.fetch(localXRef, &obj);
597 if (!obj.isNull()) {
598 gfx->saveState();
599 gfx->display(&obj);
600 gfx->restoreState();
601 } else {
602 // empty pages need to call dump to do any setup required by the
603 // OutputDev
604 out->dump();
606 obj.free();
608 // draw annotations
609 annotList = getAnnots();
611 if (annotList->getNumAnnots() > 0) {
612 if (globalParams->getPrintCommands()) {
613 printf("***** Annotations\n");
615 for (i = 0; i < annotList->getNumAnnots(); ++i) {
616 Annot *annot = annotList->getAnnot(i);
617 if ((annotDisplayDecideCbk &&
618 (*annotDisplayDecideCbk)(annot, annotDisplayDecideCbkData)) ||
619 !annotDisplayDecideCbk) {
620 annotList->getAnnot(i)->draw(gfx, printing);
623 out->dump();
626 delete gfx;
627 if (copyXRef) {
628 replaceXRef(doc->getXRef());
629 delete localXRef;
633 void Page::display(Gfx *gfx) {
634 Object obj;
636 contents.fetch(xref, &obj);
637 if (!obj.isNull()) {
638 gfx->saveState();
639 gfx->display(&obj);
640 gfx->restoreState();
642 obj.free();
645 GBool Page::loadThumb(unsigned char **data_out,
646 int *width_out, int *height_out,
647 int *rowstride_out)
649 unsigned int pixbufdatasize;
650 int width, height, bits;
651 Object obj1, fetched_thumb;
652 Dict *dict;
653 GfxColorSpace *colorSpace;
654 GBool success = gFalse;
655 Stream *str;
656 GfxImageColorMap *colorMap;
658 /* Get stream dict */
659 pageLocker();
660 thumb.fetch(xref, &fetched_thumb);
661 if (!fetched_thumb.isStream()) {
662 fetched_thumb.free();
663 return gFalse;
666 dict = fetched_thumb.streamGetDict();
667 str = fetched_thumb.getStream();
669 if (!dict->lookupInt("Width", "W", &width))
670 goto fail1;
671 if (!dict->lookupInt("Height", "H", &height))
672 goto fail1;
673 if (!dict->lookupInt("BitsPerComponent", "BPC", &bits))
674 goto fail1;
676 /* Check for invalid dimensions and integer overflow. */
677 if (width <= 0 || height <= 0)
678 goto fail1;
679 if (width > INT_MAX / 3 / height)
680 goto fail1;
681 pixbufdatasize = width * height * 3;
683 /* Get color space */
684 dict->lookup ("ColorSpace", &obj1);
685 if (obj1.isNull ()) {
686 obj1.free ();
687 dict->lookup ("CS", &obj1);
689 colorSpace = GfxColorSpace::parse(NULL, &obj1, NULL, NULL);
690 obj1.free();
691 if (!colorSpace) {
692 fprintf (stderr, "Error: Cannot parse color space\n");
693 goto fail1;
696 dict->lookup("Decode", &obj1);
697 if (obj1.isNull()) {
698 obj1.free();
699 dict->lookup("D", &obj1);
701 colorMap = new GfxImageColorMap(bits, &obj1, colorSpace);
702 obj1.free();
703 if (!colorMap->isOk()) {
704 fprintf (stderr, "Error: invalid colormap\n");
705 delete colorMap;
706 goto fail1;
709 if (data_out) {
710 unsigned char *pixbufdata = (unsigned char *) gmalloc(pixbufdatasize);
711 unsigned char *p = pixbufdata;
712 ImageStream *imgstr = new ImageStream(str, width,
713 colorMap->getNumPixelComps(),
714 colorMap->getBits());
715 imgstr->reset();
716 for (int row = 0; row < height; ++row) {
717 for (int col = 0; col < width; ++col) {
718 Guchar pix[gfxColorMaxComps];
719 GfxRGB rgb;
721 imgstr->getPixel(pix);
722 colorMap->getRGB(pix, &rgb);
724 *p++ = colToByte(rgb.r);
725 *p++ = colToByte(rgb.g);
726 *p++ = colToByte(rgb.b);
729 *data_out = pixbufdata;
730 imgstr->close();
731 delete imgstr;
734 success = gTrue;
736 if (width_out)
737 *width_out = width;
738 if (height_out)
739 *height_out = height;
740 if (rowstride_out)
741 *rowstride_out = width * 3;
743 delete colorMap;
744 fail1:
745 fetched_thumb.free();
747 return success;
750 void Page::makeBox(double hDPI, double vDPI, int rotate,
751 GBool useMediaBox, GBool upsideDown,
752 double sliceX, double sliceY, double sliceW, double sliceH,
753 PDFRectangle *box, GBool *crop) {
754 PDFRectangle *mediaBox, *cropBox, *baseBox;
755 double kx, ky;
757 mediaBox = getMediaBox();
758 cropBox = getCropBox();
759 if (sliceW >= 0 && sliceH >= 0) {
760 baseBox = useMediaBox ? mediaBox : cropBox;
761 kx = 72.0 / hDPI;
762 ky = 72.0 / vDPI;
763 if (rotate == 90) {
764 if (upsideDown) {
765 box->x1 = baseBox->x1 + ky * sliceY;
766 box->x2 = baseBox->x1 + ky * (sliceY + sliceH);
767 } else {
768 box->x1 = baseBox->x2 - ky * (sliceY + sliceH);
769 box->x2 = baseBox->x2 - ky * sliceY;
771 box->y1 = baseBox->y1 + kx * sliceX;
772 box->y2 = baseBox->y1 + kx * (sliceX + sliceW);
773 } else if (rotate == 180) {
774 box->x1 = baseBox->x2 - kx * (sliceX + sliceW);
775 box->x2 = baseBox->x2 - kx * sliceX;
776 if (upsideDown) {
777 box->y1 = baseBox->y1 + ky * sliceY;
778 box->y2 = baseBox->y1 + ky * (sliceY + sliceH);
779 } else {
780 box->y1 = baseBox->y2 - ky * (sliceY + sliceH);
781 box->y2 = baseBox->y2 - ky * sliceY;
783 } else if (rotate == 270) {
784 if (upsideDown) {
785 box->x1 = baseBox->x2 - ky * (sliceY + sliceH);
786 box->x2 = baseBox->x2 - ky * sliceY;
787 } else {
788 box->x1 = baseBox->x1 + ky * sliceY;
789 box->x2 = baseBox->x1 + ky * (sliceY + sliceH);
791 box->y1 = baseBox->y2 - kx * (sliceX + sliceW);
792 box->y2 = baseBox->y2 - kx * sliceX;
793 } else {
794 box->x1 = baseBox->x1 + kx * sliceX;
795 box->x2 = baseBox->x1 + kx * (sliceX + sliceW);
796 if (upsideDown) {
797 box->y1 = baseBox->y2 - ky * (sliceY + sliceH);
798 box->y2 = baseBox->y2 - ky * sliceY;
799 } else {
800 box->y1 = baseBox->y1 + ky * sliceY;
801 box->y2 = baseBox->y1 + ky * (sliceY + sliceH);
804 } else if (useMediaBox) {
805 *box = *mediaBox;
806 } else {
807 *box = *cropBox;
808 *crop = gFalse;
812 void Page::processLinks(OutputDev *out) {
813 Links *links;
814 int i;
816 links = getLinks();
817 for (i = 0; i < links->getNumLinks(); ++i) {
818 out->processLink(links->getLink(i));
820 delete links;
823 void Page::getDefaultCTM(double *ctm, double hDPI, double vDPI,
824 int rotate, GBool useMediaBox, GBool upsideDown) {
825 GfxState *state;
826 int i;
827 rotate += getRotate();
828 if (rotate >= 360) {
829 rotate -= 360;
830 } else if (rotate < 0) {
831 rotate += 360;
833 state = new GfxState(hDPI, vDPI,
834 useMediaBox ? getMediaBox() : getCropBox(),
835 rotate, upsideDown);
836 for (i = 0; i < 6; ++i) {
837 ctm[i] = state->getCTM()[i];
839 delete state;
842 LinkAction* Page::getAdditionalAction(PageAdditionalActionsType type) {
843 Object additionalActionsObject;
844 LinkAction *linkAction = NULL;
846 if (actions.fetch(doc->getXRef(), &additionalActionsObject)->isDict()) {
847 const char *key = (type == actionOpenPage ? "O" :
848 type == actionClosePage ? "C" : NULL);
850 Object actionObject;
852 if (additionalActionsObject.dictLookup(key, &actionObject)->isDict())
853 linkAction = LinkAction::parseAction(&actionObject, doc->getCatalog()->getBaseURI());
854 actionObject.free();
857 additionalActionsObject.free();
859 return linkAction;