1691 lines
44 KiB
C++
1691 lines
44 KiB
C++
//========================================================================
|
|
//
|
|
// 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:
|
|
if (!(pg == state->getScrollPage() ||
|
|
(pg == state->getScrollPage() + 1 &&
|
|
state->getScrollPage() + 1 <= state->getDoc()->getNumPages()))) {
|
|
*xw = *yw = 0;
|
|
return gFalse;
|
|
}
|
|
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 (pg == state->getScrollPage()) {
|
|
*xw = xd + offsetX - state->getScrollX();
|
|
*yw = yd + offsetY - state->getScrollY();
|
|
} 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;
|
|
}
|