private int loadPage(final int userPage, final int nbOfPartsLoadable) {

        // Finds the document page associated with the given userPage
        int documentPage = userPage;
        if (filteredUserPages != null) {
            if (userPage < 0 || userPage >= filteredUserPages.length) {
                return 0;
            } else {
                documentPage = filteredUserPages[userPage];
            }
        }
        final int documentPageFinal = documentPage;
        if (documentPage < 0 || userPage >= documentPageCount) {
            return 0;
        }

        // Render thumbnail of the page
        if (!cacheManager.containsThumbnail(userPage, documentPage, //
                (int) (optimalPageWidth * Constants.THUMBNAIL_RATIO), //
                (int) (optimalPageHeight * Constants.THUMBNAIL_RATIO), //
                new RectF(0, 0, 1, 1))) {
            renderingAsyncTask.addRenderingTask(userPage, documentPage, //
                    (int) (optimalPageWidth * Constants.THUMBNAIL_RATIO), //
                    (int) (optimalPageHeight * Constants.THUMBNAIL_RATIO), //
                    new RectF(0, 0, 1, 1), true, 0);
        }

        // When we want to render a 256x256 bloc, we also need to provide
        // the bounds (left, top, right, bottom) of the rendered part in
        // the PDF page. These four coordinates are ratios (0 -> 1), where
        // (0,0) is the top left corner of the PDF page, and (1,1) is the
        // bottom right corner.
        float ratioX = 1f / (float) optimalPageWidth;
        float ratioY = 1f / (float) optimalPageHeight;
        final float partHeight = (Constants.PART_SIZE * ratioY) / zoom;
        final float partWidth = (Constants.PART_SIZE * ratioX) / zoom;
        final int nbRows = (int) Math.ceil(1f / partHeight);
        final int nbCols = (int) Math.ceil(1f / partWidth);
        final float pageRelativePartWidth = 1f / (float) nbCols;
        final float pageRelativePartHeight = 1f / (float) nbRows;

        // To improve user experience, we need to start displaying the
        // 256x256 blocs with the middle of the screen. Imagine the cut
        // page as a grid. This part calculates which cell of this grid
        // is currently in the middle of the screen, given the current
        // zoom level and the offsets.
        float middleOfScreenX = (-currentXOffset + getWidth() / 2);
        float middleOfScreenY = (-currentYOffset + getHeight() / 2);
        float middleOfScreenPageX;
        float middleOfScreenPageY;
        if (!swipeVertical) {
        	middleOfScreenPageX = middleOfScreenX - userPage * toCurrentScale(optimalPageWidth);
        	middleOfScreenPageY = middleOfScreenY;
        } else {
        	middleOfScreenPageY = middleOfScreenY - userPage * toCurrentScale(optimalPageHeight);
        	middleOfScreenPageX = middleOfScreenX;
        }
        float middleOfScreenPageXRatio = middleOfScreenPageX / toCurrentScale(optimalPageWidth);
        float middleOfScreenPageYRatio = middleOfScreenPageY / toCurrentScale(optimalPageHeight);
        int startingRow = (int) (middleOfScreenPageYRatio * nbRows);
        int startingCol = (int) (middleOfScreenPageXRatio * nbCols);

        // Avoid outside values
        startingRow = NumberUtils.limit(startingRow, 0, nbRows);
        startingCol = NumberUtils.limit(startingCol, 0, nbCols);

        // Prepare the loop listener
        class SpiralLoopListenerImpl implements SpiralLoopManager.SpiralLoopListener {
            int nbItemTreated = 0;

            @Override
            public boolean onLoop(int row, int col) {

                // Create relative page bounds
                float relX = pageRelativePartWidth * col;
                float relY = pageRelativePartHeight * row;
                float relWidth = pageRelativePartWidth;
                float relHeight = pageRelativePartHeight;

                // Adjust width and height to
                // avoid being outside the page
                float renderWidth = Constants.PART_SIZE / relWidth;
                float renderHeight = Constants.PART_SIZE / relHeight;
                if (relX + relWidth > 1) {
                    relWidth = 1 - relX;
                }
                if (relY + relHeight > 1) {
                    relHeight = 1 - relY;
                }
                renderWidth *= relWidth;
                renderHeight *= relHeight;
                RectF pageRelativeBounds = new RectF(relX, relY, relX + relWidth, relY + relHeight);

                if (renderWidth != 0 && renderHeight != 0) {

                    // Check it the calculated part is already contained in the Cache
                    // If it is, this call will insure the part will go to the right
                    // place in the cache and won't be deleted if the cache need space.
                    if (!cacheManager.upPartIfContained(userPage, documentPageFinal, //
                            renderWidth, renderHeight, pageRelativeBounds, nbItemTreated)) {

                        // If not already in cache, register the rendering
                        // task for further execution.
                        renderingAsyncTask.addRenderingTask(userPage, documentPageFinal, //
                                renderWidth, renderHeight, pageRelativeBounds, false, nbItemTreated);
                    }

                }

                nbItemTreated++;
                if (nbItemTreated >= nbOfPartsLoadable) {
                    // Return false to stop the loop
                    return false;
                }
                return true;
            }
        }

        // Starts the loop
        SpiralLoopListenerImpl spiralLoopListener;
        new SpiralLoopManager(spiralLoopListener = new SpiralLoopListenerImpl())//
                .startLoop(nbRows, nbCols, startingRow, startingCol);

        return spiralLoopListener.nbItemTreated;
    }
