aboutsummaryrefslogtreecommitdiff
path: root/xpdf/TileMap.cc
diff options
context:
space:
mode:
authorCalvin Morrison <calvin@pobox.com>2023-04-05 14:13:39 -0400
committerCalvin Morrison <calvin@pobox.com>2023-04-05 14:13:39 -0400
commit835e373b3eeaabcd0621ed6798ab500f37982fae (patch)
treedfa16b0e2e1b4956b38f693220eac4e607802133 /xpdf/TileMap.cc
xpdf-no-select-disableHEADmaster
Diffstat (limited to 'xpdf/TileMap.cc')
-rw-r--r--xpdf/TileMap.cc1690
1 files changed, 1690 insertions, 0 deletions
diff --git a/xpdf/TileMap.cc b/xpdf/TileMap.cc
new file mode 100644
index 0000000..d591662
--- /dev/null
+++ b/xpdf/TileMap.cc
@@ -0,0 +1,1690 @@
+//========================================================================
+//
+// TileMap.cc
+//
+// Copyright 2014 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include "gmem.h"
+#include "gmempp.h"
+#include "GList.h"
+#include "PDFDoc.h"
+#include "DisplayState.h"
+#include "TileMap.h"
+
+//------------------------------------------------------------------------
+
+// Number of pixels of matte color between pages (above and below each
+// other) in continuous mode.
+#define continuousPageSpacing 3
+
+// Number of pixels of matte color between facing pages (left and
+// right of each other) in side-by-side mode.
+#define sideBySidePageSpacing 3
+
+// Number of pixels of matte color between pages (left and right of
+// each other) in horizontal continuous mode.
+#define horizContinuousPageSpacing 3
+
+//------------------------------------------------------------------------
+
+TileMap::TileMap(DisplayState *stateA) {
+ state = stateA;
+ state->setTileMap(this);
+ pageDPI = NULL;
+ pageW = pageH = NULL;
+ tileW = tileH = NULL;
+ pageBoxW = pageBoxH = NULL;
+ pageX = pageY = NULL;
+ tiles = NULL;
+}
+
+TileMap::~TileMap() {
+ clearPageParams();
+ clearContinuousModeParams();
+ gfree(pageBoxW);
+ gfree(pageBoxH);
+ if (tiles) {
+ deleteGList(tiles, PlacedTileDesc);
+ }
+}
+
+GList *TileMap::getTileList() {
+ double pageDPI1, pageDPI2;
+ int pageW1, pageH1, tileW1, tileH1, pageW2, pageH2, tileW2, tileH2;
+ int offsetX, offsetY, offsetX2;
+ int x0, y0, x1, y1, x, y, tx, ty, tw, th, page;
+
+ if (tiles) {
+ return tiles;
+ }
+
+ tiles = new GList();
+
+ if (!state->getDoc() || !state->getDoc()->getNumPages()) {
+ return tiles;
+ }
+
+ updatePageParams();
+ updateContinuousModeParams();
+
+ switch (state->getDisplayMode()) {
+
+ case displaySingle:
+ page = state->getScrollPage();
+ pageDPI1 = pageDPI[page - 1];
+ pageW1 = pageW[page - 1];
+ pageH1 = pageH[page - 1];
+ tileW1 = tileW[page - 1];
+ tileH1 = tileH[page - 1];
+ if (pageW1 < state->getWinW()) {
+ offsetX = (state->getWinW() - pageW1) / 2;
+ } else {
+ offsetX = 0;
+ }
+ if (pageH1 < state->getWinH()) {
+ offsetY = (state->getWinH() - pageH1) / 2;
+ } else {
+ offsetY = 0;
+ }
+ if ((x0 = state->getScrollX() - offsetX) < 0) {
+ x0 = 0;
+ }
+ if ((y0 = state->getScrollY() - offsetY) < 0) {
+ y0 = 0;
+ }
+ if ((x1 = state->getScrollX() + state->getWinW() - 1 - offsetX) >= pageW1) {
+ x1 = pageW1 - 1;
+ }
+ if ((y1 = state->getScrollY() + state->getWinH() - 1 - offsetY) >= pageH1) {
+ y1 = pageH1 - 1;
+ }
+ for (y = y0 / tileH1; y <= y1 / tileH1; ++y) {
+ for (x = x0 / tileW1; x <= x1 / tileW1; ++x) {
+ tx = x * tileW1;
+ ty = y * tileH1;
+ tw = tileW1;
+ if (tx + tw > pageW1) {
+ tw = pageW1 - tx;
+ }
+ th = tileH1;
+ if (ty + th > pageH1) {
+ th = pageH1 - ty;
+ }
+ tiles->append(new PlacedTileDesc(page, state->getRotate(), pageDPI1,
+ tx, ty, tw, th,
+ tx - state->getScrollX() + offsetX,
+ ty - state->getScrollY() + offsetY));
+ }
+ }
+ break;
+
+ case displayContinuous:
+ if (totalH < state->getWinH()) {
+ offsetY = (state->getWinH() - totalH) / 2;
+ } else {
+ offsetY = 0;
+ }
+ page = findContinuousPage(state->getScrollY());
+ while (page <= state->getDoc()->getNumPages() &&
+ pageY[page - 1] < state->getScrollY() + state->getWinH()) {
+ pageDPI1 = pageDPI[page - 1];
+ pageW1 = pageW[page - 1];
+ pageH1 = pageH[page - 1];
+ tileW1 = tileW[page - 1];
+ tileH1 = tileH[page - 1];
+ if (maxW < state->getWinW()) {
+ offsetX = (state->getWinW() - maxW) / 2;
+ } else {
+ offsetX = 0;
+ }
+ offsetX += (maxW - pageW1) / 2;
+ if ((x0 = state->getScrollX() - offsetX) < 0) {
+ x0 = 0;
+ }
+ if ((y0 = state->getScrollY() - pageY[page - 1] - offsetY) < 0) {
+ y0 = 0;
+ }
+ if ((x1 = state->getScrollX() + state->getWinW() - 1 - offsetX)
+ >= pageW1) {
+ x1 = pageW1 - 1;
+ }
+ if ((y1 = state->getScrollY() - pageY[page - 1]
+ + state->getWinH() - 1 - offsetY)
+ >= pageH1) {
+ y1 = pageH1 - 1;
+ }
+ for (y = y0 / tileH1; y <= y1 / tileH1; ++y) {
+ for (x = x0 / tileW1; x <= x1 / tileW1; ++x) {
+ tx = x * tileW1;
+ ty = y * tileH1;
+ tw = tileW1;
+ if (tx + tw > pageW1) {
+ tw = pageW1 - tx;
+ }
+ th = tileH1;
+ if (ty + th > pageH1) {
+ th = pageH1 - ty;
+ }
+ tiles->append(new PlacedTileDesc(
+ page, state->getRotate(), pageDPI1,
+ tx, ty, tw, th,
+ tx - state->getScrollX() + offsetX,
+ ty - state->getScrollY() + pageY[page - 1]
+ + offsetY));
+ }
+ }
+ ++page;
+ }
+ break;
+
+ case displaySideBySideSingle:
+ page = state->getScrollPage();
+ pageDPI1 = pageDPI[page - 1];
+ pageW1 = pageW[page - 1];
+ pageH1 = pageH[page - 1];
+ tileW1 = tileW[page - 1];
+ tileH1 = tileH[page - 1];
+ if (page + 1 <= state->getDoc()->getNumPages()) {
+ pageDPI2 = pageDPI[page];
+ pageW2 = pageW[page];
+ pageH2 = pageH[page];
+ tileW2 = tileW[page];
+ tileH2 = tileH[page];
+ } else {
+ // display a single page as though there were a blank facing
+ // page of the same size
+ pageDPI2 = pageDPI1;
+ pageW2 = pageW1;
+ pageH2 = pageH1;
+ tileW2 = tileW1;
+ tileH2 = tileH1;
+ }
+ if (pageW1 + sideBySidePageSpacing + pageW2 < state->getWinW()) {
+ offsetX = (state->getWinW() -
+ (pageW1 + sideBySidePageSpacing + pageW2)) / 2;
+ } else {
+ offsetX = 0;
+ }
+ offsetX2 = offsetX + pageW1 + sideBySidePageSpacing;
+ if (pageH1 < state->getWinH() && pageH2 < state->getWinH()) {
+ if (pageH1 > pageH2) {
+ offsetY = (state->getWinH() - pageH1) / 2;
+ } else {
+ offsetY = (state->getWinH() - pageH2) / 2;
+ }
+ } else {
+ offsetY = 0;
+ }
+ // left page
+ if ((x0 = state->getScrollX() - offsetX) < 0) {
+ x0 = 0;
+ }
+ if ((y0 = state->getScrollY() - offsetY) < 0) {
+ y0 = 0;
+ }
+ if ((x1 = state->getScrollX() + state->getWinW() - 1 - offsetX) >= pageW1) {
+ x1 = pageW1 - 1;
+ } else if (x1 < 0) {
+ x1 = -tileW2;
+ }
+ if ((y1 = state->getScrollY() + state->getWinH() - 1 - offsetY) >= pageH1) {
+ y1 = pageH1 - 1;
+ } else if (y1 < 0) {
+ y1 = -tileH2;
+ }
+ for (y = y0 / tileH1; y <= y1 / tileH1; ++y) {
+ for (x = x0 / tileW1; x <= x1 / tileW1; ++x) {
+ tx = x * tileW1;
+ ty = y * tileH1;
+ tw = tileW1;
+ if (tx + tw > pageW1) {
+ tw = pageW1 - tx;
+ }
+ th = tileH1;
+ if (ty + th > pageH1) {
+ th = pageH1 - ty;
+ }
+ tiles->append(new PlacedTileDesc(page,
+ state->getRotate(), pageDPI1,
+ tx, ty, tw, th,
+ tx - state->getScrollX() + offsetX,
+ ty - state->getScrollY() + offsetY));
+ }
+ }
+ // right page
+ if (page + 1 <= state->getDoc()->getNumPages()) {
+ if ((x0 = state->getScrollX() - offsetX2) < 0) {
+ x0 = 0;
+ }
+ if ((y0 = state->getScrollY() - offsetY) < 0) {
+ y0 = 0;
+ }
+ if ((x1 = state->getScrollX() + state->getWinW() - 1 - offsetX2)
+ >= pageW2) {
+ x1 = pageW2 - 1;
+ } else if (x1 < 0) {
+ x1 = -tileW2;
+ }
+ if ((y1 = state->getScrollY() + state->getWinH() - 1 - offsetY)
+ >= pageH2) {
+ y1 = pageH2 - 1;
+ } else if (y1 < 0) {
+ y1 = -tileH2;
+ }
+ for (y = y0 / tileH2; y <= y1 / tileH2; ++y) {
+ for (x = x0 / tileW2; x <= x1 / tileW2; ++x) {
+ tx = x * tileW2;
+ ty = y * tileH2;
+ tw = tileW2;
+ if (tx + tw > pageW2) {
+ tw = pageW2 - tx;
+ }
+ th = tileH2;
+ if (ty + th > pageH2) {
+ th = pageH2 - ty;
+ }
+ tiles->append(new PlacedTileDesc(page + 1,
+ state->getRotate(), pageDPI2,
+ tx, ty, tw, th,
+ tx - state->getScrollX() + offsetX2,
+ ty - state->getScrollY() + offsetY));
+ }
+ }
+ }
+ break;
+
+ case displaySideBySideContinuous:
+ if (totalH < state->getWinH()) {
+ offsetY = (state->getWinH() - totalH) / 2;
+ } else {
+ offsetY = 0;
+ }
+ page = findSideBySideContinuousPage(state->getScrollY());
+ while (page <= state->getDoc()->getNumPages() &&
+ (pageY[page - 1] < state->getScrollY() + state->getWinH() ||
+ (page + 1 <= state->getDoc()->getNumPages() &&
+ pageY[page] < state->getScrollY() + state->getWinH()))) {
+ pageDPI1 = pageDPI[page - 1];
+ pageW1 = pageW[page - 1];
+ pageH1 = pageH[page - 1];
+ tileW1 = tileW[page - 1];
+ tileH1 = tileH[page - 1];
+ if (page + 1 <= state->getDoc()->getNumPages()) {
+ pageDPI2 = pageDPI[page];
+ pageW2 = pageW[page];
+ pageH2 = pageH[page];
+ tileW2 = tileW[page];
+ tileH2 = tileH[page];
+ } else {
+ // display a single page as though there were a blank facing
+ // page of the same size
+ pageDPI2 = pageDPI1;
+ pageW2 = pageW1;
+ pageH2 = pageH1;
+ tileW2 = tileW1;
+ tileH2 = tileH1;
+ }
+ if (maxW + sideBySidePageSpacing + maxW2 < state->getWinW()) {
+ offsetX = (state->getWinW() -
+ (maxW + sideBySidePageSpacing + maxW2)) / 2;
+ } else {
+ offsetX = 0;
+ }
+ offsetX += maxW - pageW1;
+ offsetX2 = offsetX + pageW1 + sideBySidePageSpacing;
+ // left page
+ if ((x0 = state->getScrollX() - offsetX) < 0) {
+ x0 = 0;
+ }
+ if ((y0 = state->getScrollY() - pageY[page - 1] - offsetY) < 0) {
+ y0 = 0;
+ }
+ if ((x1 = state->getScrollX() + state->getWinW() - 1 - offsetX)
+ >= pageW1) {
+ x1 = pageW1 - 1;
+ } else if (x1 < 0) {
+ x1 = -tileW2;
+ }
+ if ((y1 = state->getScrollY() - pageY[page - 1]
+ + state->getWinH() - 1 - offsetY)
+ >= pageH1) {
+ y1 = pageH1 - 1;
+ } else if (y1 < 0) {
+ y1 = -tileH2;
+ }
+ for (y = y0 / tileH1; y <= y1 / tileH1; ++y) {
+ for (x = x0 / tileW1; x <= x1 / tileW1; ++x) {
+ tx = x * tileW1;
+ ty = y * tileH1;
+ tw = tileW1;
+ if (tx + tw > pageW1) {
+ tw = pageW1 - tx;
+ }
+ th = tileH1;
+ if (ty + th > pageH1) {
+ th = pageH1 - ty;
+ }
+ tiles->append(new PlacedTileDesc(
+ page, state->getRotate(), pageDPI1,
+ tx, ty, tw, th,
+ tx - state->getScrollX() + offsetX,
+ ty - state->getScrollY() + pageY[page - 1]
+ + offsetY));
+ }
+ }
+ ++page;
+ // right page
+ if (page <= state->getDoc()->getNumPages()) {
+ if ((x0 = state->getScrollX() - offsetX2) < 0) {
+ x0 = 0;
+ }
+ if ((y0 = state->getScrollY() - pageY[page - 1] - offsetY) < 0) {
+ y0 = 0;
+ }
+ if ((x1 = state->getScrollX() + state->getWinW() - 1 - offsetX2)
+ >= pageW2) {
+ x1 = pageW2 - 1;
+ } else if (x1 < 0) {
+ x1 = -tileW2;
+ }
+ if ((y1 = state->getScrollY() - pageY[page - 1]
+ + state->getWinH() - 1 - offsetY)
+ >= pageH2) {
+ y1 = pageH2 - 1;
+ } else if (y1 < 0) {
+ y1 = -tileH2;
+ }
+ for (y = y0 / tileH2; y <= y1 / tileH2; ++y) {
+ for (x = x0 / tileW2; x <= x1 / tileW2; ++x) {
+ tx = x * tileW2;
+ ty = y * tileH2;
+ tw = tileW2;
+ if (tx + tw > pageW2) {
+ tw = pageW2 - tx;
+ }
+ th = tileH2;
+ if (ty + th > pageH2) {
+ th = pageH2 - ty;
+ }
+ tiles->append(new PlacedTileDesc(
+ page, state->getRotate(), pageDPI2,
+ tx, ty, tw, th,
+ tx - state->getScrollX() + offsetX2,
+ ty - state->getScrollY() + pageY[page - 1]
+ + offsetY));
+ }
+ }
+ }
+ ++page;
+ }
+ break;
+
+ case displayHorizontalContinuous:
+ if (totalW < state->getWinW()) {
+ offsetX = (state->getWinW() - totalW) / 2;
+ } else {
+ offsetX = 0;
+ }
+ page = findHorizContinuousPage(state->getScrollX());
+ while (page <= state->getDoc()->getNumPages() &&
+ pageX[page - 1] < state->getScrollX() + state->getWinW()) {
+ pageDPI1 = pageDPI[page - 1];
+ pageW1 = pageW[page - 1];
+ pageH1 = pageH[page - 1];
+ tileW1 = tileW[page - 1];
+ tileH1 = tileH[page - 1];
+ if (maxH < state->getWinH()) {
+ offsetY = (state->getWinH() - maxH) / 2;
+ } else {
+ offsetY = 0;
+ }
+ if ((x0 = state->getScrollX() - pageX[page - 1] - offsetX) < 0) {
+ x0 = 0;
+ }
+ if ((y0 = state->getScrollY() - offsetY) < 0) {
+ y0 = 0;
+ }
+ if ((x1 = state->getScrollX() - pageX[page - 1]
+ + state->getWinW() - 1 - offsetX)
+ >= pageW1) {
+ x1 = pageW1 - 1;
+ }
+ if ((y1 = state->getScrollY() + state->getWinH() - 1 - offsetY)
+ >= pageH1) {
+ y1 = pageH1 - 1;
+ }
+ for (y = y0 / tileH1; y <= y1 / tileH1; ++y) {
+ for (x = x0 / tileW1; x <= x1 / tileW1; ++x) {
+ tx = x * tileW1;
+ ty = y * tileH1;
+ tw = tileW1;
+ if (tx + tw > pageW1) {
+ tw = pageW1 - tx;
+ }
+ th = tileH1;
+ if (ty + th > pageH1) {
+ th = pageH1 - ty;
+ }
+ tiles->append(new PlacedTileDesc(
+ page, state->getRotate(), pageDPI1,
+ tx, ty, tw, th,
+ tx - state->getScrollX() + pageX[page - 1]
+ + offsetX,
+ ty - state->getScrollY() + offsetY));
+ }
+ }
+ ++page;
+ }
+ break;
+ }
+
+ return tiles;
+}
+
+void TileMap::getScrollLimits(int *horizMax, int *vertMax) {
+ int pageW1, pageH1, pageW2, pageH2;
+
+ if (!state->getDoc() || !state->getDoc()->getNumPages()) {
+ *horizMax = *vertMax = 0;
+ return;
+ }
+
+ updatePageParams();
+ updateContinuousModeParams();
+
+ switch (state->getDisplayMode()) {
+ case displaySingle:
+ *horizMax = pageW[state->getScrollPage() - 1];
+ *vertMax = pageH[state->getScrollPage() - 1];
+ break;
+ case displayContinuous:
+ *horizMax = maxW;
+ *vertMax = totalH;
+ break;
+ case displaySideBySideSingle:
+ pageW1 = pageW[state->getScrollPage() - 1];
+ pageH1 = pageH[state->getScrollPage() - 1];
+ if (state->getScrollPage() + 1 <= state->getDoc()->getNumPages()) {
+ pageW2 = pageW[state->getScrollPage()];
+ pageH2 = pageH[state->getScrollPage()];
+ } else {
+ pageW2 = pageW1;
+ pageH2 = pageH1;
+ }
+ *horizMax = pageW1 + sideBySidePageSpacing + pageW2;
+ *vertMax = pageH1 > pageH2 ? pageH1 : pageH2;
+ break;
+ case displaySideBySideContinuous:
+ *horizMax = maxW + sideBySidePageSpacing + maxW2;
+ *vertMax = totalH;
+ break;
+ case displayHorizontalContinuous:
+ *horizMax = totalW;
+ *vertMax = maxH;
+ break;
+ default: // should never happen
+ *horizMax = *vertMax = 0;
+ break;
+ }
+}
+
+GBool TileMap::cvtWindowToUser(int xw, int yw,
+ int *pg, double *xu, double *yu) {
+ GBool ok;
+ int xd, yd;
+
+ if (!state->getDoc() || !state->getDoc()->getNumPages()) {
+ *pg = 0;
+ *xu = *yu = 0;
+ return gFalse;
+ }
+
+ ok = cvtWindowToDev(xw, yw, pg, &xd, &yd);
+ cvtDevToUser(*pg, xd, yd, xu, yu);
+ return ok;
+}
+
+GBool TileMap::cvtWindowToDev(int xw, int yw,
+ int *pg, int *xd, int *yd) {
+ int pageW1, pageH1, pageW2, pageH2, offsetX, offsetX2, offsetY;
+
+ if (!state->getDoc() || !state->getDoc()->getNumPages()) {
+ *pg = 0;
+ *xd = *yd = 0;
+ return gFalse;
+ }
+
+ updatePageParams();
+ updateContinuousModeParams();
+
+ switch (state->getDisplayMode()) {
+
+ case displaySingle:
+ *pg = state->getScrollPage();
+ pageW1 = pageW[*pg - 1];
+ pageH1 = pageH[*pg - 1];
+ if (pageW1 < state->getWinW()) {
+ offsetX = (state->getWinW() - pageW1) / 2;
+ } else {
+ offsetX = 0;
+ }
+ if (pageH1 < state->getWinH()) {
+ offsetY = (state->getWinH() - pageH1) / 2;
+ } else {
+ offsetY = 0;
+ }
+ *xd = xw - offsetX + state->getScrollX();
+ *yd = yw - offsetY + state->getScrollY();
+ return *xd >= 0 && *xd < pageW1 && *yd >= 0 && *yd < pageH1;
+
+ case displayContinuous:
+ if (totalH < state->getWinH()) {
+ offsetY = (state->getWinH() - totalH) / 2;
+ } else {
+ offsetY = 0;
+ }
+ *pg = findContinuousPage(yw - offsetY + state->getScrollY());
+ if (*pg < 1 || *pg > state->getDoc()->getNumPages()) {
+ *pg = 0;
+ *xd = *yd = 0;
+ return gFalse;
+ }
+ pageW1 = pageW[*pg - 1];
+ pageH1 = pageH[*pg - 1];
+ if (maxW < state->getWinW()) {
+ offsetX = (state->getWinW() - maxW) / 2;
+ } else {
+ offsetX = 0;
+ }
+ offsetX += (maxW - pageW1) / 2;
+ *xd = xw - offsetX + state->getScrollX();
+ *yd = yw - offsetY - pageY[*pg - 1] + state->getScrollY();
+ return *xd >= 0 && *xd < pageW1 && *yd >= 0 && *yd < pageH1;
+
+ case displaySideBySideSingle:
+ pageW1 = pageW[state->getScrollPage() - 1];
+ pageH1 = pageH[state->getScrollPage() - 1];
+ if (state->getScrollPage() + 1 <= state->getDoc()->getNumPages()) {
+ pageW2 = pageW[state->getScrollPage()];
+ pageH2 = pageH[state->getScrollPage()];
+ } else {
+ // display a single page as though there were a blank facing
+ // page of the same size
+ pageW2 = pageW1;
+ pageH2 = pageH1;
+ }
+ if (pageW1 + sideBySidePageSpacing + pageW2 < state->getWinW()) {
+ offsetX = (state->getWinW() -
+ (pageW1 + sideBySidePageSpacing + pageW2)) / 2;
+ } else {
+ offsetX = 0;
+ }
+ offsetX2 = offsetX + pageW1 + sideBySidePageSpacing;
+ if (pageH1 < state->getWinH() && pageH2 < state->getWinH()) {
+ if (pageH1 > pageH2) {
+ offsetY = (state->getWinH() - pageH1) / 2;
+ } else {
+ offsetY = (state->getWinH() - pageH2) / 2;
+ }
+ } else {
+ offsetY = 0;
+ }
+ if (xw + state->getScrollX() < offsetX2) {
+ *pg = state->getScrollPage();
+ *xd = xw - offsetX + state->getScrollX();
+ *yd = yw - offsetY + state->getScrollY();
+ return *xd >= 0 && *xd < pageW1 && *yd >= 0 && *yd < pageH1;
+ } else {
+ if (state->getScrollPage() + 1 > state->getDoc()->getNumPages()) {
+ *pg = *xd = *yd = 0;
+ return gFalse;
+ }
+ *pg = state->getScrollPage() + 1;
+ *xd = xw - offsetX2 + state->getScrollX();
+ *yd = yw - offsetY + state->getScrollY();
+ return *xd >= 0 && *xd < pageW2 && *yd >= 0 && *yd < pageH2;
+ }
+
+ case displaySideBySideContinuous:
+ if (totalH < state->getWinH()) {
+ offsetY = (state->getWinH() - totalH) / 2;
+ } else {
+ offsetY = 0;
+ }
+ *pg = findSideBySideContinuousPage(yw - offsetY + state->getScrollY());
+ if (*pg < 1 || *pg > state->getDoc()->getNumPages()) {
+ *pg = 0;
+ *xd = *yd = 0;
+ return gFalse;
+ }
+ pageW1 = pageW[*pg - 1];
+ pageH1 = pageH[*pg - 1];
+ if (*pg + 1 <= state->getDoc()->getNumPages()) {
+ pageW2 = pageW[*pg];
+ pageH2 = pageH[*pg];
+ } else {
+ pageW2 = pageH2 = 0;
+ }
+ if (maxW + sideBySidePageSpacing + maxW2 < state->getWinW()) {
+ offsetX = (state->getWinW() -
+ (maxW + sideBySidePageSpacing + maxW2)) / 2;
+ } else {
+ offsetX = 0;
+ }
+ offsetX += maxW - pageW1;
+ offsetX2 = offsetX + pageW1 + sideBySidePageSpacing;
+ if (xw + state->getScrollX() < offsetX2) {
+ *xd = xw - offsetX + state->getScrollX();
+ *yd = yw - offsetY - pageY[*pg - 1] + state->getScrollY();
+ return *xd >= 0 && *xd < pageW1 && *yd >= 0 && *yd < pageH1;
+ } else {
+ if (*pg + 1 > state->getDoc()->getNumPages()) {
+ *pg = *xd = *yd = 0;
+ return false;
+ }
+ ++*pg;
+ *xd = xw - offsetX2 + state->getScrollX();
+ *yd = yw - offsetY - pageY[*pg - 1] + state->getScrollY();
+ return *xd >= 0 && *xd < pageW2 && *yd >= 0 && *yd < pageH2;
+ }
+
+ case displayHorizontalContinuous:
+ if (totalW < state->getWinW()) {
+ offsetX = (state->getWinW() - totalW) / 2;
+ } else {
+ offsetX = 0;
+ }
+ *pg = findHorizContinuousPage(xw - offsetX + state->getScrollX());
+ if (*pg < 1 || *pg > state->getDoc()->getNumPages()) {
+ *pg = 0;
+ *xd = *yd = 0;
+ return gFalse;
+ }
+ pageW1 = pageW[*pg - 1];
+ pageH1 = pageH[*pg - 1];
+ if (maxH < state->getWinH()) {
+ offsetY = (state->getWinH() - maxH) / 2;
+ } else {
+ offsetY = 0;
+ }
+ *xd = xw - offsetX - pageX[*pg - 1] + state->getScrollX();
+ *yd = yw - offsetY + state->getScrollY();
+ return *xd >= 0 && *xd < pageW1 && *yd >= 0 && *yd < pageH1;
+ }
+
+ return gFalse;
+}
+
+GBool TileMap::cvtUserToWindow(int pg, double xu, double yu,
+ int *xw, int *yw) {
+ int xd, yd;
+
+ cvtUserToDev(pg, xu, yu, &xd, &yd);
+ return cvtDevToWindow(pg, xd, yd, xw, yw);
+}
+
+GBool TileMap::cvtDevToWindow(int pg, int xd, int yd,
+ int *xw, int *yw) {
+ int leftPg, pageW1, pageH1, pageW2, pageH2, offsetX, offsetX2, offsetY;
+
+ if (!state->getDoc() ||
+ pg < 1 || pg > state->getDoc()->getNumPages()) {
+ *xw = *yw = 0;
+ return gFalse;
+ }
+
+ updatePageParams();
+ updateContinuousModeParams();
+
+ switch (state->getDisplayMode()) {
+
+ case displaySingle:
+ if (pg != state->getScrollPage()) {
+ *xw = *yw = 0;
+ return gFalse;
+ }
+ pageW1 = pageW[pg - 1];
+ pageH1 = pageH[pg - 1];
+ if (pageW1 < state->getWinW()) {
+ offsetX = (state->getWinW() - pageW1) / 2;
+ } else {
+ offsetX = 0;
+ }
+ if (pageH1 < state->getWinH()) {
+ offsetY = (state->getWinH() - pageH1) / 2;
+ } else {
+ offsetY = 0;
+ }
+ *xw = xd + offsetX - state->getScrollX();
+ *yw = yd + offsetY - state->getScrollY();
+ break;
+
+ case displayContinuous:
+ pageW1 = pageW[pg - 1];
+ pageH1 = pageH[pg - 1];
+ if (maxW < state->getWinW()) {
+ offsetX = (state->getWinW() - maxW) / 2;
+ } else {
+ offsetX = 0;
+ }
+ offsetX += (maxW - pageW1) / 2;
+ if (totalH < state->getWinH()) {
+ offsetY = (state->getWinH() - totalH) / 2;
+ } else {
+ offsetY = 0;
+ }
+ *xw = xd + offsetX - state->getScrollX();
+ *yw = pageY[pg - 1] + yd + offsetY - state->getScrollY();
+ break;
+
+ case displaySideBySideSingle:
+ leftPg = (state->getScrollPage() - 1) | 1;
+ if (!(pg == leftPg ||
+ (pg == leftPg + 1 &&
+ leftPg + 1 <= state->getDoc()->getNumPages()))) {
+ *xw = *yw = 0;
+ return gFalse;
+ }
+ pageW1 = pageW[leftPg - 1];
+ pageH1 = pageH[leftPg - 1];
+ if (leftPg + 1 <= state->getDoc()->getNumPages()) {
+ pageW2 = pageW[leftPg];
+ pageH2 = pageH[leftPg];
+ } else {
+ // display a single page as though there were a blank facing
+ // page of the same size
+ pageW2 = pageW1;
+ pageH2 = pageH1;
+ }
+ if (pageW1 + sideBySidePageSpacing + pageW2 < state->getWinW()) {
+ offsetX = (state->getWinW() -
+ (pageW1 + sideBySidePageSpacing + pageW2)) / 2;
+ } else {
+ offsetX = 0;
+ }
+ offsetX2 = offsetX + pageW1 + sideBySidePageSpacing;
+ if (pageH1 < state->getWinH() && pageH2 < state->getWinH()) {
+ if (pageH1 > pageH2) {
+ offsetY = (state->getWinH() - pageH1) / 2;
+ } else {
+ offsetY = (state->getWinH() - pageH2) / 2;
+ }
+ } else {
+ offsetY = 0;
+ }
+ if (pg == leftPg) {
+ *xw = xd + offsetX - state->getScrollX();
+ } else {
+ *xw = xd + offsetX2 - state->getScrollX();
+ }
+ *yw = yd + offsetY - state->getScrollY();
+ break;
+
+ case displaySideBySideContinuous:
+ leftPg = (pg - 1) | 1;
+ pageW1 = pageW[leftPg - 1];
+ pageH1 = pageH[leftPg - 1];
+ if (maxW + sideBySidePageSpacing + maxW2 < state->getWinW()) {
+ offsetX = (state->getWinW() -
+ (maxW + sideBySidePageSpacing + maxW2)) / 2;
+ } else {
+ offsetX = 0;
+ }
+ offsetX += maxW - pageW1;
+ offsetX2 = offsetX + pageW1 + sideBySidePageSpacing;
+ if (totalH < state->getWinH()) {
+ offsetY = (state->getWinH() - totalH) / 2;
+ } else {
+ offsetY = 0;
+ }
+ if (pg == leftPg) {
+ *xw = xd + offsetX - state->getScrollX();
+ } else {
+ *xw = xd + offsetX2 - state->getScrollX();
+ }
+ *yw = pageY[pg - 1] + yd + offsetY - state->getScrollY();
+ break;
+
+ case displayHorizontalContinuous:
+ if (totalW < state->getWinW()) {
+ offsetX = (state->getWinW() - totalW) / 2;
+ } else {
+ offsetX = 0;
+ }
+ if (maxH < state->getWinH()) {
+ offsetY = (state->getWinH() - maxH) / 2;
+ } else {
+ offsetY = 0;
+ }
+ *xw = pageX[pg - 1] + xd + offsetX - state->getScrollX();
+ *yw = yd + offsetY - state->getScrollY();
+ break;
+ }
+
+ return gTrue;
+}
+
+void TileMap::cvtUserToDev(int pg, double xu, double yu, int *xd, int *yd) {
+ double m[6];
+
+ if (!state->getDoc() ||
+ pg < 1 || pg > state->getDoc()->getNumPages()) {
+ *xd = *yd = 0;
+ return;
+ }
+
+ computePageMatrix(pg, m);
+ *xd = (int)(xu * m[0] + yu * m[2] + m[4] + 0.5);
+ *yd = (int)(xu * m[1] + yu * m[3] + m[5] + 0.5);
+}
+
+void TileMap::cvtDevToUser(int pg, int xd, int yd, double *xu, double *yu) {
+ double m[6], im[6];
+
+ if (!state->getDoc() ||
+ pg < 1 || pg > state->getDoc()->getNumPages()) {
+ *xu = *yu = 0;
+ return;
+ }
+
+ computePageMatrix(pg, m);
+ invertMatrix(m, im);
+ *xu = xd * im[0] + yd * im[2] + im[4];
+ *yu = xd * im[1] + yd * im[3] + im[5];
+}
+
+void TileMap::getWindowPageRange(int x, int y, int w, int h,
+ int *firstPage, int *lastPage) {
+ GList *tiles;
+ PlacedTileDesc *tile;
+ int i;
+
+ if (!state->getDoc() || !state->getDoc()->getNumPages()) {
+ *firstPage = *lastPage = 0;
+ return;
+ }
+ *firstPage = state->getDoc()->getNumPages();
+ *lastPage = 0;
+ tiles = getTileList();
+ for (i = 0; i < tiles->getLength(); ++i) {
+ tile = (PlacedTileDesc *)tiles->get(i);
+ if (tile->px < x + w &&
+ tile->px + tile->tw > x &&
+ tile->py < y + h &&
+ tile->py + tile->th > y) {
+ if (tile->page < *firstPage) {
+ *firstPage = tile->page;
+ }
+ if (tile->page > *lastPage) {
+ *lastPage = tile->page;
+ }
+ }
+ }
+}
+
+int TileMap::getPageTopY(int page) {
+ if (!state->getDoc() || !state->getDoc()->getNumPages()) {
+ return 0;
+ }
+
+ updateContinuousModeParams();
+
+ switch (state->getDisplayMode()) {
+ case displaySingle:
+ case displaySideBySideSingle:
+ case displayHorizontalContinuous:
+ default:
+ return 0;
+ case displayContinuous:
+ case displaySideBySideContinuous:
+ return pageY[page - 1];
+ }
+}
+
+int TileMap::getPageBottomY(int page) {
+ if (!state->getDoc() || !state->getDoc()->getNumPages()) {
+ return 0;
+ }
+
+ updatePageParams();
+ updateContinuousModeParams();
+
+ switch (state->getDisplayMode()) {
+ case displaySingle:
+ case displaySideBySideSingle:
+ case displayHorizontalContinuous:
+ default:
+ return pageH[page - 1] - state->getWinH();
+ case displayContinuous:
+ case displaySideBySideContinuous:
+ return pageY[page - 1] + pageH[page - 1] - state->getWinH();
+ }
+}
+
+int TileMap::getPageLeftX(int page) {
+ int leftPage, rightPage, pageW1, pageW2, offsetX, offsetX2;
+
+ if (!state->getDoc() || !state->getDoc()->getNumPages()) {
+ return 0;
+ }
+
+ updatePageParams();
+ updateContinuousModeParams();
+
+ switch (state->getDisplayMode()) {
+ case displaySingle:
+ default:
+ return 0;
+ case displayContinuous:
+ return (maxW - pageW[page - 1]) / 2;
+ case displaySideBySideSingle:
+ leftPage = ((page - 1) & ~1) + 1;
+ rightPage = leftPage + 1;
+ pageW1 = pageW[leftPage - 1];
+ if (rightPage <= state->getDoc()->getNumPages()) {
+ pageW2 = pageW[rightPage - 1];
+ } else {
+ // display a single page as though there were a blank facing
+ // page of the same size
+ pageW2 = pageW1;
+ }
+ if (pageW1 + sideBySidePageSpacing + pageW2 < state->getWinW()) {
+ offsetX = (state->getWinW() -
+ (pageW1 + sideBySidePageSpacing + pageW2)) / 2;
+ } else {
+ offsetX = 0;
+ }
+ offsetX2 = offsetX + pageW1 + sideBySidePageSpacing;
+ return (page == leftPage) ? offsetX : offsetX2;
+ case displaySideBySideContinuous:
+ leftPage = ((page - 1) & ~1) + 1;
+ rightPage = leftPage + 1;
+ pageW1 = pageW[leftPage - 1];
+ if (maxW + sideBySidePageSpacing + maxW2 < state->getWinW()) {
+ offsetX = (state->getWinW() -
+ (maxW + sideBySidePageSpacing + maxW2)) / 2;
+ } else {
+ offsetX = 0;
+ }
+ offsetX += maxW - pageW1;
+ offsetX2 = offsetX + pageW1 + sideBySidePageSpacing;
+ return (page == leftPage) ? offsetX : offsetX2;
+ case displayHorizontalContinuous:
+ return pageX[page - 1];
+ }
+}
+
+int TileMap::getPageRightX(int page) {
+ int leftPage, rightPage, pageW1, pageW2, offsetX, offsetX2;
+
+ if (!state->getDoc() || !state->getDoc()->getNumPages()) {
+ return 0;
+ }
+
+ updatePageParams();
+ updateContinuousModeParams();
+
+ switch (state->getDisplayMode()) {
+ case displaySingle:
+ default:
+ return pageW[page - 1] - state->getWinW();
+ case displayContinuous:
+ return (maxW + pageW[page - 1]) / 2 - state->getWinW();
+ case displaySideBySideSingle:
+ leftPage = ((page - 1) & ~1) + 1;
+ rightPage = leftPage + 1;
+ pageW1 = pageW[leftPage - 1];
+ if (rightPage <= state->getDoc()->getNumPages()) {
+ pageW2 = pageW[rightPage - 1];
+ } else {
+ // display a single page as though there were a blank facing
+ // page of the same size
+ pageW2 = pageW1;
+ }
+ if (pageW1 + sideBySidePageSpacing + pageW2 < state->getWinW()) {
+ offsetX = (state->getWinW() -
+ (pageW1 + sideBySidePageSpacing + pageW2)) / 2;
+ } else {
+ offsetX = 0;
+ }
+ offsetX2 = offsetX + pageW1 + sideBySidePageSpacing;
+ return (page == leftPage) ? offsetX + pageW1 - state->getWinW()
+ : offsetX2 + pageW2 - state->getWinW();
+ case displaySideBySideContinuous:
+ leftPage = ((page - 1) & ~1) + 1;
+ rightPage = leftPage + 1;
+ pageW1 = pageW[leftPage - 1];
+ if (rightPage <= state->getDoc()->getNumPages()) {
+ pageW2 = pageW[rightPage - 1];
+ } else {
+ // display a single page as though there were a blank facing
+ // page of the same size
+ pageW2 = pageW1;
+ }
+ if (maxW + sideBySidePageSpacing + maxW2 < state->getWinW()) {
+ offsetX = (state->getWinW() -
+ (maxW + sideBySidePageSpacing + maxW2)) / 2;
+ } else {
+ offsetX = 0;
+ }
+ offsetX += maxW - pageW1;
+ offsetX2 = offsetX + pageW1 + sideBySidePageSpacing;
+ return (page == leftPage) ? offsetX + pageW1 - state->getWinW()
+ : offsetX2 + pageW2 - state->getWinW();
+ case displayHorizontalContinuous:
+ return pageX[page - 1] + pageW[page - 1] - state->getWinW();
+ }
+}
+
+int TileMap::getFirstPage() {
+ updateContinuousModeParams();
+ switch (state->getDisplayMode()) {
+ case displaySingle:
+ default:
+ return state->getScrollPage();
+ case displayContinuous:
+ return findContinuousPage(state->getScrollY());
+ case displaySideBySideSingle:
+ return state->getScrollPage();
+ case displaySideBySideContinuous:
+ return findSideBySideContinuousPage(state->getScrollY());
+ case displayHorizontalContinuous:
+ return findHorizContinuousPage(state->getScrollX());
+ }
+}
+
+int TileMap::getFirstPageTop() {
+ int page;
+
+ updateContinuousModeParams();
+ switch (state->getDisplayMode()) {
+ case displaySingle:
+ default:
+ return state->getScrollPage();
+ case displayContinuous:
+ page = findContinuousPage(state->getScrollY());
+ if (page < state->getDoc()->getNumPages() &&
+ pageY[page - 1] < state->getScrollY()) {
+ return page + 1;
+ } else {
+ return page;
+ }
+ case displaySideBySideSingle:
+ return state->getScrollPage();
+ case displaySideBySideContinuous:
+ page = findSideBySideContinuousPage(state->getScrollY());
+ if (page < state->getDoc()->getNumPages() &&
+ pageY[page - 1] < state->getScrollY()) {
+ return page + 1;
+ } else {
+ return page;
+ }
+ case displayHorizontalContinuous:
+ page = findHorizContinuousPage(state->getScrollX());
+ if (page < state->getDoc()->getNumPages() &&
+ pageX[page - 1] < state->getScrollX()) {
+ return page + 1;
+ } else {
+ return page;
+ }
+ }
+}
+
+int TileMap::getMidPage() {
+ int wx, wy, pg, x, y;
+
+ wx = state->getWinW() / 2;
+ wy = state->getWinH() / 2;
+ if (!cvtWindowToDev(wx, wy, &pg, &x, &y)) {
+ if (state->getDisplayMode() == displayContinuous) {
+ wy += continuousPageSpacing;
+ } else if (state->getDisplayMode() == displaySideBySideContinuous) {
+ wx += sideBySidePageSpacing;
+ wy += continuousPageSpacing;
+ } else if (state->getDisplayMode() == displayHorizontalContinuous) {
+ wx += horizContinuousPageSpacing;
+ } else {
+ return state->getScrollPage();
+ }
+ if (!cvtWindowToDev(wx, wy, &pg, &x, &y)) {
+ return 1;
+ }
+ }
+ return pg;
+}
+
+int TileMap::getLastPage() {
+ int pg, x, y, n;
+
+ switch (state->getDisplayMode()) {
+ case displaySingle:
+ default:
+ return state->getScrollPage();
+ case displayContinuous:
+ if (!cvtWindowToDev(state->getWinW() / 2, state->getWinH() - 1,
+ &pg, &x, &y)) {
+ return state->getDoc()->getNumPages();
+ }
+ return pg;
+ case displaySideBySideSingle:
+ pg = state->getScrollPage() + 1;
+ n = state->getDoc()->getNumPages();
+ if (pg > n) {
+ pg = n;
+ }
+ return pg;
+ case displaySideBySideContinuous:
+ if (!cvtWindowToDev(state->getWinW() / 2, state->getWinH() - 1,
+ &pg, &x, &y)) {
+ return state->getScrollPage();
+ }
+ pg = ((pg - 1) & ~1) + 2;
+ n = state->getDoc()->getNumPages();
+ if (pg > n) {
+ pg = n;
+ }
+ return pg;
+ case displayHorizontalContinuous:
+ x = state->getWinW() - 1;
+ y = state->getWinH() / 2;
+ if (!cvtWindowToDev(state->getWinW() - 1, state->getWinH() / 2,
+ &pg, &x, &y)) {
+ return state->getDoc()->getNumPages();
+ }
+ return pg;
+ }
+}
+
+double TileMap::getDPI(int page) {
+ if (page < 1 || page > state->getDoc()->getNumPages()) {
+ return 0;
+ }
+ updatePageParams();
+ return pageDPI[page - 1];
+}
+
+double TileMap::getPageBoxWidth(int page) {
+ return pageBoxW[page - 1];
+}
+
+double TileMap::getPageBoxHeight(int page) {
+ return pageBoxH[page - 1];
+}
+
+int TileMap::getContinuousPageSpacing() {
+ return continuousPageSpacing;
+}
+
+int TileMap::getSideBySidePageSpacing() {
+ return sideBySidePageSpacing;
+}
+
+int TileMap::getHorizContinuousPageSpacing() {
+ return horizContinuousPageSpacing;
+}
+
+void TileMap::docChanged() {
+ PDFDoc *doc;
+ int nPages, pg, rot;
+
+ doc = state->getDoc();
+
+ if (doc) {
+ nPages = doc->getNumPages();
+ } else {
+ nPages = 0;
+ }
+ pageBoxW = (double *)greallocn(pageBoxW, nPages, sizeof(double));
+ pageBoxH = (double *)greallocn(pageBoxH, nPages, sizeof(double));
+ for (pg = 1; pg <= nPages; ++pg) {
+ rot = doc->getPageRotate(pg);
+ if (rot == 0 || rot == 180) {
+ pageBoxW[pg - 1] = doc->getPageCropWidth(pg);
+ pageBoxH[pg - 1] = doc->getPageCropHeight(pg);
+ } else {
+ pageBoxW[pg - 1] = doc->getPageCropHeight(pg);
+ pageBoxH[pg - 1] = doc->getPageCropWidth(pg);
+ }
+ }
+
+ clearPageParams();
+ clearContinuousModeParams();
+ if (tiles) {
+ deleteGList(tiles, PlacedTileDesc);
+ tiles = NULL;
+ }
+}
+
+void TileMap::windowSizeChanged() {
+ clearPageParams();
+ clearContinuousModeParams();
+ if (tiles) {
+ deleteGList(tiles, PlacedTileDesc);
+ tiles = NULL;
+ }
+}
+
+void TileMap::displayModeChanged() {
+ clearPageParams();
+ clearContinuousModeParams();
+ if (tiles) {
+ deleteGList(tiles, PlacedTileDesc);
+ tiles = NULL;
+ }
+}
+
+void TileMap::zoomChanged() {
+ clearPageParams();
+ clearContinuousModeParams();
+ if (tiles) {
+ deleteGList(tiles, PlacedTileDesc);
+ tiles = NULL;
+ }
+}
+
+void TileMap::rotateChanged() {
+ clearPageParams();
+ clearContinuousModeParams();
+ if (tiles) {
+ deleteGList(tiles, PlacedTileDesc);
+ tiles = NULL;
+ }
+}
+
+void TileMap::scrollPositionChanged() {
+ if (tiles) {
+ deleteGList(tiles, PlacedTileDesc);
+ tiles = NULL;
+ }
+}
+
+
+void TileMap::forceRedraw() {
+ clearPageParams();
+ clearContinuousModeParams();
+ if (tiles) {
+ deleteGList(tiles, PlacedTileDesc);
+ tiles = NULL;
+ }
+}
+
+void TileMap::clearPageParams() {
+ gfree(pageDPI);
+ gfree(pageW);
+ gfree(pageH);
+ gfree(tileW);
+ gfree(tileH);
+ pageDPI = NULL;
+ pageW = pageH = NULL;
+ tileW = tileH = NULL;
+}
+
+void TileMap::updatePageParams() {
+ double rotPageBoxW, rotPageBoxW2, rotPageBoxH, rotPageBoxH2, rotPageBoxHMax;
+ double hDPI, vDPI, dpi;
+ int page, otherPage, nxTiles, nyTiles;
+
+ //--- check to see if the continuous mode params have already been updated
+ if (pageDPI) {
+ return;
+ }
+
+ //--- allocate memory
+ pageDPI = (double *)gmallocn(state->getDoc()->getNumPages(), sizeof(double));
+ pageW = (int *)gmallocn(state->getDoc()->getNumPages(), sizeof(int));
+ pageH = (int *)gmallocn(state->getDoc()->getNumPages(), sizeof(int));
+ tileW = (int *)gmallocn(state->getDoc()->getNumPages(), sizeof(int));
+ tileH = (int *)gmallocn(state->getDoc()->getNumPages(), sizeof(int));
+
+ for (page = 1; page <= state->getDoc()->getNumPages(); ++page) {
+
+ //--- special handling for side-by-side modes
+ if (state->displayModeIsSideBySide()) {
+
+ // rotate the page boxes
+ if (page & 1) {
+ otherPage = page + 1;
+ if (otherPage >= state->getDoc()->getNumPages()) {
+ otherPage = page;
+ }
+ } else {
+ otherPage = page - 1;
+ if (otherPage < 1) {
+ otherPage = page;
+ }
+ }
+ if (state->getRotate() == 0 || state->getRotate() == 180) {
+ rotPageBoxW = pageBoxW[page - 1];
+ rotPageBoxW2 = pageBoxW[otherPage - 1];
+ rotPageBoxH = pageBoxH[page - 1];
+ rotPageBoxH2 = pageBoxH[otherPage - 1];
+ } else {
+ rotPageBoxW = pageBoxH[page - 1];
+ rotPageBoxW2 = pageBoxH[otherPage - 1];
+ rotPageBoxH = pageBoxW[page - 1];
+ rotPageBoxH2 = pageBoxW[otherPage - 1];
+ }
+ rotPageBoxHMax = (rotPageBoxH > rotPageBoxH2) ? rotPageBoxH
+ : rotPageBoxH2;
+
+ // compute resolution
+ if (state->getZoom() == zoomPage) {
+ hDPI = ((state->getWinW() - sideBySidePageSpacing) /
+ (rotPageBoxW + rotPageBoxW2)) * 72.0;
+ vDPI = (state->getWinH() / rotPageBoxHMax) * 72.0;
+ dpi = hDPI < vDPI ? hDPI : vDPI;
+ // allow for some floating point jitter
+ dpi -= 0.01;
+ } else if (state->getZoom() == zoomWidth) {
+ dpi = ((state->getWinW() - sideBySidePageSpacing) /
+ (rotPageBoxW + rotPageBoxW2)) * 72.0;
+ // allow for some floating point jitter
+ dpi -= 0.01;
+ } else if (state->getZoom() == zoomHeight) {
+ dpi = (state->getWinH() / rotPageBoxHMax) * 72.0;
+ // allow for some floating point jitter
+ dpi -= 0.01;
+ } else {
+ dpi = 0.01 * state->getZoom() * 72.0;
+ }
+
+ //--- all other (non-side-by-side) modes
+ } else {
+
+ // rotate the page boxes
+ if (state->getRotate() == 0 || state->getRotate() == 180) {
+ rotPageBoxW = pageBoxW[page - 1];
+ rotPageBoxH = pageBoxH[page - 1];
+ } else {
+ rotPageBoxW = pageBoxH[page - 1];
+ rotPageBoxH = pageBoxW[page - 1];
+ }
+
+ // compute resolution
+ if (state->getZoom() == zoomPage) {
+ hDPI = (state->getWinW() / rotPageBoxW) * 72.0;
+ vDPI = (state->getWinH() / rotPageBoxH) * 72.0;
+ dpi = hDPI < vDPI ? hDPI : vDPI;
+ // allow for some floating point jitter
+ dpi -= 0.01;
+ } else if (state->getZoom() == zoomWidth) {
+ dpi = (state->getWinW() / rotPageBoxW) * 72.0;
+ // allow for some floating point jitter
+ dpi -= 0.01;
+ } else if (state->getZoom() == zoomHeight) {
+ dpi = (state->getWinH() / rotPageBoxH) * 72.0;
+ // allow for some floating point jitter
+ dpi -= 0.01;
+ } else {
+ dpi = 0.01 * state->getZoom() * 72.0;
+ }
+
+ }
+ pageDPI[page - 1] = dpi;
+
+ // compute bitmap size
+ pageW[page - 1] = (int)((rotPageBoxW * dpi / 72.0) + 0.5);
+ if (pageW[page - 1] < 1) {
+ pageW[page - 1] = 1;
+ }
+ pageH[page - 1] = (int)((rotPageBoxH * dpi / 72.0) + 0.5);
+ if (pageH[page - 1] < 1) {
+ pageH[page - 1] = 1;
+ }
+
+ // compute tile size
+ // (tile width and height are rounded up -- the bottom and right
+ // tiles may be slightly smaller than the computed size)
+ if (pageW[page - 1] <= state->getMaxTileWidth()) {
+ nxTiles = 1;
+ tileW[page - 1] = pageW[page - 1];
+ } else {
+ nxTiles = (pageW[page - 1] + state->getMaxTileWidth() - 1)
+ / state->getMaxTileWidth();
+ tileW[page - 1] = (pageW[page - 1] + nxTiles - 1) / nxTiles;
+ }
+ if (pageH[page - 1] <= state->getMaxTileHeight()) {
+ nyTiles = 1;
+ tileH[page - 1] = pageH[page - 1];
+ } else {
+ nyTiles = (pageH[page - 1] + state->getMaxTileHeight() - 1)
+ / state->getMaxTileHeight();
+ tileH[page - 1] = (pageH[page - 1] + nyTiles - 1) / nyTiles;
+ }
+
+ }
+}
+
+void TileMap::clearContinuousModeParams() {
+ gfree(pageX);
+ pageX = pageY = NULL;
+}
+
+void TileMap::updateContinuousModeParams() {
+ int page, pageW1, pageH1, pageW2, pageH2, x, y;
+
+ // check to see if the continuous mode params have already been updated
+ if (pageX) {
+ return;
+ }
+
+ updatePageParams();
+
+ switch (state->getDisplayMode()) {
+ case displayContinuous:
+ if (!pageX) {
+ pageX = pageY = (int *)gmallocn(state->getDoc()->getNumPages(),
+ sizeof(int));
+ }
+ y = 0;
+ maxW = 0;
+ for (page = 1; page <= state->getDoc()->getNumPages(); ++page) {
+ pageY[page - 1] = y;
+ y += pageH[page - 1] + continuousPageSpacing;
+ if (page == 1 || pageW[page - 1] > maxW) {
+ maxW = pageW[page - 1];
+ }
+ }
+ totalH = y - continuousPageSpacing;
+ break;
+ case displaySideBySideContinuous:
+ if (!pageX) {
+ pageX = pageY = (int *)gmallocn(state->getDoc()->getNumPages(),
+ sizeof(int));
+ }
+ y = 0;
+ maxW = maxW2 = 0;
+ for (page = 1; page <= state->getDoc()->getNumPages(); page += 2) {
+ pageW1 = pageW[page - 1];
+ pageH1 = pageH[page - 1];
+ if (page + 1 <= state->getDoc()->getNumPages()) {
+ pageW2 = pageW[page];
+ pageH2 = pageH[page];
+ } else {
+ pageW2 = pageW1;
+ pageH2 = pageH1;
+ }
+ pageY[page - 1] = y;
+ if (page == 1 || pageW1 > maxW) {
+ maxW = pageW1;
+ }
+ if (page + 1 <= state->getDoc()->getNumPages()) {
+ pageY[page] = y;
+ }
+ if (pageW2 > maxW2) {
+ maxW2 = pageW2;
+ }
+ y += (pageH1 > pageH2) ? pageH1 : pageH2;
+ y += continuousPageSpacing;
+ }
+ totalH = y - continuousPageSpacing;
+ break;
+ case displayHorizontalContinuous:
+ if (!pageX) {
+ pageX = pageY = (int *)gmallocn(state->getDoc()->getNumPages(),
+ sizeof(int));
+ }
+ x = 0;
+ maxH = 0;
+ for (page = 1; page <= state->getDoc()->getNumPages(); ++page) {
+ pageX[page - 1] = x;
+ x += pageW[page - 1] + horizContinuousPageSpacing;
+ if (page == 1 || pageH[page - 1] > maxH) {
+ maxH = pageH[page - 1];
+ }
+ }
+ totalW = x - horizContinuousPageSpacing;
+ break;
+ default:
+ break;
+ }
+}
+
+void TileMap::computePageMatrix(int page, double *m) {
+ PDFRectangle *cropBox;
+ double px1, py1, px2, py2, k;
+ int rotate;
+
+ updatePageParams();
+ cropBox = state->getDoc()->getCatalog()->getPage(page)->getCropBox();
+ px1 = cropBox->x1;
+ py1 = cropBox->y1;
+ px2 = cropBox->x2;
+ py2 = cropBox->y2;
+ k = pageDPI[page - 1] / 72.0;
+ rotate = state->getRotate() +
+ state->getDoc()->getCatalog()->getPage(page)->getRotate();
+ if (rotate > 360) {
+ rotate -= 360;
+ }
+ switch (rotate) {
+ case 0:
+ default:
+ m[0] = k;
+ m[1] = 0;
+ m[2] = 0;
+ m[3] = -k;
+ m[4] = -k * px1;
+ m[5] = k * py2;
+ break;
+ case 90:
+ m[0] = 0;
+ m[1] = k;
+ m[2] = k;
+ m[3] = 0;
+ m[4] = -k * py1;
+ m[5] = -k * px1;
+ break;
+ case 180:
+ m[0] = -k;
+ m[1] = 0;
+ m[2] = 0;
+ m[3] = k;
+ m[4] = k * px2;
+ m[5] = -k * py1;
+ break;
+ case 270:
+ m[0] = 0;
+ m[1] = -k;
+ m[2] = -k;
+ m[3] = 0;
+ m[4] = k * py2;
+ m[5] = k * px2;
+ break;
+ }
+}
+
+void TileMap::invertMatrix(double *m, double *im) {
+ double det;
+
+ det = 1 / (m[0] * m[3] - m[1] * m[2]);
+ im[0] = m[3] * det;
+ im[1] = -m[1] * det;
+ im[2] = -m[2] * det;
+ im[3] = m[0] * det;
+ im[4] = (m[2] * m[5] - m[3] * m[4]) * det;
+ im[5] = (m[1] * m[4] - m[0] * m[5]) * det;
+}
+
+int TileMap::findContinuousPage(int y) {
+ int a, b, m;
+
+ if (y < pageY[0]) {
+ return 0;
+ }
+ if (y >= totalH) {
+ return state->getDoc()->getNumPages() + 1;
+ }
+ a = -1;
+ b = state->getDoc()->getNumPages();
+ // invariant: pageY[a] < y < pageY[b]
+ while (b - a > 1) {
+ m = (a + b) / 2;
+ if (y > pageY[m] - continuousPageSpacing) {
+ a = m;
+ } else if (y < pageY[m] - continuousPageSpacing) {
+ b = m;
+ } else {
+ return m + 1;
+ }
+ }
+ return a + 1;
+}
+
+int TileMap::findSideBySideContinuousPage(int y) {
+ int a, b, m;
+
+ if (y < pageY[0]) {
+ return 0;
+ }
+ if (y >= totalH) {
+ return (state->getDoc()->getNumPages() + 2) & ~1;
+ }
+ a = -2;
+ b = (state->getDoc()->getNumPages() + 1) & ~1;
+ // invariant: pageY[a] < y < pageY[b]
+ while (b - a > 2) {
+ m = ((a + b) / 2) & ~1;
+ if (y > pageY[m] - continuousPageSpacing) {
+ a = m;
+ } else if (y < pageY[m] - continuousPageSpacing) {
+ b = m;
+ } else {
+ return m + 1;
+ }
+ }
+ return a + 1;
+}
+
+int TileMap::findHorizContinuousPage(int x) {
+ int a, b, m;
+
+ if (x < pageX[0]) {
+ return 0;
+ }
+ if (x >= totalW) {
+ return state->getDoc()->getNumPages() + 1;
+ }
+ a = -1;
+ b = state->getDoc()->getNumPages();
+ // invariant: pageX[a] < x < pageX[b]
+ while (b - a > 1) {
+ m = (a + b) / 2;
+ if (x > pageX[m] - horizContinuousPageSpacing) {
+ a = m;
+ } else if (x < pageX[m] - horizContinuousPageSpacing) {
+ b = m;
+ } else {
+ return m + 1;
+ }
+ }
+ return a + 1;
+}