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