⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 displaymodel.cc.svn-base

📁 SumatraPDF是一款小型开源的pdf阅读工具。虽然玲珑小巧(只有800多KB)
💻 SVN-BASE
📖 第 1 页 / 共 4 页
字号:
    newPageNo = currentPageNo();
    if (newPageNo != currPageNo)
        pageChanged();
    repaintDisplay(true);
}

void DisplayModel::goToPage(int pageNo, int scrollY, int scrollX)
{
    assert(validPageNo(pageNo));
    if (!validPageNo(pageNo))
        return;

    /* in facing mode only start at odd pages (odd because page
       numbering starts with 1, so odd is really an even page) */
    if (displayModeFacing(displayMode()))
      pageNo = ((pageNo-1) & ~1) + 1;

    if (!displayModeContinuous(displayMode())) {
        /* in single page mode going to another page involves recalculating
           the size of canvas */
        changeStartPage(pageNo);
    }
    //DBG_OUT("DisplayModel::goToPage(pageNo=%d, scrollY=%d)\n", pageNo, scrollY);
    if (-1 != scrollX)
        areaOffset.x = (double)scrollX;
    PdfPageInfo * pageInfo = getPageInfo(pageNo);

    /* Hack: if an image is smaller in Y axis than the draw area, then we center
       the image by setting pageInfo->currPosY in RecalcPagesInfo. So we shouldn't
       scroll (adjust areaOffset.y) there because it defeats the purpose.
       TODO: is there a better way of y-centering?
       TODO: it probably doesn't work in continuous mode (but that's a corner
             case, I hope) */
    if (!displayModeContinuous(displayMode()))
        areaOffset.y = (double)scrollY;
    else
        areaOffset.y = pageInfo->currPosY - PADDING_PAGE_BORDER_TOP + (double)scrollY;
    /* TODO: prevent scrolling too far */

    recalcVisibleParts();
    recalcLinksCanvasPos();
    renderVisibleParts();
    setScrollbarsState();
    pageChanged();
    repaintDisplay(true);
}


void DisplayModel::changeDisplayMode(DisplayMode displayMode)
{
    if (_displayMode == displayMode)
        return;

    _displayMode = displayMode;
    int currPageNo = currentPageNo();
    if (displayModeContinuous(displayMode)) {
        /* mark all pages as shown but not yet visible. The equivalent code
           for non-continuous mode is in DisplayModel::changeStartPage() called
           from DisplayModel::goToPage() */
        for (int pageNo = 1; pageNo <= pageCount(); pageNo++) {
            PdfPageInfo *pageInfo = &(_pagesInfo[pageNo-1]);
            pageInfo->shown = true;
            pageInfo->visible = false;
        }
        relayout(zoomVirtual(), rotation());
    }
    goToPage(currPageNo, 0);
}

/* given 'columns' and an absolute 'pageNo', return the number of the first
   page in a row to which a 'pageNo' belongs e.g. if 'columns' is 2 and we
   have 5 pages in 3 rows:
   (1,2)
   (3,4)
   (5)
   then, we return 1 for pages (1,2), 3 for (3,4) and 5 for (5).
   This is 1-based index, not 0-based. */
static int FirstPageInARowNo(int pageNo, int columns)
{
    int row = ((pageNo - 1) / columns); /* 0-based row number */
    int firstPageNo = row * columns + 1; /* 1-based page in a row */
    return firstPageNo;
}

/* In continuous mode just scrolls to the next page. In single page mode
   rebuilds the display model for the next page.
   Returns true if advanced to the next page or false if couldn't advance
   (e.g. because already was at the last page) */
bool DisplayModel::goToNextPage(int scrollY)
{
    int columns = columnsFromDisplayMode(displayMode());
    int currPageNo = currentPageNo();
    int firstPageInCurrRow = FirstPageInARowNo(currPageNo, columns);
    int newPageNo = currPageNo + columns;
    int firstPageInNewRow = FirstPageInARowNo(newPageNo, columns);

//    DBG_OUT("DisplayModel::goToNextPage(scrollY=%d), currPageNo=%d, firstPageInNewRow=%d\n", scrollY, currPageNo, firstPageInNewRow);
    if ((firstPageInNewRow > pageCount()) || (firstPageInCurrRow == firstPageInNewRow)) {
        /* we're on a last row or after it, can't go any further */
        return FALSE;
    }
    goToPage(firstPageInNewRow, scrollY);
    return TRUE;
}

