Bringing apdf from vendor into main branch.
[AROS-Contrib.git] / apdf / xpdf / PDFCore.cc
blob2b9931073a57b2936f481d011b5e697ea18535be
1 //========================================================================
2 //
3 // PDFCore.cc
4 //
5 // Copyright 2004 Glyph & Cog, LLC
6 //
7 //========================================================================
9 #include <aconf.h>
11 #ifdef USE_GCC_PRAGMAS
12 #pragma implementation
13 #endif
15 #include <stdio.h>
16 #include <math.h>
17 #include "GString.h"
18 #include "GList.h"
19 #include "GlobalParams.h"
20 #include "Splash.h"
21 #include "SplashBitmap.h"
22 #include "SplashPattern.h"
23 #include "SplashPath.h"
24 #include "Error.h"
25 #include "ErrorCodes.h"
26 #include "PDFDoc.h"
27 #include "TextOutputDev.h"
28 #include "CoreOutputDev.h"
29 #include "PDFCore.h"
31 //------------------------------------------------------------------------
32 // PDFCorePage
33 //------------------------------------------------------------------------
35 PDFCorePage::PDFCorePage(int pageA, int wA, int hA, int tileWA, int tileHA) {
36 page = pageA;
37 tiles = new GList();
38 w = wA;
39 h = hA;
40 tileW = tileWA;
41 tileH = tileHA;
42 links = NULL;
43 text = NULL;
46 PDFCorePage::~PDFCorePage() {
47 deleteGList(tiles, PDFCoreTile);
48 /*if (links) {
49 delete links;
50 }*/
51 if (text) {
52 delete text;
56 //------------------------------------------------------------------------
57 // PDFCoreTile
58 //------------------------------------------------------------------------
60 PDFCoreTile::PDFCoreTile(int xDestA, int yDestA) {
61 xMin = 0;
62 yMin = 0;
63 xMax = 0;
64 yMax = 0;
65 xDest = xDestA;
66 yDest = yDestA;
67 bitmap = NULL;
70 PDFCoreTile::~PDFCoreTile() {
71 if (bitmap) {
72 delete bitmap;
77 //------------------------------------------------------------------------
78 // PDFCore
79 //------------------------------------------------------------------------
81 PDFCore::PDFCore(SplashColorMode colorModeA, int bitmapRowPadA,
82 GBool reverseVideoA, SplashColorPtr paperColorA) {
83 int i;
85 doc = NULL;
86 continuousMode = globalParams->getContinuousView();
87 drawAreaWidth = drawAreaHeight = 0;
88 maxPageW = totalDocH = 0;
89 pageY = NULL;
90 topPage = 0;
91 scrollX = scrollY = 0;
92 zoom = defZoom;
93 dpi = 0;
94 rotate = 0;
96 selectPage = 0;
97 selectULX = selectLRX = 0;
98 selectULY = selectLRY = 0;
99 dragging = gFalse;
100 lastDragLeft = lastDragTop = gTrue;
102 historyCur = pdfHistorySize - 1;
103 historyBLen = historyFLen = 0;
104 for (i = 0; i < pdfHistorySize; ++i) {
105 history[i].fileName = NULL;
109 pages = new GList();
110 curTile = NULL;
112 splashColorCopy(paperColor, paperColorA);
113 out = new CoreOutputDev(colorModeA, bitmapRowPadA,
114 reverseVideoA, paperColorA, gTrue,
115 &redrawCbk, this);
116 out->startDoc(NULL);
119 PDFCore::~PDFCore() {
120 int i;
122 if (doc) {
123 delete doc;
125 for (i = 0; i < pdfHistorySize; ++i) {
126 if (history[i].fileName) {
127 delete history[i].fileName;
130 gfree(pageY);
131 deleteGList(pages, PDFCorePage);
132 delete out;
135 int PDFCore::loadFile(GString *fileName, GString *ownerPassword,
136 GString *userPassword) {
137 int err;
139 setBusyCursor(gTrue);
140 err = loadFile2(new PDFDoc(fileName->copy(), ownerPassword, userPassword,
141 this));
142 setBusyCursor(gFalse);
143 return err;
146 #ifdef WIN32
147 int PDFCore::loadFile(wchar_t *fileName, int fileNameLen,
148 GString *ownerPassword, GString *userPassword) {
149 int err;
151 setBusyCursor(gTrue);
152 err = loadFile2(new PDFDoc(fileName, fileNameLen,
153 ownerPassword, userPassword, this));
154 setBusyCursor(gFalse);
155 return err;
157 #endif
159 int PDFCore::loadFile(BaseStream *stream, GString *ownerPassword,
160 GString *userPassword) {
161 int err;
163 setBusyCursor(gTrue);
164 err = loadFile2(new PDFDoc(stream, ownerPassword, userPassword, this));
165 setBusyCursor(gFalse);
166 return err;
169 int PDFCore::loadFile2(PDFDoc *newDoc) {
170 int err;
171 double w, h, t;
172 int i;
174 // open the PDF file
175 if (!newDoc->isOk()) {
176 err = newDoc->getErrorCode();
177 delete newDoc;
178 return err;
181 // replace old document
182 if (doc) {
183 delete doc;
185 doc = newDoc;
186 if (out) {
187 out->startDoc(doc->getXRef());
190 // nothing displayed yet
191 topPage = -99;
192 while (pages->getLength() > 0) {
193 delete (PDFCorePage *)pages->del(0);
196 // compute the max unscaled page size
197 maxUnscaledPageW = maxUnscaledPageH = 0;
198 for (i = 1; i <= doc->getNumPages(); ++i) {
199 w = doc->getPageCropWidth(i);
200 h = doc->getPageCropHeight(i);
201 if (doc->getPageRotate(i) == 90 || doc->getPageRotate(i) == 270) {
202 t = w; w = h; h = t;
204 if (w > maxUnscaledPageW) {
205 maxUnscaledPageW = w;
207 if (h > maxUnscaledPageH) {
208 maxUnscaledPageH = h;
212 return errNone;
215 void PDFCore::clear() {
216 if (!doc) {
217 return;
220 // no document
221 delete doc;
222 doc = NULL;
223 out->clear();
225 // no page displayed
226 topPage = -99;
227 while (pages->getLength() > 0) {
228 delete (PDFCorePage *)pages->del(0);
231 // redraw
232 scrollX = scrollY = 0;
233 redrawWindow(0, 0, drawAreaWidth, drawAreaHeight, gTrue);
234 updateScrollbars();
237 void PDFCore::displayPage(int topPageA, double zoomA, int rotateA,
238 GBool scrollToTop, GBool addToHist) {
239 int scrollXA, scrollYA;
241 scrollXA = scrollX;
242 if (continuousMode) {
243 scrollYA = -1;
244 } else if (scrollToTop) {
245 scrollYA = 0;
246 } else {
247 scrollYA = scrollY;
249 if (zoomA != zoom) {
250 scrollXA = 0;
251 scrollYA = continuousMode ? -1 : 0;
254 dragging = gFalse;
255 lastDragLeft = lastDragTop = gTrue;
257 update(topPageA, scrollXA, scrollYA, zoomA, rotateA, gTrue, addToHist);
260 void PDFCore::displayDest(LinkDest *dest, double zoomA, int rotateA,
261 GBool addToHist) {
262 #if 0
263 Ref pageRef;
264 int topPageA;
265 int dx, dy, scrollXA, scrollYA;
267 if (dest->isPageRef()) {
268 pageRef = dest->getPageRef();
269 topPageA = doc->findPage(pageRef.num, pageRef.gen);
270 } else {
271 topPageA = dest->getPageNum();
273 if (topPageA <= 0 || topPageA > doc->getNumPages()) {
274 topPageA = 1;
276 scrollXA = scrollX;
277 scrollYA = continuousMode ? -1 : scrollY;
278 switch (dest->getKind()) {
279 case destXYZ:
280 cvtUserToDev(topPageA, dest->getLeft(), dest->getTop(), &dx, &dy);
281 if (continuousMode && topPage > 0) {
282 dy += pageY[topPageA - 1];
284 scrollXA = dest->getChangeLeft() ? dx : scrollX;
285 scrollYA = dest->getChangeTop() ? dy : scrollY;
286 //~ what is the zoom parameter?
287 break;
288 case destFit:
289 case destFitB:
290 //~ do fit
291 scrollXA = 0;
292 scrollYA = continuousMode ? -1 : 0;
293 break;
294 case destFitH:
295 case destFitBH:
296 //~ do fit
297 cvtUserToDev(topPageA, 0, dest->getTop(), &dx, &dy);
298 if (continuousMode && topPage > 0) {
299 dy += pageY[topPageA - 1];
301 scrollXA = 0;
302 scrollYA = dy;
303 break;
304 case destFitV:
305 case destFitBV:
306 //~ do fit
307 cvtUserToDev(topPageA, dest->getLeft(), 0, &dx, &dy);
308 scrollXA = dx;
309 scrollYA = continuousMode ? -1 : 0;
310 break;
311 case destFitR:
312 //~ do fit
313 cvtUserToDev(topPageA, dest->getLeft(), dest->getTop(), &dx, &dy);
314 if (continuousMode && topPage > 0) {
315 dy += pageY[topPageA - 1];
317 scrollXA = dx;
318 scrollYA = dy;
319 break;
321 update(topPageA, scrollXA, scrollYA, zoom, rotate, gFalse,
322 addToHist && topPageA != topPage);
323 #endif
326 void PDFCore::update(int topPageA, int scrollXA, int scrollYA,
327 double zoomA, int rotateA, GBool force, GBool addToHist) {
328 double hDPI, vDPI, dpiA, uw, uh, ut;
329 int w, h, t, x0, x1, y0, y1, x, y;
330 int rot;
331 int pg0, pg1;
332 PDFCoreTile *tile;
333 PDFCorePage *page;
334 PDFHistory *hist;
335 SplashColor xorColor;
336 GBool needUpdate;
337 int i, j;
339 //~ handle fullScreen
341 // check for document and valid page number
342 if (!doc) {
343 // save the new settings
344 zoom = zoomA;
345 rotate = rotateA;
346 return;
348 if (topPageA <= 0 || topPageA > doc->getNumPages()) {
349 return;
352 needUpdate = gFalse;
354 // check for changes to the PDF file
355 if ((force || (!continuousMode && topPage != topPageA)) &&
356 checkForNewFile()) {
357 if (loadFile(doc->getFileName()) == errNone) {
358 if (topPageA > doc->getNumPages()) {
359 topPageA = doc->getNumPages();
361 needUpdate = gTrue;
365 // compute the DPI
366 if (continuousMode) {
367 uw = maxUnscaledPageW;
368 uh = maxUnscaledPageH;
369 rot = rotateA;
370 } else {
371 uw = doc->getPageCropWidth(topPageA);
372 uh = doc->getPageCropHeight(topPageA);
373 rot = rotateA + doc->getPageRotate(topPageA);
374 if (rot >= 360) {
375 rot -= 360;
376 } else if (rot < 0) {
377 rot += 360;
380 if (rot == 90 || rot == 270) {
381 ut = uw; uw = uh; uh = ut;
383 if (zoomA == zoomPage) {
384 hDPI = (drawAreaWidth / uw) * 72;
385 if (continuousMode) {
386 vDPI = ((drawAreaHeight - continuousModePageSpacing) / uh) * 72;
387 } else {
388 vDPI = (drawAreaHeight / uh) * 72;
390 dpiA = (hDPI < vDPI) ? hDPI : vDPI;
391 } else if (zoomA == zoomWidth) {
392 dpiA = (drawAreaWidth / uw) * 72;
393 } else {
394 dpiA = 0.01 * zoomA * 72;
396 // this can happen if the window hasn't been sized yet
397 if (dpiA <= 0) {
398 dpiA = 1;
401 // if the display properties have changed, create a new PDFCorePage
402 // object
403 if (force || pages->getLength() == 0 ||
404 (!continuousMode && topPageA != topPage) ||
405 zoomA != zoom || dpiA != dpi || rotateA != rotate) {
406 needUpdate = gTrue;
407 setSelection(0, 0, 0, 0, 0);
408 while (pages->getLength() > 0) {
409 delete (PDFCorePage *)pages->del(0);
411 zoom = zoomA;
412 rotate = rotateA;
413 dpi = dpiA;
414 if (continuousMode) {
415 maxPageW = totalDocH = 0;
416 pageY = (int *)greallocn(pageY, doc->getNumPages(), sizeof(int));
417 for (i = 1; i <= doc->getNumPages(); ++i) {
418 pageY[i-1] = totalDocH;
419 w = (int)((doc->getPageCropWidth(i) * dpi) / 72 + 0.5);
420 h = (int)((doc->getPageCropHeight(i) * dpi) / 72 + 0.5);
421 rot = rotate + doc->getPageRotate(i);
422 if (rot >= 360) {
423 rot -= 360;
424 } else if (rot < 0) {
425 rot += 360;
427 if (rot == 90 || rot == 270) {
428 t = w; w = h; h = t;
430 if (w > maxPageW) {
431 maxPageW = w;
433 totalDocH += h;
434 if (i < doc->getNumPages()) {
435 totalDocH += continuousModePageSpacing;
438 } else {
439 rot = rotate + doc->getPageRotate(topPageA);
440 if (rot >= 360) {
441 rot -= 360;
442 } else if (rot < 0) {
443 rot += 360;
445 addPage(topPageA, rot);
447 } else {
448 // erase the selection
449 if (selectULX != selectLRX && selectULY != selectLRY) {
450 xorColor[0] = xorColor[1] = xorColor[2] = 0xff;
451 xorRectangle(selectPage, selectULX, selectULY, selectLRX, selectLRY,
452 new SplashSolidColor(xorColor));
455 if (continuousMode) {
456 page = NULL; // make gcc happy
457 } else {
458 page = (PDFCorePage *)pages->get(0);
460 topPage = topPageA;
462 // adjust the scroll position
463 scrollX = scrollXA;
464 if (continuousMode && scrollYA < 0) {
465 scrollY = pageY[topPage - 1];
466 } else {
467 scrollY = scrollYA;
469 w = continuousMode ? maxPageW : page->w;
470 if (scrollX > w - drawAreaWidth) {
471 scrollX = w - drawAreaWidth;
473 if (scrollX < 0) {
474 scrollX = 0;
476 h = continuousMode ? totalDocH : page->h;
477 if (scrollY > h - drawAreaHeight) {
478 scrollY = h - drawAreaHeight;
480 if (scrollY < 0) {
481 scrollY = 0;
484 // find topPage, and the first and last pages to be rasterized
485 if (continuousMode) {
486 //~ should use a binary search
487 for (i = 2; i <= doc->getNumPages(); ++i) {
488 if (pageY[i-1] > scrollY - drawAreaHeight / 2) {
489 break;
492 pg0 = i - 1;
493 for (i = pg0 + 1; i <= doc->getNumPages(); ++i) {
494 if (pageY[i-1] > scrollY) {
495 break;
498 topPage = i - 1;
499 for (i = topPage + 1; i <= doc->getNumPages(); ++i) {
500 if (pageY[i-1] > scrollY + drawAreaHeight + drawAreaHeight / 2) {
501 break;
504 pg1 = i - 1;
506 // delete pages that are no longer needed and insert new pages
507 // objects that are needed
508 while (pages->getLength() > 0 &&
509 ((PDFCorePage *)pages->get(0))->page < pg0) {
510 delete (PDFCorePage *)pages->del(0);
512 i = pages->getLength() - 1;
513 while (i > 0 && ((PDFCorePage *)pages->get(i))->page > pg1) {
514 delete (PDFCorePage *)pages->del(i--);
516 j = pages->getLength() > 0 ? ((PDFCorePage *)pages->get(0))->page - 1
517 : pg1;
518 for (i = pg0; i <= j; ++i) {
519 rot = rotate + doc->getPageRotate(i);
520 if (rot >= 360) {
521 rot -= 360;
522 } else if (rot < 0) {
523 rot += 360;
525 addPage(i, rot);
527 j = ((PDFCorePage *)pages->get(pages->getLength() - 1))->page;
528 for (i = j + 1; i <= pg1; ++i) {
529 rot = rotate + doc->getPageRotate(i);
530 if (rot >= 360) {
531 rot -= 360;
532 } else if (rot < 0) {
533 rot += 360;
535 addPage(i, rot);
538 } else {
539 pg0 = pg1 = topPage;
542 // delete tiles that are no longer needed
543 for (i = 0; i < pages->getLength(); ++i) {
544 page = (PDFCorePage *)pages->get(i);
545 j = 0;
546 while (j < page->tiles->getLength()) {
547 tile = (PDFCoreTile *)page->tiles->get(j);
548 if (continuousMode) {
549 y0 = pageY[page->page - 1] + tile->yMin;
550 y1 = pageY[page->page - 1] + tile->yMax;
551 } else {
552 y0 = tile->yMin;
553 y1 = tile->yMax;
555 if (tile->xMax < scrollX - drawAreaWidth / 2 ||
556 tile->xMin > scrollX + drawAreaWidth + drawAreaWidth / 2 ||
557 y1 < scrollY - drawAreaHeight / 2 ||
558 y0 > scrollY + drawAreaHeight + drawAreaHeight / 2) {
559 delete (PDFCoreTile *)page->tiles->del(j);
560 } else {
561 ++j;
566 // update page positions
567 for (i = 0; i < pages->getLength(); ++i) {
568 page = (PDFCorePage *)pages->get(i);
569 page->xDest = -scrollX;
570 if (continuousMode) {
571 page->yDest = pageY[page->page - 1] - scrollY;
572 } else {
573 page->yDest = -scrollY;
575 if (continuousMode) {
576 if (page->w < maxPageW) {
577 page->xDest += (maxPageW - page->w) / 2;
579 if (maxPageW < drawAreaWidth) {
580 page->xDest += (drawAreaWidth - maxPageW) / 2;
582 } else if (page->w < drawAreaWidth) {
583 page->xDest += (drawAreaWidth - page->w) / 2;
585 if (continuousMode && totalDocH < drawAreaHeight) {
586 page->yDest += (drawAreaHeight - totalDocH) / 2;
587 } else if (!continuousMode && page->h < drawAreaHeight) {
588 page->yDest += (drawAreaHeight - page->h) / 2;
592 // rasterize any new tiles
593 for (i = 0; i < pages->getLength(); ++i) {
594 page = (PDFCorePage *)pages->get(i);
595 x0 = page->xDest;
596 x1 = x0 + page->w - 1;
597 if (x0 < -drawAreaWidth / 2) {
598 x0 = -drawAreaWidth / 2;
600 if (x1 > drawAreaWidth + drawAreaWidth / 2) {
601 x1 = drawAreaWidth + drawAreaWidth / 2;
603 x0 = ((x0 - page->xDest) / page->tileW) * page->tileW;
604 x1 = ((x1 - page->xDest) / page->tileW) * page->tileW;
605 y0 = page->yDest;
606 y1 = y0 + page->h - 1;
607 if (y0 < -drawAreaHeight / 2) {
608 y0 = -drawAreaHeight / 2;
610 if (y1 > drawAreaHeight + drawAreaHeight / 2) {
611 y1 = drawAreaHeight + drawAreaHeight / 2;
613 y0 = ((y0 - page->yDest) / page->tileH) * page->tileH;
614 y1 = ((y1 - page->yDest) / page->tileH) * page->tileH;
615 for (y = y0; y <= y1; y += page->tileH) {
616 for (x = x0; x <= x1; x += page->tileW) {
617 needTile(page, x, y);
622 // update tile positions
623 for (i = 0; i < pages->getLength(); ++i) {
624 page = (PDFCorePage *)pages->get(i);
625 for (j = 0; j < page->tiles->getLength(); ++j) {
626 tile = (PDFCoreTile *)page->tiles->get(j);
627 tile->xDest = tile->xMin - scrollX;
628 if (continuousMode) {
629 tile->yDest = tile->yMin + pageY[page->page - 1] - scrollY;
630 } else {
631 tile->yDest = tile->yMin - scrollY;
633 if (continuousMode) {
634 if (page->w < maxPageW) {
635 tile->xDest += (maxPageW - page->w) / 2;
637 if (maxPageW < drawAreaWidth) {
638 tile->xDest += (drawAreaWidth - maxPageW) / 2;
640 } else if (page->w < drawAreaWidth) {
641 tile->xDest += (drawAreaWidth - page->w) / 2;
643 if (continuousMode && totalDocH < drawAreaHeight) {
644 tile->yDest += (drawAreaHeight - totalDocH) / 2;
645 } else if (!continuousMode && page->h < drawAreaHeight) {
646 tile->yDest += (drawAreaHeight - page->h) / 2;
651 // redraw the selection
652 if (selectULX != selectLRX && selectULY != selectLRY) {
653 xorColor[0] = xorColor[1] = xorColor[2] = 0xff;
654 xorRectangle(selectPage, selectULX, selectULY, selectLRX, selectLRY,
655 new SplashSolidColor(xorColor));
658 // redraw the window
659 redrawWindow(0, 0, drawAreaWidth, drawAreaHeight, needUpdate);
660 updateScrollbars();
662 // add to history
663 if (addToHist) {
664 if (++historyCur == pdfHistorySize) {
665 historyCur = 0;
667 hist = &history[historyCur];
668 if (hist->fileName) {
669 delete hist->fileName;
671 if (doc->getFileName()) {
672 hist->fileName = doc->getFileName()->copy();
673 } else {
674 hist->fileName = NULL;
676 hist->page = topPage;
677 if (historyBLen < pdfHistorySize) {
678 ++historyBLen;
680 historyFLen = 0;
684 void PDFCore::addPage(int pg, int rot) {
685 PDFCorePage *page;
686 int w, h, t, tileW, tileH, i;
688 w = (int)((doc->getPageCropWidth(pg) * dpi) / 72 + 0.5);
689 h = (int)((doc->getPageCropHeight(pg) * dpi) / 72 + 0.5);
690 if (rot == 90 || rot == 270) {
691 t = w; w = h; h = t;
693 tileW = 2 * drawAreaWidth;
694 if (tileW < 1500) {
695 tileW = 1500;
697 if (tileW > w) {
698 tileW = w;
700 tileH = 2 * drawAreaHeight;
701 if (tileH < 1500) {
702 tileH = 1500;
704 if (tileH > h) {
705 tileH = h;
707 page = new PDFCorePage(pg, w, h, tileW, tileH);
708 for (i = 0;
709 i < pages->getLength() && pg > ((PDFCorePage *)pages->get(i))->page;
710 ++i) ;
711 pages->insert(i, page);
714 void PDFCore::needTile(PDFCorePage *page, int x, int y) {
715 PDFCoreTile *tile;
716 TextOutputDev *textOut;
717 int xDest, yDest, sliceW, sliceH;
718 int i;
720 for (i = 0; i < page->tiles->getLength(); ++i) {
721 tile = (PDFCoreTile *)page->tiles->get(i);
722 if (x == tile->xMin && y == tile->yMin) {
723 return;
727 setBusyCursor(gTrue);
729 sliceW = page->tileW;
730 if (x + sliceW > page->w) {
731 sliceW = page->w - x;
733 sliceH = page->tileH;
734 if (y + sliceH > page->h) {
735 sliceH = page->h - y;
738 xDest = x - scrollX;
739 if (continuousMode) {
740 yDest = y + pageY[page->page - 1] - scrollY;
741 } else {
742 yDest = y - scrollY;
744 if (continuousMode) {
745 if (page->w < maxPageW) {
746 xDest += (maxPageW - page->w) / 2;
748 if (maxPageW < drawAreaWidth) {
749 xDest += (drawAreaWidth - maxPageW) / 2;
751 } else if (page->w < drawAreaWidth) {
752 xDest += (drawAreaWidth - page->w) / 2;
754 if (continuousMode && totalDocH < drawAreaHeight) {
755 yDest += (drawAreaHeight - totalDocH) / 2;
756 } else if (!continuousMode && page->h < drawAreaHeight) {
757 yDest += (drawAreaHeight - page->h) / 2;
759 curTile = tile = newTile(xDest, yDest);
760 tile->xMin = x;
761 tile->yMin = y;
762 tile->xMax = x + sliceW;
763 tile->yMax = y + sliceH;
764 tile->edges = 0;
765 if (tile->xMin == 0) {
766 tile->edges |= pdfCoreTileLeftEdge;
768 if (tile->xMax == page->w) {
769 tile->edges |= pdfCoreTileRightEdge;
771 if (continuousMode) {
772 if (tile->yMin == 0) {
773 tile->edges |= pdfCoreTileTopSpace;
774 if (page->page == 1) {
775 tile->edges |= pdfCoreTileTopEdge;
778 if (tile->yMax == page->h) {
779 tile->edges |= pdfCoreTileBottomSpace;
780 if (page->page == doc->getNumPages()) {
781 tile->edges |= pdfCoreTileBottomEdge;
784 } else {
785 if (tile->yMin == 0) {
786 tile->edges |= pdfCoreTileTopEdge;
788 if (tile->yMax == page->h) {
789 tile->edges |= pdfCoreTileBottomEdge;
792 doc->displayPageSlice(out, page->page, dpi, dpi, rotate,
793 gFalse, gTrue, gTrue, x, y, sliceW, sliceH);
794 tile->bitmap = out->takeBitmap();
795 memcpy(tile->ctm, out->getDefCTM(), 6 * sizeof(double));
796 memcpy(tile->ictm, out->getDefICTM(), 6 * sizeof(double));
797 if (!page->links) {
798 page->links = doc->takeLinks();
800 if (!page->text) {
801 if ((textOut = new TextOutputDev(NULL, gTrue, gFalse, gFalse))) {
802 doc->displayPage(textOut, page->page, dpi, dpi, rotate,
803 gFalse, gTrue, gFalse);
804 page->text = textOut->takeText();
805 delete textOut;
808 page->tiles->append(tile);
810 setBusyCursor(gFalse);
813 GBool PDFCore::gotoNextPage(int inc, GBool top) {
814 int pg, scrollYA;
816 if (!doc || doc->getNumPages() == 0 || topPage >= doc->getNumPages()) {
817 return gFalse;
819 if ((pg = topPage + inc) > doc->getNumPages()) {
820 pg = doc->getNumPages();
822 if (continuousMode) {
823 scrollYA = -1;
824 } else if (top) {
825 scrollYA = 0;
826 } else {
827 scrollYA = scrollY;
829 update(pg, scrollX, scrollYA, zoom, rotate, gFalse, gTrue);
830 return gTrue;
833 GBool PDFCore::gotoPrevPage(int dec, GBool top, GBool bottom) {
834 int pg, scrollYA;
836 if (!doc || doc->getNumPages() == 0 || topPage <= 1) {
837 return gFalse;
839 if ((pg = topPage - dec) < 1) {
840 pg = 1;
842 if (continuousMode) {
843 scrollYA = -1;
844 } else if (top) {
845 scrollYA = 0;
846 } else if (bottom) {
847 scrollYA = ((PDFCorePage *)pages->get(0))->h - drawAreaHeight;
848 if (scrollYA < 0) {
849 scrollYA = 0;
851 } else {
852 scrollYA = scrollY;
854 update(pg, scrollX, scrollYA, zoom, rotate, gFalse, gTrue);
855 return gTrue;
858 GBool PDFCore::gotoNamedDestination(GString *dest) {
859 #if 0
860 LinkDest *d;
862 if (!doc) {
863 return gFalse;
865 if (!(d = doc->findDest(dest))) {
866 return gFalse;
868 displayDest(d, zoom, rotate, gTrue);
869 delete d;
870 return gTrue;
871 #else
872 return gFalse;
873 #endif
876 GBool PDFCore::goForward() {
877 int pg;
879 if (historyFLen == 0) {
880 return gFalse;
882 if (++historyCur == pdfHistorySize) {
883 historyCur = 0;
885 --historyFLen;
886 ++historyBLen;
887 if (!doc || history[historyCur].fileName->cmp(doc->getFileName()) != 0) {
888 if (loadFile(history[historyCur].fileName) != errNone) {
889 return gFalse;
892 pg = history[historyCur].page;
893 update(pg, scrollX, continuousMode ? -1 : scrollY,
894 zoom, rotate, gFalse, gFalse);
895 return gTrue;
898 GBool PDFCore::goBackward() {
899 int pg;
901 if (historyBLen <= 1) {
902 return gFalse;
904 if (--historyCur < 0) {
905 historyCur = pdfHistorySize - 1;
907 --historyBLen;
908 ++historyFLen;
909 if (!doc || history[historyCur].fileName->cmp(doc->getFileName()) != 0) {
910 if (loadFile(history[historyCur].fileName) != errNone) {
911 return gFalse;
914 pg = history[historyCur].page;
915 update(pg, scrollX, continuousMode ? -1 : scrollY,
916 zoom, rotate, gFalse, gFalse);
917 return gTrue;
920 void PDFCore::scrollLeft(int nCols) {
921 scrollTo(scrollX - nCols * 16, scrollY);
924 void PDFCore::scrollRight(int nCols) {
925 scrollTo(scrollX + nCols * 16, scrollY);
928 void PDFCore::scrollUp(int nLines) {
929 scrollTo(scrollX, scrollY - nLines * 16);
932 void PDFCore::scrollDown(int nLines) {
933 scrollTo(scrollX, scrollY + nLines * 16);
936 void PDFCore::scrollPageUp() {
937 if (!continuousMode && scrollY == 0) {
938 gotoPrevPage(1, gFalse, gTrue);
939 } else {
940 scrollTo(scrollX, scrollY - drawAreaHeight);
944 void PDFCore::scrollPageDown() {
945 if (!continuousMode &&
946 scrollY >= ((PDFCorePage *)pages->get(0))->h - drawAreaHeight) {
947 gotoNextPage(1, gTrue);
948 } else {
949 scrollTo(scrollX, scrollY + drawAreaHeight);
953 void PDFCore::scrollTo(int x, int y) {
954 update(topPage, x, y < 0 ? 0 : y, zoom, rotate, gFalse, gFalse);
957 void PDFCore::zoomToRect(int pg, double ulx, double uly,
958 double lrx, double lry) {
959 int x0, y0, x1, y1, u, sx, sy;
960 double rx, ry, newZoom, t;
961 PDFCorePage *p;
963 cvtUserToDev(pg, ulx, uly, &x0, &y0);
964 cvtUserToDev(pg, lrx, lry, &x1, &y1);
965 if (x0 > x1) {
966 u = x0; x0 = x1; x1 = u;
968 if (y0 > y1) {
969 u = y0; y0 = y1; y1 = u;
971 rx = (double)drawAreaWidth / (double)(x1 - x0);
972 ry = (double)drawAreaHeight / (double)(y1 - y0);
973 if (rx < ry) {
974 newZoom = rx * (dpi / (0.01 * 72));
975 sx = (int)(rx * x0);
976 t = (drawAreaHeight * (x1 - x0)) / drawAreaWidth;
977 sy = (int)(rx * (y0 + y1 - t) / 2);
978 if (continuousMode) {
979 if ((p = findPage(pg)) && p->w < maxPageW) {
980 sx += (int)(0.5 * rx * (maxPageW - p->w));
982 u = (pg - 1) * continuousModePageSpacing;
983 sy += (int)(rx * (pageY[pg - 1] - u)) + u;
985 } else {
986 newZoom = ry * (dpi / (0.01 * 72));
987 t = (drawAreaWidth * (y1 - y0)) / drawAreaHeight;
988 sx = (int)(ry * (x0 + x1 - t) / 2);
989 sy = (int)(ry * y0);
990 if (continuousMode) {
991 if ((p = findPage(pg)) && p->w < maxPageW) {
992 sx += (int)(0.5 * rx * (maxPageW - p->w));
994 u = (pg - 1) * continuousModePageSpacing;
995 sy += (int)(ry * (pageY[pg - 1] - u)) + u;
998 update(pg, sx, sy, newZoom, rotate, gFalse, gFalse);
1001 void PDFCore::setContinuousMode(GBool cm) {
1002 if (continuousMode != cm) {
1003 continuousMode = cm;
1004 update(topPage, scrollX, -1, zoom, rotate, gTrue, gFalse);
1008 void PDFCore::setSelection(int newSelectPage,
1009 int newSelectULX, int newSelectULY,
1010 int newSelectLRX, int newSelectLRY) {
1011 int x0, y0, x1, y1, py;
1012 GBool haveSel, newHaveSel;
1013 GBool needRedraw, needScroll;
1014 GBool moveLeft, moveRight, moveTop, moveBottom;
1015 SplashColor xorColor;
1016 PDFCorePage *page;
1019 haveSel = selectULX != selectLRX && selectULY != selectLRY;
1020 newHaveSel = newSelectULX != newSelectLRX && newSelectULY != newSelectLRY;
1022 // erase old selection on off-screen bitmap
1023 needRedraw = gFalse;
1024 if (haveSel) {
1025 xorColor[0] = xorColor[1] = xorColor[2] = 0xff;
1026 xorRectangle(selectPage, selectULX, selectULY, selectLRX, selectLRY,
1027 new SplashSolidColor(xorColor));
1028 needRedraw = gTrue;
1031 // draw new selection on off-screen bitmap
1032 if (newHaveSel) {
1033 xorColor[0] = xorColor[1] = xorColor[2] = 0xff;
1034 xorRectangle(newSelectPage, newSelectULX, newSelectULY,
1035 newSelectLRX, newSelectLRY,
1036 new SplashSolidColor(xorColor));
1037 needRedraw = gTrue;
1040 // check which edges moved
1041 if (!haveSel || newSelectPage != selectPage) {
1042 moveLeft = moveTop = moveRight = moveBottom = gTrue;
1043 } else {
1044 moveLeft = newSelectULX != selectULX;
1045 moveTop = newSelectULY != selectULY;
1046 moveRight = newSelectLRX != selectLRX;
1047 moveBottom = newSelectLRY != selectLRY;
1050 // redraw currently visible part of bitmap
1051 if (needRedraw) {
1052 if (!haveSel) {
1053 page = findPage(newSelectPage);
1054 x0 = newSelectULX;
1055 y0 = newSelectULY;
1056 x1 = newSelectLRX;
1057 y1 = newSelectLRY;
1058 redrawWindow(page->xDest + x0, page->yDest + y0,
1059 x1 - x0 + 1, y1 - y0 + 1, gFalse);
1060 } else if (!newHaveSel) {
1061 if ((page = findPage(selectPage))) {
1062 x0 = selectULX;
1063 y0 = selectULY;
1064 x1 = selectLRX;
1065 y1 = selectLRY;
1066 redrawWindow(page->xDest + x0, page->yDest + y0,
1067 x1 - x0 + 1, y1 - y0 + 1, gFalse);
1069 } else {
1070 page = findPage(newSelectPage);
1071 if (moveLeft) {
1072 x0 = newSelectULX < selectULX ? newSelectULX : selectULX;
1073 y0 = newSelectULY < selectULY ? newSelectULY : selectULY;
1074 x1 = newSelectULX > selectULX ? newSelectULX : selectULX;
1075 y1 = newSelectLRY > selectLRY ? newSelectLRY : selectLRY;
1076 redrawWindow(page->xDest + x0, page->yDest + y0,
1077 x1 - x0 + 1, y1 - y0 + 1, gFalse);
1079 if (moveRight) {
1080 x0 = newSelectLRX < selectLRX ? newSelectLRX : selectLRX;
1081 y0 = newSelectULY < selectULY ? newSelectULY : selectULY;
1082 x1 = newSelectLRX > selectLRX ? newSelectLRX : selectLRX;
1083 y1 = newSelectLRY > selectLRY ? newSelectLRY : selectLRY;
1084 redrawWindow(page->xDest + x0, page->yDest + y0,
1085 x1 - x0 + 1, y1 - y0 + 1, gFalse);
1087 if (moveTop) {
1088 x0 = newSelectULX < selectULX ? newSelectULX : selectULX;
1089 y0 = newSelectULY < selectULY ? newSelectULY : selectULY;
1090 x1 = newSelectLRX > selectLRX ? newSelectLRX : selectLRX;
1091 y1 = newSelectULY > selectULY ? newSelectULY : selectULY;
1092 redrawWindow(page->xDest + x0, page->yDest + y0,
1093 x1 - x0 + 1, y1 - y0 + 1, gFalse);
1095 if (moveBottom) {
1096 x0 = newSelectULX < selectULX ? newSelectULX : selectULX;
1097 y0 = newSelectLRY < selectLRY ? newSelectLRY : selectLRY;
1098 x1 = newSelectLRX > selectLRX ? newSelectLRX : selectLRX;
1099 y1 = newSelectLRY > selectLRY ? newSelectLRY : selectLRY;
1100 redrawWindow(page->xDest + x0, page->yDest + y0,
1101 x1 - x0 + 1, y1 - y0 + 1, gFalse);
1106 // switch to new selection coords
1107 selectPage = newSelectPage;
1108 selectULX = newSelectULX;
1109 selectULY = newSelectULY;
1110 selectLRX = newSelectLRX;
1111 selectLRY = newSelectLRY;
1113 // scroll if necessary
1114 #if 0 //~tmp
1115 if (fullScreen) {
1116 return;
1118 #endif
1119 if (newHaveSel) {
1120 page = findPage(selectPage);
1121 needScroll = gFalse;
1122 x0 = scrollX;
1123 y0 = scrollY;
1124 if (moveLeft && page->xDest + selectULX < 0) {
1125 x0 += page->xDest + selectULX;
1126 needScroll = gTrue;
1127 } else if (moveRight && page->xDest + selectLRX >= drawAreaWidth) {
1128 x0 += page->xDest + selectLRX - drawAreaWidth;
1129 needScroll = gTrue;
1130 } else if (moveLeft && page->xDest + selectULX >= drawAreaWidth) {
1131 x0 += page->xDest + selectULX - drawAreaWidth;
1132 needScroll = gTrue;
1133 } else if (moveRight && page->xDest + selectLRX < 0) {
1134 x0 += page->xDest + selectLRX;
1135 needScroll = gTrue;
1137 py = continuousMode ? pageY[selectPage - 1] : 0;
1138 if (moveTop && py + selectULY < y0) {
1139 y0 = py + selectULY;
1140 needScroll = gTrue;
1141 } else if (moveBottom && py + selectLRY >= y0 + drawAreaHeight) {
1142 y0 = py + selectLRY - drawAreaHeight;
1143 needScroll = gTrue;
1144 } else if (moveTop && py + selectULY >= y0 + drawAreaHeight) {
1145 y0 = py + selectULY - drawAreaHeight;
1146 needScroll = gTrue;
1147 } else if (moveBottom && py + selectLRY < y0) {
1148 y0 = py + selectLRY;
1149 needScroll = gTrue;
1151 if (needScroll) {
1152 scrollTo(x0, y0);
1157 void PDFCore::moveSelection(int pg, int x, int y) {
1158 int newSelectULX, newSelectULY, newSelectLRX, newSelectLRY;
1160 // don't allow selections to span multiple pages
1161 if (pg != selectPage) {
1162 return;
1165 // move appropriate edges of selection
1166 if (lastDragLeft) {
1167 if (x < selectLRX) {
1168 newSelectULX = x;
1169 newSelectLRX = selectLRX;
1170 } else {
1171 newSelectULX = selectLRX;
1172 newSelectLRX = x;
1173 lastDragLeft = gFalse;
1175 } else {
1176 if (x > selectULX) {
1177 newSelectULX = selectULX;
1178 newSelectLRX = x;
1179 } else {
1180 newSelectULX = x;
1181 newSelectLRX = selectULX;
1182 lastDragLeft = gTrue;
1185 if (lastDragTop) {
1186 if (y < selectLRY) {
1187 newSelectULY = y;
1188 newSelectLRY = selectLRY;
1189 } else {
1190 newSelectULY = selectLRY;
1191 newSelectLRY = y;
1192 lastDragTop = gFalse;
1194 } else {
1195 if (y > selectULY) {
1196 newSelectULY = selectULY;
1197 newSelectLRY = y;
1198 } else {
1199 newSelectULY = y;
1200 newSelectLRY = selectULY;
1201 lastDragTop = gTrue;
1205 // redraw the selection
1206 setSelection(selectPage, newSelectULX, newSelectULY,
1207 newSelectLRX, newSelectLRY);
1210 void PDFCore::xorRectangle(int pg, int x0, int y0, int x1, int y1,
1211 SplashPattern *pattern, PDFCoreTile *oneTile) {
1212 Splash *splash;
1213 SplashPath *path;
1214 PDFCorePage *page;
1215 PDFCoreTile *tile;
1216 SplashCoord xx0, yy0, xx1, yy1;
1217 int xi, yi, wi, hi;
1218 int i;
1220 if ((page = findPage(pg))) {
1221 for (i = 0; i < page->tiles->getLength(); ++i) {
1222 tile = (PDFCoreTile *)page->tiles->get(i);
1223 if (!oneTile || tile == oneTile) {
1224 splash = new Splash(tile->bitmap);
1225 splash->setFillPattern(pattern->copy());
1226 xx0 = (SplashCoord)(x0 - tile->xMin);
1227 yy0 = (SplashCoord)(y0 - tile->yMin);
1228 xx1 = (SplashCoord)(x1 - tile->xMin);
1229 yy1 = (SplashCoord)(y1 - tile->yMin);
1230 path = new SplashPath();
1231 path->moveTo(xx0, yy0);
1232 path->lineTo(xx1, yy0);
1233 path->lineTo(xx1, yy1);
1234 path->lineTo(xx0, yy1);
1235 path->close();
1236 splash->xorFill(path, gTrue);
1237 delete path;
1238 delete splash;
1239 xi = x0 - tile->xMin;
1240 wi = x1 - x0;
1241 if (xi < 0) {
1242 wi += xi;
1243 xi = 0;
1245 if (xi + wi > tile->bitmap->getWidth()) {
1246 wi = tile->bitmap->getWidth() - xi;
1248 yi = y0 - tile->yMin;
1249 hi = y1 - y0;
1250 if (yi < 0) {
1251 hi += yi;
1252 yi = 0;
1254 if (yi + hi > tile->bitmap->getHeight()) {
1255 hi = tile->bitmap->getHeight() - yi;
1257 updateTileData(tile, xi, yi, wi, hi);
1261 delete pattern;
1264 GBool PDFCore::getSelection(int *pg, double *ulx, double *uly,
1265 double *lrx, double *lry) {
1266 if (selectULX == selectLRX || selectULY == selectLRY) {
1267 return gFalse;
1269 *pg = selectPage;
1270 cvtDevToUser(selectPage, selectULX, selectULY, ulx, uly);
1271 cvtDevToUser(selectPage, selectLRX, selectLRY, lrx, lry);
1272 return gTrue;
1275 GString *PDFCore::extractText(int pg, double xMin, double yMin,
1276 double xMax, double yMax) {
1277 PDFCorePage *page;
1278 TextOutputDev *textOut;
1279 int x0, y0, x1, y1, t;
1280 GString *s;
1282 if (!doc->okToCopy()) {
1283 return NULL;
1285 if ((page = findPage(pg))) {
1286 cvtUserToDev(pg, xMin, yMin, &x0, &y0);
1287 cvtUserToDev(pg, xMax, yMax, &x1, &y1);
1288 if (x0 > x1) {
1289 t = x0; x0 = x1; x1 = t;
1291 if (y0 > y1) {
1292 t = y0; y0 = y1; y1 = t;
1294 s = page->text->getText(x0, y0, x1, y1);
1295 } else {
1296 textOut = new TextOutputDev(NULL, gTrue, gFalse, gFalse);
1297 if (textOut->isOk()) {
1298 doc->displayPage(textOut, pg, dpi, dpi, rotate, gFalse, gTrue, gFalse);
1299 textOut->cvtUserToDev(xMin, yMin, &x0, &y0);
1300 textOut->cvtUserToDev(xMax, yMax, &x1, &y1);
1301 if (x0 > x1) {
1302 t = x0; x0 = x1; x1 = t;
1304 if (y0 > y1) {
1305 t = y0; y0 = y1; y1 = t;
1307 s = textOut->getText(x0, y0, x1, y1);
1308 } else {
1309 s = new GString();
1311 delete textOut;
1313 return s;
1316 GBool PDFCore::find(char *s, GBool caseSensitive, GBool next, GBool backward,
1317 GBool onePageOnly) {
1318 Unicode *u;
1319 int len, i;
1320 GBool ret;
1322 // convert to Unicode
1323 len = strlen(s);
1324 u = (Unicode *)gmallocn(len, sizeof(Unicode));
1325 for (i = 0; i < len; ++i) {
1326 u[i] = (Unicode)(s[i] & 0xff);
1329 ret = findU(u, len, caseSensitive, next, backward, onePageOnly);
1331 gfree(u);
1332 return ret;
1335 GBool PDFCore::findU(Unicode *u, int len, GBool caseSensitive,
1336 GBool next, GBool backward, GBool onePageOnly) {
1337 TextOutputDev *textOut;
1338 double xMin, yMin, xMax, yMax;
1339 PDFCorePage *page;
1340 PDFCoreTile *tile;
1341 int pg;
1342 GBool startAtTop, startAtLast, stopAtLast;
1344 // check for zero-length string
1345 if (len == 0) {
1346 return gFalse;
1349 setBusyCursor(gTrue);
1351 // search current page starting at previous result, current
1352 // selection, or top/bottom of page
1353 startAtTop = startAtLast = gFalse;
1354 xMin = yMin = xMax = yMax = 0;
1355 pg = topPage;
1356 if (next) {
1357 startAtLast = gTrue;
1358 } else if (selectULX != selectLRX && selectULY != selectLRY) {
1359 pg = selectPage;
1360 if (backward) {
1361 xMin = selectULX - 1;
1362 yMin = selectULY - 1;
1363 } else {
1364 xMin = selectULX + 1;
1365 yMin = selectULY + 1;
1367 } else {
1368 startAtTop = gTrue;
1370 if (!(page = findPage(pg))) {
1371 displayPage(pg, zoom, rotate, gTrue, gFalse);
1372 page = findPage(pg);
1374 if (page->text->findText(u, len, startAtTop, gTrue, startAtLast, gFalse,
1375 caseSensitive, backward,
1376 &xMin, &yMin, &xMax, &yMax)) {
1377 goto found;
1380 if (!onePageOnly) {
1382 // search following/previous pages
1383 textOut = new TextOutputDev(NULL, gTrue, gFalse, gFalse);
1384 if (!textOut->isOk()) {
1385 delete textOut;
1386 goto notFound;
1388 for (pg = backward ? pg - 1 : pg + 1;
1389 backward ? pg >= 1 : pg <= doc->getNumPages();
1390 pg += backward ? -1 : 1) {
1391 doc->displayPage(textOut, pg, 72, 72, 0, gFalse, gTrue, gFalse);
1392 if (textOut->findText(u, len, gTrue, gTrue, gFalse, gFalse,
1393 caseSensitive, backward,
1394 &xMin, &yMin, &xMax, &yMax)) {
1395 delete textOut;
1396 goto foundPage;
1400 // search previous/following pages
1401 for (pg = backward ? doc->getNumPages() : 1;
1402 backward ? pg > topPage : pg < topPage;
1403 pg += backward ? -1 : 1) {
1404 doc->displayPage(textOut, pg, 72, 72, 0, gFalse, gTrue, gFalse);
1405 if (textOut->findText(u, len, gTrue, gTrue, gFalse, gFalse,
1406 caseSensitive, backward,
1407 &xMin, &yMin, &xMax, &yMax)) {
1408 delete textOut;
1409 goto foundPage;
1412 delete textOut;
1416 // search current page ending at previous result, current selection,
1417 // or bottom/top of page
1418 if (!startAtTop) {
1419 xMin = yMin = xMax = yMax = 0;
1420 if (next) {
1421 stopAtLast = gTrue;
1422 } else {
1423 stopAtLast = gFalse;
1424 xMax = selectLRX;
1425 yMax = selectLRY;
1427 if (page->text->findText(u, len, gTrue, gFalse, gFalse, stopAtLast,
1428 caseSensitive, backward,
1429 &xMin, &yMin, &xMax, &yMax)) {
1430 goto found;
1434 // not found
1435 notFound:
1436 setBusyCursor(gFalse);
1437 return gFalse;
1439 // found on a different page
1440 foundPage:
1441 update(pg, scrollX, continuousMode ? -1 : 0, zoom, rotate, gFalse, gTrue);
1442 page = findPage(pg);
1443 if (!page->text->findText(u, len, gTrue, gTrue, gFalse, gFalse,
1444 caseSensitive, backward,
1445 &xMin, &yMin, &xMax, &yMax)) {
1446 // this can happen if coalescing is bad
1447 goto notFound;
1450 // found: change the selection
1451 found:
1452 tile = (PDFCoreTile *)page->tiles->get(0);
1453 setSelection(pg, (int)floor(xMin), (int)floor(yMin),
1454 (int)ceil(xMax), (int)ceil(yMax));
1456 setBusyCursor(gFalse);
1457 return gTrue;
1461 GBool PDFCore::cvtWindowToUser(int xw, int yw,
1462 int *pg, double *xu, double *yu) {
1463 PDFCorePage *page;
1464 PDFCoreTile *tile;
1465 int i, j;
1467 for (i = 0; i < pages->getLength(); ++i) {
1468 page = (PDFCorePage *)pages->get(i);
1469 for (j = 0; j < page->tiles->getLength(); ++j) {
1470 tile = (PDFCoreTile *)page->tiles->get(j);
1471 if ((xw >= tile->xDest && xw < tile->xDest + tile->xMax - tile->xMin &&
1472 yw >= tile->yDest && yw < tile->yDest + tile->yMax - tile->yMin) ||
1473 ((tile->edges & pdfCoreTileTopEdge) &&
1474 (tile->edges & pdfCoreTileLeftEdge) &&
1475 xw < tile->xDest + tile->xMax - tile->xMin &&
1476 yw < tile->yDest + tile->yMax - tile->yMin) ||
1477 ((tile->edges & pdfCoreTileTopEdge) &&
1478 (tile->edges & pdfCoreTileRightEdge) &&
1479 xw >= tile->xDest &&
1480 yw < tile->yDest + tile->yMax - tile->yMin) ||
1481 ((tile->edges & pdfCoreTileTopEdge) &&
1482 xw >= tile->xDest && xw < tile->xDest + tile->xMax - tile->xMin &&
1483 yw < tile->yDest + tile->yMax - tile->yMin) ||
1484 ((tile->edges & pdfCoreTileBottomEdge) &&
1485 (tile->edges & pdfCoreTileLeftEdge) &&
1486 xw < tile->xDest + tile->xMax - tile->xMin &&
1487 yw >= tile->yDest) ||
1488 ((tile->edges & pdfCoreTileBottomEdge) &&
1489 (tile->edges & pdfCoreTileRightEdge) &&
1490 xw >= tile->xDest &&
1491 yw >= tile->yDest) ||
1492 ((tile->edges & pdfCoreTileBottomEdge) &&
1493 xw >= tile->xDest && xw < tile->xDest + tile->xMax - tile->xMin &&
1494 yw >= tile->yDest) ||
1495 ((tile->edges & pdfCoreTileLeftEdge) &&
1496 xw < tile->xDest + tile->xMax - tile->xMin &&
1497 yw >= tile->yDest && yw < tile->yDest + tile->yMax - tile->yMin) ||
1498 ((tile->edges & pdfCoreTileRightEdge) &&
1499 xw >= tile->xDest &&
1500 yw >= tile->yDest && yw < tile->yDest + tile->yMax - tile->yMin)) {
1501 *pg = page->page;
1502 xw -= tile->xDest;
1503 yw -= tile->yDest;
1504 *xu = tile->ictm[0] * xw + tile->ictm[2] * yw + tile->ictm[4];
1505 *yu = tile->ictm[1] * xw + tile->ictm[3] * yw + tile->ictm[5];
1506 return gTrue;
1510 *pg = 0;
1511 *xu = *yu = 0;
1512 return gFalse;
1515 GBool PDFCore::cvtWindowToDev(int xw, int yw, int *pg, int *xd, int *yd) {
1516 PDFCorePage *page;
1517 PDFCoreTile *tile;
1518 int i, j;
1520 for (i = 0; i < pages->getLength(); ++i) {
1521 page = (PDFCorePage *)pages->get(i);
1522 for (j = 0; j < page->tiles->getLength(); ++j) {
1523 tile = (PDFCoreTile *)page->tiles->get(j);
1524 if ((xw >= tile->xDest && xw < tile->xDest + tile->xMax - tile->xMin &&
1525 yw >= tile->yDest && yw < tile->yDest + tile->yMax - tile->yMin) ||
1526 ((tile->edges & pdfCoreTileTopEdge) &&
1527 (tile->edges & pdfCoreTileLeftEdge) &&
1528 xw < tile->xDest + tile->xMax - tile->xMin &&
1529 yw < tile->yDest + tile->yMax - tile->yMin) ||
1530 ((tile->edges & pdfCoreTileTopEdge) &&
1531 (tile->edges & pdfCoreTileRightEdge) &&
1532 xw >= tile->xDest &&
1533 yw < tile->yDest + tile->yMax - tile->yMin) ||
1534 ((tile->edges & pdfCoreTileTopEdge) &&
1535 xw >= tile->xDest && xw < tile->xDest + tile->xMax - tile->xMin &&
1536 yw < tile->yDest + tile->yMax - tile->yMin) ||
1537 ((tile->edges & pdfCoreTileBottomEdge) &&
1538 (tile->edges & pdfCoreTileLeftEdge) &&
1539 xw < tile->xDest + tile->xMax - tile->xMin &&
1540 yw >= tile->yDest) ||
1541 ((tile->edges & pdfCoreTileBottomEdge) &&
1542 (tile->edges & pdfCoreTileRightEdge) &&
1543 xw >= tile->xDest &&
1544 yw >= tile->yDest) ||
1545 ((tile->edges & pdfCoreTileBottomEdge) &&
1546 xw >= tile->xDest && xw < tile->xDest + tile->xMax - tile->xMin &&
1547 yw >= tile->yDest) ||
1548 ((tile->edges & pdfCoreTileLeftEdge) &&
1549 xw < tile->xDest + tile->xMax - tile->xMin &&
1550 yw >= tile->yDest && yw < tile->yDest + tile->yMax - tile->yMin) ||
1551 ((tile->edges & pdfCoreTileRightEdge) &&
1552 xw >= tile->xDest &&
1553 yw >= tile->yDest && yw < tile->yDest + tile->yMax - tile->yMin)) {
1554 *pg = page->page;
1555 *xd = tile->xMin + xw - tile->xDest;
1556 *yd = tile->yMin + yw - tile->yDest;
1557 return gTrue;
1561 *pg = 0;
1562 *xd = *yd = 0;
1563 return gFalse;
1566 void PDFCore::cvtUserToWindow(int pg, double xu, double yu, int *xw, int *yw) {
1567 PDFCorePage *page;
1568 PDFCoreTile *tile;
1570 if ((page = findPage(pg))) {
1571 tile = (PDFCoreTile *)page->tiles->get(0);
1572 *xw = tile->xDest + (int)(tile->ctm[0] * xu + tile->ctm[2] * yu +
1573 tile->ctm[4] + 0.5);
1574 *yw = tile->yDest + (int)(tile->ctm[1] * xu + tile->ctm[3] * yu +
1575 tile->ctm[5] + 0.5);
1576 return;
1578 // this should never happen
1579 *xw = *yw = 0;
1582 void PDFCore::cvtUserToDev(int pg, double xu, double yu, int *xd, int *yd) {
1583 PDFCorePage *page;
1584 PDFCoreTile *tile;
1585 double ctm[6];
1587 if ((page = findPage(pg))) {
1588 tile = (PDFCoreTile *)page->tiles->get(0);
1589 *xd = (int)(tile->xMin + tile->ctm[0] * xu +
1590 tile->ctm[2] * yu + tile->ctm[4] + 0.5);
1591 *yd = (int)(tile->yMin + tile->ctm[1] * xu +
1592 tile->ctm[3] * yu + tile->ctm[5] + 0.5);
1593 } else {
1594 doc->getCatalog()->getPage(pg)->getDefaultCTM(ctm, dpi, dpi, rotate,
1595 out->upsideDown());
1596 *xd = (int)(ctm[0] * xu + ctm[2] * yu + ctm[4] + 0.5);
1597 *yd = (int)(ctm[1] * xu + ctm[3] * yu + ctm[5] + 0.5);
1601 void PDFCore::cvtDevToWindow(int pg, int xd, int yd, int *xw, int *yw) {
1602 PDFCorePage *page;
1603 PDFCoreTile *tile;
1604 int i;
1606 if ((page = findPage(pg))) {
1607 for (i = 0; i < page->tiles->getLength(); ++i) {
1608 tile = (PDFCoreTile *)page->tiles->get(i);
1609 if (xd >= tile->xMin && xd < tile->xMax &&
1610 yd >= tile->yMin && yd < tile->yMax) {
1611 *xw = tile->xDest + xd - tile->xMin;
1612 *yw = tile->yDest + yd - tile->yMin;
1613 return;
1617 // this should never happen
1618 *xw = *yw = 0;
1621 void PDFCore::cvtDevToUser(int pg, int xd, int yd, double *xu, double *yu) {
1622 PDFCorePage *page;
1623 PDFCoreTile *tile;
1625 if ((page = findPage(pg))) {
1626 tile = (PDFCoreTile *)page->tiles->get(0);
1627 *xu = tile->ictm[0] * (xd - tile->xMin) +
1628 tile->ictm[2] * (yd - tile->yMin) + tile->ictm[4];
1629 *yu = tile->ictm[1] * (xd - tile->xMin) +
1630 tile->ictm[3] * (yd - tile->yMin) + tile->ictm[5];
1631 return;
1633 // this should never happen
1634 *xu = *yu = 0;
1637 void PDFCore::setReverseVideo(GBool reverseVideoA) {
1638 out->setReverseVideo(reverseVideoA);
1639 update(topPage, scrollX, scrollY, zoom, rotate, gTrue, gFalse);
1642 LinkAction *PDFCore::findLink(int pg, double x, double y) {
1643 #if 0
1644 PDFCorePage *page;
1646 if ((page = findPage(pg))) {
1647 return page->links ? page->links->find(x, y) : (LinkAction *)NULL;
1649 #endif
1650 return NULL;
1653 PDFCorePage *PDFCore::findPage(int pg) {
1654 PDFCorePage *page;
1655 int i;
1657 for (i = 0; i < pages->getLength(); ++i) {
1658 page = (PDFCorePage *)pages->get(i);
1659 if (page->page == pg) {
1660 return page;
1663 return NULL;
1666 void PDFCore::redrawCbk(void *data, int x0, int y0, int x1, int y1) {
1667 PDFCore *core = (PDFCore *)data;
1669 core->curTile->bitmap = core->out->getBitmap();
1670 core->clippedRedrawRect(core->curTile, x0, y0,
1671 core->curTile->xDest + x0, core->curTile->yDest + y0,
1672 x1 - x0 + 1, y1 - y0 + 1,
1673 0, 0, core->drawAreaWidth, core->drawAreaHeight,
1674 gTrue);
1677 void PDFCore::redrawWindow(int x, int y, int width, int height,
1678 GBool needUpdate) {
1679 PDFCorePage *page;
1680 PDFCoreTile *tile;
1681 int xDest, yDest, w, i, j;
1683 if (pages->getLength() == 0) {
1684 redrawRect(NULL, 0, 0, x, y, width, height);
1685 return;
1688 for (i = 0; i < pages->getLength(); ++i) {
1689 page = (PDFCorePage *)pages->get(i);
1690 for (j = 0; j < page->tiles->getLength(); ++j) {
1691 tile = (PDFCoreTile *)page->tiles->get(j);
1692 if (tile->edges & pdfCoreTileTopEdge) {
1693 if (tile->edges & pdfCoreTileLeftEdge) {
1694 xDest = 0;
1695 } else {
1696 xDest = tile->xDest;
1698 if (tile->edges & pdfCoreTileRightEdge) {
1699 w = drawAreaWidth - xDest;
1700 } else {
1701 w = tile->xDest + (tile->xMax - tile->xMin) - xDest;
1703 clippedRedrawRect(NULL, 0, 0,
1704 xDest, 0, w, tile->yDest,
1705 x, y, width, height, gFalse);
1707 if (tile->edges & pdfCoreTileBottomEdge) {
1708 if (tile->edges & pdfCoreTileLeftEdge) {
1709 xDest = 0;
1710 } else {
1711 xDest = tile->xDest;
1713 if (tile->edges & pdfCoreTileRightEdge) {
1714 w = drawAreaWidth - xDest;
1715 } else {
1716 w = tile->xDest + (tile->xMax - tile->xMin) - xDest;
1718 yDest = tile->yDest + (tile->yMax - tile->yMin);
1719 clippedRedrawRect(NULL, 0, 0,
1720 xDest, yDest, w, drawAreaHeight - yDest,
1721 x, y, width, height, gFalse);
1722 } else if ((tile->edges & pdfCoreTileBottomSpace) &&
1723 i+1 < pages->getLength()) {
1724 if (tile->edges & pdfCoreTileLeftEdge) {
1725 xDest = 0;
1726 } else {
1727 xDest = tile->xDest;
1729 if (tile->edges & pdfCoreTileRightEdge) {
1730 w = drawAreaWidth - xDest;
1731 } else {
1732 w = tile->xDest + (tile->xMax - tile->xMin) - xDest;
1734 yDest = tile->yDest + (tile->yMax - tile->yMin);
1735 clippedRedrawRect(NULL, 0, 0,
1736 xDest, yDest,
1737 w, ((PDFCorePage *)pages->get(i+1))->yDest - yDest,
1738 x, y, width, height, gFalse);
1740 if (tile->edges & pdfCoreTileLeftEdge) {
1741 clippedRedrawRect(NULL, 0, 0,
1742 0, tile->yDest,
1743 tile->xDest, tile->yMax - tile->yMin,
1744 x, y, width, height, gFalse);
1746 if (tile->edges & pdfCoreTileRightEdge) {
1747 xDest = tile->xDest + (tile->xMax - tile->xMin);
1748 clippedRedrawRect(NULL, 0, 0,
1749 xDest, tile->yDest,
1750 drawAreaWidth - xDest, tile->yMax - tile->yMin,
1751 x, y, width, height, gFalse);
1753 clippedRedrawRect(tile, 0, 0, tile->xDest, tile->yDest,
1754 tile->bitmap->getWidth(), tile->bitmap->getHeight(),
1755 x, y, width, height, needUpdate);
1760 PDFCoreTile *PDFCore::newTile(int xDestA, int yDestA) {
1761 return new PDFCoreTile(xDestA, yDestA);
1764 void PDFCore::updateTileData(PDFCoreTile *tileA,
1765 int xSrc, int ySrc, int width, int height) {
1768 void PDFCore::clippedRedrawRect(PDFCoreTile *tile, int xSrc, int ySrc,
1769 int xDest, int yDest, int width, int height,
1770 int xClip, int yClip, int wClip, int hClip,
1771 GBool needUpdate) {
1772 if (tile && needUpdate) {
1773 updateTileData(tile, xSrc, ySrc, width, height);
1775 if (xDest < xClip) {
1776 xSrc += xClip - xDest;
1777 width -= xClip - xDest;
1778 xDest = xClip;
1780 if (xDest + width > xClip + wClip) {
1781 width = xClip + wClip - xDest;
1783 if (yDest < yClip) {
1784 ySrc += yClip - yDest;
1785 height -= yClip - yDest;
1786 yDest = yClip;
1788 if (yDest + height > yClip + hClip) {
1789 height = yClip + hClip - yDest;
1791 if (width > 0 && height > 0) {
1792 redrawRect(tile, xSrc, ySrc, xDest, yDest, width, height);