private int loadPage ( final int userPage , final int nbOfPartsLoadable ) { int documentPage = userPage ; if ( filteredUserPages != null ) { if ( userPage < 0 || userPage >= filteredUserPages . length ) { return 0 ; } else { documentPage = filteredUserPages [ userPage ] ; } } final int documentPageFinal = documentPage ; if ( documentPage < 0 || userPage >= documentPageCount ) { return 0 ; } if ( ! cacheManager . containsThumbnail ( userPage , documentPage , ( int ) ( optimalPageWidth * Constants . THUMBNAIL_RATIO ) , ( int ) ( optimalPageHeight * Constants . THUMBNAIL_RATIO ) , new RectF ( 0 , 0 , 1 , 1 ) ) ) { renderingAsyncTask . addRenderingTask ( userPage , documentPage , ( int ) ( optimalPageWidth * Constants . THUMBNAIL_RATIO ) , ( int ) ( optimalPageHeight * Constants . THUMBNAIL_RATIO ) , new RectF ( 0 , 0 , 1 , 1 ) , true , 0 ) ; } float ratioX = 1f / ( float ) optimalPageWidth ; float ratioY = 1f / ( float ) optimalPageHeight ; final float partHeight = ( Constants . PART_SIZE * ratioY ) / zoom ; final float partWidth = ( Constants . PART_SIZE * ratioX ) / zoom ; final int nbRows = ( int ) Math . ceil ( 1f / partHeight ) ; final int nbCols = ( int ) Math . ceil ( 1f / partWidth ) ; final float pageRelativePartWidth = 1f / ( float ) nbCols ; final float pageRelativePartHeight = 1f / ( float ) nbRows ; float middleOfScreenX = ( - currentXOffset + getWidth ( ) / 2 ) ; float middleOfScreenY = ( - currentYOffset + getHeight ( ) / 2 ) ; float middleOfScreenPageX ; float middleOfScreenPageY ; if ( ! swipeVertical ) { middleOfScreenPageX = middleOfScreenX - userPage * toCurrentScale ( optimalPageWidth ) ; middleOfScreenPageY = middleOfScreenY ; } else { middleOfScreenPageY = middleOfScreenY - userPage * toCurrentScale ( optimalPageHeight ) ; middleOfScreenPageX = middleOfScreenX ; } float middleOfScreenPageXRatio = middleOfScreenPageX / toCurrentScale ( optimalPageWidth ) ; float middleOfScreenPageYRatio = middleOfScreenPageY / toCurrentScale ( optimalPageHeight ) ; int startingRow = ( int ) ( middleOfScreenPageYRatio * nbRows ) ; int startingCol = ( int ) ( middleOfScreenPageXRatio * nbCols ) ; startingRow = NumberUtils . limit ( startingRow , 0 , nbRows ) ; startingCol = NumberUtils . limit ( startingCol , 0 , nbCols ) ; class SpiralLoopListenerImpl implements SpiralLoopManager . SpiralLoopListener { int nbItemTreated = 0 ; @ Override public boolean onLoop ( int row , int col ) { float relX = pageRelativePartWidth * col ; float relY = pageRelativePartHeight * row ; float relWidth = pageRelativePartWidth ; float relHeight = pageRelativePartHeight ; float renderWidth = Constants . PART_SIZE / relWidth ; float renderHeight = Constants . PART_SIZE / relHeight ; if ( relX + relWidth > 1 ) { relWidth = 1 - relX ; } if ( relY + relHeight > 1 ) { relHeight = 1 - relY ; } renderWidth *= relWidth ; renderHeight *= relHeight ; RectF pageRelativeBounds = new RectF ( relX , relY , relX + relWidth , relY + relHeight ) ; if ( renderWidth != 0 && renderHeight != 0 ) { if ( ! cacheManager . upPartIfContained ( userPage , documentPageFinal , renderWidth , renderHeight , pageRelativeBounds , nbItemTreated ) ) { renderingAsyncTask . addRenderingTask ( userPage , documentPageFinal , renderWidth , renderHeight , pageRelativeBounds , false , nbItemTreated ) ; } } nbItemTreated ++ ; if ( nbItemTreated >= nbOfPartsLoadable ) { return false ; } return true ; } } SpiralLoopListenerImpl spiralLoopListener ; new SpiralLoopManager ( spiralLoopListener = new SpiralLoopListenerImpl ( ) ) . startLoop ( nbRows , nbCols , startingRow , startingCol ) ; return spiralLoopListener . nbItemTreated ; }
Render a page, creating 1 to <i>nbOfPartsLoadable</i> page parts. <br><br>
<p/>
This is one of the trickiest method of this library. It finds
the DocumentPage associated with the given UserPage, loads its
thumbnail, cut this page into 256x256 blocs considering the
current zoom level, calculate the bloc containing the center of
the screen, and start loading these parts in a spiral {@link SpiralLoopManager},
only if the given part is not already in the Cache, in which case it
moves the part up in the cache.
@param userPage          The user page to load.
@param nbOfPartsLoadable Maximum number of parts it can load.
@return The number of parts loaded.