162ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav/*
262ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav * Copyright (C) 2014 The Android Open Source Project
362ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav *
462ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav * Licensed under the Apache License, Version 2.0 (the "License");
562ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav * you may not use this file except in compliance with the License.
662ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav * You may obtain a copy of the License at
762ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav *
862ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav *      http://www.apache.org/licenses/LICENSE-2.0
962ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav *
1062ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav * Unless required by applicable law or agreed to in writing, software
1162ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav * distributed under the License is distributed on an "AS IS" BASIS,
1262ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1362ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav * See the License for the specific language governing permissions and
1462ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav * limitations under the License.
1562ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav */
1662ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav
1762ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslavpackage android.graphics.pdf;
1862ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav
1962ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslavimport android.annotation.NonNull;
20bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslavimport android.annotation.Nullable;
21bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslavimport android.graphics.Matrix;
22bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslavimport android.graphics.Point;
23bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslavimport android.graphics.Rect;
2462ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslavimport android.os.ParcelFileDescriptor;
2562ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslavimport android.system.ErrnoException;
2662ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslavimport android.system.OsConstants;
2762ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslavimport dalvik.system.CloseGuard;
2862ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslavimport libcore.io.IoUtils;
2962ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslavimport libcore.io.Libcore;
3062ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav
3162ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslavimport java.io.IOException;
3262ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav
3362ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav/**
3462ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav * Class for editing PDF files.
3562ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav *
3662ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav * @hide
3762ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav */
3862ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslavpublic final class PdfEditor {
3962ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav
4062ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    private final CloseGuard mCloseGuard = CloseGuard.get();
4162ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav
4262ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    private final long mNativeDocument;
4362ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav
4462ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    private int mPageCount;
4562ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav
4662ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    private ParcelFileDescriptor mInput;
4762ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav
4862ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    /**
4962ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav     * Creates a new instance.
5062ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav     * <p>
5162ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav     * <strong>Note:</strong> The provided file descriptor must be <strong>seekable</strong>,
5262ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav     * i.e. its data being randomly accessed, e.g. pointing to a file. After finishing
5362ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav     * with this class you must call {@link #close()}.
5462ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav     * </p>
5562ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav     * <p>
5662ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav     * <strong>Note:</strong> This class takes ownership of the passed in file descriptor
5762ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav     * and is responsible for closing it when the editor is closed.
5862ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav     * </p>
5962ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav     *
6062ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav     * @param input Seekable file descriptor to read from.
6162ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav     *
62fce84f035c35606c5707e735f503f7bdcfd5b2a1Svet Ganov     * @throws java.io.IOException If an error occurs while reading the file.
63fce84f035c35606c5707e735f503f7bdcfd5b2a1Svet Ganov     * @throws java.lang.SecurityException If the file requires a password or
64fce84f035c35606c5707e735f503f7bdcfd5b2a1Svet Ganov     *         the security scheme is not supported.
65fce84f035c35606c5707e735f503f7bdcfd5b2a1Svet Ganov     *
6662ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav     * @see #close()
6762ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav     */
6862ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    public PdfEditor(@NonNull ParcelFileDescriptor input) throws IOException {
6962ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav        if (input == null) {
7062ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav            throw new NullPointerException("input cannot be null");
7162ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav        }
7262ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav
7362ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav        final long size;
7462ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav        try {
7562ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav            Libcore.os.lseek(input.getFileDescriptor(), 0, OsConstants.SEEK_SET);
7662ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav            size = Libcore.os.fstat(input.getFileDescriptor()).st_size;
7762ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav        } catch (ErrnoException ee) {
7862ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav            throw new IllegalArgumentException("file descriptor not seekable");
7962ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav        }
8062ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav
8162ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav        mInput = input;
8262ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav        mNativeDocument = nativeOpen(mInput.getFd(), size);
8362ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav        mPageCount = nativeGetPageCount(mNativeDocument);
8462ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav        mCloseGuard.open("close");
8562ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    }
8662ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav
8762ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    /**
8862ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav     * Gets the number of pages in the document.
8962ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav     *
9062ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav     * @return The page count.
9162ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav     */
9262ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    public int getPageCount() {
9362ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav        throwIfClosed();
9462ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav        return mPageCount;
9562ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    }
9662ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav
9762ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    /**
9862ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav     * Removes the page with a given index.
9962ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav     *
10062ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav     * @param pageIndex The page to remove.
10162ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav     */
10262ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    public void removePage(int pageIndex) {
10362ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav        throwIfClosed();
10462ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav        throwIfPageNotInDocument(pageIndex);
10562ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav        mPageCount = nativeRemovePage(mNativeDocument, pageIndex);
10662ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    }
10762ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav
10862ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    /**
109bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav     * Sets a transformation and clip for a given page. The transformation matrix if
110bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav     * non-null must be affine as per {@link android.graphics.Matrix#isAffine()}. If
111bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav     * the clip is null, then no clipping is performed.
112bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav     *
113bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav     * @param pageIndex The page whose transform to set.
114bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav     * @param transform The transformation to apply.
115bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav     * @param clip The clip to apply.
116bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav     */
117bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    public void setTransformAndClip(int pageIndex, @Nullable Matrix transform,
118bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav            @Nullable Rect clip) {
119bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        throwIfClosed();
120bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        throwIfPageNotInDocument(pageIndex);
121bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        throwIfNotNullAndNotAfine(transform);
122bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        if (transform == null) {
123bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav            transform = Matrix.IDENTITY_MATRIX;
124bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        }
125bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        if (clip == null) {
126bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav            Point size = new Point();
127bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav            getPageSize(pageIndex, size);
128bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav            nativeSetTransformAndClip(mNativeDocument, pageIndex, transform.native_instance,
129bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav                    0, 0, size.x, size.y);
130bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        } else {
131bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav            nativeSetTransformAndClip(mNativeDocument, pageIndex, transform.native_instance,
132bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav                    clip.left, clip.top, clip.right, clip.bottom);
133bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        }
134bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    }
135bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav
136bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    /**
137bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav     * Gets the size of a given page in mils (1/72").
138bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav     *
139bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav     * @param pageIndex The page index.
140bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav     * @param outSize The size output.
141bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav     */
142bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    public void getPageSize(int pageIndex, @NonNull Point outSize) {
143bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        throwIfClosed();
144bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        throwIfOutSizeNull(outSize);
145bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        throwIfPageNotInDocument(pageIndex);
146bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        nativeGetPageSize(mNativeDocument, pageIndex, outSize);
147bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    }
148bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav
149bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    /**
150bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav     * Gets the media box of a given page in mils (1/72").
151bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav     *
152bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav     * @param pageIndex The page index.
153bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav     * @param outMediaBox The media box output.
154bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav     */
155bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    public boolean getPageMediaBox(int pageIndex, @NonNull Rect outMediaBox) {
156bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        throwIfClosed();
157bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        throwIfOutMediaBoxNull(outMediaBox);
158bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        throwIfPageNotInDocument(pageIndex);
159bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        return nativeGetPageMediaBox(mNativeDocument, pageIndex, outMediaBox);
160bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    }
161bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav
162bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    /**
163bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav     * Sets the media box of a given page in mils (1/72").
164bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav     *
165bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav     * @param pageIndex The page index.
166bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav     * @param mediaBox The media box.
167bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav     */
168bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    public void setPageMediaBox(int pageIndex, @NonNull Rect mediaBox) {
169bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        throwIfClosed();
170bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        throwIfMediaBoxNull(mediaBox);
171bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        throwIfPageNotInDocument(pageIndex);
172bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        nativeSetPageMediaBox(mNativeDocument, pageIndex, mediaBox);
173bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    }
174bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav
175bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    /**
176bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav     * Gets the crop box of a given page in mils (1/72").
177bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav     *
178bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav     * @param pageIndex The page index.
179bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav     * @param outCropBox The crop box output.
180bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav     */
181bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    public boolean getPageCropBox(int pageIndex, @NonNull Rect outCropBox) {
182bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        throwIfClosed();
183bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        throwIfOutCropBoxNull(outCropBox);
184bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        throwIfPageNotInDocument(pageIndex);
185bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        return nativeGetPageCropBox(mNativeDocument, pageIndex, outCropBox);
186bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    }
187bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav
188bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    /**
189bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav     * Sets the crop box of a given page in mils (1/72").
190bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav     *
191bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav     * @param pageIndex The page index.
192bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav     * @param cropBox The crop box.
193bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav     */
194bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    public void setPageCropBox(int pageIndex, @NonNull Rect cropBox) {
195bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        throwIfClosed();
196bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        throwIfCropBoxNull(cropBox);
197bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        throwIfPageNotInDocument(pageIndex);
198bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        nativeSetPageCropBox(mNativeDocument, pageIndex, cropBox);
199bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    }
200bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav
201bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    /**
202bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav     * Gets whether the document prefers to be scaled for printing.
203bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav     *
204bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav     * @return Whether to scale the document.
205bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav     */
206bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    public boolean shouldScaleForPrinting() {
207bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        throwIfClosed();
208bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        return nativeScaleForPrinting(mNativeDocument);
209bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    }
210bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav
211bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    /**
21262ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav     * Writes the PDF file to the provided destination.
21362ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav     * <p>
21462ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav     * <strong>Note:</strong> This method takes ownership of the passed in file
21562ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav     * descriptor and is responsible for closing it when writing completes.
21662ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav     * </p>
21762ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav     * @param output The destination.
21862ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav     */
21962ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    public void write(ParcelFileDescriptor output) throws IOException {
22062ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav        try {
22162ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav            throwIfClosed();
22262ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav            nativeWrite(mNativeDocument, output.getFd());
22362ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav        } finally {
22462ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav            IoUtils.closeQuietly(output);
22562ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav        }
22662ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    }
22762ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav
22862ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    /**
22962ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav     * Closes this editor. You should not use this instance
23062ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav     * after this method is called.
23162ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav     */
23262ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    public void close() {
23362ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav        throwIfClosed();
23462ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav        doClose();
23562ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    }
23662ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav
23762ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    @Override
23862ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    protected void finalize() throws Throwable {
23962ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav        try {
24062ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav            mCloseGuard.warnIfOpen();
24162ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav            if (mInput != null) {
24262ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav                doClose();
24362ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav            }
24462ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav        } finally {
24562ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav            super.finalize();
24662ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav        }
24762ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    }
24862ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav
24962ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    private void doClose() {
25062ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav        nativeClose(mNativeDocument);
25162ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav        IoUtils.closeQuietly(mInput);
25262ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav        mInput = null;
25362ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav        mCloseGuard.close();
25462ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    }
25562ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav
25662ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    private void throwIfClosed() {
25762ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav        if (mInput == null) {
25862ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav            throw new IllegalStateException("Already closed");
25962ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav        }
26062ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    }
26162ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav
26262ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    private void throwIfPageNotInDocument(int pageIndex) {
26362ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav        if (pageIndex < 0 || pageIndex >= mPageCount) {
26462ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav            throw new IllegalArgumentException("Invalid page index");
26562ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav        }
26662ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    }
26762ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav
268bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    private void throwIfNotNullAndNotAfine(Matrix matrix) {
269bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        if (matrix != null && !matrix.isAffine()) {
270bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav            throw new IllegalStateException("Matrix must be afine");
271bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        }
272bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    }
273bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav
274bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    private void throwIfOutSizeNull(Point outSize) {
275bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        if (outSize == null) {
276bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav            throw new NullPointerException("outSize cannot be null");
277bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        }
278bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    }
279bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav
280bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    private void throwIfOutMediaBoxNull(Rect outMediaBox) {
281bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        if (outMediaBox == null) {
282bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav            throw new NullPointerException("outMediaBox cannot be null");
283bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        }
284bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    }
285bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav
286bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    private void throwIfMediaBoxNull(Rect mediaBox) {
287bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        if (mediaBox == null) {
288bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav            throw new NullPointerException("mediaBox cannot be null");
289bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        }
290bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    }
291bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav
292bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    private void throwIfOutCropBoxNull(Rect outCropBox) {
293bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        if (outCropBox == null) {
294bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav            throw new NullPointerException("outCropBox cannot be null");
295bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        }
296bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    }
297bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav
298bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    private void throwIfCropBoxNull(Rect cropBox) {
299bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        if (cropBox == null) {
300bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav            throw new NullPointerException("cropBox cannot be null");
301bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        }
302bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    }
303bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav
30462ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    private static native long nativeOpen(int fd, long size);
30562ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    private static native void nativeClose(long documentPtr);
30662ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    private static native int nativeGetPageCount(long documentPtr);
30762ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    private static native int nativeRemovePage(long documentPtr, int pageIndex);
30862ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    private static native void nativeWrite(long documentPtr, int fd);
309bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    private static native void nativeSetTransformAndClip(long documentPtr, int pageIndex,
310bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav            long transformPtr, int clipLeft, int clipTop, int clipRight, int clipBottom);
311bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    private static native void nativeGetPageSize(long documentPtr, int pageIndex, Point outSize);
312bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    private static native boolean nativeGetPageMediaBox(long documentPtr, int pageIndex,
313bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav            Rect outMediaBox);
314bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    private static native void nativeSetPageMediaBox(long documentPtr, int pageIndex,
315bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav            Rect mediaBox);
316bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    private static native boolean nativeGetPageCropBox(long documentPtr, int pageIndex,
317bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav            Rect outMediaBox);
318bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    private static native void nativeSetPageCropBox(long documentPtr, int pageIndex,
319bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav            Rect mediaBox);
320bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    private static native boolean nativeScaleForPrinting(long documentPtr);
32162ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav}
322