1 //========================================================================
2 //
3 // TileMap.cc
4 //
5 // Copyright 2014 Glyph & Cog, LLC
6 //
7 //========================================================================
8
9 #include <aconf.h>
10
11 #ifdef USE_GCC_PRAGMAS
12 #pragma implementation
13 #endif
14
15 #include "gmem.h"
16 #include "gmempp.h"
17 #include "GList.h"
18 #include "PDFDoc.h"
19 #include "DisplayState.h"
20 #include "TileMap.h"
21
22 //------------------------------------------------------------------------
23
24 // Number of pixels of matte color between pages (above and below each
25 // other) in continuous mode.
26 #define continuousPageSpacing 3
27
28 // Number of pixels of matte color between facing pages (left and
29 // right of each other) in side-by-side mode.
30 #define sideBySidePageSpacing 3
31
32 // Number of pixels of matte color between pages (left and right of
33 // each other) in horizontal continuous mode.
34 #define horizContinuousPageSpacing 3
35
36 //------------------------------------------------------------------------
37
TileMap(DisplayState * stateA)38 TileMap::TileMap(DisplayState *stateA) {
39 state = stateA;
40 state->setTileMap(this);
41 pageDPI = NULL;
42 pageW = pageH = NULL;
43 tileW = tileH = NULL;
44 pageBoxW = pageBoxH = NULL;
45 pageX = pageY = NULL;
46 tiles = NULL;
47 }
48
~TileMap()49 TileMap::~TileMap() {
50 clearPageParams();
51 clearContinuousModeParams();
52 gfree(pageBoxW);
53 gfree(pageBoxH);
54 if (tiles) {
55 deleteGList(tiles, PlacedTileDesc);
56 }
57 }
58
getTileList()59 GList *TileMap::getTileList() {
60 double pageDPI1, pageDPI2;
61 int pageW1, pageH1, tileW1, tileH1, pageW2, pageH2, tileW2, tileH2;
62 int offsetX, offsetY, offsetX2;
63 int x0, y0, x1, y1, x, y, tx, ty, tw, th, page;
64
65 if (tiles) {
66 return tiles;
67 }
68
69 tiles = new GList();
70
71 if (!state->getDoc() || !state->getDoc()->getNumPages()) {
72 return tiles;
73 }
74
75 updatePageParams();
76 updateContinuousModeParams();
77
78 switch (state->getDisplayMode()) {
79
80 case displaySingle:
81 page = state->getScrollPage();
82 pageDPI1 = pageDPI[page - 1];
83 pageW1 = pageW[page - 1];
84 pageH1 = pageH[page - 1];
85 tileW1 = tileW[page - 1];
86 tileH1 = tileH[page - 1];
87 if (pageW1 < state->getWinW()) {
88 offsetX = (state->getWinW() - pageW1) / 2;
89 } else {
90 offsetX = 0;
91 }
92 if (pageH1 < state->getWinH()) {
93 offsetY = (state->getWinH() - pageH1) / 2;
94 } else {
95 offsetY = 0;
96 }
97 if ((x0 = state->getScrollX() - offsetX) < 0) {
98 x0 = 0;
99 }
100 if ((y0 = state->getScrollY() - offsetY) < 0) {
101 y0 = 0;
102 }
103 if ((x1 = state->getScrollX() + state->getWinW() - 1 - offsetX) >= pageW1) {
104 x1 = pageW1 - 1;
105 }
106 if ((y1 = state->getScrollY() + state->getWinH() - 1 - offsetY) >= pageH1) {
107 y1 = pageH1 - 1;
108 }
109 for (y = y0 / tileH1; y <= y1 / tileH1; ++y) {
110 for (x = x0 / tileW1; x <= x1 / tileW1; ++x) {
111 tx = x * tileW1;
112 ty = y * tileH1;
113 tw = tileW1;
114 if (tx + tw > pageW1) {
115 tw = pageW1 - tx;
116 }
117 th = tileH1;
118 if (ty + th > pageH1) {
119 th = pageH1 - ty;
120 }
121 tiles->append(new PlacedTileDesc(page, state->getRotate(), pageDPI1,
122 tx, ty, tw, th,
123 tx - state->getScrollX() + offsetX,
124 ty - state->getScrollY() + offsetY));
125 }
126 }
127 break;
128
129 case displayContinuous:
130 if (totalH < state->getWinH()) {
131 offsetY = (state->getWinH() - totalH) / 2;
132 } else {
133 offsetY = 0;
134 }
135 page = findContinuousPage(state->getScrollY());
136 while (page <= state->getDoc()->getNumPages() &&
137 pageY[page - 1] < state->getScrollY() + state->getWinH()) {
138 pageDPI1 = pageDPI[page - 1];
139 pageW1 = pageW[page - 1];
140 pageH1 = pageH[page - 1];
141 tileW1 = tileW[page - 1];
142 tileH1 = tileH[page - 1];
143 if (maxW < state->getWinW()) {
144 offsetX = (state->getWinW() - maxW) / 2;
145 } else {
146 offsetX = 0;
147 }
148 offsetX += (maxW - pageW1) / 2;
149 if ((x0 = state->getScrollX() - offsetX) < 0) {
150 x0 = 0;
151 }
152 if ((y0 = state->getScrollY() - pageY[page - 1] - offsetY) < 0) {
153 y0 = 0;
154 }
155 if ((x1 = state->getScrollX() + state->getWinW() - 1 - offsetX)
156 >= pageW1) {
157 x1 = pageW1 - 1;
158 }
159 if ((y1 = state->getScrollY() - pageY[page - 1]
160 + state->getWinH() - 1 - offsetY)
161 >= pageH1) {
162 y1 = pageH1 - 1;
163 }
164 for (y = y0 / tileH1; y <= y1 / tileH1; ++y) {
165 for (x = x0 / tileW1; x <= x1 / tileW1; ++x) {
166 tx = x * tileW1;
167 ty = y * tileH1;
168 tw = tileW1;
169 if (tx + tw > pageW1) {
170 tw = pageW1 - tx;
171 }
172 th = tileH1;
173 if (ty + th > pageH1) {
174 th = pageH1 - ty;
175 }
176 tiles->append(new PlacedTileDesc(
177 page, state->getRotate(), pageDPI1,
178 tx, ty, tw, th,
179 tx - state->getScrollX() + offsetX,
180 ty - state->getScrollY() + pageY[page - 1]
181 + offsetY));
182 }
183 }
184 ++page;
185 }
186 break;
187
188 case displaySideBySideSingle:
189 page = state->getScrollPage();
190 pageDPI1 = pageDPI[page - 1];
191 pageW1 = pageW[page - 1];
192 pageH1 = pageH[page - 1];
193 tileW1 = tileW[page - 1];
194 tileH1 = tileH[page - 1];
195 if (page + 1 <= state->getDoc()->getNumPages()) {
196 pageDPI2 = pageDPI[page];
197 pageW2 = pageW[page];
198 pageH2 = pageH[page];
199 tileW2 = tileW[page];
200 tileH2 = tileH[page];
201 } else {
202 // display a single page as though there were a blank facing
203 // page of the same size
204 pageDPI2 = pageDPI1;
205 pageW2 = pageW1;
206 pageH2 = pageH1;
207 tileW2 = tileW1;
208 tileH2 = tileH1;
209 }
210 if (pageW1 + sideBySidePageSpacing + pageW2 < state->getWinW()) {
211 offsetX = (state->getWinW() -
212 (pageW1 + sideBySidePageSpacing + pageW2)) / 2;
213 } else {
214 offsetX = 0;
215 }
216 offsetX2 = offsetX + pageW1 + sideBySidePageSpacing;
217 if (pageH1 < state->getWinH() && pageH2 < state->getWinH()) {
218 if (pageH1 > pageH2) {
219 offsetY = (state->getWinH() - pageH1) / 2;
220 } else {
221 offsetY = (state->getWinH() - pageH2) / 2;
222 }
223 } else {
224 offsetY = 0;
225 }
226 // left page
227 if ((x0 = state->getScrollX() - offsetX) < 0) {
228 x0 = 0;
229 }
230 if ((y0 = state->getScrollY() - offsetY) < 0) {
231 y0 = 0;
232 }
233 if ((x1 = state->getScrollX() + state->getWinW() - 1 - offsetX) >= pageW1) {
234 x1 = pageW1 - 1;
235 } else if (x1 < 0) {
236 x1 = -tileW2;
237 }
238 if ((y1 = state->getScrollY() + state->getWinH() - 1 - offsetY) >= pageH1) {
239 y1 = pageH1 - 1;
240 } else if (y1 < 0) {
241 y1 = -tileH2;
242 }
243 for (y = y0 / tileH1; y <= y1 / tileH1; ++y) {
244 for (x = x0 / tileW1; x <= x1 / tileW1; ++x) {
245 tx = x * tileW1;
246 ty = y * tileH1;
247 tw = tileW1;
248 if (tx + tw > pageW1) {
249 tw = pageW1 - tx;
250 }
251 th = tileH1;
252 if (ty + th > pageH1) {
253 th = pageH1 - ty;
254 }
255 tiles->append(new PlacedTileDesc(page,
256 state->getRotate(), pageDPI1,
257 tx, ty, tw, th,
258 tx - state->getScrollX() + offsetX,
259 ty - state->getScrollY() + offsetY));
260 }
261 }
262 // right page
263 if (page + 1 <= state->getDoc()->getNumPages()) {
264 if ((x0 = state->getScrollX() - offsetX2) < 0) {
265 x0 = 0;
266 }
267 if ((y0 = state->getScrollY() - offsetY) < 0) {
268 y0 = 0;
269 }
270 if ((x1 = state->getScrollX() + state->getWinW() - 1 - offsetX2)
271 >= pageW2) {
272 x1 = pageW2 - 1;
273 } else if (x1 < 0) {
274 x1 = -tileW2;
275 }
276 if ((y1 = state->getScrollY() + state->getWinH() - 1 - offsetY)
277 >= pageH2) {
278 y1 = pageH2 - 1;
279 } else if (y1 < 0) {
280 y1 = -tileH2;
281 }
282 for (y = y0 / tileH2; y <= y1 / tileH2; ++y) {
283 for (x = x0 / tileW2; x <= x1 / tileW2; ++x) {
284 tx = x * tileW2;
285 ty = y * tileH2;
286 tw = tileW2;
287 if (tx + tw > pageW2) {
288 tw = pageW2 - tx;
289 }
290 th = tileH2;
291 if (ty + th > pageH2) {
292 th = pageH2 - ty;
293 }
294 tiles->append(new PlacedTileDesc(page + 1,
295 state->getRotate(), pageDPI2,
296 tx, ty, tw, th,
297 tx - state->getScrollX() + offsetX2,
298 ty - state->getScrollY() + offsetY));
299 }
300 }
301 }
302 break;
303
304 case displaySideBySideContinuous:
305 if (totalH < state->getWinH()) {
306 offsetY = (state->getWinH() - totalH) / 2;
307 } else {
308 offsetY = 0;
309 }
310 page = findSideBySideContinuousPage(state->getScrollY());
311 while (page <= state->getDoc()->getNumPages() &&
312 (pageY[page - 1] < state->getScrollY() + state->getWinH() ||
313 (page + 1 <= state->getDoc()->getNumPages() &&
314 pageY[page] < state->getScrollY() + state->getWinH()))) {
315 pageDPI1 = pageDPI[page - 1];
316 pageW1 = pageW[page - 1];
317 pageH1 = pageH[page - 1];
318 tileW1 = tileW[page - 1];
319 tileH1 = tileH[page - 1];
320 if (page + 1 <= state->getDoc()->getNumPages()) {
321 pageDPI2 = pageDPI[page];
322 pageW2 = pageW[page];
323 pageH2 = pageH[page];
324 tileW2 = tileW[page];
325 tileH2 = tileH[page];
326 } else {
327 // display a single page as though there were a blank facing
328 // page of the same size
329 pageDPI2 = pageDPI1;
330 pageW2 = pageW1;
331 pageH2 = pageH1;
332 tileW2 = tileW1;
333 tileH2 = tileH1;
334 }
335 if (maxW + sideBySidePageSpacing + maxW2 < state->getWinW()) {
336 offsetX = (state->getWinW() -
337 (maxW + sideBySidePageSpacing + maxW2)) / 2;
338 } else {
339 offsetX = 0;
340 }
341 offsetX += maxW - pageW1;
342 offsetX2 = offsetX + pageW1 + sideBySidePageSpacing;
343 // left page
344 if ((x0 = state->getScrollX() - offsetX) < 0) {
345 x0 = 0;
346 }
347 if ((y0 = state->getScrollY() - pageY[page - 1] - offsetY) < 0) {
348 y0 = 0;
349 }
350 if ((x1 = state->getScrollX() + state->getWinW() - 1 - offsetX)
351 >= pageW1) {
352 x1 = pageW1 - 1;
353 } else if (x1 < 0) {
354 x1 = -tileW2;
355 }
356 if ((y1 = state->getScrollY() - pageY[page - 1]
357 + state->getWinH() - 1 - offsetY)
358 >= pageH1) {
359 y1 = pageH1 - 1;
360 } else if (y1 < 0) {
361 y1 = -tileH2;
362 }
363 for (y = y0 / tileH1; y <= y1 / tileH1; ++y) {
364 for (x = x0 / tileW1; x <= x1 / tileW1; ++x) {
365 tx = x * tileW1;
366 ty = y * tileH1;
367 tw = tileW1;
368 if (tx + tw > pageW1) {
369 tw = pageW1 - tx;
370 }
371 th = tileH1;
372 if (ty + th > pageH1) {
373 th = pageH1 - ty;
374 }
375 tiles->append(new PlacedTileDesc(
376 page, state->getRotate(), pageDPI1,
377 tx, ty, tw, th,
378 tx - state->getScrollX() + offsetX,
379 ty - state->getScrollY() + pageY[page - 1]
380 + offsetY));
381 }
382 }
383 ++page;
384 // right page
385 if (page <= state->getDoc()->getNumPages()) {
386 if ((x0 = state->getScrollX() - offsetX2) < 0) {
387 x0 = 0;
388 }
389 if ((y0 = state->getScrollY() - pageY[page - 1] - offsetY) < 0) {
390 y0 = 0;
391 }
392 if ((x1 = state->getScrollX() + state->getWinW() - 1 - offsetX2)
393 >= pageW2) {
394 x1 = pageW2 - 1;
395 } else if (x1 < 0) {
396 x1 = -tileW2;
397 }
398 if ((y1 = state->getScrollY() - pageY[page - 1]
399 + state->getWinH() - 1 - offsetY)
400 >= pageH2) {
401 y1 = pageH2 - 1;
402 } else if (y1 < 0) {
403 y1 = -tileH2;
404 }
405 for (y = y0 / tileH2; y <= y1 / tileH2; ++y) {
406 for (x = x0 / tileW2; x <= x1 / tileW2; ++x) {
407 tx = x * tileW2;
408 ty = y * tileH2;
409 tw = tileW2;
410 if (tx + tw > pageW2) {
411 tw = pageW2 - tx;
412 }
413 th = tileH2;
414 if (ty + th > pageH2) {
415 th = pageH2 - ty;
416 }
417 tiles->append(new PlacedTileDesc(
418 page, state->getRotate(), pageDPI2,
419 tx, ty, tw, th,
420 tx - state->getScrollX() + offsetX2,
421 ty - state->getScrollY() + pageY[page - 1]
422 + offsetY));
423 }
424 }
425 }
426 ++page;
427 }
428 break;
429
430 case displayHorizontalContinuous:
431 if (totalW < state->getWinW()) {
432 offsetX = (state->getWinW() - totalW) / 2;
433 } else {
434 offsetX = 0;
435 }
436 page = findHorizContinuousPage(state->getScrollX());
437 while (page <= state->getDoc()->getNumPages() &&
438 pageX[page - 1] < state->getScrollX() + state->getWinW()) {
439 pageDPI1 = pageDPI[page - 1];
440 pageW1 = pageW[page - 1];
441 pageH1 = pageH[page - 1];
442 tileW1 = tileW[page - 1];
443 tileH1 = tileH[page - 1];
444 if (maxH < state->getWinH()) {
445 offsetY = (state->getWinH() - maxH) / 2;
446 } else {
447 offsetY = 0;
448 }
449 if ((x0 = state->getScrollX() - pageX[page - 1] - offsetX) < 0) {
450 x0 = 0;
451 }
452 if ((y0 = state->getScrollY() - offsetY) < 0) {
453 y0 = 0;
454 }
455 if ((x1 = state->getScrollX() - pageX[page - 1]
456 + state->getWinW() - 1 - offsetX)
457 >= pageW1) {
458 x1 = pageW1 - 1;
459 }
460 if ((y1 = state->getScrollY() + state->getWinH() - 1 - offsetY)
461 >= pageH1) {
462 y1 = pageH1 - 1;
463 }
464 for (y = y0 / tileH1; y <= y1 / tileH1; ++y) {
465 for (x = x0 / tileW1; x <= x1 / tileW1; ++x) {
466 tx = x * tileW1;
467 ty = y * tileH1;
468 tw = tileW1;
469 if (tx + tw > pageW1) {
470 tw = pageW1 - tx;
471 }
472 th = tileH1;
473 if (ty + th > pageH1) {
474 th = pageH1 - ty;
475 }
476 tiles->append(new PlacedTileDesc(
477 page, state->getRotate(), pageDPI1,
478 tx, ty, tw, th,
479 tx - state->getScrollX() + pageX[page - 1]
480 + offsetX,
481 ty - state->getScrollY() + offsetY));
482 }
483 }
484 ++page;
485 }
486 break;
487 }
488
489 return tiles;
490 }
491
getScrollLimits(int * horizMax,int * vertMax)492 void TileMap::getScrollLimits(int *horizMax, int *vertMax) {
493 int pageW1, pageH1, pageW2, pageH2;
494
495 if (!state->getDoc() || !state->getDoc()->getNumPages()) {
496 *horizMax = *vertMax = 0;
497 return;
498 }
499
500 updatePageParams();
501 updateContinuousModeParams();
502
503 switch (state->getDisplayMode()) {
504 case displaySingle:
505 *horizMax = pageW[state->getScrollPage() - 1];
506 *vertMax = pageH[state->getScrollPage() - 1];
507 break;
508 case displayContinuous:
509 *horizMax = maxW;
510 *vertMax = totalH;
511 break;
512 case displaySideBySideSingle:
513 pageW1 = pageW[state->getScrollPage() - 1];
514 pageH1 = pageH[state->getScrollPage() - 1];
515 if (state->getScrollPage() + 1 <= state->getDoc()->getNumPages()) {
516 pageW2 = pageW[state->getScrollPage()];
517 pageH2 = pageH[state->getScrollPage()];
518 } else {
519 pageW2 = pageW1;
520 pageH2 = pageH1;
521 }
522 *horizMax = pageW1 + sideBySidePageSpacing + pageW2;
523 *vertMax = pageH1 > pageH2 ? pageH1 : pageH2;
524 break;
525 case displaySideBySideContinuous:
526 *horizMax = maxW + sideBySidePageSpacing + maxW2;
527 *vertMax = totalH;
528 break;
529 case displayHorizontalContinuous:
530 *horizMax = totalW;
531 *vertMax = maxH;
532 break;
533 default: // should never happen
534 *horizMax = *vertMax = 0;
535 break;
536 }
537 }
538
cvtWindowToUser(int xw,int yw,int * pg,double * xu,double * yu)539 GBool TileMap::cvtWindowToUser(int xw, int yw,
540 int *pg, double *xu, double *yu) {
541 GBool ok;
542 int xd, yd;
543
544 if (!state->getDoc() || !state->getDoc()->getNumPages()) {
545 *pg = 0;
546 *xu = *yu = 0;
547 return gFalse;
548 }
549
550 ok = cvtWindowToDev(xw, yw, pg, &xd, &yd);
551 cvtDevToUser(*pg, xd, yd, xu, yu);
552 return ok;
553 }
554
cvtWindowToDev(int xw,int yw,int * pg,int * xd,int * yd)555 GBool TileMap::cvtWindowToDev(int xw, int yw,
556 int *pg, int *xd, int *yd) {
557 int pageW1, pageH1, pageW2, pageH2, offsetX, offsetX2, offsetY;
558
559 if (!state->getDoc() || !state->getDoc()->getNumPages()) {
560 *pg = 0;
561 *xd = *yd = 0;
562 return gFalse;
563 }
564
565 updatePageParams();
566 updateContinuousModeParams();
567
568 switch (state->getDisplayMode()) {
569
570 case displaySingle:
571 *pg = state->getScrollPage();
572 pageW1 = pageW[*pg - 1];
573 pageH1 = pageH[*pg - 1];
574 if (pageW1 < state->getWinW()) {
575 offsetX = (state->getWinW() - pageW1) / 2;
576 } else {
577 offsetX = 0;
578 }
579 if (pageH1 < state->getWinH()) {
580 offsetY = (state->getWinH() - pageH1) / 2;
581 } else {
582 offsetY = 0;
583 }
584 *xd = xw - offsetX + state->getScrollX();
585 *yd = yw - offsetY + state->getScrollY();
586 return *xd >= 0 && *xd < pageW1 && *yd >= 0 && *yd < pageH1;
587
588 case displayContinuous:
589 if (totalH < state->getWinH()) {
590 offsetY = (state->getWinH() - totalH) / 2;
591 } else {
592 offsetY = 0;
593 }
594 *pg = findContinuousPage(yw - offsetY + state->getScrollY());
595 if (*pg < 1 || *pg > state->getDoc()->getNumPages()) {
596 *pg = 0;
597 *xd = *yd = 0;
598 return gFalse;
599 }
600 pageW1 = pageW[*pg - 1];
601 pageH1 = pageH[*pg - 1];
602 if (maxW < state->getWinW()) {
603 offsetX = (state->getWinW() - maxW) / 2;
604 } else {
605 offsetX = 0;
606 }
607 offsetX += (maxW - pageW1) / 2;
608 *xd = xw - offsetX + state->getScrollX();
609 *yd = yw - offsetY - pageY[*pg - 1] + state->getScrollY();
610 return *xd >= 0 && *xd < pageW1 && *yd >= 0 && *yd < pageH1;
611
612 case displaySideBySideSingle:
613 pageW1 = pageW[state->getScrollPage() - 1];
614 pageH1 = pageH[state->getScrollPage() - 1];
615 if (state->getScrollPage() + 1 <= state->getDoc()->getNumPages()) {
616 pageW2 = pageW[state->getScrollPage()];
617 pageH2 = pageH[state->getScrollPage()];
618 } else {
619 // display a single page as though there were a blank facing
620 // page of the same size
621 pageW2 = pageW1;
622 pageH2 = pageH1;
623 }
624 if (pageW1 + sideBySidePageSpacing + pageW2 < state->getWinW()) {
625 offsetX = (state->getWinW() -
626 (pageW1 + sideBySidePageSpacing + pageW2)) / 2;
627 } else {
628 offsetX = 0;
629 }
630 offsetX2 = offsetX + pageW1 + sideBySidePageSpacing;
631 if (pageH1 < state->getWinH() && pageH2 < state->getWinH()) {
632 if (pageH1 > pageH2) {
633 offsetY = (state->getWinH() - pageH1) / 2;
634 } else {
635 offsetY = (state->getWinH() - pageH2) / 2;
636 }
637 } else {
638 offsetY = 0;
639 }
640 if (xw + state->getScrollX() < offsetX2) {
641 *pg = state->getScrollPage();
642 *xd = xw - offsetX + state->getScrollX();
643 *yd = yw - offsetY + state->getScrollY();
644 return *xd >= 0 && *xd < pageW1 && *yd >= 0 && *yd < pageH1;
645 } else {
646 if (state->getScrollPage() + 1 > state->getDoc()->getNumPages()) {
647 *pg = *xd = *yd = 0;
648 return gFalse;
649 }
650 *pg = state->getScrollPage() + 1;
651 *xd = xw - offsetX2 + state->getScrollX();
652 *yd = yw - offsetY + state->getScrollY();
653 return *xd >= 0 && *xd < pageW2 && *yd >= 0 && *yd < pageH2;
654 }
655
656 case displaySideBySideContinuous:
657 if (totalH < state->getWinH()) {
658 offsetY = (state->getWinH() - totalH) / 2;
659 } else {
660 offsetY = 0;
661 }
662 *pg = findSideBySideContinuousPage(yw - offsetY + state->getScrollY());
663 if (*pg < 1 || *pg > state->getDoc()->getNumPages()) {
664 *pg = 0;
665 *xd = *yd = 0;
666 return gFalse;
667 }
668 pageW1 = pageW[*pg - 1];
669 pageH1 = pageH[*pg - 1];
670 if (*pg + 1 <= state->getDoc()->getNumPages()) {
671 pageW2 = pageW[*pg];
672 pageH2 = pageH[*pg];
673 } else {
674 pageW2 = pageH2 = 0;
675 }
676 if (maxW + sideBySidePageSpacing + maxW2 < state->getWinW()) {
677 offsetX = (state->getWinW() -
678 (maxW + sideBySidePageSpacing + maxW2)) / 2;
679 } else {
680 offsetX = 0;
681 }
682 offsetX += maxW - pageW1;
683 offsetX2 = offsetX + pageW1 + sideBySidePageSpacing;
684 if (xw + state->getScrollX() < offsetX2) {
685 *xd = xw - offsetX + state->getScrollX();
686 *yd = yw - offsetY - pageY[*pg - 1] + state->getScrollY();
687 return *xd >= 0 && *xd < pageW1 && *yd >= 0 && *yd < pageH1;
688 } else {
689 if (*pg + 1 > state->getDoc()->getNumPages()) {
690 *pg = *xd = *yd = 0;
691 return false;
692 }
693 ++*pg;
694 *xd = xw - offsetX2 + state->getScrollX();
695 *yd = yw - offsetY - pageY[*pg - 1] + state->getScrollY();
696 return *xd >= 0 && *xd < pageW2 && *yd >= 0 && *yd < pageH2;
697 }
698
699 case displayHorizontalContinuous:
700 if (totalW < state->getWinW()) {
701 offsetX = (state->getWinW() - totalW) / 2;
702 } else {
703 offsetX = 0;
704 }
705 *pg = findHorizContinuousPage(xw - offsetX + state->getScrollX());
706 if (*pg < 1 || *pg > state->getDoc()->getNumPages()) {
707 *pg = 0;
708 *xd = *yd = 0;
709 return gFalse;
710 }
711 pageW1 = pageW[*pg - 1];
712 pageH1 = pageH[*pg - 1];
713 if (maxH < state->getWinH()) {
714 offsetY = (state->getWinH() - maxH) / 2;
715 } else {
716 offsetY = 0;
717 }
718 *xd = xw - offsetX - pageX[*pg - 1] + state->getScrollX();
719 *yd = yw - offsetY + state->getScrollY();
720 return *xd >= 0 && *xd < pageW1 && *yd >= 0 && *yd < pageH1;
721 }
722
723 return gFalse;
724 }
725
cvtUserToWindow(int pg,double xu,double yu,int * xw,int * yw)726 GBool TileMap::cvtUserToWindow(int pg, double xu, double yu,
727 int *xw, int *yw) {
728 int xd, yd;
729
730 cvtUserToDev(pg, xu, yu, &xd, &yd);
731 return cvtDevToWindow(pg, xd, yd, xw, yw);
732 }
733
cvtDevToWindow(int pg,int xd,int yd,int * xw,int * yw)734 GBool TileMap::cvtDevToWindow(int pg, int xd, int yd,
735 int *xw, int *yw) {
736 int leftPg, pageW1, pageH1, pageW2, pageH2, offsetX, offsetX2, offsetY;
737
738 if (!state->getDoc() ||
739 pg < 1 || pg > state->getDoc()->getNumPages()) {
740 *xw = *yw = 0;
741 return gFalse;
742 }
743
744 updatePageParams();
745 updateContinuousModeParams();
746
747 switch (state->getDisplayMode()) {
748
749 case displaySingle:
750 if (pg != state->getScrollPage()) {
751 *xw = *yw = 0;
752 return gFalse;
753 }
754 pageW1 = pageW[pg - 1];
755 pageH1 = pageH[pg - 1];
756 if (pageW1 < state->getWinW()) {
757 offsetX = (state->getWinW() - pageW1) / 2;
758 } else {
759 offsetX = 0;
760 }
761 if (pageH1 < state->getWinH()) {
762 offsetY = (state->getWinH() - pageH1) / 2;
763 } else {
764 offsetY = 0;
765 }
766 *xw = xd + offsetX - state->getScrollX();
767 *yw = yd + offsetY - state->getScrollY();
768 break;
769
770 case displayContinuous:
771 pageW1 = pageW[pg - 1];
772 pageH1 = pageH[pg - 1];
773 if (maxW < state->getWinW()) {
774 offsetX = (state->getWinW() - maxW) / 2;
775 } else {
776 offsetX = 0;
777 }
778 offsetX += (maxW - pageW1) / 2;
779 if (totalH < state->getWinH()) {
780 offsetY = (state->getWinH() - totalH) / 2;
781 } else {
782 offsetY = 0;
783 }
784 *xw = xd + offsetX - state->getScrollX();
785 *yw = pageY[pg - 1] + yd + offsetY - state->getScrollY();
786 break;
787
788 case displaySideBySideSingle:
789 if (!(pg == state->getScrollPage() ||
790 (pg == state->getScrollPage() + 1 &&
791 state->getScrollPage() + 1 <= state->getDoc()->getNumPages()))) {
792 *xw = *yw = 0;
793 return gFalse;
794 }
795 pageW1 = pageW[state->getScrollPage() - 1];
796 pageH1 = pageH[state->getScrollPage() - 1];
797 if (state->getScrollPage() + 1 <= state->getDoc()->getNumPages()) {
798 pageW2 = pageW[state->getScrollPage()];
799 pageH2 = pageH[state->getScrollPage()];
800 } else {
801 // display a single page as though there were a blank facing
802 // page of the same size
803 pageW2 = pageW1;
804 pageH2 = pageH1;
805 }
806 if (pageW1 + sideBySidePageSpacing + pageW2 < state->getWinW()) {
807 offsetX = (state->getWinW() -
808 (pageW1 + sideBySidePageSpacing + pageW2)) / 2;
809 } else {
810 offsetX = 0;
811 }
812 offsetX2 = offsetX + pageW1 + sideBySidePageSpacing;
813 if (pageH1 < state->getWinH() && pageH2 < state->getWinH()) {
814 if (pageH1 > pageH2) {
815 offsetY = (state->getWinH() - pageH1) / 2;
816 } else {
817 offsetY = (state->getWinH() - pageH2) / 2;
818 }
819 } else {
820 offsetY = 0;
821 }
822 if (pg == state->getScrollPage()) {
823 *xw = xd + offsetX - state->getScrollX();
824 *yw = yd + offsetY - state->getScrollY();
825 } else {
826 *xw = xd + offsetX2 - state->getScrollX();
827 *yw = yd + offsetY - state->getScrollY();
828 }
829 break;
830
831 case displaySideBySideContinuous:
832 leftPg = (pg - 1) | 1;
833 pageW1 = pageW[leftPg - 1];
834 pageH1 = pageH[leftPg - 1];
835 if (maxW + sideBySidePageSpacing + maxW2 < state->getWinW()) {
836 offsetX = (state->getWinW() -
837 (maxW + sideBySidePageSpacing + maxW2)) / 2;
838 } else {
839 offsetX = 0;
840 }
841 offsetX += maxW - pageW1;
842 offsetX2 = offsetX + pageW1 + sideBySidePageSpacing;
843 if (totalH < state->getWinH()) {
844 offsetY = (state->getWinH() - totalH) / 2;
845 } else {
846 offsetY = 0;
847 }
848 if (pg == leftPg) {
849 *xw = xd + offsetX - state->getScrollX();
850 } else {
851 *xw = xd + offsetX2 - state->getScrollX();
852 }
853 *yw = pageY[pg - 1] + yd + offsetY - state->getScrollY();
854 break;
855
856 case displayHorizontalContinuous:
857 if (totalW < state->getWinW()) {
858 offsetX = (state->getWinW() - totalW) / 2;
859 } else {
860 offsetX = 0;
861 }
862 if (maxH < state->getWinH()) {
863 offsetY = (state->getWinH() - maxH) / 2;
864 } else {
865 offsetY = 0;
866 }
867 *xw = pageX[pg - 1] + xd + offsetX - state->getScrollX();
868 *yw = yd + offsetY - state->getScrollY();
869 break;
870 }
871
872 return gTrue;
873 }
874
cvtUserToDev(int pg,double xu,double yu,int * xd,int * yd)875 void TileMap::cvtUserToDev(int pg, double xu, double yu, int *xd, int *yd) {
876 double m[6];
877
878 if (!state->getDoc() ||
879 pg < 1 || pg > state->getDoc()->getNumPages()) {
880 *xd = *yd = 0;
881 return;
882 }
883
884 computePageMatrix(pg, m);
885 *xd = (int)(xu * m[0] + yu * m[2] + m[4] + 0.5);
886 *yd = (int)(xu * m[1] + yu * m[3] + m[5] + 0.5);
887 }
888
cvtDevToUser(int pg,int xd,int yd,double * xu,double * yu)889 void TileMap::cvtDevToUser(int pg, int xd, int yd, double *xu, double *yu) {
890 double m[6], im[6];
891
892 if (!state->getDoc() ||
893 pg < 1 || pg > state->getDoc()->getNumPages()) {
894 *xu = *yu = 0;
895 return;
896 }
897
898 computePageMatrix(pg, m);
899 invertMatrix(m, im);
900 *xu = xd * im[0] + yd * im[2] + im[4];
901 *yu = xd * im[1] + yd * im[3] + im[5];
902 }
903
getWindowPageRange(int x,int y,int w,int h,int * firstPage,int * lastPage)904 void TileMap::getWindowPageRange(int x, int y, int w, int h,
905 int *firstPage, int *lastPage) {
906 GList *tiles;
907 PlacedTileDesc *tile;
908 int i;
909
910 if (!state->getDoc() || !state->getDoc()->getNumPages()) {
911 *firstPage = *lastPage = 0;
912 return;
913 }
914 *firstPage = state->getDoc()->getNumPages();
915 *lastPage = 0;
916 tiles = getTileList();
917 for (i = 0; i < tiles->getLength(); ++i) {
918 tile = (PlacedTileDesc *)tiles->get(i);
919 if (tile->px < x + w &&
920 tile->px + tile->tw > x &&
921 tile->py < y + h &&
922 tile->py + tile->th > y) {
923 if (tile->page < *firstPage) {
924 *firstPage = tile->page;
925 }
926 if (tile->page > *lastPage) {
927 *lastPage = tile->page;
928 }
929 }
930 }
931 }
932
getPageTopY(int page)933 int TileMap::getPageTopY(int page) {
934 if (!state->getDoc() || !state->getDoc()->getNumPages()) {
935 return 0;
936 }
937
938 updateContinuousModeParams();
939
940 switch (state->getDisplayMode()) {
941 case displaySingle:
942 case displaySideBySideSingle:
943 case displayHorizontalContinuous:
944 default:
945 return 0;
946 case displayContinuous:
947 case displaySideBySideContinuous:
948 return pageY[page - 1];
949 }
950 }
951
getPageBottomY(int page)952 int TileMap::getPageBottomY(int page) {
953 if (!state->getDoc() || !state->getDoc()->getNumPages()) {
954 return 0;
955 }
956
957 updatePageParams();
958 updateContinuousModeParams();
959
960 switch (state->getDisplayMode()) {
961 case displaySingle:
962 case displaySideBySideSingle:
963 case displayHorizontalContinuous:
964 default:
965 return pageH[page - 1] - state->getWinH();
966 case displayContinuous:
967 case displaySideBySideContinuous:
968 return pageY[page - 1] + pageH[page - 1] - state->getWinH();
969 }
970 }
971
getPageLeftX(int page)972 int TileMap::getPageLeftX(int page) {
973 int leftPage, rightPage, pageW1, pageW2, offsetX, offsetX2;
974
975 if (!state->getDoc() || !state->getDoc()->getNumPages()) {
976 return 0;
977 }
978
979 updatePageParams();
980 updateContinuousModeParams();
981
982 switch (state->getDisplayMode()) {
983 case displaySingle:
984 default:
985 return 0;
986 case displayContinuous:
987 return (maxW - pageW[page - 1]) / 2;
988 case displaySideBySideSingle:
989 leftPage = ((page - 1) & ~1) + 1;
990 rightPage = leftPage + 1;
991 pageW1 = pageW[leftPage - 1];
992 if (rightPage <= state->getDoc()->getNumPages()) {
993 pageW2 = pageW[rightPage - 1];
994 } else {
995 // display a single page as though there were a blank facing
996 // page of the same size
997 pageW2 = pageW1;
998 }
999 if (pageW1 + sideBySidePageSpacing + pageW2 < state->getWinW()) {
1000 offsetX = (state->getWinW() -
1001 (pageW1 + sideBySidePageSpacing + pageW2)) / 2;
1002 } else {
1003 offsetX = 0;
1004 }
1005 offsetX2 = offsetX + pageW1 + sideBySidePageSpacing;
1006 return (page == leftPage) ? offsetX : offsetX2;
1007 case displaySideBySideContinuous:
1008 leftPage = ((page - 1) & ~1) + 1;
1009 rightPage = leftPage + 1;
1010 pageW1 = pageW[leftPage - 1];
1011 if (maxW + sideBySidePageSpacing + maxW2 < state->getWinW()) {
1012 offsetX = (state->getWinW() -
1013 (maxW + sideBySidePageSpacing + maxW2)) / 2;
1014 } else {
1015 offsetX = 0;
1016 }
1017 offsetX += maxW - pageW1;
1018 offsetX2 = offsetX + pageW1 + sideBySidePageSpacing;
1019 return (page == leftPage) ? offsetX : offsetX2;
1020 case displayHorizontalContinuous:
1021 return pageX[page - 1];
1022 }
1023 }
1024
getPageRightX(int page)1025 int TileMap::getPageRightX(int page) {
1026 int leftPage, rightPage, pageW1, pageW2, offsetX, offsetX2;
1027
1028 if (!state->getDoc() || !state->getDoc()->getNumPages()) {
1029 return 0;
1030 }
1031
1032 updatePageParams();
1033 updateContinuousModeParams();
1034
1035 switch (state->getDisplayMode()) {
1036 case displaySingle:
1037 default:
1038 return pageW[page - 1] - state->getWinW();
1039 case displayContinuous:
1040 return (maxW + pageW[page - 1]) / 2 - state->getWinW();
1041 case displaySideBySideSingle:
1042 leftPage = ((page - 1) & ~1) + 1;
1043 rightPage = leftPage + 1;
1044 pageW1 = pageW[leftPage - 1];
1045 if (rightPage <= state->getDoc()->getNumPages()) {
1046 pageW2 = pageW[rightPage - 1];
1047 } else {
1048 // display a single page as though there were a blank facing
1049 // page of the same size
1050 pageW2 = pageW1;
1051 }
1052 if (pageW1 + sideBySidePageSpacing + pageW2 < state->getWinW()) {
1053 offsetX = (state->getWinW() -
1054 (pageW1 + sideBySidePageSpacing + pageW2)) / 2;
1055 } else {
1056 offsetX = 0;
1057 }
1058 offsetX2 = offsetX + pageW1 + sideBySidePageSpacing;
1059 return (page == leftPage) ? offsetX + pageW1 - state->getWinW()
1060 : offsetX2 + pageW2 - state->getWinW();
1061 case displaySideBySideContinuous:
1062 leftPage = ((page - 1) & ~1) + 1;
1063 rightPage = leftPage + 1;
1064 pageW1 = pageW[leftPage - 1];
1065 if (rightPage <= state->getDoc()->getNumPages()) {
1066 pageW2 = pageW[rightPage - 1];
1067 } else {
1068 // display a single page as though there were a blank facing
1069 // page of the same size
1070 pageW2 = pageW1;
1071 }
1072 if (maxW + sideBySidePageSpacing + maxW2 < state->getWinW()) {
1073 offsetX = (state->getWinW() -
1074 (maxW + sideBySidePageSpacing + maxW2)) / 2;
1075 } else {
1076 offsetX = 0;
1077 }
1078 offsetX += maxW - pageW1;
1079 offsetX2 = offsetX + pageW1 + sideBySidePageSpacing;
1080 return (page == leftPage) ? offsetX + pageW1 - state->getWinW()
1081 : offsetX2 + pageW2 - state->getWinW();
1082 case displayHorizontalContinuous:
1083 return pageX[page - 1] + pageW[page - 1] - state->getWinW();
1084 }
1085 }
1086
getFirstPage()1087 int TileMap::getFirstPage() {
1088 updateContinuousModeParams();
1089 switch (state->getDisplayMode()) {
1090 case displaySingle:
1091 default:
1092 return state->getScrollPage();
1093 case displayContinuous:
1094 return findContinuousPage(state->getScrollY());
1095 case displaySideBySideSingle:
1096 return state->getScrollPage();
1097 case displaySideBySideContinuous:
1098 return findSideBySideContinuousPage(state->getScrollY());
1099 case displayHorizontalContinuous:
1100 return findHorizContinuousPage(state->getScrollX());
1101 }
1102 }
1103
getFirstPageTop()1104 int TileMap::getFirstPageTop() {
1105 int page;
1106
1107 updateContinuousModeParams();
1108 switch (state->getDisplayMode()) {
1109 case displaySingle:
1110 default:
1111 return state->getScrollPage();
1112 case displayContinuous:
1113 page = findContinuousPage(state->getScrollY());
1114 if (page < state->getDoc()->getNumPages() &&
1115 pageY[page - 1] < state->getScrollY()) {
1116 return page + 1;
1117 } else {
1118 return page;
1119 }
1120 case displaySideBySideSingle:
1121 return state->getScrollPage();
1122 case displaySideBySideContinuous:
1123 page = findSideBySideContinuousPage(state->getScrollY());
1124 if (page < state->getDoc()->getNumPages() &&
1125 pageY[page - 1] < state->getScrollY()) {
1126 return page + 1;
1127 } else {
1128 return page;
1129 }
1130 case displayHorizontalContinuous:
1131 page = findHorizContinuousPage(state->getScrollX());
1132 if (page < state->getDoc()->getNumPages() &&
1133 pageX[page - 1] < state->getScrollX()) {
1134 return page + 1;
1135 } else {
1136 return page;
1137 }
1138 }
1139 }
1140
getMidPage()1141 int TileMap::getMidPage() {
1142 int wx, wy, pg, x, y;
1143
1144 wx = state->getWinW() / 2;
1145 wy = state->getWinH() / 2;
1146 if (!cvtWindowToDev(wx, wy, &pg, &x, &y)) {
1147 if (state->getDisplayMode() == displayContinuous) {
1148 wy += continuousPageSpacing;
1149 } else if (state->getDisplayMode() == displaySideBySideContinuous) {
1150 wx += sideBySidePageSpacing;
1151 wy += continuousPageSpacing;
1152 } else if (state->getDisplayMode() == displayHorizontalContinuous) {
1153 wx += horizContinuousPageSpacing;
1154 } else {
1155 return state->getScrollPage();
1156 }
1157 if (!cvtWindowToDev(wx, wy, &pg, &x, &y)) {
1158 return 1;
1159 }
1160 }
1161 return pg;
1162 }
1163
getLastPage()1164 int TileMap::getLastPage() {
1165 int pg, x, y, n;
1166
1167 switch (state->getDisplayMode()) {
1168 case displaySingle:
1169 default:
1170 return state->getScrollPage();
1171 case displayContinuous:
1172 if (!cvtWindowToDev(state->getWinW() / 2, state->getWinH() - 1,
1173 &pg, &x, &y)) {
1174 return state->getDoc()->getNumPages();
1175 }
1176 return pg;
1177 case displaySideBySideSingle:
1178 pg = state->getScrollPage() + 1;
1179 n = state->getDoc()->getNumPages();
1180 if (pg > n) {
1181 pg = n;
1182 }
1183 return pg;
1184 case displaySideBySideContinuous:
1185 if (!cvtWindowToDev(state->getWinW() / 2, state->getWinH() - 1,
1186 &pg, &x, &y)) {
1187 return state->getScrollPage();
1188 }
1189 pg = ((pg - 1) & ~1) + 2;
1190 n = state->getDoc()->getNumPages();
1191 if (pg > n) {
1192 pg = n;
1193 }
1194 return pg;
1195 case displayHorizontalContinuous:
1196 x = state->getWinW() - 1;
1197 y = state->getWinH() / 2;
1198 if (!cvtWindowToDev(state->getWinW() - 1, state->getWinH() / 2,
1199 &pg, &x, &y)) {
1200 return state->getDoc()->getNumPages();
1201 }
1202 return pg;
1203 }
1204 }
1205
getDPI(int page)1206 double TileMap::getDPI(int page) {
1207 if (page < 1 || page > state->getDoc()->getNumPages()) {
1208 return 0;
1209 }
1210 updatePageParams();
1211 return pageDPI[page - 1];
1212 }
1213
getPageBoxWidth(int page)1214 double TileMap::getPageBoxWidth(int page) {
1215 return pageBoxW[page - 1];
1216 }
1217
getPageBoxHeight(int page)1218 double TileMap::getPageBoxHeight(int page) {
1219 return pageBoxH[page - 1];
1220 }
1221
getContinuousPageSpacing()1222 int TileMap::getContinuousPageSpacing() {
1223 return continuousPageSpacing;
1224 }
1225
getSideBySidePageSpacing()1226 int TileMap::getSideBySidePageSpacing() {
1227 return sideBySidePageSpacing;
1228 }
1229
getHorizContinuousPageSpacing()1230 int TileMap::getHorizContinuousPageSpacing() {
1231 return horizContinuousPageSpacing;
1232 }
1233
docChanged()1234 void TileMap::docChanged() {
1235 PDFDoc *doc;
1236 int nPages, pg, rot;
1237
1238 doc = state->getDoc();
1239
1240 if (doc) {
1241 nPages = doc->getNumPages();
1242 } else {
1243 nPages = 0;
1244 }
1245 pageBoxW = (double *)greallocn(pageBoxW, nPages, sizeof(double));
1246 pageBoxH = (double *)greallocn(pageBoxH, nPages, sizeof(double));
1247 for (pg = 1; pg <= nPages; ++pg) {
1248 rot = doc->getPageRotate(pg);
1249 if (rot == 0 || rot == 180) {
1250 pageBoxW[pg - 1] = doc->getPageCropWidth(pg);
1251 pageBoxH[pg - 1] = doc->getPageCropHeight(pg);
1252 } else {
1253 pageBoxW[pg - 1] = doc->getPageCropHeight(pg);
1254 pageBoxH[pg - 1] = doc->getPageCropWidth(pg);
1255 }
1256 }
1257
1258 clearPageParams();
1259 clearContinuousModeParams();
1260 if (tiles) {
1261 deleteGList(tiles, PlacedTileDesc);
1262 tiles = NULL;
1263 }
1264 }
1265
windowSizeChanged()1266 void TileMap::windowSizeChanged() {
1267 clearPageParams();
1268 clearContinuousModeParams();
1269 if (tiles) {
1270 deleteGList(tiles, PlacedTileDesc);
1271 tiles = NULL;
1272 }
1273 }
1274
displayModeChanged()1275 void TileMap::displayModeChanged() {
1276 clearPageParams();
1277 clearContinuousModeParams();
1278 if (tiles) {
1279 deleteGList(tiles, PlacedTileDesc);
1280 tiles = NULL;
1281 }
1282 }
1283
zoomChanged()1284 void TileMap::zoomChanged() {
1285 clearPageParams();
1286 clearContinuousModeParams();
1287 if (tiles) {
1288 deleteGList(tiles, PlacedTileDesc);
1289 tiles = NULL;
1290 }
1291 }
1292
rotateChanged()1293 void TileMap::rotateChanged() {
1294 clearPageParams();
1295 clearContinuousModeParams();
1296 if (tiles) {
1297 deleteGList(tiles, PlacedTileDesc);
1298 tiles = NULL;
1299 }
1300 }
1301
scrollPositionChanged()1302 void TileMap::scrollPositionChanged() {
1303 if (tiles) {
1304 deleteGList(tiles, PlacedTileDesc);
1305 tiles = NULL;
1306 }
1307 }
1308
1309
forceRedraw()1310 void TileMap::forceRedraw() {
1311 clearPageParams();
1312 clearContinuousModeParams();
1313 if (tiles) {
1314 deleteGList(tiles, PlacedTileDesc);
1315 tiles = NULL;
1316 }
1317 }
1318
clearPageParams()1319 void TileMap::clearPageParams() {
1320 gfree(pageDPI);
1321 gfree(pageW);
1322 gfree(pageH);
1323 gfree(tileW);
1324 gfree(tileH);
1325 pageDPI = NULL;
1326 pageW = pageH = NULL;
1327 tileW = tileH = NULL;
1328 }
1329
updatePageParams()1330 void TileMap::updatePageParams() {
1331 double rotPageBoxW, rotPageBoxW2, rotPageBoxH, rotPageBoxH2, rotPageBoxHMax;
1332 double hDPI, vDPI, dpi;
1333 int page, otherPage, nxTiles, nyTiles;
1334
1335 //--- check to see if the continuous mode params have already been updated
1336 if (pageDPI) {
1337 return;
1338 }
1339
1340 //--- allocate memory
1341 pageDPI = (double *)gmallocn(state->getDoc()->getNumPages(), sizeof(double));
1342 pageW = (int *)gmallocn(state->getDoc()->getNumPages(), sizeof(int));
1343 pageH = (int *)gmallocn(state->getDoc()->getNumPages(), sizeof(int));
1344 tileW = (int *)gmallocn(state->getDoc()->getNumPages(), sizeof(int));
1345 tileH = (int *)gmallocn(state->getDoc()->getNumPages(), sizeof(int));
1346
1347 for (page = 1; page <= state->getDoc()->getNumPages(); ++page) {
1348
1349 //--- special handling for side-by-side modes
1350 if (state->displayModeIsSideBySide()) {
1351
1352 // rotate the page boxes
1353 if (page & 1) {
1354 otherPage = page + 1;
1355 if (otherPage >= state->getDoc()->getNumPages()) {
1356 otherPage = page;
1357 }
1358 } else {
1359 otherPage = page - 1;
1360 if (otherPage < 1) {
1361 otherPage = page;
1362 }
1363 }
1364 if (state->getRotate() == 0 || state->getRotate() == 180) {
1365 rotPageBoxW = pageBoxW[page - 1];
1366 rotPageBoxW2 = pageBoxW[otherPage - 1];
1367 rotPageBoxH = pageBoxH[page - 1];
1368 rotPageBoxH2 = pageBoxH[otherPage - 1];
1369 } else {
1370 rotPageBoxW = pageBoxH[page - 1];
1371 rotPageBoxW2 = pageBoxH[otherPage - 1];
1372 rotPageBoxH = pageBoxW[page - 1];
1373 rotPageBoxH2 = pageBoxW[otherPage - 1];
1374 }
1375 rotPageBoxHMax = (rotPageBoxH > rotPageBoxH2) ? rotPageBoxH
1376 : rotPageBoxH2;
1377
1378 // compute resolution
1379 if (state->getZoom() == zoomPage) {
1380 hDPI = ((state->getWinW() - sideBySidePageSpacing) /
1381 (rotPageBoxW + rotPageBoxW2)) * 72.0;
1382 vDPI = (state->getWinH() / rotPageBoxHMax) * 72.0;
1383 dpi = hDPI < vDPI ? hDPI : vDPI;
1384 // allow for some floating point jitter
1385 dpi -= 0.01;
1386 } else if (state->getZoom() == zoomWidth) {
1387 dpi = ((state->getWinW() - sideBySidePageSpacing) /
1388 (rotPageBoxW + rotPageBoxW2)) * 72.0;
1389 // allow for some floating point jitter
1390 dpi -= 0.01;
1391 } else if (state->getZoom() == zoomHeight) {
1392 dpi = (state->getWinH() / rotPageBoxHMax) * 72.0;
1393 // allow for some floating point jitter
1394 dpi -= 0.01;
1395 } else {
1396 dpi = 0.01 * state->getZoom() * 72.0;
1397 }
1398
1399 //--- all other (non-side-by-side) modes
1400 } else {
1401
1402 // rotate the page boxes
1403 if (state->getRotate() == 0 || state->getRotate() == 180) {
1404 rotPageBoxW = pageBoxW[page - 1];
1405 rotPageBoxH = pageBoxH[page - 1];
1406 } else {
1407 rotPageBoxW = pageBoxH[page - 1];
1408 rotPageBoxH = pageBoxW[page - 1];
1409 }
1410
1411 // compute resolution
1412 if (state->getZoom() == zoomPage) {
1413 hDPI = (state->getWinW() / rotPageBoxW) * 72.0;
1414 vDPI = (state->getWinH() / rotPageBoxH) * 72.0;
1415 dpi = hDPI < vDPI ? hDPI : vDPI;
1416 // allow for some floating point jitter
1417 dpi -= 0.01;
1418 } else if (state->getZoom() == zoomWidth) {
1419 dpi = (state->getWinW() / rotPageBoxW) * 72.0;
1420 // allow for some floating point jitter
1421 dpi -= 0.01;
1422 } else if (state->getZoom() == zoomHeight) {
1423 dpi = (state->getWinH() / rotPageBoxH) * 72.0;
1424 // allow for some floating point jitter
1425 dpi -= 0.01;
1426 } else {
1427 dpi = 0.01 * state->getZoom() * 72.0;
1428 }
1429
1430 }
1431 pageDPI[page - 1] = dpi;
1432
1433 // compute bitmap size
1434 pageW[page - 1] = (int)((rotPageBoxW * dpi / 72.0) + 0.5);
1435 if (pageW[page - 1] < 1) {
1436 pageW[page - 1] = 1;
1437 }
1438 pageH[page - 1] = (int)((rotPageBoxH * dpi / 72.0) + 0.5);
1439 if (pageH[page - 1] < 1) {
1440 pageH[page - 1] = 1;
1441 }
1442
1443 // compute tile size
1444 // (tile width and height are rounded up -- the bottom and right
1445 // tiles may be slightly smaller than the computed size)
1446 if (pageW[page - 1] <= state->getMaxTileWidth()) {
1447 nxTiles = 1;
1448 tileW[page - 1] = pageW[page - 1];
1449 } else {
1450 nxTiles = (pageW[page - 1] + state->getMaxTileWidth() - 1)
1451 / state->getMaxTileWidth();
1452 tileW[page - 1] = (pageW[page - 1] + nxTiles - 1) / nxTiles;
1453 }
1454 if (pageH[page - 1] <= state->getMaxTileHeight()) {
1455 nyTiles = 1;
1456 tileH[page - 1] = pageH[page - 1];
1457 } else {
1458 nyTiles = (pageH[page - 1] + state->getMaxTileHeight() - 1)
1459 / state->getMaxTileHeight();
1460 tileH[page - 1] = (pageH[page - 1] + nyTiles - 1) / nyTiles;
1461 }
1462
1463 }
1464 }
1465
clearContinuousModeParams()1466 void TileMap::clearContinuousModeParams() {
1467 gfree(pageX);
1468 pageX = pageY = NULL;
1469 }
1470
updateContinuousModeParams()1471 void TileMap::updateContinuousModeParams() {
1472 int page, pageW1, pageH1, pageW2, pageH2, x, y;
1473
1474 // check to see if the continuous mode params have already been updated
1475 if (pageX) {
1476 return;
1477 }
1478
1479 updatePageParams();
1480
1481 switch (state->getDisplayMode()) {
1482 case displayContinuous:
1483 if (!pageX) {
1484 pageX = pageY = (int *)gmallocn(state->getDoc()->getNumPages(),
1485 sizeof(int));
1486 }
1487 y = 0;
1488 maxW = 0;
1489 for (page = 1; page <= state->getDoc()->getNumPages(); ++page) {
1490 pageY[page - 1] = y;
1491 y += pageH[page - 1] + continuousPageSpacing;
1492 if (page == 1 || pageW[page - 1] > maxW) {
1493 maxW = pageW[page - 1];
1494 }
1495 }
1496 totalH = y - continuousPageSpacing;
1497 break;
1498 case displaySideBySideContinuous:
1499 if (!pageX) {
1500 pageX = pageY = (int *)gmallocn(state->getDoc()->getNumPages(),
1501 sizeof(int));
1502 }
1503 y = 0;
1504 maxW = maxW2 = 0;
1505 for (page = 1; page <= state->getDoc()->getNumPages(); page += 2) {
1506 pageW1 = pageW[page - 1];
1507 pageH1 = pageH[page - 1];
1508 if (page + 1 <= state->getDoc()->getNumPages()) {
1509 pageW2 = pageW[page];
1510 pageH2 = pageH[page];
1511 } else {
1512 pageW2 = pageW1;
1513 pageH2 = pageH1;
1514 }
1515 pageY[page - 1] = y;
1516 if (page == 1 || pageW1 > maxW) {
1517 maxW = pageW1;
1518 }
1519 if (page + 1 <= state->getDoc()->getNumPages()) {
1520 pageY[page] = y;
1521 }
1522 if (pageW2 > maxW2) {
1523 maxW2 = pageW2;
1524 }
1525 y += (pageH1 > pageH2) ? pageH1 : pageH2;
1526 y += continuousPageSpacing;
1527 }
1528 totalH = y - continuousPageSpacing;
1529 break;
1530 case displayHorizontalContinuous:
1531 if (!pageX) {
1532 pageX = pageY = (int *)gmallocn(state->getDoc()->getNumPages(),
1533 sizeof(int));
1534 }
1535 x = 0;
1536 maxH = 0;
1537 for (page = 1; page <= state->getDoc()->getNumPages(); ++page) {
1538 pageX[page - 1] = x;
1539 x += pageW[page - 1] + horizContinuousPageSpacing;
1540 if (page == 1 || pageH[page - 1] > maxH) {
1541 maxH = pageH[page - 1];
1542 }
1543 }
1544 totalW = x - horizContinuousPageSpacing;
1545 break;
1546 default:
1547 break;
1548 }
1549 }
1550
computePageMatrix(int page,double * m)1551 void TileMap::computePageMatrix(int page, double *m) {
1552 PDFRectangle *cropBox;
1553 double px1, py1, px2, py2, k;
1554 int rotate;
1555
1556 updatePageParams();
1557 cropBox = state->getDoc()->getCatalog()->getPage(page)->getCropBox();
1558 px1 = cropBox->x1;
1559 py1 = cropBox->y1;
1560 px2 = cropBox->x2;
1561 py2 = cropBox->y2;
1562 k = pageDPI[page - 1] / 72.0;
1563 rotate = state->getRotate() +
1564 state->getDoc()->getCatalog()->getPage(page)->getRotate();
1565 if (rotate > 360) {
1566 rotate -= 360;
1567 }
1568 switch (rotate) {
1569 case 0:
1570 default:
1571 m[0] = k;
1572 m[1] = 0;
1573 m[2] = 0;
1574 m[3] = -k;
1575 m[4] = -k * px1;
1576 m[5] = k * py2;
1577 break;
1578 case 90:
1579 m[0] = 0;
1580 m[1] = k;
1581 m[2] = k;
1582 m[3] = 0;
1583 m[4] = -k * py1;
1584 m[5] = -k * px1;
1585 break;
1586 case 180:
1587 m[0] = -k;
1588 m[1] = 0;
1589 m[2] = 0;
1590 m[3] = k;
1591 m[4] = k * px2;
1592 m[5] = -k * py1;
1593 break;
1594 case 270:
1595 m[0] = 0;
1596 m[1] = -k;
1597 m[2] = -k;
1598 m[3] = 0;
1599 m[4] = k * py2;
1600 m[5] = k * px2;
1601 break;
1602 }
1603 }
1604
invertMatrix(double * m,double * im)1605 void TileMap::invertMatrix(double *m, double *im) {
1606 double det;
1607
1608 det = 1 / (m[0] * m[3] - m[1] * m[2]);
1609 im[0] = m[3] * det;
1610 im[1] = -m[1] * det;
1611 im[2] = -m[2] * det;
1612 im[3] = m[0] * det;
1613 im[4] = (m[2] * m[5] - m[3] * m[4]) * det;
1614 im[5] = (m[1] * m[4] - m[0] * m[5]) * det;
1615 }
1616
findContinuousPage(int y)1617 int TileMap::findContinuousPage(int y) {
1618 int a, b, m;
1619
1620 if (y < pageY[0]) {
1621 return 0;
1622 }
1623 if (y >= totalH) {
1624 return state->getDoc()->getNumPages() + 1;
1625 }
1626 a = -1;
1627 b = state->getDoc()->getNumPages();
1628 // invariant: pageY[a] < y < pageY[b]
1629 while (b - a > 1) {
1630 m = (a + b) / 2;
1631 if (y > pageY[m] - continuousPageSpacing) {
1632 a = m;
1633 } else if (y < pageY[m] - continuousPageSpacing) {
1634 b = m;
1635 } else {
1636 return m + 1;
1637 }
1638 }
1639 return a + 1;
1640 }
1641
findSideBySideContinuousPage(int y)1642 int TileMap::findSideBySideContinuousPage(int y) {
1643 int a, b, m;
1644
1645 if (y < pageY[0]) {
1646 return 0;
1647 }
1648 if (y >= totalH) {
1649 return (state->getDoc()->getNumPages() + 2) & ~1;
1650 }
1651 a = -2;
1652 b = (state->getDoc()->getNumPages() + 1) & ~1;
1653 // invariant: pageY[a] < y < pageY[b]
1654 while (b - a > 2) {
1655 m = ((a + b) / 2) & ~1;
1656 if (y > pageY[m] - continuousPageSpacing) {
1657 a = m;
1658 } else if (y < pageY[m] - continuousPageSpacing) {
1659 b = m;
1660 } else {
1661 return m + 1;
1662 }
1663 }
1664 return a + 1;
1665 }
1666
findHorizContinuousPage(int x)1667 int TileMap::findHorizContinuousPage(int x) {
1668 int a, b, m;
1669
1670 if (x < pageX[0]) {
1671 return 0;
1672 }
1673 if (x >= totalW) {
1674 return state->getDoc()->getNumPages() + 1;
1675 }
1676 a = -1;
1677 b = state->getDoc()->getNumPages();
1678 // invariant: pageX[a] < x < pageX[b]
1679 while (b - a > 1) {
1680 m = (a + b) / 2;
1681 if (x > pageX[m] - horizContinuousPageSpacing) {
1682 a = m;
1683 } else if (x < pageX[m] - horizContinuousPageSpacing) {
1684 b = m;
1685 } else {
1686 return m + 1;
1687 }
1688 }
1689 return a + 1;
1690 }
1691