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 */
16121ab7001b3d818f7e7cf3cd4a95bcb3453b44e2Mark Salyzyn#define LOG_TAG "PdfEditor"
17121ab7001b3d818f7e7cf3cd4a95bcb3453b44e2Mark Salyzyn
18121ab7001b3d818f7e7cf3cd4a95bcb3453b44e2Mark Salyzyn#include <sys/types.h>
19121ab7001b3d818f7e7cf3cd4a95bcb3453b44e2Mark Salyzyn#include <unistd.h>
20121ab7001b3d818f7e7cf3cd4a95bcb3453b44e2Mark Salyzyn
21121ab7001b3d818f7e7cf3cd4a95bcb3453b44e2Mark Salyzyn#include <vector>
22121ab7001b3d818f7e7cf3cd4a95bcb3453b44e2Mark Salyzyn
2396bf5985d5a360568832fd26b6d5b44236c9343eMark Salyzyn#include <log/log.h>
24121ab7001b3d818f7e7cf3cd4a95bcb3453b44e2Mark Salyzyn#include <utils/Log.h>
2562ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav
2612328c0fd190c7baddb5f412c48005371672dc55Philip P. Moltmann#include "PdfUtils.h"
2712328c0fd190c7baddb5f412c48005371672dc55Philip P. Moltmann
2862ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav#include "jni.h"
292279b2534272282a5b5152723235da397e49195cSteven Moreland#include <nativehelper/JNIHelp.h>
30f4e341d99c4c29cb6cc7380829a316cf4847f3dfAndreas Gampe
31f4e341d99c4c29cb6cc7380829a316cf4847f3dfAndreas Gampe#pragma GCC diagnostic push
32f4e341d99c4c29cb6cc7380829a316cf4847f3dfAndreas Gampe#pragma GCC diagnostic ignored "-Wdelete-non-virtual-dtor"
3362ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav#include "fpdfview.h"
34fbd02886559e7ca2b619ed0d9bff76b10cdb23c3Svet Ganov#include "fpdf_edit.h"
35fbd02886559e7ca2b619ed0d9bff76b10cdb23c3Svet Ganov#include "fpdf_save.h"
36bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav#include "fpdf_transformpage.h"
37f4e341d99c4c29cb6cc7380829a316cf4847f3dfAndreas Gampe#pragma GCC diagnostic pop
38f4e341d99c4c29cb6cc7380829a316cf4847f3dfAndreas Gampe
39bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav#include "SkMatrix.h"
4062ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav
41ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe#include <core_jni_helpers.h>
4262ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav
4362ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslavnamespace android {
4462ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav
45bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslavenum PageBox {PAGE_BOX_MEDIA, PAGE_BOX_CROP};
46bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav
47bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslavstatic struct {
48bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    jfieldID x;
49bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    jfieldID y;
50bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav} gPointClassInfo;
51bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav
52bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslavstatic struct {
53bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    jfieldID left;
54bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    jfieldID top;
55bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    jfieldID right;
56bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    jfieldID bottom;
57bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav} gRectClassInfo;
58bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav
5962ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslavstatic jint nativeRemovePage(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex) {
6062ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
6112328c0fd190c7baddb5f412c48005371672dc55Philip P. Moltmann
6262ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    FPDFPage_Delete(document, pageIndex);
6312328c0fd190c7baddb5f412c48005371672dc55Philip P. Moltmann    HANDLE_PDFIUM_ERROR_STATE_WITH_RET_CODE(env, -1)
6412328c0fd190c7baddb5f412c48005371672dc55Philip P. Moltmann
6512328c0fd190c7baddb5f412c48005371672dc55Philip P. Moltmann    int pageCount = FPDF_GetPageCount(document);
6612328c0fd190c7baddb5f412c48005371672dc55Philip P. Moltmann    HANDLE_PDFIUM_ERROR_STATE_WITH_RET_CODE(env, -1)
6712328c0fd190c7baddb5f412c48005371672dc55Philip P. Moltmann
6812328c0fd190c7baddb5f412c48005371672dc55Philip P. Moltmann    return pageCount;
6962ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav}
7062ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav
7162ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslavstruct PdfToFdWriter : FPDF_FILEWRITE {
7262ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    int dstFd;
7362ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav};
7462ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav
7562ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslavstatic bool writeAllBytes(const int fd, const void* buffer, const size_t byteCount) {
7662ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    char* writeBuffer = static_cast<char*>(const_cast<void*>(buffer));
7762ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    size_t remainingBytes = byteCount;
7862ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    while (remainingBytes > 0) {
7962ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav        ssize_t writtenByteCount = write(fd, writeBuffer, remainingBytes);
8062ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav        if (writtenByteCount == -1) {
8162ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav            if (errno == EINTR) {
8262ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav                continue;
8362ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav            }
84121ab7001b3d818f7e7cf3cd4a95bcb3453b44e2Mark Salyzyn            ALOGE("Error writing to buffer: %d", errno);
8562ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav            return false;
8662ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav        }
8762ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav        remainingBytes -= writtenByteCount;
8862ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav        writeBuffer += writtenByteCount;
8962ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    }
9062ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    return true;
9162ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav}
9262ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav
9362ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslavstatic int writeBlock(FPDF_FILEWRITE* owner, const void* buffer, unsigned long size) {
9462ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    const PdfToFdWriter* writer = reinterpret_cast<PdfToFdWriter*>(owner);
9562ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    const bool success = writeAllBytes(writer->dstFd, buffer, size);
9692ddfcfff5cec32456e2d1e0d96671f1eb0e2986Bernhard Rosenkränzer    if (!success) {
9762ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav        ALOGE("Cannot write to file descriptor. Error:%d", errno);
9862ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav        return 0;
9962ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    }
10062ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    return 1;
10162ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav}
10262ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav
10362ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslavstatic void nativeWrite(JNIEnv* env, jclass thiz, jlong documentPtr, jint fd) {
10462ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
10562ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    PdfToFdWriter writer;
10662ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    writer.dstFd = fd;
10762ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    writer.WriteBlock = &writeBlock;
10862ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    const bool success = FPDF_SaveAsCopy(document, &writer, FPDF_NO_INCREMENTAL);
10962ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    if (!success) {
11046d8444631b4b1253a76bfcc78a29d26014d022fDan Albert        jniThrowExceptionFmt(env, "java/io/IOException",
11146d8444631b4b1253a76bfcc78a29d26014d022fDan Albert                "cannot write to fd. Error: %d", errno);
11262ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    }
11312328c0fd190c7baddb5f412c48005371672dc55Philip P. Moltmann    HANDLE_PDFIUM_ERROR_STATE(env)
11462ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav}
11562ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav
116bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslavstatic void nativeSetTransformAndClip(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex,
117bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        jlong transformPtr, jint clipLeft, jint clipTop, jint clipRight, jint clipBottom) {
118bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
119bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav
12061a530742f70e59d7fbd7c35a22292176ca554faPhilip P. Moltmann    FPDF_PAGE* page = (FPDF_PAGE*) FPDF_LoadPage(document, pageIndex);
121bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    if (!page) {
122bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        jniThrowException(env, "java/lang/IllegalStateException",
123bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav                "cannot open page");
124bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        return;
125bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    }
12612328c0fd190c7baddb5f412c48005371672dc55Philip P. Moltmann    HANDLE_PDFIUM_ERROR_STATE(env);
127bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav
128bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    double width = 0;
129bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    double height = 0;
130bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav
131bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    const int result = FPDF_GetPageSizeByIndex(document, pageIndex, &width, &height);
132bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    if (!result) {
133bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        jniThrowException(env, "java/lang/IllegalStateException",
134bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav                    "cannot get page size");
135bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        return;
136bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    }
13712328c0fd190c7baddb5f412c48005371672dc55Philip P. Moltmann    bool isExceptionPending = forwardPdfiumError(env);
13812328c0fd190c7baddb5f412c48005371672dc55Philip P. Moltmann    if (isExceptionPending) {
13912328c0fd190c7baddb5f412c48005371672dc55Philip P. Moltmann        FPDF_ClosePage(page);
14012328c0fd190c7baddb5f412c48005371672dc55Philip P. Moltmann        return;
14112328c0fd190c7baddb5f412c48005371672dc55Philip P. Moltmann    }
142bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav
14361a530742f70e59d7fbd7c35a22292176ca554faPhilip P. Moltmann    // PDF's coordinate system origin is left-bottom while in graphics it
14461a530742f70e59d7fbd7c35a22292176ca554faPhilip P. Moltmann    // is the top-left. So, translate the PDF coordinates to ours.
14561a530742f70e59d7fbd7c35a22292176ca554faPhilip P. Moltmann    SkMatrix reflectOnX = SkMatrix::MakeScale(1, -1);
14661a530742f70e59d7fbd7c35a22292176ca554faPhilip P. Moltmann    SkMatrix moveUp = SkMatrix::MakeTrans(0, FPDF_GetPageHeight(page));
14761a530742f70e59d7fbd7c35a22292176ca554faPhilip P. Moltmann    SkMatrix coordinateChange = SkMatrix::Concat(moveUp, reflectOnX);
14861a530742f70e59d7fbd7c35a22292176ca554faPhilip P. Moltmann
14961a530742f70e59d7fbd7c35a22292176ca554faPhilip P. Moltmann    // Apply the transformation what was created in our coordinates.
15061a530742f70e59d7fbd7c35a22292176ca554faPhilip P. Moltmann    SkMatrix matrix = SkMatrix::Concat(*reinterpret_cast<SkMatrix*>(transformPtr),
15161a530742f70e59d7fbd7c35a22292176ca554faPhilip P. Moltmann            coordinateChange);
15261a530742f70e59d7fbd7c35a22292176ca554faPhilip P. Moltmann
15361a530742f70e59d7fbd7c35a22292176ca554faPhilip P. Moltmann    // Translate the result back to PDF coordinates.
15461a530742f70e59d7fbd7c35a22292176ca554faPhilip P. Moltmann    matrix.setConcat(coordinateChange, matrix);
155bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav
156bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    SkScalar transformValues[6];
15761a530742f70e59d7fbd7c35a22292176ca554faPhilip P. Moltmann    if (!matrix.asAffine(transformValues)) {
15812328c0fd190c7baddb5f412c48005371672dc55Philip P. Moltmann        FPDF_ClosePage(page);
15912328c0fd190c7baddb5f412c48005371672dc55Philip P. Moltmann
16071487eb0ceb2b7dea02649e78d99bb5952f5eaefMike Reed        jniThrowException(env, "java/lang/IllegalArgumentException",
16171487eb0ceb2b7dea02649e78d99bb5952f5eaefMike Reed                "transform matrix has perspective. Only affine matrices are allowed.");
16271487eb0ceb2b7dea02649e78d99bb5952f5eaefMike Reed        return;
16371487eb0ceb2b7dea02649e78d99bb5952f5eaefMike Reed    }
164bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav
16561a530742f70e59d7fbd7c35a22292176ca554faPhilip P. Moltmann    FS_MATRIX transform = {transformValues[SkMatrix::kAScaleX], transformValues[SkMatrix::kASkewY],
16661a530742f70e59d7fbd7c35a22292176ca554faPhilip P. Moltmann                           transformValues[SkMatrix::kASkewX], transformValues[SkMatrix::kAScaleY],
16761a530742f70e59d7fbd7c35a22292176ca554faPhilip P. Moltmann                           transformValues[SkMatrix::kATransX],
16861a530742f70e59d7fbd7c35a22292176ca554faPhilip P. Moltmann                           transformValues[SkMatrix::kATransY]};
169bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav
170bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    FS_RECTF clip = {(float) clipLeft, (float) clipTop, (float) clipRight, (float) clipBottom};
171bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav
172bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    FPDFPage_TransFormWithClip(page, &transform, &clip);
17312328c0fd190c7baddb5f412c48005371672dc55Philip P. Moltmann    isExceptionPending = forwardPdfiumError(env);
17412328c0fd190c7baddb5f412c48005371672dc55Philip P. Moltmann    if (isExceptionPending) {
17512328c0fd190c7baddb5f412c48005371672dc55Philip P. Moltmann        FPDF_ClosePage(page);
17612328c0fd190c7baddb5f412c48005371672dc55Philip P. Moltmann        return;
17712328c0fd190c7baddb5f412c48005371672dc55Philip P. Moltmann    }
178bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav
179bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    FPDF_ClosePage(page);
18012328c0fd190c7baddb5f412c48005371672dc55Philip P. Moltmann    HANDLE_PDFIUM_ERROR_STATE(env);
181bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav}
182bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav
183bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslavstatic void nativeGetPageSize(JNIEnv* env, jclass thiz, jlong documentPtr,
184bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        jint pageIndex, jobject outSize) {
185bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
186bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav
187bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    FPDF_PAGE page = FPDF_LoadPage(document, pageIndex);
188bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    if (!page) {
189bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        jniThrowException(env, "java/lang/IllegalStateException",
190bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav                "cannot open page");
191bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        return;
192bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    }
19312328c0fd190c7baddb5f412c48005371672dc55Philip P. Moltmann    HANDLE_PDFIUM_ERROR_STATE(env);
194bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav
195bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    double width = 0;
196bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    double height = 0;
197bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav
198bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    const int result = FPDF_GetPageSizeByIndex(document, pageIndex, &width, &height);
199bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    if (!result) {
200bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        jniThrowException(env, "java/lang/IllegalStateException",
201bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav                    "cannot get page size");
202bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        return;
203bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    }
20412328c0fd190c7baddb5f412c48005371672dc55Philip P. Moltmann    bool isExceptionPending = forwardPdfiumError(env);
20512328c0fd190c7baddb5f412c48005371672dc55Philip P. Moltmann    if (isExceptionPending) {
20612328c0fd190c7baddb5f412c48005371672dc55Philip P. Moltmann        FPDF_ClosePage(page);
20712328c0fd190c7baddb5f412c48005371672dc55Philip P. Moltmann        return;
20812328c0fd190c7baddb5f412c48005371672dc55Philip P. Moltmann    }
209bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav
210bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    env->SetIntField(outSize, gPointClassInfo.x, width);
211bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    env->SetIntField(outSize, gPointClassInfo.y, height);
212bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav
213bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    FPDF_ClosePage(page);
21412328c0fd190c7baddb5f412c48005371672dc55Philip P. Moltmann    HANDLE_PDFIUM_ERROR_STATE(env);
215bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav}
216bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav
217bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslavstatic bool nativeGetPageBox(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex,
218bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        PageBox pageBox, jobject outBox) {
219bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
220bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav
221bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    FPDF_PAGE page = FPDF_LoadPage(document, pageIndex);
222bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    if (!page) {
223bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        jniThrowException(env, "java/lang/IllegalStateException",
224bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav                "cannot open page");
225bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        return false;
226bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    }
22712328c0fd190c7baddb5f412c48005371672dc55Philip P. Moltmann    HANDLE_PDFIUM_ERROR_STATE_WITH_RET_CODE(env, false);
228bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav
229bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    float left;
230bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    float top;
231bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    float right;
232bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    float bottom;
233bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav
234bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    const FPDF_BOOL success = (pageBox == PAGE_BOX_MEDIA)
235bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        ? FPDFPage_GetMediaBox(page, &left, &top, &right, &bottom)
236bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        : FPDFPage_GetCropBox(page, &left, &top, &right, &bottom);
23712328c0fd190c7baddb5f412c48005371672dc55Philip P. Moltmann    bool isExceptionPending = forwardPdfiumError(env);
23812328c0fd190c7baddb5f412c48005371672dc55Philip P. Moltmann    if (isExceptionPending) {
23912328c0fd190c7baddb5f412c48005371672dc55Philip P. Moltmann        FPDF_ClosePage(page);
24012328c0fd190c7baddb5f412c48005371672dc55Philip P. Moltmann        return false;
24112328c0fd190c7baddb5f412c48005371672dc55Philip P. Moltmann    }
242bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav
243bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    FPDF_ClosePage(page);
24412328c0fd190c7baddb5f412c48005371672dc55Philip P. Moltmann    HANDLE_PDFIUM_ERROR_STATE_WITH_RET_CODE(env, false);
245bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav
246bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    if (!success) {
247bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        return false;
248bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    }
249bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav
250bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    env->SetIntField(outBox, gRectClassInfo.left, (int) left);
251bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    env->SetIntField(outBox, gRectClassInfo.top, (int) top);
252bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    env->SetIntField(outBox, gRectClassInfo.right, (int) right);
253bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    env->SetIntField(outBox, gRectClassInfo.bottom, (int) bottom);
254bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav
255bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    return true;
256bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav}
257bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav
258bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslavstatic jboolean nativeGetPageMediaBox(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex,
259bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        jobject outMediaBox) {
260bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    const bool success = nativeGetPageBox(env, thiz, documentPtr, pageIndex, PAGE_BOX_MEDIA,
261bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav            outMediaBox);
262bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    return success ? JNI_TRUE : JNI_FALSE;
263bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav}
264bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav
265bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslavstatic jboolean nativeGetPageCropBox(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex,
266bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        jobject outMediaBox) {
267bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    const bool success = nativeGetPageBox(env, thiz, documentPtr, pageIndex, PAGE_BOX_CROP,
268bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav         outMediaBox);
269bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    return success ? JNI_TRUE : JNI_FALSE;
270bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav}
271bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav
272bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslavstatic void nativeSetPageBox(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex,
273bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        PageBox pageBox, jobject box) {
274bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
275bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav
276bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    FPDF_PAGE page = FPDF_LoadPage(document, pageIndex);
277bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    if (!page) {
278bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        jniThrowException(env, "java/lang/IllegalStateException",
279bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav                "cannot open page");
280bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        return;
281bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    }
28212328c0fd190c7baddb5f412c48005371672dc55Philip P. Moltmann    HANDLE_PDFIUM_ERROR_STATE(env);
283bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav
284bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    const int left = env->GetIntField(box, gRectClassInfo.left);
285bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    const int top = env->GetIntField(box, gRectClassInfo.top);
286bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    const int right = env->GetIntField(box, gRectClassInfo.right);
287bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    const int bottom = env->GetIntField(box, gRectClassInfo.bottom);
288bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav
289bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    if (pageBox == PAGE_BOX_MEDIA) {
290bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        FPDFPage_SetMediaBox(page, left, top, right, bottom);
291bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    } else {
292bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        FPDFPage_SetCropBox(page, left, top, right, bottom);
293bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    }
29412328c0fd190c7baddb5f412c48005371672dc55Philip P. Moltmann    bool isExceptionPending = forwardPdfiumError(env);
29512328c0fd190c7baddb5f412c48005371672dc55Philip P. Moltmann    if (isExceptionPending) {
29612328c0fd190c7baddb5f412c48005371672dc55Philip P. Moltmann        FPDF_ClosePage(page);
29712328c0fd190c7baddb5f412c48005371672dc55Philip P. Moltmann        return;
29812328c0fd190c7baddb5f412c48005371672dc55Philip P. Moltmann    }
299bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav
300bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    FPDF_ClosePage(page);
30112328c0fd190c7baddb5f412c48005371672dc55Philip P. Moltmann    HANDLE_PDFIUM_ERROR_STATE(env);
302bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav}
303bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav
304bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslavstatic void nativeSetPageMediaBox(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex,
305bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        jobject mediaBox) {
306bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    nativeSetPageBox(env, thiz, documentPtr, pageIndex, PAGE_BOX_MEDIA, mediaBox);
307bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav}
308bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav
309bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslavstatic void nativeSetPageCropBox(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex,
310bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav        jobject mediaBox) {
311bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    nativeSetPageBox(env, thiz, documentPtr, pageIndex, PAGE_BOX_CROP, mediaBox);
312bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav}
313bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav
31476f6a86de25e1bf74717e047e55fd44b089673f3Daniel Micaystatic const JNINativeMethod gPdfEditor_Methods[] = {
31562ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    {"nativeOpen", "(IJ)J", (void*) nativeOpen},
31662ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    {"nativeClose", "(J)V", (void*) nativeClose},
31762ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    {"nativeGetPageCount", "(J)I", (void*) nativeGetPageCount},
31862ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav    {"nativeRemovePage", "(JI)I", (void*) nativeRemovePage},
319bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    {"nativeWrite", "(JI)V", (void*) nativeWrite},
320bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    {"nativeSetTransformAndClip", "(JIJIIII)V", (void*) nativeSetTransformAndClip},
321bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    {"nativeGetPageSize", "(JILandroid/graphics/Point;)V", (void*) nativeGetPageSize},
322bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    {"nativeScaleForPrinting", "(J)Z", (void*) nativeScaleForPrinting},
323bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    {"nativeGetPageMediaBox", "(JILandroid/graphics/Rect;)Z", (void*) nativeGetPageMediaBox},
324bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    {"nativeSetPageMediaBox", "(JILandroid/graphics/Rect;)V", (void*) nativeSetPageMediaBox},
325bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    {"nativeGetPageCropBox", "(JILandroid/graphics/Rect;)Z", (void*) nativeGetPageCropBox},
326bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    {"nativeSetPageCropBox", "(JILandroid/graphics/Rect;)V", (void*) nativeSetPageCropBox}
32762ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav};
32862ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav
32962ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslavint register_android_graphics_pdf_PdfEditor(JNIEnv* env) {
3307d13d9db1ef90063cb542ccd6554042a6a3263b7Andreas Gampe    const int result = RegisterMethodsOrDie(
33162ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav            env, "android/graphics/pdf/PdfEditor", gPdfEditor_Methods,
33262ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav            NELEM(gPdfEditor_Methods));
333bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav
3347d13d9db1ef90063cb542ccd6554042a6a3263b7Andreas Gampe    jclass pointClass = FindClassOrDie(env, "android/graphics/Point");
3357d13d9db1ef90063cb542ccd6554042a6a3263b7Andreas Gampe    gPointClassInfo.x = GetFieldIDOrDie(env, pointClass, "x", "I");
3367d13d9db1ef90063cb542ccd6554042a6a3263b7Andreas Gampe    gPointClassInfo.y = GetFieldIDOrDie(env, pointClass, "y", "I");
337bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav
3387d13d9db1ef90063cb542ccd6554042a6a3263b7Andreas Gampe    jclass rectClass = FindClassOrDie(env, "android/graphics/Rect");
3397d13d9db1ef90063cb542ccd6554042a6a3263b7Andreas Gampe    gRectClassInfo.left = GetFieldIDOrDie(env, rectClass, "left", "I");
3407d13d9db1ef90063cb542ccd6554042a6a3263b7Andreas Gampe    gRectClassInfo.top = GetFieldIDOrDie(env, rectClass, "top", "I");
3417d13d9db1ef90063cb542ccd6554042a6a3263b7Andreas Gampe    gRectClassInfo.right = GetFieldIDOrDie(env, rectClass, "right", "I");
3427d13d9db1ef90063cb542ccd6554042a6a3263b7Andreas Gampe    gRectClassInfo.bottom = GetFieldIDOrDie(env, rectClass, "bottom", "I");
343bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav
344bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav    return result;
34562ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav};
34662ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav
34762ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav};
348