📄 displaymodel.cc.svn-base
字号:
freedSomething = true;
BitmapCacheEntry_Free(gBitmapCache[i]);
gBitmapCache[i] = NULL;
--gBitmapCacheCount;
}
if (curPos != i)
gBitmapCache[curPos] = gBitmapCache[i];
if (!shouldFree)
++curPos;
}
UnlockCache();
if (freedSomething)
DBG_OUT("\n");
return freedSomething;
}
void BitmapCache_Add(DisplayModel *dm, int pageNo, double zoomLevel, int rotation,
RenderedBitmap *bitmap, double renderTime) {
assert(gBitmapCacheCount <= MAX_BITMAPS_CACHED);
assert(dm);
assert(validRotation(rotation));
normalizeRotation(&rotation);
DBG_OUT("BitmapCache_Add(pageNo=%d, zoomLevel=%.2f%%, rotation=%d)\n", pageNo, zoomLevel, rotation);
LockCache();
/* It's possible there still is a cached bitmap with different zoomLevel/rotation */
BitmapCache_FreePage(dm, pageNo);
if (gBitmapCacheCount >= MAX_BITMAPS_CACHED - 1) {
/* TODO: find entry that is not visible and remove it from cache to
make room for new entry */
delete bitmap;
goto UnlockAndExit;
}
BitmapCacheEntry* entry = (BitmapCacheEntry*)malloc(sizeof(BitmapCacheEntry));
if (!entry) {
delete bitmap;
goto UnlockAndExit;
}
entry->dm = dm;
entry->pageNo = pageNo;
entry->zoomLevel = zoomLevel;
entry->rotation = rotation;
entry->bitmap = bitmap;
entry->renderTime = renderTime;
gBitmapCache[gBitmapCacheCount++] = entry;
UnlockAndExit:
UnlockCache();
}
BitmapCacheEntry *BitmapCache_Find(DisplayModel *dm, int pageNo) {
BitmapCacheEntry* entry;
LockCache();
for (int i = 0; i < gBitmapCacheCount; i++) {
entry = gBitmapCache[i];
if ( (dm == entry->dm) && (pageNo == entry->pageNo) ) {
goto Exit;
}
}
entry = NULL;
Exit:
UnlockCache();
return entry;
}
BitmapCacheEntry *BitmapCache_Find(DisplayModel *dm, int pageNo, double zoomLevel, int rotation) {
BitmapCacheEntry *entry;
normalizeRotation(&rotation);
LockCache();
for (int i = 0; i < gBitmapCacheCount; i++) {
entry = gBitmapCache[i];
if ( (dm == entry->dm) && (pageNo == entry->pageNo) &&
(zoomLevel == entry->zoomLevel) && (rotation == entry->rotation)) {
goto Exit;
}
}
entry = NULL;
Exit:
UnlockCache();
return entry;
}
/* Return true if a bitmap for a page defined by <dm>, <pageNo>, <zoomLevel>
and <rotation> exists in the cache */
bool BitmapCache_Exists(DisplayModel *dm, int pageNo, double zoomLevel, int rotation) {
if (BitmapCache_Find(dm, pageNo, zoomLevel, rotation))
return true;
return false;
}
PdfSearchResult *DisplayModel::Find(PdfSearchDirection direction, wchar_t *text)
{
showBusyCursor();
bool forward = (direction == FIND_FORWARD);
_pdfSearch->SetDirection(forward);
if (text != NULL)
bFoundText = _pdfSearch->FindFirst(currentPageNo(), text);
else
bFoundText = _pdfSearch->FindNext();
if (bFoundText) {
PdfSearchResult &rect = _pdfSearch->result;
goToPage(rect.page, 0);
MapResultRectToScreen(&rect);
showNormalCursor();
return ▭
}
showNormalCursor();
return NULL;
}
DisplayModel *DisplayModel_CreateFromFileName(
const WCHAR *fileName,
SizeD totalDrawAreaSize,
int scrollbarXDy, int scrollbarYDx,
DisplayMode displayMode, int startPage,
WindowInfo *win, bool tryrepair)
{
DisplayModel * dm = NULL;
dm = new DisplayModel(displayMode);
if (!dm)
goto Error;
if (!dm->load(fileName, startPage, win, tryrepair))
goto Error;
dm->setScrollbarsSize(scrollbarXDy, scrollbarYDx);
dm->setTotalDrawAreaSize(totalDrawAreaSize);
// DBG_OUT("DisplayModel_CreateFromPageTree() pageCount = %d, startPage=%d, displayMode=%d\n",
// dm->pageCount(), (int)dm->startPage, (int)displayMode);
return dm;
Error:
delete dm;
return NULL;
}
bool DisplayModel::cvtUserToScreen(int pageNo, double *x, double *y)
{
pdf_page *page = pdfEngine->getPdfPage(pageNo);
double zoom = zoomReal();
int rot = rotation();
fz_point p;
assert(page);
if(!page)
return false;
normalizeRotation(&rot);
zoom *= 0.01;
p.x = *x;
p.y = *y;
fz_matrix ctm = pdfEngine->viewctm(page, zoom, rot);
fz_point tp = fz_transformpoint(ctm, p);
PdfPageInfo *pageInfo = getPageInfo(pageNo);
rot += pageInfo->rotation;
double vx = 0, vy = 0;
if (rot == 90 || rot == 180)
vx += pageInfo->currDx;
if (rot == 180 || rot == 270)
vy += pageInfo->currDy;
*x = tp.x + 0.5 + pageInfo->screenX - pageInfo->bitmapX + vx;
*y = tp.y + 0.5 + pageInfo->screenY - pageInfo->bitmapY + vy;
return true;
}
bool DisplayModel::cvtScreenToUser(int *pageNo, double *x, double *y)
{
double zoom = zoomReal();
int rot = rotation();
fz_point p;
normalizeRotation(&rot);
zoom *= 0.01;
*pageNo = getPageNoByPoint(*x, *y);
if (*pageNo == POINT_OUT_OF_PAGE)
return false;
pdf_page *page = pdfEngine->getPdfPage(*pageNo);
const PdfPageInfo *pageInfo = getPageInfo(*pageNo);
p.x = *x - 0.5 - pageInfo->screenX + pageInfo->bitmapX;
p.y = *y - 0.5 - pageInfo->screenY + pageInfo->bitmapY;
fz_matrix ctm = pdfEngine->viewctm(page, zoom, rot);
fz_matrix invCtm = fz_invertmatrix(ctm);
fz_point tp = fz_transformpoint(invCtm, p);
double vx = 0, vy = 0;
if (rot == 90 || rot == 180)
vy -= pageInfo->pageDy;
if (rot == 180 || rot == 270)
vx += pageInfo->pageDx;
*x = tp.x + vx;
*y = tp.y + vy;
return true;
}
static void launch_url_a(const char *url)
{
SHELLEXECUTEINFOA sei;
ZeroMemory(&sei, sizeof(sei));
sei.cbSize = sizeof(sei);
sei.fMask = SEE_MASK_FLAG_NO_UI;
sei.lpVerb = "open";
sei.lpFile = url;
sei.nShow = SW_SHOWNORMAL;
ShellExecuteExA(&sei);
}
void DisplayModel::handleLink2(pdf_link* link)
{
if (PDF_LURI == link->kind)
{
char *uri = fz_tostrbuf(link->dest);
if (!str_startswithi(uri, "http"))
{
/* unsupported uri type */
return;
}
launch_url_a(uri);
} else if (PDF_LGOTO == link->kind)
{
int page = pdfEngine->findPageNo(link->dest);
if (page > 0)
goToPage(page, 0);
}
}
void DisplayModel::handleLink(PdfLink *link)
{
handleLink2(link->link);
}
void DisplayModel::goToTocLink(void *linktmp)
{
if (!linktmp)
return;
pdf_link *link = (pdf_link*)linktmp;
handleLink2(link);
}
void DisplayModel::goToNamedDest(const char *name)
{
fz_obj *dest = pdfEngine->getNamedDest(name);
if (!dest)
{
goToPage(1, 0);
return;
}
int page = pdfEngine->findPageNo(dest);
if (page > 0)
goToPage(page, 0);
}
/* Given <region> (in user coordinates ) on page <pageNo>, copies text in that region
* to <buf>. Returnes number of copied characters */
int DisplayModel::getTextInRegion(int pageNo, RectD *region, unsigned short *buf, int buflen)
{
int bxMin, bxMax, byMin, byMax;
int xMin, xMax, yMin, yMax;
pdf_textline * line, *ln;
fz_error * error;
pdf_page * page = pdfEngine->getPdfPage(pageNo);
fz_tree * tree = page->tree;
double rot = 0;
double zoom = 1;
error = pdf_loadtextfromtree(&line, tree, fz_identity());
if (error)
return 0;
xMin = (int)region->x;
xMax = xMin + (int)region->dx;
yMin = (int)region->y;
yMax = yMin + (int)region->dy;
int p = 0;
for (ln = line; ln; ln = ln->next) {
int oldP = p;
for (int i = 0; i < ln->len; i++) {
bxMin = ln->text[i].bbox.x0;
bxMax = ln->text[i].bbox.x1;
byMin = ln->text[i].bbox.y0;
byMax = ln->text[i].bbox.y1;
int c = ln->text[i].c;
if (c < 32)
c = '?';
if (bxMax >= xMin && bxMin <= xMax && byMax >= yMin && byMin <= yMax
&& p < buflen) {
buf[p++] = c;
//DBG_OUT("Char: %c : %d; ushort: %hu\n", (char)c, (int)c, (unsigned short)c);
//DBG_OUT("Found char: %c : %hu; real %c : %hu\n", c, (unsigned short)(unsigned char) c, ln->text[i].c, ln->text[i].c);
}
}
if (p > oldP && p < buflen - 1) {
#ifdef WIN32
buf[p++] = '\r'; buf[p++] = 10;
//DBG_OUT("Char: %c : %d; ushort: %hu\n", (char)buf[p], (int)(unsigned char)buf[p], buf[p]);
#else
buf[p++] = '\n';
#endif
}
}
pdf_droptextline(line);
return p;
}
void DisplayModel::MapResultRectToScreen(PdfSearchResult *rect)
{
PdfPageInfo *pageInfo = getPageInfo(rect->page);
pdf_page *page = pdfEngine->getPdfPage(rect->page);
if(!page)
return;
int rot = rotation();
normalizeRotation (&rot);
double vx = pageInfo->screenX - pageInfo->bitmapX,
vy = pageInfo->screenY - pageInfo->bitmapY;
if (rot == 90 || rot == 180)
vx += pageInfo->currDx;
if (rot == 180 || rot == 270)
vy += pageInfo->currDy;
double left = rect->left, top = rect->top, right = rect->right, bottom = rect->bottom;
fz_matrix ctm = pdfEngine->viewctm(page, zoomReal() * 0.01, rot);
fz_point tp, p1 = {left, top}, p2 = {right, bottom};
tp = fz_transformpoint(ctm, p1);
left = tp.x - 0.5 + vx;
top = tp.y - 0.5 + vy;
tp = fz_transformpoint(ctm, p2);
right = tp.x + 0.5 + vx;
bottom = tp.y + 0.5 + vy;
if (top > bottom) {
double tmp = top;
top = bottom;
bottom = tmp;
}
rect->left = (int)floor(left);
rect->top = (int)floor(top);
rect->right = (int)ceil(right) + 5;
rect->bottom = (int)ceil(bottom) + 5;
int sx = 0, sy = 0;
if (rect->bottom > pageInfo->screenY + pageInfo->bitmapY + pageInfo->bitmapDy)
sy = rect->bottom - pageInfo->screenY - pageInfo->bitmapY - pageInfo->bitmapDy;
if (rect->left < pageInfo->screenX + pageInfo->bitmapX) {
sx = rect->left - pageInfo->screenX - pageInfo->bitmapX - 5;
if (sx + pageInfo->screenX + pageInfo->bitmapX < 0)
sx = -(pageInfo->screenX + pageInfo->bitmapX);
}
else
if (rect->right > pageInfo->screenX + pageInfo->bitmapDx) {
sx = rect->right - (pageInfo->screenX + pageInfo->bitmapDx) + 5;
}
if (sx != 0) {
scrollXBy(sx);
rect->left -= sx;
rect->right -= sx;
}
if (sy > 0) {
scrollYBy(sy, false);
rect->top -= sy;
rect->bottom -= sy;
}
}
void DisplayModel::rebuildLinks()
{
int count = pdfEngine->linkCount();
assert(count > _linksCount);
free(_links);
_links = (PdfLink*)malloc(count * sizeof(PdfLink));
_linksCount = count;
pdfEngine->fillPdfLinks(_links, _linksCount);
recalcLinksCanvasPos();
}
int DisplayModel::getLinkCount()
{
/* TODO: let's hope it's not too expensive. An alternative would be
to update link count only when it could have changed i.e. after
loading a page */
int count = pdfEngine->linkCount();
if (count != _linksCount)
{
assert(count > _linksCount);
rebuildLinks();
}
return count;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -