1 //========================================================================
2 //
3 // PDFCore.cc
4 //
5 // Copyright 2004-2013 Glyph & Cog, LLC
6 //
7 //========================================================================
8 
9 #include <aconf.h>
10 
11 #ifdef USE_GCC_PRAGMAS
12 #pragma implementation
13 #endif
14 
15 #include <math.h>
16 #include "GString.h"
17 #include "GList.h"
18 #include "GlobalParams.h"
19 #include "Splash.h"
20 #include "SplashBitmap.h"
21 #include "SplashPattern.h"
22 #include "SplashPath.h"
23 #include "Error.h"
24 #include "ErrorCodes.h"
25 #include "PDFDoc.h"
26 #include "Link.h"
27 #include "TextOutputDev.h"
28 #include "CoreOutputDev.h"
29 #include "PDFCore.h"
30 
31 //------------------------------------------------------------------------
32 // PDFCorePage
33 //------------------------------------------------------------------------
34 
PDFCorePage(int pageA,int wA,int hA,int tileWA,int tileHA)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;
44 }
45 
~PDFCorePage()46 PDFCorePage::~PDFCorePage() {
47   deleteGList(tiles, PDFCoreTile);
48   if (links) {
49     delete links;
50   }
51   if (text) {
52     delete text;
53   }
54 }
55 
56 //------------------------------------------------------------------------
57 // PDFCoreTile
58 //------------------------------------------------------------------------
59 
PDFCoreTile(int xDestA,int yDestA)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;
68 }
69 
~PDFCoreTile()70 PDFCoreTile::~PDFCoreTile() {
71   if (bitmap) {
72     delete bitmap;
73   }
74 }
75 
76 
77 //------------------------------------------------------------------------
78 // PDFCore
79 //------------------------------------------------------------------------
80 
PDFCore(SplashColorMode colorModeA,int bitmapRowPadA,GBool reverseVideoA,SplashColorPtr paperColorA,GBool incrementalUpdate)81 PDFCore::PDFCore(SplashColorMode colorModeA, int bitmapRowPadA,
82 		 GBool reverseVideoA, SplashColorPtr paperColorA,
83 		 GBool incrementalUpdate) {
84   int i;
85 
86   doc = NULL;
87   continuousMode = globalParams->getContinuousView();
88   drawAreaWidth = drawAreaHeight = 0;
89   maxPageW = totalDocH = 0;
90   pageY = NULL;
91   topPage = 0;
92   midPage = 0;
93   scrollX = scrollY = 0;
94   zoom = defZoom;
95   dpi = 0;
96   rotate = 0;
97 
98   selectPage = 0;
99   selectULX = selectLRX = 0;
100   selectULY = selectLRY = 0;
101   dragging = gFalse;
102   lastDragLeft = lastDragTop = gTrue;
103   selectXorColor[0] = selectXorColor[1] = selectXorColor[2] =
104       reverseVideoA ? 0xff : 0x00;
105   splashColorXor(selectXorColor, paperColorA);
106 
107   historyCur = pdfHistorySize - 1;
108   historyBLen = historyFLen = 0;
109   for (i = 0; i < pdfHistorySize; ++i) {
110     history[i].fileName = NULL;
111   }
112 
113 
114   pages = new GList();
115   curTile = NULL;
116 
117   splashColorCopy(paperColor, paperColorA);
118   out = new CoreOutputDev(colorModeA, bitmapRowPadA,
119 			  reverseVideoA, paperColorA, incrementalUpdate,
120 			  &redrawCbk, this);
121   out->startDoc(NULL);
122 }
123 
~PDFCore()124 PDFCore::~PDFCore() {
125   int i;
126 
127   if (doc) {
128     delete doc;
129   }
130   for (i = 0; i < pdfHistorySize; ++i) {
131     if (history[i].fileName) {
132 #ifdef _WIN32
133       delete[] history[i].fileName;
134 #else
135       delete history[i].fileName;
136 #endif
137     }
138   }
139   gfree(pageY);
140   deleteGList(pages, PDFCorePage);
141   delete out;
142 }
143 
loadFile(GString * fileName,GString * ownerPassword,GString * userPassword)144 int PDFCore::loadFile(GString *fileName, GString *ownerPassword,
145 		      GString *userPassword) {
146   int err;
147 
148   setBusyCursor(gTrue);
149   err = loadFile2(new PDFDoc(fileName->copy(), ownerPassword, userPassword,
150 			     this));
151   setBusyCursor(gFalse);
152   return err;
153 }
154 
155 #ifdef _WIN32
loadFile(wchar_t * fileName,int fileNameLen,GString * ownerPassword,GString * userPassword)156 int PDFCore::loadFile(wchar_t *fileName, int fileNameLen,
157 		      GString *ownerPassword, GString *userPassword) {
158   int err;
159 
160   setBusyCursor(gTrue);
161   err = loadFile2(new PDFDoc(fileName, fileNameLen,
162 			     ownerPassword, userPassword, this));
163   setBusyCursor(gFalse);
164   return err;
165 }
166 #endif
167 
loadFile(BaseStream * stream,GString * ownerPassword,GString * userPassword)168 int PDFCore::loadFile(BaseStream *stream, GString *ownerPassword,
169 		      GString *userPassword) {
170   int err;
171 
172   setBusyCursor(gTrue);
173   err = loadFile2(new PDFDoc(stream, ownerPassword, userPassword, this));
174   setBusyCursor(gFalse);
175   return err;
176 }
177 
loadDoc(PDFDoc * docA)178 void PDFCore::loadDoc(PDFDoc *docA) {
179   setBusyCursor(gTrue);
180   loadFile2(docA);
181   setBusyCursor(gFalse);
182 }
183 
loadFile2(PDFDoc * newDoc)184 int PDFCore::loadFile2(PDFDoc *newDoc) {
185   int err;
186   double w, h, t;
187   int i;
188 
189   // open the PDF file
190   if (!newDoc->isOk()) {
191     err = newDoc->getErrorCode();
192     delete newDoc;
193     return err;
194   }
195 
196   // replace old document
197   if (doc) {
198     delete doc;
199   }
200   doc = newDoc;
201   if (out) {
202     out->startDoc(doc->getXRef());
203   }
204 
205   // nothing displayed yet
206   topPage = -99;
207   midPage = -99;
208   while (pages->getLength() > 0) {
209     delete (PDFCorePage *)pages->del(0);
210   }
211 
212   // compute the max unscaled page size
213   maxUnscaledPageW = maxUnscaledPageH = 0;
214   for (i = 1; i <= doc->getNumPages(); ++i) {
215     w = doc->getPageCropWidth(i);
216     h = doc->getPageCropHeight(i);
217     if (doc->getPageRotate(i) == 90 || doc->getPageRotate(i) == 270) {
218       t = w; w = h; h = t;
219     }
220     if (w > maxUnscaledPageW) {
221       maxUnscaledPageW = w;
222     }
223     if (h > maxUnscaledPageH) {
224       maxUnscaledPageH = h;
225     }
226   }
227 
228   return errNone;
229 }
230 
clear()231 void PDFCore::clear() {
232   if (!doc) {
233     return;
234   }
235 
236   // no document
237   delete doc;
238   doc = NULL;
239   out->clear();
240 
241   // no page displayed
242   topPage = -99;
243   midPage = -99;
244   while (pages->getLength() > 0) {
245     delete (PDFCorePage *)pages->del(0);
246   }
247 
248   // redraw
249   scrollX = scrollY = 0;
250   redrawWindow(0, 0, drawAreaWidth, drawAreaHeight, gTrue);
251   updateScrollbars();
252 }
253 
takeDoc(GBool redraw)254 PDFDoc *PDFCore::takeDoc(GBool redraw) {
255   PDFDoc *docA;
256 
257   if (!doc) {
258     return NULL;
259   }
260 
261   // no document
262   docA = doc;
263   doc = NULL;
264   out->clear();
265 
266   // no page displayed
267   topPage = -99;
268   midPage = -99;
269   while (pages->getLength() > 0) {
270     delete (PDFCorePage *)pages->del(0);
271   }
272 
273   // redraw
274   scrollX = scrollY = 0;
275   if (redraw) {
276     redrawWindow(0, 0, drawAreaWidth, drawAreaHeight, gTrue);
277     updateScrollbars();
278   }
279 
280   return docA;
281 }
282 
displayPage(int topPageA,double zoomA,int rotateA,GBool scrollToTop,GBool addToHist)283 void PDFCore::displayPage(int topPageA, double zoomA, int rotateA,
284 			  GBool scrollToTop, GBool addToHist) {
285   int scrollXA, scrollYA;
286 
287   scrollXA = scrollX;
288   if (continuousMode) {
289     scrollYA = -1;
290   } else if (scrollToTop) {
291     scrollYA = 0;
292   } else {
293     scrollYA = scrollY;
294   }
295   if (zoomA != zoom) {
296     scrollXA = 0;
297     scrollYA = continuousMode ? -1 : 0;
298   }
299 
300   dragging = gFalse;
301   lastDragLeft = lastDragTop = gTrue;
302 
303   update(topPageA, scrollXA, scrollYA, zoomA, rotateA, gTrue, addToHist,
304 	 gTrue);
305 }
306 
displayDest(LinkDest * dest,double zoomA,int rotateA,GBool addToHist)307 void PDFCore::displayDest(LinkDest *dest, double zoomA, int rotateA,
308 			  GBool addToHist) {
309   Ref pageRef;
310   int topPageA;
311   int dx, dy, scrollXA, scrollYA;
312 
313   if (dest->isPageRef()) {
314     pageRef = dest->getPageRef();
315     topPageA = doc->findPage(pageRef.num, pageRef.gen);
316   } else {
317     topPageA = dest->getPageNum();
318   }
319   if (topPageA <= 0 || topPageA > doc->getNumPages()) {
320     topPageA = 1;
321   }
322   scrollXA = scrollX;
323   scrollYA = continuousMode ? -1 : scrollY;
324   switch (dest->getKind()) {
325   case destXYZ:
326     cvtUserToDev(topPageA, dest->getLeft(), dest->getTop(), &dx, &dy);
327     scrollXA = dest->getChangeLeft() ? dx : scrollX;
328     if (continuousMode) {
329       if (topPage <= 0) {
330 	scrollYA = -1;
331       } else if (dest->getChangeTop()) {
332 	scrollYA = pageY[topPageA - 1] + dy;
333       } else {
334 	scrollYA = pageY[topPageA - 1] + (scrollY - pageY[topPage - 1]);
335       }
336     } else {
337       if (dest->getChangeTop()) {
338 	scrollYA = dy;
339       } else if (topPage > 0) {
340 	scrollYA = scrollY;
341       } else {
342 	scrollYA = 0;
343       }
344     }
345     //~ this doesn't currently handle the zoom parameter
346     update(topPageA, scrollXA, scrollYA, zoom, rotate, gFalse,
347 	   addToHist && topPageA != topPage, gTrue);
348     break;
349   case destFit:
350   case destFitB:
351     scrollXA = 0;
352     scrollYA = continuousMode ? -1 : 0;
353     update(topPageA, scrollXA, scrollYA, zoomPage, rotate, gFalse,
354 	   addToHist && topPageA != topPage, gTrue);
355     break;
356   case destFitH:
357   case destFitBH:
358     //~ do fit: need a function similar to zoomToRect which will
359     //~ accept an absolute top coordinate (rather than centering)
360     scrollXA = 0;
361     cvtUserToDev(topPageA, 0, dest->getTop(), &dx, &dy);
362     if (continuousMode) {
363       if (topPage <= 0) {
364 	scrollYA = -1;
365       } else if (dest->getChangeTop()) {
366 	scrollYA = pageY[topPageA - 1] + dy;
367       } else {
368 	scrollYA = pageY[topPageA - 1] + (scrollY - pageY[topPage - 1]);
369       }
370     } else {
371       if (dest->getChangeTop()) {
372 	scrollYA = dy;
373       } else if (topPage > 0) {
374 	scrollYA = scrollY;
375       } else {
376 	scrollYA = 0;
377       }
378     }
379     update(topPageA, scrollXA, scrollYA, zoom, rotate, gFalse,
380 	   addToHist && topPageA != topPage, gTrue);
381     break;
382   case destFitV:
383   case destFitBV:
384     //~ do fit: need a function similar to zoomToRect which will
385     //~ accept an absolute left coordinate (rather than centering)
386     if (dest->getChangeLeft()) {
387       cvtUserToDev(topPageA, dest->getLeft(), 0, &dx, &dy);
388       scrollXA = dx;
389     } else {
390       scrollXA = scrollX;
391     }
392     scrollYA = continuousMode ? -1 : 0;
393     update(topPageA, scrollXA, scrollYA, zoom, rotate, gFalse,
394 	   addToHist && topPageA != topPage, gTrue);
395     break;
396   case destFitR:
397     zoomToRect(topPageA, dest->getLeft(), dest->getTop(),
398 	       dest->getRight(), dest->getBottom());
399     break;
400   }
401 }
402 
update(int topPageA,int scrollXA,int scrollYA,double zoomA,int rotateA,GBool force,GBool addToHist,GBool adjustScrollX)403 void PDFCore::update(int topPageA, int scrollXA, int scrollYA,
404 		     double zoomA, int rotateA, GBool force,
405 		     GBool addToHist, GBool adjustScrollX) {
406   double hDPI, vDPI, dpiA, uw, uh, ut;
407   int w, h, t, x0, x1, y0, y1, x, y;
408   int rot;
409   int pg0, pg1;
410   PDFCoreTile *tile;
411   PDFCorePage *page;
412   PDFHistory *hist;
413   GBool needUpdate;
414   int i, j;
415 
416   // check for document and valid page number
417   if (!doc) {
418     // save the new settings
419     zoom = zoomA;
420     rotate = rotateA;
421     return;
422   }
423   if (topPageA <= 0 || topPageA > doc->getNumPages()) {
424     return;
425   }
426 
427   needUpdate = gFalse;
428 
429   // check for changes to the PDF file
430   if ((force || (!continuousMode && topPage != topPageA)) &&
431       doc->getFileName() &&
432       checkForNewFile()) {
433     if (loadFile(doc->getFileName()) == errNone) {
434       if (topPageA > doc->getNumPages()) {
435 	topPageA = doc->getNumPages();
436       }
437       needUpdate = gTrue;
438     }
439   }
440 
441   // compute the DPI
442   if (continuousMode) {
443     uw = maxUnscaledPageW;
444     uh = maxUnscaledPageH;
445     rot = rotateA;
446   } else {
447     uw = doc->getPageCropWidth(topPageA);
448     uh = doc->getPageCropHeight(topPageA);
449     rot = rotateA + doc->getPageRotate(topPageA);
450     if (rot >= 360) {
451       rot -= 360;
452     } else if (rot < 0) {
453       rot += 360;
454     }
455   }
456   if (rot == 90 || rot == 270) {
457     ut = uw; uw = uh; uh = ut;
458   }
459   if (zoomA == zoomPage) {
460     hDPI = (drawAreaWidth / uw) * 72;
461     if (continuousMode) {
462       vDPI = ((drawAreaHeight - continuousModePageSpacing) / uh) * 72;
463     } else {
464       vDPI = (drawAreaHeight / uh) * 72;
465     }
466     dpiA = (hDPI < vDPI) ? hDPI : vDPI;
467   } else if (zoomA == zoomWidth) {
468     dpiA = (drawAreaWidth / uw) * 72;
469   } else {
470     dpiA = 0.01 * zoomA * 72;
471   }
472   // this can happen if the window hasn't been sized yet
473   if (dpiA <= 0) {
474     dpiA = 1;
475   }
476 
477   // if the display properties have changed, create a new PDFCorePage
478   // object
479   if (force || pages->getLength() == 0 ||
480       (!continuousMode && topPageA != topPage) ||
481       fabs(zoomA - zoom) > 1e-8 || fabs(dpiA - dpi) > 1e-8 ||
482       rotateA != rotate) {
483     needUpdate = gTrue;
484     setSelection(0, 0, 0, 0, 0);
485     while (pages->getLength() > 0) {
486       delete (PDFCorePage *)pages->del(0);
487     }
488     zoom = zoomA;
489     rotate = rotateA;
490     dpi = dpiA;
491     if (continuousMode) {
492       maxPageW = totalDocH = 0;
493       pageY = (int *)greallocn(pageY, doc->getNumPages(), sizeof(int));
494       for (i = 1; i <= doc->getNumPages(); ++i) {
495 	pageY[i-1] = totalDocH;
496 	w = (int)((doc->getPageCropWidth(i) * dpi) / 72 + 0.5);
497 	h = (int)((doc->getPageCropHeight(i) * dpi) / 72 + 0.5);
498 	rot = rotate + doc->getPageRotate(i);
499 	if (rot >= 360) {
500 	  rot -= 360;
501 	} else if (rot < 0) {
502 	  rot += 360;
503 	}
504 	if (rot == 90 || rot == 270) {
505 	  t = w; w = h; h = t;
506 	}
507 	if (w > maxPageW) {
508 	  maxPageW = w;
509 	}
510 	totalDocH += h;
511 	if (i < doc->getNumPages()) {
512 	  totalDocH += continuousModePageSpacing;
513 	}
514       }
515     } else {
516       rot = rotate + doc->getPageRotate(topPageA);
517       if (rot >= 360) {
518 	rot -= 360;
519       } else if (rot < 0) {
520 	rot += 360;
521       }
522       addPage(topPageA, rot);
523     }
524   } else {
525     // erase the selection
526     if (selectULX != selectLRX && selectULY != selectLRY) {
527       xorRectangle(selectPage, selectULX, selectULY, selectLRX, selectLRY,
528 		   new SplashSolidColor(selectXorColor));
529     }
530   }
531   if (continuousMode) {
532     page = NULL; // make gcc happy
533   } else {
534     page = (PDFCorePage *)pages->get(0);
535   }
536   topPage = topPageA;
537   midPage = topPage;
538 
539   // adjust the scroll position
540   scrollX = scrollXA;
541   if (continuousMode && scrollYA < 0) {
542     scrollY = pageY[topPage - 1];
543   } else {
544     scrollY = scrollYA;
545   }
546   if (continuousMode && adjustScrollX) {
547     rot = rotate + doc->getPageRotate(topPage);
548     if (rot >= 360) {
549       rot -= 360;
550     } else if (rot < 0) {
551       rot += 360;
552     }
553     if (rot == 90 || rot == 270) {
554       w = (int)((doc->getPageCropHeight(topPage) * dpi) / 72 + 0.5);
555     } else {
556       w = (int)((doc->getPageCropWidth(topPage) * dpi) / 72 + 0.5);
557     }
558     if (scrollX < (maxPageW - w) / 2) {
559       scrollX = (maxPageW - w) / 2;
560     }
561   }
562   w = continuousMode ? maxPageW : page->w;
563   if (scrollX > w - drawAreaWidth) {
564     scrollX = w - drawAreaWidth;
565   }
566   if (scrollX < 0) {
567     scrollX = 0;
568   }
569   h = continuousMode ? totalDocH : page->h;
570   if (scrollY > h - drawAreaHeight) {
571     scrollY = h - drawAreaHeight;
572   }
573   if (scrollY < 0) {
574     scrollY = 0;
575   }
576 
577   // find topPage, and the first and last pages to be rasterized
578   if (continuousMode) {
579     //~ should use a binary search
580     for (i = 2; i <= doc->getNumPages(); ++i) {
581       if (pageY[i-1] > scrollY - drawAreaHeight / 2) {
582 	break;
583       }
584     }
585     pg0 = i - 1;
586     for (i = pg0 + 1; i <= doc->getNumPages(); ++i) {
587       if (pageY[i-1] > scrollY) {
588 	break;
589       }
590     }
591     topPage = i - 1;
592     for (i = topPage + 1; i <= doc->getNumPages(); ++i) {
593       if (pageY[i-1] > scrollY + drawAreaHeight / 2) {
594 	break;
595       }
596     }
597     midPage = i - 1;
598     for (i = midPage + 1; i <= doc->getNumPages(); ++i) {
599       if (pageY[i-1] > scrollY + drawAreaHeight + drawAreaHeight / 2) {
600 	break;
601       }
602     }
603     pg1 = i - 1;
604 
605     // delete pages that are no longer needed and insert new pages
606     // objects that are needed
607     while (pages->getLength() > 0 &&
608 	   ((PDFCorePage *)pages->get(0))->page < pg0) {
609       delete (PDFCorePage *)pages->del(0);
610     }
611     i = pages->getLength() - 1;
612     while (i > 0 && ((PDFCorePage *)pages->get(i))->page > pg1) {
613       delete (PDFCorePage *)pages->del(i--);
614     }
615     j = pages->getLength() > 0 ? ((PDFCorePage *)pages->get(0))->page - 1
616                                : pg1;
617     for (i = pg0; i <= j; ++i) {
618       rot = rotate + doc->getPageRotate(i);
619       if (rot >= 360) {
620 	rot -= 360;
621       } else if (rot < 0) {
622 	rot += 360;
623       }
624       addPage(i, rot);
625     }
626     j = ((PDFCorePage *)pages->get(pages->getLength() - 1))->page;
627     for (i = j + 1; i <= pg1; ++i) {
628       rot = rotate + doc->getPageRotate(i);
629       if (rot >= 360) {
630 	rot -= 360;
631       } else if (rot < 0) {
632 	rot += 360;
633       }
634       addPage(i, rot);
635     }
636 
637   } else {
638     pg0 = pg1 = topPage;
639   }
640 
641   // delete tiles that are no longer needed
642   for (i = 0; i < pages->getLength(); ++i) {
643     page = (PDFCorePage *)pages->get(i);
644     j = 0;
645     while (j < page->tiles->getLength()) {
646       tile = (PDFCoreTile *)page->tiles->get(j);
647       if (continuousMode) {
648 	y0 = pageY[page->page - 1] + tile->yMin;
649 	y1 = pageY[page->page - 1] + tile->yMax;
650       } else {
651 	y0 = tile->yMin;
652 	y1 = tile->yMax;
653       }
654       if (tile->xMax < scrollX - drawAreaWidth / 2 ||
655 	  tile->xMin > scrollX + drawAreaWidth + drawAreaWidth / 2 ||
656 	  y1 < scrollY - drawAreaHeight / 2 ||
657 	  y0 > scrollY + drawAreaHeight + drawAreaHeight / 2) {
658 	delete (PDFCoreTile *)page->tiles->del(j);
659       } else {
660 	++j;
661       }
662     }
663   }
664 
665   // update page positions
666   for (i = 0; i < pages->getLength(); ++i) {
667     page = (PDFCorePage *)pages->get(i);
668     page->xDest = -scrollX;
669     if (continuousMode) {
670       page->yDest = pageY[page->page - 1] - scrollY;
671     } else {
672       page->yDest = -scrollY;
673     }
674     if (continuousMode) {
675       if (page->w < maxPageW) {
676 	page->xDest += (maxPageW - page->w) / 2;
677       }
678       if (maxPageW < drawAreaWidth) {
679 	page->xDest += (drawAreaWidth - maxPageW) / 2;
680       }
681     } else if (page->w < drawAreaWidth) {
682       page->xDest += (drawAreaWidth - page->w) / 2;
683     }
684     if (continuousMode && totalDocH < drawAreaHeight) {
685       page->yDest += (drawAreaHeight - totalDocH) / 2;
686     } else if (!continuousMode && page->h < drawAreaHeight) {
687       page->yDest += (drawAreaHeight - page->h) / 2;
688     }
689   }
690 
691   // rasterize any new tiles
692   for (i = 0; i < pages->getLength(); ++i) {
693     page = (PDFCorePage *)pages->get(i);
694     x0 = page->xDest;
695     x1 = x0 + page->w - 1;
696     if (x0 < -drawAreaWidth / 2) {
697       x0 = -drawAreaWidth / 2;
698     }
699     if (x1 > drawAreaWidth + drawAreaWidth / 2) {
700       x1 = drawAreaWidth + drawAreaWidth / 2;
701     }
702     x0 = ((x0 - page->xDest) / page->tileW) * page->tileW;
703     x1 = ((x1 - page->xDest) / page->tileW) * page->tileW;
704     y0 = page->yDest;
705     y1 = y0 + page->h - 1;
706     if (y0 < -drawAreaHeight / 2) {
707       y0 = -drawAreaHeight / 2;
708     }
709     if (y1 > drawAreaHeight + drawAreaHeight / 2) {
710       y1 = drawAreaHeight + drawAreaHeight / 2;
711     }
712     y0 = ((y0 - page->yDest) / page->tileH) * page->tileH;
713     y1 = ((y1 - page->yDest) / page->tileH) * page->tileH;
714     for (y = y0; y <= y1; y += page->tileH) {
715       for (x = x0; x <= x1; x += page->tileW) {
716 	needTile(page, x, y);
717       }
718     }
719   }
720 
721   // update tile positions
722   for (i = 0; i < pages->getLength(); ++i) {
723     page = (PDFCorePage *)pages->get(i);
724     for (j = 0; j < page->tiles->getLength(); ++j) {
725       tile = (PDFCoreTile *)page->tiles->get(j);
726       tile->xDest = tile->xMin - scrollX;
727       if (continuousMode) {
728 	tile->yDest = tile->yMin + pageY[page->page - 1] - scrollY;
729       } else {
730 	tile->yDest = tile->yMin - scrollY;
731       }
732       if (continuousMode) {
733 	if (page->w < maxPageW) {
734 	  tile->xDest += (maxPageW - page->w) / 2;
735 	}
736 	if (maxPageW < drawAreaWidth) {
737 	  tile->xDest += (drawAreaWidth - maxPageW) / 2;
738 	}
739       } else if (page->w < drawAreaWidth) {
740 	tile->xDest += (drawAreaWidth - page->w) / 2;
741       }
742       if (continuousMode && totalDocH < drawAreaHeight) {
743 	tile->yDest += (drawAreaHeight - totalDocH) / 2;
744       } else if (!continuousMode && page->h < drawAreaHeight) {
745 	tile->yDest += (drawAreaHeight - page->h) / 2;
746       }
747     }
748   }
749 
750   // redraw the selection
751   if (selectULX != selectLRX && selectULY != selectLRY) {
752     xorRectangle(selectPage, selectULX, selectULY, selectLRX, selectLRY,
753 		 new SplashSolidColor(selectXorColor));
754   }
755 
756   // redraw the window
757   redrawWindow(0, 0, drawAreaWidth, drawAreaHeight, needUpdate);
758   updateScrollbars();
759 
760   // add to history
761   if (addToHist) {
762     if (++historyCur == pdfHistorySize) {
763       historyCur = 0;
764     }
765     hist = &history[historyCur];
766     if (hist->fileName) {
767 #ifdef _WIN32
768       delete[] hist->fileName;
769 #else
770       delete hist->fileName;
771 #endif
772     }
773 #ifdef _WIN32
774     if (doc->getFileNameU()) {
775       hist->fileName = (wchar_t *)gmallocn(MAX_PATH + 1, sizeof(wchar_t));
776       if (GetFullPathNameW(doc->getFileNameU(), MAX_PATH + 1,
777 			   hist->fileName, NULL) == 0) {
778 	delete[] hist->fileName;
779 	hist->fileName = NULL;
780       }
781     } else {
782       hist->fileName = NULL;
783     }
784 #else
785     if (doc->getFileName()) {
786       hist->fileName = doc->getFileName()->copy();
787     } else {
788       hist->fileName = NULL;
789     }
790 #endif
791     hist->page = topPage;
792     if (historyBLen < pdfHistorySize) {
793       ++historyBLen;
794     }
795     historyFLen = 0;
796   }
797 }
798 
addPage(int pg,int rot)799 void PDFCore::addPage(int pg, int rot) {
800   PDFCorePage *page;
801   int w, h, t, tileW, tileH, i;
802 
803   w = (int)((doc->getPageCropWidth(pg) * dpi) / 72 + 0.5);
804   h = (int)((doc->getPageCropHeight(pg) * dpi) / 72 + 0.5);
805   if (rot == 90 || rot == 270) {
806     t = w; w = h; h = t;
807   }
808   tileW = 2 * drawAreaWidth;
809   if (tileW < 1500) {
810     tileW = 1500;
811   }
812   if (tileW > w) {
813     // tileW can't be zero -- we end up with div-by-zero problems
814     tileW = w ? w : 1;
815   }
816   tileH = 2 * drawAreaHeight;
817   if (tileH < 1500) {
818     tileH = 1500;
819   }
820   if (tileH > h) {
821     // tileH can't be zero -- we end up with div-by-zero problems
822     tileH = h ? h : 1;
823   }
824   page = new PDFCorePage(pg, w, h, tileW, tileH);
825   for (i = 0;
826        i < pages->getLength() && pg > ((PDFCorePage *)pages->get(i))->page;
827        ++i) ;
828   pages->insert(i, page);
829 }
830 
needTile(PDFCorePage * page,int x,int y)831 void PDFCore::needTile(PDFCorePage *page, int x, int y) {
832   PDFCoreTile *tile;
833   TextOutputControl textOutCtrl;
834   TextOutputDev *textOut;
835   int xDest, yDest, sliceW, sliceH;
836   int i;
837 
838   for (i = 0; i < page->tiles->getLength(); ++i) {
839     tile = (PDFCoreTile *)page->tiles->get(i);
840     if (x == tile->xMin && y == tile->yMin) {
841       return;
842     }
843   }
844 
845   setBusyCursor(gTrue);
846 
847   sliceW = page->tileW;
848   if (x + sliceW > page->w) {
849     sliceW = page->w - x;
850   }
851   sliceH = page->tileH;
852   if (y + sliceH > page->h) {
853     sliceH = page->h - y;
854   }
855 
856   xDest = x - scrollX;
857   if (continuousMode) {
858     yDest = y + pageY[page->page - 1] - scrollY;
859   } else {
860     yDest = y - scrollY;
861   }
862   if (continuousMode) {
863     if (page->w < maxPageW) {
864       xDest += (maxPageW - page->w) / 2;
865     }
866     if (maxPageW < drawAreaWidth) {
867       xDest += (drawAreaWidth - maxPageW) / 2;
868     }
869   } else if (page->w < drawAreaWidth) {
870     xDest += (drawAreaWidth - page->w) / 2;
871   }
872   if (continuousMode && totalDocH < drawAreaHeight) {
873     yDest += (drawAreaHeight - totalDocH) / 2;
874   } else if (!continuousMode && page->h < drawAreaHeight) {
875     yDest += (drawAreaHeight - page->h) / 2;
876   }
877   curTile = tile = newTile(xDest, yDest);
878   curPage = page;
879   tile->xMin = x;
880   tile->yMin = y;
881   tile->xMax = x + sliceW;
882   tile->yMax = y + sliceH;
883   tile->edges = 0;
884   if (tile->xMin == 0) {
885     tile->edges |= pdfCoreTileLeftEdge;
886   }
887   if (tile->xMax == page->w) {
888     tile->edges |= pdfCoreTileRightEdge;
889   }
890   if (continuousMode) {
891     if (tile->yMin == 0) {
892       tile->edges |= pdfCoreTileTopSpace;
893       if (page->page == 1) {
894 	tile->edges |= pdfCoreTileTopEdge;
895       }
896     }
897     if (tile->yMax == page->h) {
898       tile->edges |= pdfCoreTileBottomSpace;
899       if (page->page == doc->getNumPages()) {
900 	tile->edges |= pdfCoreTileBottomEdge;
901       }
902     }
903   } else {
904     if (tile->yMin == 0) {
905       tile->edges |= pdfCoreTileTopEdge;
906     }
907     if (tile->yMax == page->h) {
908       tile->edges |= pdfCoreTileBottomEdge;
909     }
910   }
911   doc->displayPageSlice(out, page->page, dpi, dpi, rotate,
912 			gFalse, gTrue, gFalse, x, y, sliceW, sliceH);
913   tile->bitmap = out->takeBitmap();
914   memcpy(tile->ctm, out->getDefCTM(), 6 * sizeof(double));
915   memcpy(tile->ictm, out->getDefICTM(), 6 * sizeof(double));
916   if (!page->links) {
917     page->links = doc->getLinks(page->page);
918   }
919   if (!page->text) {
920     textOutCtrl.mode = textOutPhysLayout;
921     if ((textOut = new TextOutputDev(NULL, &textOutCtrl, gFalse))) {
922       doc->displayPage(textOut, page->page, dpi, dpi, rotate,
923 		       gFalse, gTrue, gFalse);
924       page->text = textOut->takeText();
925       delete textOut;
926     }
927   }
928   page->tiles->append(tile);
929   curTile = NULL;
930   curPage = NULL;
931 
932   setBusyCursor(gFalse);
933 }
934 
gotoNextPage(int inc,GBool top)935 GBool PDFCore::gotoNextPage(int inc, GBool top) {
936   int pg, scrollYA;
937 
938   if (!doc || doc->getNumPages() == 0 || topPage >= doc->getNumPages()) {
939     return gFalse;
940   }
941   if ((pg = topPage + inc) > doc->getNumPages()) {
942     pg = doc->getNumPages();
943   }
944   if (continuousMode) {
945     scrollYA = -1;
946   } else if (top) {
947     scrollYA = 0;
948   } else {
949     scrollYA = scrollY;
950   }
951   update(pg, scrollX, scrollYA, zoom, rotate, gFalse, gTrue, gTrue);
952   return gTrue;
953 }
954 
gotoPrevPage(int dec,GBool top,GBool bottom)955 GBool PDFCore::gotoPrevPage(int dec, GBool top, GBool bottom) {
956   int pg, scrollYA;
957 
958   if (!doc || doc->getNumPages() == 0 || topPage <= 1) {
959     return gFalse;
960   }
961   if ((pg = topPage - dec) < 1) {
962     pg = 1;
963   }
964   if (continuousMode) {
965     scrollYA = -1;
966   } else if (top) {
967     scrollYA = 0;
968   } else if (bottom) {
969     scrollYA = ((PDFCorePage *)pages->get(0))->h - drawAreaHeight;
970     if (scrollYA < 0) {
971       scrollYA = 0;
972     }
973   } else {
974     scrollYA = scrollY;
975   }
976   update(pg, scrollX, scrollYA, zoom, rotate, gFalse, gTrue, gTrue);
977   return gTrue;
978 }
979 
gotoNamedDestination(GString * dest)980 GBool PDFCore::gotoNamedDestination(GString *dest) {
981   LinkDest *d;
982 
983   if (!doc) {
984     return gFalse;
985   }
986   if (!(d = doc->findDest(dest))) {
987     return gFalse;
988   }
989   displayDest(d, zoom, rotate, gTrue);
990   delete d;
991   return gTrue;
992 }
993 
goForward()994 GBool PDFCore::goForward() {
995   int pg;
996 
997   if (historyFLen == 0) {
998     return gFalse;
999   }
1000   if (++historyCur == pdfHistorySize) {
1001     historyCur = 0;
1002   }
1003   --historyFLen;
1004   ++historyBLen;
1005   if (!history[historyCur].fileName) {
1006     return gFalse;
1007   }
1008 #ifdef _WIN32
1009   if (!doc ||
1010       !doc->getFileNameU() ||
1011       wcscmp(history[historyCur].fileName, doc->getFileNameU()) != 0) {
1012     if (loadFile(history[historyCur].fileName,
1013 		 wcslen(history[historyCur].fileName)) != errNone) {
1014       return gFalse;
1015     }
1016   }
1017 #else
1018   if (!doc ||
1019       !doc->getFileName() ||
1020       history[historyCur].fileName->cmp(doc->getFileName()) != 0) {
1021     if (loadFile(history[historyCur].fileName) != errNone) {
1022       return gFalse;
1023     }
1024   }
1025 #endif
1026   pg = history[historyCur].page;
1027   update(pg, scrollX, continuousMode ? -1 : scrollY,
1028 	 zoom, rotate, gFalse, gFalse, gTrue);
1029   return gTrue;
1030 }
1031 
goBackward()1032 GBool PDFCore::goBackward() {
1033   int pg;
1034 
1035   if (historyBLen <= 1) {
1036     return gFalse;
1037   }
1038   if (--historyCur < 0) {
1039     historyCur = pdfHistorySize - 1;
1040   }
1041   --historyBLen;
1042   ++historyFLen;
1043   if (!history[historyCur].fileName) {
1044     return gFalse;
1045   }
1046 #ifdef _WIN32
1047   if (!doc ||
1048       !doc->getFileNameU() ||
1049       wcscmp(history[historyCur].fileName, doc->getFileNameU()) != 0) {
1050     if (loadFile(history[historyCur].fileName,
1051 		 wcslen(history[historyCur].fileName)) != errNone) {
1052       return gFalse;
1053     }
1054   }
1055 #else
1056   if (!doc ||
1057       !doc->getFileName() ||
1058       history[historyCur].fileName->cmp(doc->getFileName()) != 0) {
1059     if (loadFile(history[historyCur].fileName) != errNone) {
1060       return gFalse;
1061     }
1062   }
1063 #endif
1064   pg = history[historyCur].page;
1065   update(pg, scrollX, continuousMode ? -1 : scrollY,
1066 	 zoom, rotate, gFalse, gFalse, gTrue);
1067   return gTrue;
1068 }
1069 
scrollLeft(int nCols)1070 void PDFCore::scrollLeft(int nCols) {
1071   scrollTo(scrollX - nCols, scrollY);
1072 }
1073 
scrollRight(int nCols)1074 void PDFCore::scrollRight(int nCols) {
1075   scrollTo(scrollX + nCols, scrollY);
1076 }
1077 
scrollUp(int nLines)1078 void PDFCore::scrollUp(int nLines) {
1079   scrollTo(scrollX, scrollY - nLines);
1080 }
1081 
scrollUpPrevPage(int nLines)1082 void PDFCore::scrollUpPrevPage(int nLines) {
1083   if (!continuousMode && scrollY == 0) {
1084     gotoPrevPage(1, gFalse, gTrue);
1085   } else {
1086     scrollTo(scrollX, scrollY - nLines);
1087   }
1088 }
1089 
scrollDown(int nLines)1090 void PDFCore::scrollDown(int nLines) {
1091   scrollTo(scrollX, scrollY + nLines);
1092 }
1093 
scrollDownNextPage(int nLines)1094 void PDFCore::scrollDownNextPage(int nLines) {
1095   if (!continuousMode &&
1096       scrollY >= ((PDFCorePage *)pages->get(0))->h - drawAreaHeight) {
1097     gotoNextPage(1, gTrue);
1098   } else {
1099     scrollTo(scrollX, scrollY + nLines);
1100   }
1101 }
1102 
scrollPageUp()1103 void PDFCore::scrollPageUp() {
1104   if (!continuousMode && scrollY == 0) {
1105     gotoPrevPage(1, gFalse, gTrue);
1106   } else {
1107     scrollTo(scrollX, scrollY - drawAreaHeight);
1108   }
1109 }
1110 
scrollPageDown()1111 void PDFCore::scrollPageDown() {
1112   if (!continuousMode &&
1113       pages->getLength() > 0 &&
1114       scrollY >= ((PDFCorePage *)pages->get(0))->h - drawAreaHeight) {
1115     gotoNextPage(1, gTrue);
1116   } else {
1117     scrollTo(scrollX, scrollY + drawAreaHeight);
1118   }
1119 }
1120 
scrollTo(int x,int y)1121 void PDFCore::scrollTo(int x, int y) {
1122   update(topPage, x, y < 0 ? 0 : y, zoom, rotate, gFalse, gFalse, gFalse);
1123 }
1124 
scrollToLeftEdge()1125 void PDFCore::scrollToLeftEdge() {
1126   update(topPage, 0, scrollY, zoom, rotate, gFalse, gFalse, gFalse);
1127 }
1128 
scrollToRightEdge()1129 void PDFCore::scrollToRightEdge() {
1130   PDFCorePage *page;
1131 
1132   page = (PDFCorePage *)pages->get(0);
1133   update(topPage, page->w - drawAreaWidth, scrollY,
1134 	 zoom, rotate, gFalse, gFalse, gFalse);
1135 }
1136 
scrollToTopEdge()1137 void PDFCore::scrollToTopEdge() {
1138   int y;
1139 
1140   y = continuousMode ? pageY[topPage - 1] : 0;
1141   update(topPage, scrollX, y, zoom, rotate, gFalse, gFalse, gFalse);
1142 }
1143 
scrollToBottomEdge()1144 void PDFCore::scrollToBottomEdge() {
1145   PDFCorePage *page;
1146   int y, i;
1147 
1148   for (i = pages->getLength() - 1; i > 0; --i) {
1149     page = (PDFCorePage *)pages->get(i);
1150     if (page->yDest < drawAreaHeight) {
1151       break;
1152     }
1153   }
1154   page = (PDFCorePage *)pages->get(i);
1155   if (continuousMode) {
1156     y = pageY[page->page - 1] + page->h - drawAreaHeight;
1157   } else {
1158     y = page->h - drawAreaHeight;
1159   }
1160   update(topPage, scrollX, y, zoom, rotate, gFalse, gFalse, gFalse);
1161 }
1162 
scrollToTopLeft()1163 void PDFCore::scrollToTopLeft() {
1164   int y;
1165 
1166   y = continuousMode ? pageY[topPage - 1] : 0;
1167   update(topPage, 0, y, zoom, rotate, gFalse, gFalse, gFalse);
1168 }
1169 
scrollToBottomRight()1170 void PDFCore::scrollToBottomRight() {
1171   PDFCorePage *page;
1172   int x, y, i;
1173 
1174   for (i = pages->getLength() - 1; i > 0; --i) {
1175     page = (PDFCorePage *)pages->get(i);
1176     if (page->yDest < drawAreaHeight) {
1177       break;
1178     }
1179   }
1180   page = (PDFCorePage *)pages->get(i);
1181   x = page->w - drawAreaWidth;
1182   if (continuousMode) {
1183     y = pageY[page->page - 1] + page->h - drawAreaHeight;
1184   } else {
1185     y = page->h - drawAreaHeight;
1186   }
1187   update(topPage, x, y, zoom, rotate, gFalse, gFalse, gFalse);
1188 }
1189 
zoomToRect(int pg,double ulx,double uly,double lrx,double lry)1190 void PDFCore::zoomToRect(int pg, double ulx, double uly,
1191 			 double lrx, double lry) {
1192   int x0, y0, x1, y1, u, sx, sy;
1193   double rx, ry, newZoom, t;
1194   PDFCorePage *p;
1195 
1196   cvtUserToDev(pg, ulx, uly, &x0, &y0);
1197   cvtUserToDev(pg, lrx, lry, &x1, &y1);
1198   if (x0 > x1) {
1199     u = x0; x0 = x1; x1 = u;
1200   }
1201   if (y0 > y1) {
1202     u = y0; y0 = y1; y1 = u;
1203   }
1204   rx = (double)drawAreaWidth / (double)(x1 - x0);
1205   ry = (double)drawAreaHeight / (double)(y1 - y0);
1206   if (rx < ry) {
1207     newZoom = rx * (dpi / (0.01 * 72));
1208     sx = (int)(rx * x0);
1209     t = (drawAreaHeight * (x1 - x0)) / drawAreaWidth;
1210     sy = (int)(rx * (y0 + y1 - t) / 2);
1211     if (continuousMode) {
1212       if ((p = findPage(pg)) && p->w < maxPageW) {
1213 	sx += (int)(0.5 * rx * (maxPageW - p->w));
1214       }
1215       u = (pg - 1) * continuousModePageSpacing;
1216       sy += (int)(rx * (pageY[pg - 1] - u)) + u;
1217     }
1218   } else {
1219     newZoom = ry * (dpi / (0.01 * 72));
1220     t = (drawAreaWidth * (y1 - y0)) / drawAreaHeight;
1221     sx = (int)(ry * (x0 + x1 - t) / 2);
1222     sy = (int)(ry * y0);
1223     if (continuousMode) {
1224       if ((p = findPage(pg)) && p->w < maxPageW) {
1225 	sx += (int)(0.5 * rx * (maxPageW - p->w));
1226       }
1227       u = (pg - 1) * continuousModePageSpacing;
1228       sy += (int)(ry * (pageY[pg - 1] - u)) + u;
1229     }
1230   }
1231   update(pg, sx, sy, newZoom, rotate, gFalse, gFalse, gFalse);
1232 }
1233 
zoomCentered(double zoomA)1234 void PDFCore::zoomCentered(double zoomA) {
1235   int sx, sy, rot, hAdjust, vAdjust, i;
1236   double dpi1, dpi2, pageW, pageH;
1237   PDFCorePage *page;
1238 
1239   if (zoomA == zoomPage) {
1240     if (continuousMode) {
1241       pageW = (rotate == 90 || rotate == 270) ? maxUnscaledPageH
1242 	                                      : maxUnscaledPageW;
1243       pageH = (rotate == 90 || rotate == 270) ? maxUnscaledPageW
1244 	                                      : maxUnscaledPageH;
1245       dpi1 = 72.0 * (double)drawAreaWidth / pageW;
1246       dpi2 = 72.0 * (double)(drawAreaHeight - continuousModePageSpacing) /
1247 	     pageH;
1248       if (dpi2 < dpi1) {
1249 	dpi1 = dpi2;
1250       }
1251     } else {
1252       // in single-page mode, sx=sy=0 -- so dpi1 is irrelevant
1253       dpi1 = dpi;
1254     }
1255     sx = 0;
1256 
1257   } else if (zoomA == zoomWidth) {
1258     if (continuousMode) {
1259       pageW = (rotate == 90 || rotate == 270) ? maxUnscaledPageH
1260 	                                      : maxUnscaledPageW;
1261     } else {
1262       rot = rotate + doc->getPageRotate(topPage);
1263       if (rot >= 360) {
1264 	rot -= 360;
1265       } else if (rot < 0) {
1266 	rot += 360;
1267       }
1268       pageW = (rot == 90 || rot == 270) ? doc->getPageCropHeight(topPage)
1269 	                                : doc->getPageCropWidth(topPage);
1270     }
1271     dpi1 = 72.0 * (double)drawAreaWidth / pageW;
1272     sx = 0;
1273 
1274   } else if (zoomA <= 0) {
1275     return;
1276 
1277   } else {
1278     dpi1 = 72.0 * zoomA / 100.0;
1279     if ((page = (PDFCorePage *)pages->get(0)) && page->xDest > 0) {
1280       hAdjust = page->xDest;
1281     } else {
1282       hAdjust = 0;
1283     }
1284     sx = (int)((scrollX - hAdjust + drawAreaWidth / 2) * (dpi1 / dpi)) -
1285          drawAreaWidth / 2;
1286     if (sx < 0) {
1287       sx = 0;
1288     }
1289   }
1290 
1291   if (continuousMode) {
1292     // we can't just multiply scrollY by dpi1/dpi -- the rounding
1293     // errors add up (because the pageY values are integers) -- so
1294     // we compute the pageY values at the new zoom level instead
1295     sy = 0;
1296     for (i = 1; i < topPage; ++i) {
1297       rot = rotate + doc->getPageRotate(i);
1298       if (rot >= 360) {
1299 	rot -= 360;
1300       } else if (rot < 0) {
1301 	rot += 360;
1302       }
1303       if (rot == 90 || rot == 270) {
1304 	sy += (int)((doc->getPageCropWidth(i) * dpi1) / 72 + 0.5);
1305       } else {
1306 	sy += (int)((doc->getPageCropHeight(i) * dpi1) / 72 + 0.5);
1307       }
1308     }
1309     vAdjust = (topPage - 1) * continuousModePageSpacing;
1310     sy = sy + (int)((scrollY - pageY[topPage - 1] + drawAreaHeight / 2)
1311 		    * (dpi1 / dpi))
1312          + vAdjust - drawAreaHeight / 2;
1313   } else {
1314     sy = (int)((scrollY + drawAreaHeight / 2) * (dpi1 / dpi))
1315          - drawAreaHeight / 2;
1316   }
1317 
1318   update(topPage, sx, sy, zoomA, rotate, gFalse, gFalse, gFalse);
1319 }
1320 
1321 // Zoom so that the current page(s) fill the window width.  Maintain
1322 // the vertical center.
zoomToCurrentWidth()1323 void PDFCore::zoomToCurrentWidth() {
1324   double w, maxW, dpi1;
1325   int sx, sy, vAdjust, rot, i;
1326 
1327   // compute the maximum page width of visible pages
1328   rot = rotate + doc->getPageRotate(topPage);
1329   if (rot >= 360) {
1330     rot -= 360;
1331   } else if (rot < 0) {
1332     rot += 360;
1333   }
1334   if (rot == 90 || rot == 270) {
1335     maxW = doc->getPageCropHeight(topPage);
1336   } else {
1337     maxW = doc->getPageCropWidth(topPage);
1338   }
1339   if (continuousMode) {
1340     for (i = topPage + 1;
1341 	 i < doc->getNumPages() && pageY[i-1] < scrollY + drawAreaHeight;
1342 	 ++i) {
1343       rot = rotate + doc->getPageRotate(i);
1344       if (rot >= 360) {
1345 	rot -= 360;
1346       } else if (rot < 0) {
1347 	rot += 360;
1348       }
1349       if (rot == 90 || rot == 270) {
1350 	w = doc->getPageCropHeight(i);
1351       } else {
1352 	w = doc->getPageCropWidth(i);
1353       }
1354       if (w > maxW) {
1355 	maxW = w;
1356       }
1357     }
1358   }
1359 
1360   // compute the resolution
1361   dpi1 = (drawAreaWidth / maxW) * 72;
1362 
1363   // compute the horizontal scroll position
1364   if (continuousMode) {
1365     sx = ((int)(maxPageW * dpi1 / dpi) - drawAreaWidth) / 2;
1366   } else {
1367     sx = 0;
1368   }
1369 
1370   // compute the vertical scroll position
1371   if (continuousMode) {
1372     // we can't just multiply scrollY by dpi1/dpi -- the rounding
1373     // errors add up (because the pageY values are integers) -- so
1374     // we compute the pageY values at the new zoom level instead
1375     sy = 0;
1376     for (i = 1; i < topPage; ++i) {
1377       rot = rotate + doc->getPageRotate(i);
1378       if (rot >= 360) {
1379 	rot -= 360;
1380       } else if (rot < 0) {
1381 	rot += 360;
1382       }
1383       if (rot == 90 || rot == 270) {
1384 	sy += (int)((doc->getPageCropWidth(i) * dpi1) / 72 + 0.5);
1385       } else {
1386 	sy += (int)((doc->getPageCropHeight(i) * dpi1) / 72 + 0.5);
1387       }
1388     }
1389     vAdjust = (topPage - 1) * continuousModePageSpacing;
1390     sy = sy + (int)((scrollY - pageY[topPage - 1] + drawAreaHeight / 2)
1391 		    * (dpi1 / dpi))
1392          + vAdjust - drawAreaHeight / 2;
1393   } else {
1394     sy = (int)((scrollY + drawAreaHeight / 2) * (dpi1 / dpi))
1395          - drawAreaHeight / 2;
1396   }
1397 
1398   update(topPage, sx, sy, (dpi1 * 100) / 72, rotate, gFalse, gFalse, gFalse);
1399 }
1400 
setContinuousMode(GBool cm)1401 void PDFCore::setContinuousMode(GBool cm) {
1402   if (continuousMode != cm) {
1403     continuousMode = cm;
1404     update(topPage, scrollX, -1, zoom, rotate, gTrue, gFalse, gTrue);
1405   }
1406 }
1407 
setSelectionColor(SplashColor color)1408 void PDFCore::setSelectionColor(SplashColor color) {
1409   splashColorCopy(selectXorColor, color);
1410   splashColorXor(selectXorColor, paperColor);
1411 }
1412 
setSelection(int newSelectPage,int newSelectULX,int newSelectULY,int newSelectLRX,int newSelectLRY)1413 void PDFCore::setSelection(int newSelectPage,
1414 			   int newSelectULX, int newSelectULY,
1415 			   int newSelectLRX, int newSelectLRY) {
1416   int x0, y0, x1, y1, py;
1417   GBool haveSel, newHaveSel;
1418   GBool needRedraw, needScroll;
1419   GBool moveLeft, moveRight, moveTop, moveBottom;
1420   PDFCorePage *page;
1421 
1422 
1423   haveSel = selectULX != selectLRX && selectULY != selectLRY;
1424   newHaveSel = newSelectULX != newSelectLRX && newSelectULY != newSelectLRY;
1425 
1426   // erase old selection on off-screen bitmap
1427   needRedraw = gFalse;
1428   if (haveSel) {
1429     xorRectangle(selectPage, selectULX, selectULY, selectLRX, selectLRY,
1430 		 new SplashSolidColor(selectXorColor));
1431     needRedraw = gTrue;
1432   }
1433 
1434   // draw new selection on off-screen bitmap
1435   if (newHaveSel) {
1436     xorRectangle(newSelectPage, newSelectULX, newSelectULY,
1437 		 newSelectLRX, newSelectLRY,
1438 		 new SplashSolidColor(selectXorColor));
1439     needRedraw = gTrue;
1440   }
1441 
1442   // check which edges moved
1443   if (!haveSel || newSelectPage != selectPage) {
1444     moveLeft = moveTop = moveRight = moveBottom = gTrue;
1445   } else {
1446     moveLeft = newSelectULX != selectULX;
1447     moveTop = newSelectULY != selectULY;
1448     moveRight = newSelectLRX != selectLRX;
1449     moveBottom = newSelectLRY != selectLRY;
1450   }
1451 
1452   // redraw currently visible part of bitmap
1453   if (needRedraw) {
1454     if (!haveSel) {
1455       page = findPage(newSelectPage);
1456       x0 = newSelectULX;
1457       y0 = newSelectULY;
1458       x1 = newSelectLRX;
1459       y1 = newSelectLRY;
1460       redrawWindow(page->xDest + x0, page->yDest + y0,
1461 		   x1 - x0 + 1, y1 - y0 + 1, gFalse);
1462     } else if (!newHaveSel) {
1463       if ((page = findPage(selectPage))) {
1464 	x0 = selectULX;
1465 	y0 = selectULY;
1466 	x1 = selectLRX;
1467 	y1 = selectLRY;
1468 	redrawWindow(page->xDest + x0, page->yDest + y0,
1469 		     x1 - x0 + 1, y1 - y0 + 1, gFalse);
1470       }
1471     } else {
1472       page = findPage(newSelectPage);
1473       if (moveLeft) {
1474 	x0 = newSelectULX < selectULX ? newSelectULX : selectULX;
1475 	y0 = newSelectULY < selectULY ? newSelectULY : selectULY;
1476 	x1 = newSelectULX > selectULX ? newSelectULX : selectULX;
1477 	y1 = newSelectLRY > selectLRY ? newSelectLRY : selectLRY;
1478 	redrawWindow(page->xDest + x0, page->yDest + y0,
1479 		     x1 - x0 + 1, y1 - y0 + 1, gFalse);
1480       }
1481       if (moveRight) {
1482 	x0 = newSelectLRX < selectLRX ? newSelectLRX : selectLRX;
1483 	y0 = newSelectULY < selectULY ? newSelectULY : selectULY;
1484 	x1 = newSelectLRX > selectLRX ? newSelectLRX : selectLRX;
1485 	y1 = newSelectLRY > selectLRY ? newSelectLRY : selectLRY;
1486 	redrawWindow(page->xDest + x0, page->yDest + y0,
1487 		     x1 - x0 + 1, y1 - y0 + 1, gFalse);
1488       }
1489       if (moveTop) {
1490 	x0 = newSelectULX < selectULX ? newSelectULX : selectULX;
1491 	y0 = newSelectULY < selectULY ? newSelectULY : selectULY;
1492 	x1 = newSelectLRX > selectLRX ? newSelectLRX : selectLRX;
1493 	y1 = newSelectULY > selectULY ? newSelectULY : selectULY;
1494 	redrawWindow(page->xDest + x0, page->yDest + y0,
1495 		     x1 - x0 + 1, y1 - y0 + 1, gFalse);
1496       }
1497       if (moveBottom) {
1498 	x0 = newSelectULX < selectULX ? newSelectULX : selectULX;
1499 	y0 = newSelectLRY < selectLRY ? newSelectLRY : selectLRY;
1500 	x1 = newSelectLRX > selectLRX ? newSelectLRX : selectLRX;
1501 	y1 = newSelectLRY > selectLRY ? newSelectLRY : selectLRY;
1502 	redrawWindow(page->xDest + x0, page->yDest + y0,
1503 		     x1 - x0 + 1, y1 - y0 + 1, gFalse);
1504       }
1505     }
1506   }
1507 
1508   // switch to new selection coords
1509   selectPage = newSelectPage;
1510   selectULX = newSelectULX;
1511   selectULY = newSelectULY;
1512   selectLRX = newSelectLRX;
1513   selectLRY = newSelectLRY;
1514 
1515   // scroll if necessary
1516   if (newHaveSel) {
1517     page = findPage(selectPage);
1518     needScroll = gFalse;
1519     x0 = scrollX;
1520     y0 = scrollY;
1521     if (moveLeft && page->xDest + selectULX < 0) {
1522       x0 += page->xDest + selectULX;
1523       needScroll = gTrue;
1524     } else if (moveRight && page->xDest + selectLRX >= drawAreaWidth) {
1525       x0 += page->xDest + selectLRX - drawAreaWidth;
1526       needScroll = gTrue;
1527     } else if (moveLeft && page->xDest + selectULX >= drawAreaWidth) {
1528       x0 += page->xDest + selectULX - drawAreaWidth;
1529       needScroll = gTrue;
1530     } else if (moveRight && page->xDest + selectLRX < 0) {
1531       x0 += page->xDest + selectLRX;
1532       needScroll = gTrue;
1533     }
1534     py = continuousMode ? pageY[selectPage - 1] : 0;
1535     if (moveTop && py + selectULY < y0) {
1536       y0 = py + selectULY;
1537       needScroll = gTrue;
1538     } else if (moveBottom && py + selectLRY >= y0 + drawAreaHeight) {
1539       y0 = py + selectLRY - drawAreaHeight;
1540       needScroll = gTrue;
1541     } else if (moveTop && py + selectULY >= y0 + drawAreaHeight) {
1542       y0 = py + selectULY - drawAreaHeight;
1543       needScroll = gTrue;
1544     } else if (moveBottom && py + selectLRY < y0) {
1545       y0 = py + selectLRY;
1546       needScroll = gTrue;
1547     }
1548     if (needScroll) {
1549       scrollTo(x0, y0);
1550     }
1551   }
1552 }
1553 
moveSelection(int pg,int x,int y)1554 void PDFCore::moveSelection(int pg, int x, int y) {
1555   int newSelectULX, newSelectULY, newSelectLRX, newSelectLRY;
1556 
1557   // don't allow selections to span multiple pages
1558   if (pg != selectPage) {
1559     return;
1560   }
1561 
1562   // move appropriate edges of selection
1563   if (lastDragLeft) {
1564     if (x < selectLRX) {
1565       newSelectULX = x;
1566       newSelectLRX = selectLRX;
1567     } else {
1568       newSelectULX = selectLRX;
1569       newSelectLRX = x;
1570       lastDragLeft = gFalse;
1571     }
1572   } else {
1573     if (x > selectULX) {
1574       newSelectULX = selectULX;
1575       newSelectLRX = x;
1576     } else {
1577       newSelectULX = x;
1578       newSelectLRX = selectULX;
1579       lastDragLeft = gTrue;
1580     }
1581   }
1582   if (lastDragTop) {
1583     if (y < selectLRY) {
1584       newSelectULY = y;
1585       newSelectLRY = selectLRY;
1586     } else {
1587       newSelectULY = selectLRY;
1588       newSelectLRY = y;
1589       lastDragTop = gFalse;
1590     }
1591   } else {
1592     if (y > selectULY) {
1593       newSelectULY = selectULY;
1594       newSelectLRY = y;
1595     } else {
1596       newSelectULY = y;
1597       newSelectLRY = selectULY;
1598       lastDragTop = gTrue;
1599     }
1600   }
1601 
1602   // redraw the selection
1603   setSelection(selectPage, newSelectULX, newSelectULY,
1604 	       newSelectLRX, newSelectLRY);
1605 }
1606 
xorRectangle(int pg,int x0,int y0,int x1,int y1,SplashPattern * pattern,PDFCoreTile * oneTile)1607 void PDFCore::xorRectangle(int pg, int x0, int y0, int x1, int y1,
1608 			   SplashPattern *pattern, PDFCoreTile *oneTile) {
1609   Splash *splash;
1610   SplashPath *path;
1611   PDFCorePage *page;
1612   PDFCoreTile *tile;
1613   SplashCoord xx0, yy0, xx1, yy1;
1614   int xi, yi, wi, hi;
1615   int i;
1616 
1617   if ((page = findPage(pg))) {
1618     for (i = 0; i < page->tiles->getLength(); ++i) {
1619       tile = (PDFCoreTile *)page->tiles->get(i);
1620       if (!oneTile || tile == oneTile) {
1621 	splash = new Splash(tile->bitmap, gFalse);
1622 	splash->setFillPattern(pattern->copy());
1623 	xx0 = (SplashCoord)(x0 - tile->xMin);
1624 	yy0 = (SplashCoord)(y0 - tile->yMin);
1625 	xx1 = (SplashCoord)(x1 - tile->xMin);
1626 	yy1 = (SplashCoord)(y1 - tile->yMin);
1627 	path = new SplashPath();
1628 	path->moveTo(xx0, yy0);
1629 	path->lineTo(xx1, yy0);
1630 	path->lineTo(xx1, yy1);
1631 	path->lineTo(xx0, yy1);
1632 	path->close();
1633 	splash->xorFill(path, gTrue);
1634 	delete path;
1635 	delete splash;
1636 	xi = x0 - tile->xMin;
1637 	wi = x1 - x0;
1638 	if (xi < 0) {
1639 	  wi += xi;
1640 	  xi = 0;
1641 	}
1642 	if (xi + wi > tile->bitmap->getWidth()) {
1643 	  wi = tile->bitmap->getWidth() - xi;
1644 	}
1645 	yi = y0 - tile->yMin;
1646 	hi = y1 - y0;
1647 	if (yi < 0) {
1648 	  hi += yi;
1649 	  yi = 0;
1650 	}
1651 	if (yi + hi > tile->bitmap->getHeight()) {
1652 	  hi = tile->bitmap->getHeight() - yi;
1653 	}
1654 	updateTileData(tile, xi, yi, wi, hi, gTrue);
1655       }
1656     }
1657   }
1658   delete pattern;
1659 }
1660 
getSelection(int * pg,double * ulx,double * uly,double * lrx,double * lry)1661 GBool PDFCore::getSelection(int *pg, double *ulx, double *uly,
1662 			    double *lrx, double *lry) {
1663   if (selectULX == selectLRX || selectULY == selectLRY) {
1664     return gFalse;
1665   }
1666   *pg = selectPage;
1667   cvtDevToUser(selectPage, selectULX, selectULY, ulx, uly);
1668   cvtDevToUser(selectPage, selectLRX, selectLRY, lrx, lry);
1669   return gTrue;
1670 }
1671 
extractText(int pg,double xMin,double yMin,double xMax,double yMax)1672 GString *PDFCore::extractText(int pg, double xMin, double yMin,
1673 			      double xMax, double yMax) {
1674   PDFCorePage *page;
1675   TextOutputControl textOutCtrl;
1676   TextOutputDev *textOut;
1677   int x0, y0, x1, y1, t;
1678   GString *s;
1679 
1680   if (!doc->okToCopy()) {
1681     return NULL;
1682   }
1683   if ((page = findPage(pg))) {
1684     cvtUserToDev(pg, xMin, yMin, &x0, &y0);
1685     cvtUserToDev(pg, xMax, yMax, &x1, &y1);
1686     if (x0 > x1) {
1687       t = x0; x0 = x1; x1 = t;
1688     }
1689     if (y0 > y1) {
1690       t = y0; y0 = y1; y1 = t;
1691     }
1692     s = page->text->getText(x0, y0, x1, y1);
1693   } else {
1694     textOutCtrl.mode = textOutPhysLayout;
1695     textOut = new TextOutputDev(NULL, &textOutCtrl, gFalse);
1696     if (textOut->isOk()) {
1697       doc->displayPage(textOut, pg, dpi, dpi, rotate, gFalse, gTrue, gFalse);
1698       textOut->cvtUserToDev(xMin, yMin, &x0, &y0);
1699       textOut->cvtUserToDev(xMax, yMax, &x1, &y1);
1700       if (x0 > x1) {
1701 	t = x0; x0 = x1; x1 = t;
1702       }
1703       if (y0 > y1) {
1704 	t = y0; y0 = y1; y1 = t;
1705       }
1706       s = textOut->getText(x0, y0, x1, y1);
1707     } else {
1708       s = new GString();
1709     }
1710     delete textOut;
1711   }
1712   return s;
1713 }
1714 
find(char * s,GBool caseSensitive,GBool next,GBool backward,GBool wholeWord,GBool onePageOnly)1715 GBool PDFCore::find(char *s, GBool caseSensitive, GBool next, GBool backward,
1716 		    GBool wholeWord, GBool onePageOnly) {
1717   Unicode *u;
1718   int len, i;
1719   GBool ret;
1720 
1721   // convert to Unicode
1722   len = (int)strlen(s);
1723   u = (Unicode *)gmallocn(len, sizeof(Unicode));
1724   for (i = 0; i < len; ++i) {
1725     u[i] = (Unicode)(s[i] & 0xff);
1726   }
1727 
1728   ret = findU(u, len, caseSensitive, next, backward, wholeWord, onePageOnly);
1729 
1730   gfree(u);
1731   return ret;
1732 }
1733 
findU(Unicode * u,int len,GBool caseSensitive,GBool next,GBool backward,GBool wholeWord,GBool onePageOnly)1734 GBool PDFCore::findU(Unicode *u, int len, GBool caseSensitive,
1735 		     GBool next, GBool backward, GBool wholeWord,
1736 		     GBool onePageOnly) {
1737   TextOutputControl textOutCtrl;
1738   TextOutputDev *textOut;
1739   double xMin, yMin, xMax, yMax;
1740   PDFCorePage *page;
1741   int pg;
1742   GBool startAtTop, startAtLast, stopAtLast;
1743 
1744   // check for zero-length string
1745   if (len == 0) {
1746     return gFalse;
1747   }
1748 
1749   setBusyCursor(gTrue);
1750 
1751   // search current page starting at previous result, current
1752   // selection, or top/bottom of page
1753   startAtTop = startAtLast = gFalse;
1754   xMin = yMin = xMax = yMax = 0;
1755   pg = topPage;
1756   if (next) {
1757     startAtLast = gTrue;
1758   } else if (selectULX != selectLRX && selectULY != selectLRY) {
1759     pg = selectPage;
1760     if (backward) {
1761       xMin = selectULX - 1;
1762       yMin = selectULY - 1;
1763     } else {
1764       xMin = selectULX + 1;
1765       yMin = selectULY + 1;
1766     }
1767   } else {
1768     startAtTop = gTrue;
1769   }
1770   if (!(page = findPage(pg))) {
1771     displayPage(pg, zoom, rotate, gTrue, gFalse);
1772     page = findPage(pg);
1773   }
1774   if (page->text->findText(u, len, startAtTop, gTrue, startAtLast, gFalse,
1775 			   caseSensitive, backward, wholeWord,
1776 			   &xMin, &yMin, &xMax, &yMax)) {
1777     goto found;
1778   }
1779 
1780   if (!onePageOnly) {
1781 
1782     // search following/previous pages
1783     textOutCtrl.mode = textOutPhysLayout;
1784     textOut = new TextOutputDev(NULL, &textOutCtrl, gFalse);
1785     if (!textOut->isOk()) {
1786       delete textOut;
1787       goto notFound;
1788     }
1789     for (pg = backward ? pg - 1 : pg + 1;
1790 	 backward ? pg >= 1 : pg <= doc->getNumPages();
1791 	 pg += backward ? -1 : 1) {
1792       doc->displayPage(textOut, pg, 72, 72, 0, gFalse, gTrue, gFalse);
1793       if (textOut->findText(u, len, gTrue, gTrue, gFalse, gFalse,
1794 			    caseSensitive, backward, wholeWord,
1795 			    &xMin, &yMin, &xMax, &yMax)) {
1796 	delete textOut;
1797 	goto foundPage;
1798       }
1799     }
1800 
1801     // search previous/following pages
1802     for (pg = backward ? doc->getNumPages() : 1;
1803 	 backward ? pg > topPage : pg < topPage;
1804 	 pg += backward ? -1 : 1) {
1805       doc->displayPage(textOut, pg, 72, 72, 0, gFalse, gTrue, gFalse);
1806       if (textOut->findText(u, len, gTrue, gTrue, gFalse, gFalse,
1807 			    caseSensitive, backward, wholeWord,
1808 			    &xMin, &yMin, &xMax, &yMax)) {
1809 	delete textOut;
1810 	goto foundPage;
1811       }
1812     }
1813     delete textOut;
1814 
1815   }
1816 
1817   // search current page ending at previous result, current selection,
1818   // or bottom/top of page
1819   if (!startAtTop) {
1820     xMin = yMin = xMax = yMax = 0;
1821     if (next) {
1822       stopAtLast = gTrue;
1823     } else {
1824       stopAtLast = gFalse;
1825       xMax = selectLRX;
1826       yMax = selectLRY;
1827     }
1828     if (page->text->findText(u, len, gTrue, gFalse, gFalse, stopAtLast,
1829 			     caseSensitive, backward, wholeWord,
1830 			     &xMin, &yMin, &xMax, &yMax)) {
1831       goto found;
1832     }
1833   }
1834 
1835   // not found
1836  notFound:
1837   setBusyCursor(gFalse);
1838   return gFalse;
1839 
1840   // found on a different page
1841  foundPage:
1842   update(pg, scrollX, continuousMode ? -1 : 0, zoom, rotate, gFalse, gTrue,
1843 	 gTrue);
1844   page = findPage(pg);
1845   if (!page->text->findText(u, len, gTrue, gTrue, gFalse, gFalse,
1846 			    caseSensitive, backward, wholeWord,
1847 			    &xMin, &yMin, &xMax, &yMax)) {
1848     // this can happen if coalescing is bad
1849     goto notFound;
1850   }
1851 
1852   // found: change the selection
1853  found:
1854   setSelection(pg, (int)floor(xMin), (int)floor(yMin),
1855 	       (int)ceil(xMax), (int)ceil(yMax));
1856 
1857   setBusyCursor(gFalse);
1858   return gTrue;
1859 }
1860 
1861 
cvtWindowToUser(int xw,int yw,int * pg,double * xu,double * yu)1862 GBool PDFCore::cvtWindowToUser(int xw, int yw,
1863 			       int *pg, double *xu, double *yu) {
1864   PDFCorePage *page;
1865   PDFCoreTile *tile;
1866   int i;
1867 
1868   for (i = 0; i < pages->getLength(); ++i) {
1869     page = (PDFCorePage *)pages->get(i);
1870     if (xw >= page->xDest && xw < page->xDest + page->w &&
1871 	yw >= page->yDest && yw < page->yDest + page->h) {
1872       if (page->tiles->getLength() == 0) {
1873 	break;
1874       }
1875       tile = (PDFCoreTile *)page->tiles->get(0);
1876       *pg = page->page;
1877       xw -= tile->xDest;
1878       yw -= tile->yDest;
1879       *xu = tile->ictm[0] * xw + tile->ictm[2] * yw + tile->ictm[4];
1880       *yu = tile->ictm[1] * xw + tile->ictm[3] * yw + tile->ictm[5];
1881       return gTrue;
1882     }
1883   }
1884   *pg = 0;
1885   *xu = *yu = 0;
1886   return gFalse;
1887 }
1888 
cvtWindowToDev(int xw,int yw,int * pg,int * xd,int * yd)1889 GBool PDFCore::cvtWindowToDev(int xw, int yw, int *pg, int *xd, int *yd) {
1890   PDFCorePage *page;
1891   int i;
1892 
1893   for (i = 0; i < pages->getLength(); ++i) {
1894     page = (PDFCorePage *)pages->get(i);
1895     if (xw >= page->xDest && xw < page->xDest + page->w &&
1896 	yw >= page->yDest && yw < page->yDest + page->h) {
1897       *pg = page->page;
1898       *xd = xw - page->xDest;
1899       *yd = yw - page->yDest;
1900       return gTrue;
1901     }
1902   }
1903   *pg = 0;
1904   *xd = *yd = 0;
1905   return gFalse;
1906 }
1907 
cvtUserToWindow(int pg,double xu,double yu,int * xw,int * yw)1908 void PDFCore::cvtUserToWindow(int pg, double xu, double yu, int *xw, int *yw) {
1909   PDFCorePage *page;
1910   PDFCoreTile *tile;
1911 
1912   if ((page = findPage(pg)) &&
1913       page->tiles->getLength() > 0) {
1914     tile = (PDFCoreTile *)page->tiles->get(0);
1915   } else if (curTile && curPage->page == pg) {
1916     tile = curTile;
1917   } else {
1918     tile = NULL;
1919   }
1920   if (tile) {
1921     *xw = tile->xDest + (int)(tile->ctm[0] * xu + tile->ctm[2] * yu +
1922 			      tile->ctm[4] + 0.5);
1923     *yw = tile->yDest + (int)(tile->ctm[1] * xu + tile->ctm[3] * yu +
1924 			      tile->ctm[5] + 0.5);
1925   } else {
1926     // this should never happen
1927     *xw = *yw = 0;
1928   }
1929 }
1930 
cvtUserToDev(int pg,double xu,double yu,int * xd,int * yd)1931 void PDFCore::cvtUserToDev(int pg, double xu, double yu, int *xd, int *yd) {
1932   PDFCorePage *page;
1933   PDFCoreTile *tile;
1934   double ctm[6];
1935 
1936   if ((page = findPage(pg)) &&
1937       page->tiles->getLength() > 0) {
1938     tile = (PDFCoreTile *)page->tiles->get(0);
1939   } else if (curTile && curPage->page == pg) {
1940     tile = curTile;
1941   } else {
1942     tile = NULL;
1943   }
1944   if (tile) {
1945     *xd = (int)(tile->xMin + tile->ctm[0] * xu +
1946 		tile->ctm[2] * yu + tile->ctm[4] + 0.5);
1947     *yd = (int)(tile->yMin + tile->ctm[1] * xu +
1948 		tile->ctm[3] * yu + tile->ctm[5] + 0.5);
1949   } else {
1950     doc->getCatalog()->getPage(pg)->getDefaultCTM(ctm, dpi, dpi, rotate,
1951 						  gFalse, out->upsideDown());
1952     *xd = (int)(ctm[0] * xu + ctm[2] * yu + ctm[4] + 0.5);
1953     *yd = (int)(ctm[1] * xu + ctm[3] * yu + ctm[5] + 0.5);
1954   }
1955 }
1956 
cvtDevToWindow(int pg,int xd,int yd,int * xw,int * yw)1957 void PDFCore::cvtDevToWindow(int pg, int xd, int yd, int *xw, int *yw) {
1958   PDFCorePage *page;
1959 
1960   if ((page = findPage(pg))) {
1961     *xw = page->xDest + xd;
1962     *yw = page->yDest + yd;
1963   } else {
1964     // this should never happen
1965     *xw = *yw = 0;
1966   }
1967 }
1968 
cvtDevToUser(int pg,int xd,int yd,double * xu,double * yu)1969 void PDFCore::cvtDevToUser(int pg, int xd, int yd, double *xu, double *yu) {
1970   PDFCorePage *page;
1971   PDFCoreTile *tile;
1972 
1973   if ((page = findPage(pg)) &&
1974       page->tiles->getLength() > 0) {
1975     tile = (PDFCoreTile *)page->tiles->get(0);
1976   } else if (curTile && curPage->page == pg) {
1977     tile = curTile;
1978   } else {
1979     tile = NULL;
1980   }
1981   if (tile) {
1982     xd -= tile->xMin;
1983     yd -= tile->yMin;
1984     *xu = tile->ictm[0] * xd + tile->ictm[2] * yd + tile->ictm[4];
1985     *yu = tile->ictm[1] * xd + tile->ictm[3] * yd + tile->ictm[5];
1986   } else {
1987     // this should never happen
1988     *xu = *yu = 0;
1989   }
1990 }
1991 
setReverseVideo(GBool reverseVideoA)1992 void PDFCore::setReverseVideo(GBool reverseVideoA) {
1993   out->setReverseVideo(reverseVideoA);
1994   update(topPage, scrollX, scrollY, zoom, rotate, gTrue, gFalse, gFalse);
1995 }
1996 
findLink(int pg,double x,double y)1997 LinkAction *PDFCore::findLink(int pg, double x, double y) {
1998   PDFCorePage *page;
1999 
2000   if ((page = findPage(pg))) {
2001     return page->links ? page->links->find(x, y) : (LinkAction *)NULL;
2002   }
2003   return NULL;
2004 }
2005 
findPage(int pg)2006 PDFCorePage *PDFCore::findPage(int pg) {
2007   PDFCorePage *page;
2008   int i;
2009 
2010   for (i = 0; i < pages->getLength(); ++i) {
2011     page = (PDFCorePage *)pages->get(i);
2012     if (page->page == pg) {
2013       return page;
2014     }
2015   }
2016   return NULL;
2017 }
2018 
redrawCbk(void * data,int x0,int y0,int x1,int y1,GBool composited)2019 void PDFCore::redrawCbk(void *data, int x0, int y0, int x1, int y1,
2020 			GBool composited) {
2021   PDFCore *core = (PDFCore *)data;
2022 
2023   core->curTile->bitmap = core->out->getBitmap();
2024 
2025   // the default CTM is set by the Gfx constructor; tile->ctm is
2026   // needed by the coordinate conversion functions (which may be
2027   // called during redraw)
2028   memcpy(core->curTile->ctm, core->out->getDefCTM(), 6 * sizeof(double));
2029   memcpy(core->curTile->ictm, core->out->getDefICTM(), 6 * sizeof(double));
2030 
2031   // the bitmap created by Gfx and SplashOutputDev can be a slightly
2032   // different size due to rounding errors
2033   if (x1 >= core->curTile->xMax - core->curTile->xMin) {
2034     x1 = core->curTile->xMax - core->curTile->xMin - 1;
2035   }
2036   if (y1 >= core->curTile->yMax - core->curTile->yMin) {
2037     y1 = core->curTile->yMax - core->curTile->yMin - 1;
2038   }
2039 
2040   core->clippedRedrawRect(core->curTile, x0, y0,
2041 			  core->curTile->xDest + x0, core->curTile->yDest + y0,
2042 			  x1 - x0 + 1, y1 - y0 + 1,
2043 			  0, 0, core->drawAreaWidth, core->drawAreaHeight,
2044 			  gTrue, composited);
2045 }
2046 
redrawWindow(int x,int y,int width,int height,GBool needUpdate)2047 void PDFCore::redrawWindow(int x, int y, int width, int height,
2048 			   GBool needUpdate) {
2049   PDFCorePage *page;
2050   PDFCoreTile *tile;
2051   int xDest, yDest, w, i, j;
2052 
2053   if (pages->getLength() == 0) {
2054     redrawRect(NULL, 0, 0, x, y, width, height, gTrue);
2055     return;
2056   }
2057 
2058   for (i = 0; i < pages->getLength(); ++i) {
2059     page = (PDFCorePage *)pages->get(i);
2060     for (j = 0; j < page->tiles->getLength(); ++j) {
2061       tile = (PDFCoreTile *)page->tiles->get(j);
2062       if (tile->edges & pdfCoreTileTopEdge) {
2063 	if (tile->edges & pdfCoreTileLeftEdge) {
2064 	  xDest = 0;
2065 	} else {
2066 	  xDest = tile->xDest;
2067 	}
2068 	if (tile->edges & pdfCoreTileRightEdge) {
2069 	  w = drawAreaWidth - xDest;
2070 	} else {
2071 	  w = tile->xDest + (tile->xMax - tile->xMin) - xDest;
2072 	}
2073 	clippedRedrawRect(NULL, 0, 0,
2074 			  xDest, 0, w, tile->yDest,
2075 			  x, y, width, height, gFalse);
2076       }
2077       if (tile->edges & pdfCoreTileBottomEdge) {
2078 	if (tile->edges & pdfCoreTileLeftEdge) {
2079 	  xDest = 0;
2080 	} else {
2081 	  xDest = tile->xDest;
2082 	}
2083 	if (tile->edges & pdfCoreTileRightEdge) {
2084 	  w = drawAreaWidth - xDest;
2085 	} else {
2086 	  w = tile->xDest + (tile->xMax - tile->xMin) - xDest;
2087 	}
2088 	yDest = tile->yDest + (tile->yMax - tile->yMin);
2089 	clippedRedrawRect(NULL, 0, 0,
2090 			  xDest, yDest, w, drawAreaHeight - yDest,
2091 			  x, y, width, height, gFalse);
2092       } else if ((tile->edges & pdfCoreTileBottomSpace) &&
2093 		 i+1 < pages->getLength()) {
2094 	if (tile->edges & pdfCoreTileLeftEdge) {
2095 	  xDest = 0;
2096 	} else {
2097 	  xDest = tile->xDest;
2098 	}
2099 	if (tile->edges & pdfCoreTileRightEdge) {
2100 	  w = drawAreaWidth - xDest;
2101 	} else {
2102 	  w = tile->xDest + (tile->xMax - tile->xMin) - xDest;
2103 	}
2104 	yDest = tile->yDest + (tile->yMax - tile->yMin);
2105 	clippedRedrawRect(NULL, 0, 0,
2106 			  xDest, yDest,
2107 			  w, ((PDFCorePage *)pages->get(i+1))->yDest - yDest,
2108 			  x, y, width, height, gFalse);
2109       }
2110       if (tile->edges & pdfCoreTileLeftEdge) {
2111 	clippedRedrawRect(NULL, 0, 0,
2112 			  0, tile->yDest,
2113 			  tile->xDest, tile->yMax - tile->yMin,
2114 			  x, y, width, height, gFalse);
2115       }
2116       if (tile->edges & pdfCoreTileRightEdge) {
2117 	xDest = tile->xDest + (tile->xMax - tile->xMin);
2118 	clippedRedrawRect(NULL, 0, 0,
2119 			  xDest, tile->yDest,
2120 			  drawAreaWidth - xDest, tile->yMax - tile->yMin,
2121 			  x, y, width, height, gFalse);
2122       }
2123       clippedRedrawRect(tile, 0, 0, tile->xDest, tile->yDest,
2124 			tile->bitmap->getWidth(), tile->bitmap->getHeight(),
2125 			x, y, width, height, needUpdate);
2126     }
2127   }
2128 }
2129 
newTile(int xDestA,int yDestA)2130 PDFCoreTile *PDFCore::newTile(int xDestA, int yDestA) {
2131   return new PDFCoreTile(xDestA, yDestA);
2132 }
2133 
updateTileData(PDFCoreTile * tileA,int xSrc,int ySrc,int width,int height,GBool composited)2134 void PDFCore::updateTileData(PDFCoreTile *tileA, int xSrc, int ySrc,
2135 			     int width, int height, GBool composited) {
2136 }
2137 
clippedRedrawRect(PDFCoreTile * tile,int xSrc,int ySrc,int xDest,int yDest,int width,int height,int xClip,int yClip,int wClip,int hClip,GBool needUpdate,GBool composited)2138 void PDFCore::clippedRedrawRect(PDFCoreTile *tile, int xSrc, int ySrc,
2139 				int xDest, int yDest, int width, int height,
2140 				int xClip, int yClip, int wClip, int hClip,
2141 				GBool needUpdate, GBool composited) {
2142   if (tile && needUpdate) {
2143     updateTileData(tile, xSrc, ySrc, width, height, composited);
2144   }
2145   if (xDest < xClip) {
2146     xSrc += xClip - xDest;
2147     width -= xClip - xDest;
2148     xDest = xClip;
2149   }
2150   if (xDest + width > xClip + wClip) {
2151     width = xClip + wClip - xDest;
2152   }
2153   if (yDest < yClip) {
2154     ySrc += yClip - yDest;
2155     height -= yClip - yDest;
2156     yDest = yClip;
2157   }
2158   if (yDest + height > yClip + hClip) {
2159     height = yClip + hClip - yDest;
2160   }
2161   if (width > 0 && height > 0) {
2162     redrawRect(tile, xSrc, ySrc, xDest, yDest, width, height, composited);
2163   }
2164 }
2165