12961769ea94f69c191a2dd785b2504666c7292d0Svetoslav/*
22961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * Copyright (C) 2014 The Android Open Source Project
32961769ea94f69c191a2dd785b2504666c7292d0Svetoslav *
42961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * Licensed under the Apache License, Version 2.0 (the "License");
52961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * you may not use this file except in compliance with the License.
62961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * You may obtain a copy of the License at
72961769ea94f69c191a2dd785b2504666c7292d0Svetoslav *
82961769ea94f69c191a2dd785b2504666c7292d0Svetoslav *      http://www.apache.org/licenses/LICENSE-2.0
92961769ea94f69c191a2dd785b2504666c7292d0Svetoslav *
102961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * Unless required by applicable law or agreed to in writing, software
112961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * distributed under the License is distributed on an "AS IS" BASIS,
122961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
132961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * See the License for the specific language governing permissions and
142961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * limitations under the License.
152961769ea94f69c191a2dd785b2504666c7292d0Svetoslav */
162961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
172961769ea94f69c191a2dd785b2504666c7292d0Svetoslavpackage android.graphics.pdf;
182961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
192961769ea94f69c191a2dd785b2504666c7292d0Svetoslavimport android.annotation.IntDef;
202961769ea94f69c191a2dd785b2504666c7292d0Svetoslavimport android.annotation.NonNull;
212961769ea94f69c191a2dd785b2504666c7292d0Svetoslavimport android.annotation.Nullable;
222961769ea94f69c191a2dd785b2504666c7292d0Svetoslavimport android.graphics.Bitmap;
232961769ea94f69c191a2dd785b2504666c7292d0Svetoslavimport android.graphics.Bitmap.Config;
242961769ea94f69c191a2dd785b2504666c7292d0Svetoslavimport android.graphics.Matrix;
252961769ea94f69c191a2dd785b2504666c7292d0Svetoslavimport android.graphics.Point;
262961769ea94f69c191a2dd785b2504666c7292d0Svetoslavimport android.graphics.Rect;
272961769ea94f69c191a2dd785b2504666c7292d0Svetoslavimport android.os.ParcelFileDescriptor;
282961769ea94f69c191a2dd785b2504666c7292d0Svetoslavimport android.system.ErrnoException;
292961769ea94f69c191a2dd785b2504666c7292d0Svetoslavimport android.system.OsConstants;
30f126e21f433b36aa4c71f1a621d06b56206df440Philip P. Moltmannimport com.android.internal.util.Preconditions;
312961769ea94f69c191a2dd785b2504666c7292d0Svetoslavimport dalvik.system.CloseGuard;
322961769ea94f69c191a2dd785b2504666c7292d0Svetoslavimport libcore.io.Libcore;
332961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
342961769ea94f69c191a2dd785b2504666c7292d0Svetoslavimport java.io.IOException;
352961769ea94f69c191a2dd785b2504666c7292d0Svetoslavimport java.lang.annotation.Retention;
362961769ea94f69c191a2dd785b2504666c7292d0Svetoslavimport java.lang.annotation.RetentionPolicy;
372961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
382961769ea94f69c191a2dd785b2504666c7292d0Svetoslav/**
392961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * <p>
402961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * This class enables rendering a PDF document. This class is not thread safe.
412961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * </p>
422961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * <p>
432961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * If you want to render a PDF, you create a renderer and for every page you want
442961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * to render, you open the page, render it, and close the page. After you are done
452961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * with rendering, you close the renderer. After the renderer is closed it should not
462961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * be used anymore. Note that the pages are rendered one by one, i.e. you can have
472961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * only a single page opened at any given time.
482961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * </p>
492961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * <p>
502961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * A typical use of the APIs to render a PDF looks like this:
512961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * </p>
522961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * <pre>
532961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * // create a new renderer
542961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * PdfRenderer renderer = new PdfRenderer(getSeekableFileDescriptor());
552961769ea94f69c191a2dd785b2504666c7292d0Svetoslav *
562961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * // let us just render all pages
572961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * final int pageCount = renderer.getPageCount();
582961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * for (int i = 0; i < pageCount; i++) {
592961769ea94f69c191a2dd785b2504666c7292d0Svetoslav *     Page page = renderer.openPage(i);
602961769ea94f69c191a2dd785b2504666c7292d0Svetoslav *
612961769ea94f69c191a2dd785b2504666c7292d0Svetoslav *     // say we render for showing on the screen
6295b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav *     page.render(mBitmap, null, null, Page.RENDER_MODE_FOR_DISPLAY);
632961769ea94f69c191a2dd785b2504666c7292d0Svetoslav *
642961769ea94f69c191a2dd785b2504666c7292d0Svetoslav *     // do stuff with the bitmap
652961769ea94f69c191a2dd785b2504666c7292d0Svetoslav *
6695b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav *     // close the page
6795b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav *     page.close();
682961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * }
692961769ea94f69c191a2dd785b2504666c7292d0Svetoslav *
702961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * // close the renderer
712961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * renderer.close();
722961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * </pre>
732961769ea94f69c191a2dd785b2504666c7292d0Svetoslav *
74525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov * <h3>Print preview and print output</h3>
75525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov * <p>
76525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov * If you are using this class to rasterize a PDF for printing or show a print
77525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov * preview, it is recommended that you respect the following contract in order
78525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov * to provide a consistent user experience when seeing a preview and printing,
79525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov * i.e. the user sees a preview that is the same as the printout.
80525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov * </p>
81525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov * <ul>
82525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov * <li>
83525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov * Respect the property whether the document would like to be scaled for printing
84525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov * as per {@link #shouldScaleForPrinting()}.
85525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov * </li>
86525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov * <li>
87525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov * When scaling a document for printing the aspect ratio should be preserved.
88525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov * </li>
89525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov * <li>
90525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov * Do not inset the content with any margins from the {@link android.print.PrintAttributes}
91525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov * as the application is responsible to render it such that the margins are respected.
92525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov * </li>
93525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov * <li>
94525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov * If document page size is greater than the printed media size the content should
95525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov * be anchored to the upper left corner of the page for left-to-right locales and
96525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov * top right corner for right-to-left locales.
97525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov * </li>
98525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov * </ul>
99525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov *
1002961769ea94f69c191a2dd785b2504666c7292d0Svetoslav * @see #close()
1012961769ea94f69c191a2dd785b2504666c7292d0Svetoslav */
1022961769ea94f69c191a2dd785b2504666c7292d0Svetoslavpublic final class PdfRenderer implements AutoCloseable {
1030768a7dc450caf4c873c5b0883a75135536e1546Philip P. Moltmann    /**
1040768a7dc450caf4c873c5b0883a75135536e1546Philip P. Moltmann     * Any call the native pdfium code has to be single threaded as the library does not support
1050768a7dc450caf4c873c5b0883a75135536e1546Philip P. Moltmann     * parallel use.
1060768a7dc450caf4c873c5b0883a75135536e1546Philip P. Moltmann     */
1070768a7dc450caf4c873c5b0883a75135536e1546Philip P. Moltmann    final static Object sPdfiumLock = new Object();
1080768a7dc450caf4c873c5b0883a75135536e1546Philip P. Moltmann
1092961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    private final CloseGuard mCloseGuard = CloseGuard.get();
1102961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
1112961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    private final Point mTempPoint = new Point();
1122961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
1132961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    private final long mNativeDocument;
1142961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
1152961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    private final int mPageCount;
1162961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
1172961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    private ParcelFileDescriptor mInput;
1182961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
1192961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    private Page mCurrentPage;
1202961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
1212961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    /** @hide */
1222961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    @IntDef({
1232961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        Page.RENDER_MODE_FOR_DISPLAY,
1242961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        Page.RENDER_MODE_FOR_PRINT
1252961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    })
1262961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    @Retention(RetentionPolicy.SOURCE)
1272961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    public @interface RenderMode {}
1282961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
1292961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    /**
1302961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     * Creates a new instance.
1312961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     * <p>
1322961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     * <strong>Note:</strong> The provided file descriptor must be <strong>seekable</strong>,
1332961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     * i.e. its data being randomly accessed, e.g. pointing to a file.
1342961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     * </p>
1352961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     * <p>
1362961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     * <strong>Note:</strong> This class takes ownership of the passed in file descriptor
1372961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     * and is responsible for closing it when the renderer is closed.
1382961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     * </p>
1393d0d141710d23b0f08c865100b4d55b4c2976486Philip P. Moltmann     * <p>
1403d0d141710d23b0f08c865100b4d55b4c2976486Philip P. Moltmann     * If the file is from an untrusted source it is recommended to run the renderer in a separate,
1413d0d141710d23b0f08c865100b4d55b4c2976486Philip P. Moltmann     * isolated process with minimal permissions to limit the impact of security exploits.
1423d0d141710d23b0f08c865100b4d55b4c2976486Philip P. Moltmann     * </p>
1432961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     *
1442961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     * @param input Seekable file descriptor to read from.
145fce84f035c35606c5707e735f503f7bdcfd5b2a1Svet Ganov     *
146fce84f035c35606c5707e735f503f7bdcfd5b2a1Svet Ganov     * @throws java.io.IOException If an error occurs while reading the file.
147fce84f035c35606c5707e735f503f7bdcfd5b2a1Svet Ganov     * @throws java.lang.SecurityException If the file requires a password or
148fce84f035c35606c5707e735f503f7bdcfd5b2a1Svet Ganov     *         the security scheme is not supported.
1492961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     */
1502961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    public PdfRenderer(@NonNull ParcelFileDescriptor input) throws IOException {
1512961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        if (input == null) {
1522961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            throw new NullPointerException("input cannot be null");
1532961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        }
1542961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
1552961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        final long size;
1562961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        try {
1572961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            Libcore.os.lseek(input.getFileDescriptor(), 0, OsConstants.SEEK_SET);
1582961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            size = Libcore.os.fstat(input.getFileDescriptor()).st_size;
1592961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        } catch (ErrnoException ee) {
1602961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            throw new IllegalArgumentException("file descriptor not seekable");
1612961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        }
1622961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
1632961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        mInput = input;
1640768a7dc450caf4c873c5b0883a75135536e1546Philip P. Moltmann
1650768a7dc450caf4c873c5b0883a75135536e1546Philip P. Moltmann        synchronized (sPdfiumLock) {
1660768a7dc450caf4c873c5b0883a75135536e1546Philip P. Moltmann            mNativeDocument = nativeCreate(mInput.getFd(), size);
167c859cd068b3a63be962a201db46f487d13be56daPhilip P. Moltmann            try {
168c859cd068b3a63be962a201db46f487d13be56daPhilip P. Moltmann                mPageCount = nativeGetPageCount(mNativeDocument);
169c859cd068b3a63be962a201db46f487d13be56daPhilip P. Moltmann            } catch (Throwable t) {
170c859cd068b3a63be962a201db46f487d13be56daPhilip P. Moltmann                nativeClose(mNativeDocument);
171c859cd068b3a63be962a201db46f487d13be56daPhilip P. Moltmann                throw t;
172c859cd068b3a63be962a201db46f487d13be56daPhilip P. Moltmann            }
1730768a7dc450caf4c873c5b0883a75135536e1546Philip P. Moltmann        }
1740768a7dc450caf4c873c5b0883a75135536e1546Philip P. Moltmann
1752961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        mCloseGuard.open("close");
1762961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    }
1772961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
1782961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    /**
1792961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     * Closes this renderer. You should not use this instance
1802961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     * after this method is called.
1812961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     */
1822961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    public void close() {
1832961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        throwIfClosed();
1842961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        throwIfPageOpened();
1852961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        doClose();
1862961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    }
1872961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
1882961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    /**
1892961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     * Gets the number of pages in the document.
1902961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     *
1912961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     * @return The page count.
1922961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     */
1932961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    public int getPageCount() {
1942961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        throwIfClosed();
1952961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        return mPageCount;
1962961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    }
1972961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
1982961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    /**
1992961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     * Gets whether the document prefers to be scaled for printing.
2002961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     * You should take this info account if the document is rendered
2012961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     * for printing and the target media size differs from the page
2022961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     * size.
2032961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     *
2042961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     * @return If to scale the document.
2052961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     */
2062961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    public boolean shouldScaleForPrinting() {
2072961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        throwIfClosed();
2080768a7dc450caf4c873c5b0883a75135536e1546Philip P. Moltmann
2090768a7dc450caf4c873c5b0883a75135536e1546Philip P. Moltmann        synchronized (sPdfiumLock) {
2100768a7dc450caf4c873c5b0883a75135536e1546Philip P. Moltmann            return nativeScaleForPrinting(mNativeDocument);
2110768a7dc450caf4c873c5b0883a75135536e1546Philip P. Moltmann        }
2122961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    }
2132961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
2142961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    /**
2152961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     * Opens a page for rendering.
2162961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     *
2172961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     * @param index The page index.
2182961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     * @return A page that can be rendered.
2192961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     *
22095b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav     * @see android.graphics.pdf.PdfRenderer.Page#close() PdfRenderer.Page.close()
2212961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     */
2222961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    public Page openPage(int index) {
2232961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        throwIfClosed();
2242961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        throwIfPageOpened();
22513f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov        throwIfPageNotInDocument(index);
2262961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        mCurrentPage = new Page(index);
2272961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        return mCurrentPage;
2282961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    }
2292961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
2302961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    @Override
2312961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    protected void finalize() throws Throwable {
2322961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        try {
233492e9e851cadca62df84eaff1a3c1ba788492fbaNarayan Kamath            if (mCloseGuard != null) {
234492e9e851cadca62df84eaff1a3c1ba788492fbaNarayan Kamath                mCloseGuard.warnIfOpen();
235492e9e851cadca62df84eaff1a3c1ba788492fbaNarayan Kamath            }
236492e9e851cadca62df84eaff1a3c1ba788492fbaNarayan Kamath
2372961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            if (mInput != null) {
2382961769ea94f69c191a2dd785b2504666c7292d0Svetoslav                doClose();
2392961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            }
2402961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        } finally {
2412961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            super.finalize();
2422961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        }
2432961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    }
2442961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
2452961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    private void doClose() {
2462961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        if (mCurrentPage != null) {
2472961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            mCurrentPage.close();
2482961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        }
2490768a7dc450caf4c873c5b0883a75135536e1546Philip P. Moltmann        synchronized (sPdfiumLock) {
2500768a7dc450caf4c873c5b0883a75135536e1546Philip P. Moltmann            nativeClose(mNativeDocument);
2510768a7dc450caf4c873c5b0883a75135536e1546Philip P. Moltmann        }
2522961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        try {
2532961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            mInput.close();
2542961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        } catch (IOException ioe) {
2552961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            /* ignore - best effort */
2562961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        }
2572961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        mInput = null;
2582961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        mCloseGuard.close();
2592961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    }
2602961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
2612961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    private void throwIfClosed() {
2622961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        if (mInput == null) {
2632961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            throw new IllegalStateException("Already closed");
2642961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        }
2652961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    }
2662961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
2672961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    private void throwIfPageOpened() {
2682961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        if (mCurrentPage != null) {
2692961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            throw new IllegalStateException("Current page not closed");
2702961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        }
2712961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    }
2722961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
27313f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov    private void throwIfPageNotInDocument(int pageIndex) {
27462ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav        if (pageIndex < 0 || pageIndex >= mPageCount) {
27513f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov            throw new IllegalArgumentException("Invalid page index");
27613f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov        }
27713f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov    }
27813f542cabd635c55ade5442764cc4a3d2f7880eaSvet Ganov
2792961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    /**
2802961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     * This class represents a PDF document page for rendering.
2812961769ea94f69c191a2dd785b2504666c7292d0Svetoslav     */
28295b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav    public final class Page implements AutoCloseable {
28395b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav
28495b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav        private final CloseGuard mCloseGuard = CloseGuard.get();
2852961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
2862961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        /**
2872961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * Mode to render the content for display on a screen.
2882961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         */
2892961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        public static final int RENDER_MODE_FOR_DISPLAY = 1;
2902961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
2912961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        /**
2922961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * Mode to render the content for printing.
2932961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         */
2942961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        public static final int RENDER_MODE_FOR_PRINT = 2;
2952961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
2962961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        private final int mIndex;
2972961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        private final int mWidth;
2982961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        private final int mHeight;
2992961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
3002961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        private long mNativePage;
3012961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
3022961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        private Page(int index) {
3032961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            Point size = mTempPoint;
3040768a7dc450caf4c873c5b0883a75135536e1546Philip P. Moltmann            synchronized (sPdfiumLock) {
3050768a7dc450caf4c873c5b0883a75135536e1546Philip P. Moltmann                mNativePage = nativeOpenPageAndGetSize(mNativeDocument, index, size);
3060768a7dc450caf4c873c5b0883a75135536e1546Philip P. Moltmann            }
3072961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            mIndex = index;
3082961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            mWidth = size.x;
3092961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            mHeight = size.y;
31095b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav            mCloseGuard.open("close");
3112961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        }
3122961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
3132961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        /**
3142961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * Gets the page index.
3152961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         *
3162961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * @return The index.
3172961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         */
3182961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        public int getIndex() {
3192961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            return  mIndex;
3202961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        }
3212961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
3222961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        /**
3232961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * Gets the page width in points (1/72").
3242961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         *
3252961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * @return The width in points.
3262961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         */
3272961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        public int getWidth() {
3282961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            return mWidth;
3292961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        }
3302961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
3312961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        /**
3322961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * Gets the page height in points (1/72").
3332961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         *
3342961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * @return The height in points.
3352961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         */
3362961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        public int getHeight() {
3372961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            return mHeight;
3382961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        }
3392961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
3402961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        /**
3412961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * Renders a page to a bitmap.
3422961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * <p>
3432961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * You may optionally specify a rectangular clip in the bitmap bounds. No rendering
3442961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * outside the clip will be performed, hence it is your responsibility to initialize
3452961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * the bitmap outside the clip.
3462961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * </p>
3472961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * <p>
3482961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * You may optionally specify a matrix to transform the content from page coordinates
349525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov         * which are in points (1/72") to bitmap coordinates which are in pixels. If this
3502961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * matrix is not provided this method will apply a transformation that will fit the
35195b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav         * whole page to the destination clip if provided or the destination bitmap if no
3522961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * clip is provided.
3532961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * </p>
3542961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * <p>
3552961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * The clip and transformation are useful for implementing tile rendering where the
3562961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * destination bitmap contains a portion of the image, for example when zooming.
3572961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * Another useful application is for printing where the size of the bitmap holding
3582961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * the page is too large and a client can render the page in stripes.
3592961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * </p>
3602961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * <p>
3612961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * <strong>Note: </strong> The destination bitmap format must be
3622961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * {@link Config#ARGB_8888 ARGB}.
3632961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * </p>
3642961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * <p>
3652961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * <strong>Note: </strong> The optional transformation matrix must be affine as per
36695b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav         * {@link android.graphics.Matrix#isAffine() Matrix.isAffine()}. Hence, you can specify
36795b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav         * rotation, scaling, translation but not a perspective transformation.
3682961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * </p>
3692961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         *
3702961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * @param destination Destination bitmap to which to render.
3712961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * @param destClip Optional clip in the bitmap bounds.
3722961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * @param transform Optional transformation to apply when rendering.
3732961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * @param renderMode The render mode.
3742961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         *
3752961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * @see #RENDER_MODE_FOR_DISPLAY
3762961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         * @see #RENDER_MODE_FOR_PRINT
3772961769ea94f69c191a2dd785b2504666c7292d0Svetoslav         */
3782961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        public void render(@NonNull Bitmap destination, @Nullable Rect destClip,
3792961769ea94f69c191a2dd785b2504666c7292d0Svetoslav                           @Nullable Matrix transform, @RenderMode int renderMode) {
380f3f7cccccf0d8bbf04e19ada76b475f98d30f19cPhilip P. Moltmann            if (mNativePage == 0) {
381f3f7cccccf0d8bbf04e19ada76b475f98d30f19cPhilip P. Moltmann                throw new NullPointerException();
382f3f7cccccf0d8bbf04e19ada76b475f98d30f19cPhilip P. Moltmann            }
383c859cd068b3a63be962a201db46f487d13be56daPhilip P. Moltmann
384f126e21f433b36aa4c71f1a621d06b56206df440Philip P. Moltmann            destination = Preconditions.checkNotNull(destination, "bitmap null");
385f126e21f433b36aa4c71f1a621d06b56206df440Philip P. Moltmann
3862961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            if (destination.getConfig() != Config.ARGB_8888) {
3872961769ea94f69c191a2dd785b2504666c7292d0Svetoslav                throw new IllegalArgumentException("Unsupported pixel format");
3882961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            }
3892961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
3902961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            if (destClip != null) {
3912961769ea94f69c191a2dd785b2504666c7292d0Svetoslav                if (destClip.left < 0 || destClip.top < 0
3922961769ea94f69c191a2dd785b2504666c7292d0Svetoslav                        || destClip.right > destination.getWidth()
3932961769ea94f69c191a2dd785b2504666c7292d0Svetoslav                        || destClip.bottom > destination.getHeight()) {
3942961769ea94f69c191a2dd785b2504666c7292d0Svetoslav                    throw new IllegalArgumentException("destBounds not in destination");
3952961769ea94f69c191a2dd785b2504666c7292d0Svetoslav                }
3962961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            }
3972961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
3982961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            if (transform != null && !transform.isAffine()) {
3992961769ea94f69c191a2dd785b2504666c7292d0Svetoslav                 throw new IllegalArgumentException("transform not affine");
4002961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            }
4012961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
4022961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            if (renderMode != RENDER_MODE_FOR_PRINT && renderMode != RENDER_MODE_FOR_DISPLAY) {
4032961769ea94f69c191a2dd785b2504666c7292d0Svetoslav                throw new IllegalArgumentException("Unsupported render mode");
4042961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            }
4052961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
4062961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            if (renderMode == RENDER_MODE_FOR_PRINT && renderMode == RENDER_MODE_FOR_DISPLAY) {
4072961769ea94f69c191a2dd785b2504666c7292d0Svetoslav                throw new IllegalArgumentException("Only single render mode supported");
4082961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            }
4092961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
4102961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            final int contentLeft = (destClip != null) ? destClip.left : 0;
4112961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            final int contentTop = (destClip != null) ? destClip.top : 0;
4122961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            final int contentRight = (destClip != null) ? destClip.right
4132961769ea94f69c191a2dd785b2504666c7292d0Svetoslav                    : destination.getWidth();
4142961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            final int contentBottom = (destClip != null) ? destClip.bottom
4152961769ea94f69c191a2dd785b2504666c7292d0Svetoslav                    : destination.getHeight();
4162961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
417d55f20d3018d3328d9e26c971b814dfcb61aa7b2Philip P. Moltmann            // If transform is not set, stretch page to whole clipped area
418d55f20d3018d3328d9e26c971b814dfcb61aa7b2Philip P. Moltmann            if (transform == null) {
419d55f20d3018d3328d9e26c971b814dfcb61aa7b2Philip P. Moltmann                int clipWidth = contentRight - contentLeft;
420d55f20d3018d3328d9e26c971b814dfcb61aa7b2Philip P. Moltmann                int clipHeight = contentBottom - contentTop;
421d55f20d3018d3328d9e26c971b814dfcb61aa7b2Philip P. Moltmann
422d55f20d3018d3328d9e26c971b814dfcb61aa7b2Philip P. Moltmann                transform = new Matrix();
423d55f20d3018d3328d9e26c971b814dfcb61aa7b2Philip P. Moltmann                transform.postScale((float)clipWidth / getWidth(),
424d55f20d3018d3328d9e26c971b814dfcb61aa7b2Philip P. Moltmann                        (float)clipHeight / getHeight());
425d55f20d3018d3328d9e26c971b814dfcb61aa7b2Philip P. Moltmann                transform.postTranslate(contentLeft, contentTop);
426d55f20d3018d3328d9e26c971b814dfcb61aa7b2Philip P. Moltmann            }
427d55f20d3018d3328d9e26c971b814dfcb61aa7b2Philip P. Moltmann
428d55f20d3018d3328d9e26c971b814dfcb61aa7b2Philip P. Moltmann            final long transformPtr = transform.native_instance;
4292961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
4300768a7dc450caf4c873c5b0883a75135536e1546Philip P. Moltmann            synchronized (sPdfiumLock) {
4310768a7dc450caf4c873c5b0883a75135536e1546Philip P. Moltmann                nativeRenderPage(mNativeDocument, mNativePage, destination, contentLeft,
4320768a7dc450caf4c873c5b0883a75135536e1546Philip P. Moltmann                        contentTop, contentRight, contentBottom, transformPtr, renderMode);
4330768a7dc450caf4c873c5b0883a75135536e1546Philip P. Moltmann            }
4342961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        }
4352961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
43695b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav        /**
43795b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav         * Closes this page.
43895b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav         *
43995b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav         * @see android.graphics.pdf.PdfRenderer#openPage(int)
44095b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav         */
44195b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav        @Override
44295b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav        public void close() {
44395b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav            throwIfClosed();
44495b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav            doClose();
44595b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav        }
44695b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav
44795b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav        @Override
44895b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav        protected void finalize() throws Throwable {
44995b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav            try {
450492e9e851cadca62df84eaff1a3c1ba788492fbaNarayan Kamath                if (mCloseGuard != null) {
451492e9e851cadca62df84eaff1a3c1ba788492fbaNarayan Kamath                    mCloseGuard.warnIfOpen();
452492e9e851cadca62df84eaff1a3c1ba788492fbaNarayan Kamath                }
453492e9e851cadca62df84eaff1a3c1ba788492fbaNarayan Kamath
45495b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav                if (mNativePage != 0) {
45595b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav                    doClose();
45695b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav                }
45795b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav            } finally {
45895b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav                super.finalize();
45995b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav            }
46095b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav        }
46195b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav
46295b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav        private void doClose() {
4630768a7dc450caf4c873c5b0883a75135536e1546Philip P. Moltmann            synchronized (sPdfiumLock) {
4640768a7dc450caf4c873c5b0883a75135536e1546Philip P. Moltmann                nativeClosePage(mNativePage);
4650768a7dc450caf4c873c5b0883a75135536e1546Philip P. Moltmann            }
4662961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            mNativePage = 0;
46795b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav            mCloseGuard.close();
468525a66b2bb5abf844aff2109bdc9ed819566beceSvet Ganov            mCurrentPage = null;
46995b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav        }
47095b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav
47195b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav        private void throwIfClosed() {
47295b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav            if (mNativePage == 0) {
47395b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav                throw new IllegalStateException("Already closed");
47495b6fd8b7af276069cbc415da3499d5ab4873c32Svetoslav            }
4752961769ea94f69c191a2dd785b2504666c7292d0Svetoslav        }
4762961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    }
4772961769ea94f69c191a2dd785b2504666c7292d0Svetoslav
4782961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    private static native long nativeCreate(int fd, long size);
4792961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    private static native void nativeClose(long documentPtr);
4802961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    private static native int nativeGetPageCount(long documentPtr);
4812961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    private static native boolean nativeScaleForPrinting(long documentPtr);
482ed207b92747234eac88dd3664ecfb535e45d8ed1John Reck    private static native void nativeRenderPage(long documentPtr, long pagePtr, Bitmap dest,
483d55f20d3018d3328d9e26c971b814dfcb61aa7b2Philip P. Moltmann            int clipLeft, int clipTop, int clipRight, int clipBottom, long transformPtr,
484d55f20d3018d3328d9e26c971b814dfcb61aa7b2Philip P. Moltmann            int renderMode);
4852961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    private static native long nativeOpenPageAndGetSize(long documentPtr, int pageIndex,
4862961769ea94f69c191a2dd785b2504666c7292d0Svetoslav            Point outSize);
4872961769ea94f69c191a2dd785b2504666c7292d0Svetoslav    private static native void nativeClosePage(long pagePtr);
4882961769ea94f69c191a2dd785b2504666c7292d0Svetoslav}
489