diff options
author | Calvin Morrison <calvin@pobox.com> | 2023-04-05 14:13:39 -0400 |
---|---|---|
committer | Calvin Morrison <calvin@pobox.com> | 2023-04-05 14:13:39 -0400 |
commit | 835e373b3eeaabcd0621ed6798ab500f37982fae (patch) | |
tree | dfa16b0e2e1b4956b38f693220eac4e607802133 /xpdf/TileMap.cc |
Diffstat (limited to 'xpdf/TileMap.cc')
-rw-r--r-- | xpdf/TileMap.cc | 1690 |
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; +} |