bool DisplayModel::goToPrevPage(int scrollY)
{
    int columns = columnsFromDisplayMode(displayMode());
    int currPageNo = currentPageNo();
    DBG_OUT("DisplayModel::goToPrevPage(scrollY=%d), currPageNo=%d\n", scrollY, currPageNo);
    if (currPageNo <= columns) {
        /* we're on a first page, can't go back */
        return FALSE;
    }
    goToPage(currPageNo - columns, scrollY);
    return TRUE;
}

bool DisplayModel::goToLastPage(void)
{
    DBG_OUT("DisplayModel::goToLastPage()\n");

    int columns = columnsFromDisplayMode(displayMode());
    int currPageNo = currentPageNo();
    int firstPageInLastRow = FirstPageInARowNo(pageCount(), columns);

    if (currPageNo != firstPageInLastRow) { /* are we on the last page already ? */
        goToPage(firstPageInLastRow, 0);
        return TRUE;
    }
    return FALSE;
}

bool DisplayModel::goToFirstPage(void)
{
    DBG_OUT("DisplayModel::goToFirstPage()\n");

    if (displayModeContinuous(displayMode())) {
        if (0 == areaOffset.y) {
            return FALSE;
        }
    } else {
        assert(pageShown(_startPage));
        if (1 == _startPage) {
            /* we're on a first page already */
            return FALSE;
        }
    }
    goToPage(1, 0);
    return TRUE;
}

void DisplayModel::scrollXTo(int xOff)
{
    DBG_OUT("DisplayModel::scrollXTo(xOff=%d)\n", xOff);
    areaOffset.x = (double)xOff;
    recalcVisibleParts();
    recalcLinksCanvasPos();
    setScrollbarsState();
    repaintDisplay(false);
}

void DisplayModel::scrollXBy(int dx)
{
    DBG_OUT("DisplayModel::scrollXBy(dx=%d)\n", dx);

    double maxX = _canvasSize.dx() - drawAreaSize.dx();
    assert(maxX >= 0.0);
    double prevX = areaOffset.x;
    double newX = prevX + (double)dx;
    if (newX < 0.0)
        newX = 0.0;
    else
        if (newX > maxX)
            newX = maxX;

    if (newX == prevX)
        return;

    scrollXTo((int)newX);
}

void DisplayModel::scrollYTo(int yOff)
{
    DBG_OUT("DisplayModel::scrollYTo(yOff=%d)\n", yOff);

    int currPageNo = currentPageNo();
    areaOffset.y = (double)yOff;
    recalcVisibleParts();
    recalcLinksCanvasPos();
    renderVisibleParts();

    int newPageNo = currentPageNo();
    if (newPageNo != currPageNo)
        pageChanged();
    repaintDisplay(false);
}

/* Scroll the doc in y-axis by 'dy'. If 'changePage' is TRUE, automatically
   switch to prev/next page in non-continuous mode if we scroll past the edges
   of current page */
void DisplayModel::scrollYBy(int dy, bool changePage)
{
    PdfPageInfo *   pageInfo;
    int             currYOff = (int)areaOffset.y;
    int             newPageNo;
    int             currPageNo;

    DBG_OUT("DisplayModel::scrollYBy(dy=%d, changePage=%d)\n", dy, (int)changePage);
    assert(0 != dy);
    if (0 == dy) return;

    int newYOff = currYOff;

    if (!displayModeContinuous(displayMode()) && changePage) {
        if ((dy < 0) && (0 == currYOff)) {
            if (_startPage > 1) {
                newPageNo = _startPage-1;
                assert(validPageNo(newPageNo));
                pageInfo = getPageInfo(newPageNo);
                newYOff = (int)pageInfo->currDy - drawAreaSize.dyI();
                if (newYOff < 0)
                    newYOff = 0; /* TODO: center instead? */
                goToPrevPage(newYOff);
                return;
            }
        }

        /* see if we have to change page when scrolling forward */
        if ((dy > 0) && (_startPage < pageCount())) {
            if ((int)areaOffset.y + drawAreaSize.dyI() >= _canvasSize.dyI()) {
                goToNextPage(0);
                return;
            }
        }
    }

    newYOff += dy;
    if (newYOff < 0) {
        newYOff = 0;
    } else if (newYOff + drawAreaSize.dyI() > _canvasSize.dyI()) {
        newYOff = _canvasSize.dyI() - drawAreaSize.dyI();
    }

    if (newYOff == currYOff)
        return;

    currPageNo = currentPageNo();
    areaOffset.y = (double)newYOff;
    recalcVisibleParts();
    recalcLinksCanvasPos();
    renderVisibleParts();
    setScrollbarsState();
    newPageNo = currentPageNo();
    if (newPageNo != currPageNo)
        pageChanged();
    repaintDisplay(false);
}

void DisplayModel::scrollYByAreaDy(bool forward, bool changePage)
{
    int toScroll = drawAreaSize.dyI();
    if (forward)
        scrollYBy(toScroll, changePage);
    else
        scrollYBy(-toScroll, changePage);
}

void DisplayModel::zoomTo(double zoomVirtual)
{
    //DBG_OUT("DisplayModel::zoomTo() zoomVirtual=%.6f\n", _zoomVirtual);
    int currPageNo = currentPageNo();
    relayout(zoomVirtual, rotation());
    goToPage(currPageNo, 0);
}

void DisplayModel::zoomBy(double zoomFactor)
{
    double newZoom = _zoomReal * zoomFactor;
    //DBG_OUT("DisplayModel::zoomBy() zoomReal=%.6f, zoomFactor=%.2f, newZoom=%.2f\n", dm->zoomReal, zoomFactor, newZoom);
    if (newZoom > ZOOM_MAX)
        return;
    if (newZoom < ZOOM_MIN)
        return;
    zoomTo(newZoom);
}

void DisplayModel::rotateBy(int newRotation)
{
    normalizeRotation(&newRotation);
    assert(0 != newRotation);
    if (0 == newRotation)
        return;
    assert(validRotation(newRotation));
    if (!validRotation(newRotation))
        return;

    newRotation += rotation();
    normalizeRotation(&newRotation);
    assert(validRotation(newRotation));
    if (!validRotation(newRotation))
        return;

    int currPageNo = currentPageNo();
    relayout(zoomVirtual(), newRotation);
    goToPage(currPageNo, 0);
}

void DisplayModel::showNormalCursor(void)
{
    SetCursor(LoadCursor(NULL, IDC_ARROW));
}

void DisplayModel::showBusyCursor(void)
{
    // TODO: can I set it per-window only?
    SetCursor(LoadCursor(NULL, IDC_WAIT));
}

static inline void InitCacheMutext() {
    if (!cacheMutexInitialized) {
        InitializeCriticalSection(&cacheMutex);
        cacheMutexInitialized = 1;
    }
}

void LockCache(void) {
    InitCacheMutext();
    EnterCriticalSection(&cacheMutex);
}

void UnlockCache(void) {
    LeaveCriticalSection(&cacheMutex);
}

static void BitmapCacheEntry_Free(BitmapCacheEntry *entry) {
    assert(entry);
    if (!entry) return;
    delete entry->bitmap;
    free((void*)entry);
}

void BitmapCache_FreeAll(void) {
    LockCache();
    for (int i=0; i < gBitmapCacheCount; i++) {
        BitmapCacheEntry_Free(gBitmapCache[i]);
        gBitmapCache[i] = NULL;
    }
    gBitmapCacheCount = 0;
    UnlockCache();
}

/* Free all bitmaps in the cache that are not visible. Returns true if freed
   at least one item. */
bool BitmapCache_FreeNotVisible(void) {
    LockCache();
    bool freedSomething = false;
    int cacheCount = gBitmapCacheCount;
    int curPos = 0;
    for (int i = 0; i < cacheCount; i++) {
        BitmapCacheEntry* entry = gBitmapCache[i];
        bool shouldFree = !entry->dm->pageVisibleNearby(entry->pageNo);
         if (shouldFree) {
            if (!freedSomething)
                DBG_OUT("BitmapCache_FreeNotVisible() ");
            DBG_OUT("freed %d ", entry->pageNo);
            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;
}

static bool BitmapCache_FreePage(DisplayModel *dm, int pageNo) {
    LockCache();
    int cacheCount = gBitmapCacheCount;
    bool freedSomething = false;
    int curPos = 0;
    for (int i = 0; i < cacheCount; i++) {
        bool shouldFree = (gBitmapCache[i]->dm == dm) && (gBitmapCache[i]->pageNo == pageNo);
        if (shouldFree) {
            if (!freedSomething)
                DBG_OUT("BitmapCache_FreePage() ");
            DBG_OUT("freed %d ", gBitmapCache[i]->pageNo);
            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;
}

/* Free all bitmaps cached for a given <dm>. Returns TRUE if freed
   at least one item. */
bool BitmapCache_FreeForDisplayModel(DisplayModel *dm) {
    LockCache();
    int cacheCount = gBitmapCacheCount;
    bool freedSomething = false;
    int curPos = 0;
    for (int i = 0; i < cacheCount; i++) {
        bool shouldFree = (gBitmapCache[i]->dm == dm);
        if (shouldFree) {
            if (!freedSomething)
                DBG_OUT("BitmapCache_FreeForDisplayModel() ");
            DBG_OUT("freed %d ", gBitmapCache[i]->pageNo);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -