PdfEditor.cpp revision 96bf5985d5a360568832fd26b6d5b44236c9343e
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 2662ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav#include "jni.h" 2762ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav#include "JNIHelp.h" 28f4e341d99c4c29cb6cc7380829a316cf4847f3dfAndreas Gampe 29f4e341d99c4c29cb6cc7380829a316cf4847f3dfAndreas Gampe#pragma GCC diagnostic push 30f4e341d99c4c29cb6cc7380829a316cf4847f3dfAndreas Gampe#pragma GCC diagnostic ignored "-Wdelete-non-virtual-dtor" 3162ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav#include "fpdfview.h" 32fbd02886559e7ca2b619ed0d9bff76b10cdb23c3Svet Ganov#include "fpdf_edit.h" 33fbd02886559e7ca2b619ed0d9bff76b10cdb23c3Svet Ganov#include "fpdf_save.h" 34bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav#include "fsdk_rendercontext.h" 35bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav#include "fpdf_transformpage.h" 36f4e341d99c4c29cb6cc7380829a316cf4847f3dfAndreas Gampe#pragma GCC diagnostic pop 37f4e341d99c4c29cb6cc7380829a316cf4847f3dfAndreas Gampe 38bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav#include "SkMatrix.h" 3962ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav 40ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe#include <core_jni_helpers.h> 4162ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav 4262ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslavnamespace android { 4362ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav 44bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslavenum PageBox {PAGE_BOX_MEDIA, PAGE_BOX_CROP}; 45bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav 46bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslavstatic struct { 47bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav jfieldID x; 48bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav jfieldID y; 49bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav} gPointClassInfo; 50bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav 51bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslavstatic struct { 52bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav jfieldID left; 53bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav jfieldID top; 54bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav jfieldID right; 55bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav jfieldID bottom; 56bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav} gRectClassInfo; 57bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav 58be2e7121872afe2f561f20c4660da854c31e1b66Philip P. Moltmann// Also used in PdfRenderer.cpp 59be2e7121872afe2f561f20c4660da854c31e1b66Philip P. Moltmannint sUnmatchedPdfiumInitRequestCount = 0; 6062ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav 6162ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslavstatic void initializeLibraryIfNeeded() { 62be2e7121872afe2f561f20c4660da854c31e1b66Philip P. Moltmann if (sUnmatchedPdfiumInitRequestCount == 0) { 63fbd02886559e7ca2b619ed0d9bff76b10cdb23c3Svet Ganov FPDF_InitLibrary(); 6462ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav } 65be2e7121872afe2f561f20c4660da854c31e1b66Philip P. Moltmann sUnmatchedPdfiumInitRequestCount++; 6662ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav} 6762ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav 6862ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslavstatic void destroyLibraryIfNeeded() { 69be2e7121872afe2f561f20c4660da854c31e1b66Philip P. Moltmann sUnmatchedPdfiumInitRequestCount--; 70be2e7121872afe2f561f20c4660da854c31e1b66Philip P. Moltmann if (sUnmatchedPdfiumInitRequestCount == 0) { 7162ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav FPDF_DestroyLibrary(); 7262ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav } 7362ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav} 7462ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav 7562ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslavstatic int getBlock(void* param, unsigned long position, unsigned char* outBuffer, 7662ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav unsigned long size) { 7762ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav const int fd = reinterpret_cast<intptr_t>(param); 7862ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav const int readCount = pread(fd, outBuffer, size, position); 7962ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav if (readCount < 0) { 8062ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav ALOGE("Cannot read from file descriptor. Error:%d", errno); 8162ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav return 0; 8262ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav } 8362ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav return 1; 8462ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav} 8562ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav 8662ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslavstatic jlong nativeOpen(JNIEnv* env, jclass thiz, jint fd, jlong size) { 8762ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav initializeLibraryIfNeeded(); 8862ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav 8962ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav FPDF_FILEACCESS loader; 9062ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav loader.m_FileLen = size; 9162ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav loader.m_Param = reinterpret_cast<void*>(intptr_t(fd)); 9262ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav loader.m_GetBlock = &getBlock; 9362ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav 9462ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav FPDF_DOCUMENT document = FPDF_LoadCustomDocument(&loader, NULL); 9562ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav 9662ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav if (!document) { 9762ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav const long error = FPDF_GetLastError(); 98fce84f035c35606c5707e735f503f7bdcfd5b2a1Svet Ganov switch (error) { 99fce84f035c35606c5707e735f503f7bdcfd5b2a1Svet Ganov case FPDF_ERR_PASSWORD: 100fce84f035c35606c5707e735f503f7bdcfd5b2a1Svet Ganov case FPDF_ERR_SECURITY: { 1013a091b79978caa9b5d58ae19f693279e5a717c2aDan Albert jniThrowExceptionFmt(env, "java/lang/SecurityException", 1023a091b79978caa9b5d58ae19f693279e5a717c2aDan Albert "cannot create document. Error: %ld", error); 103fce84f035c35606c5707e735f503f7bdcfd5b2a1Svet Ganov } break; 104fce84f035c35606c5707e735f503f7bdcfd5b2a1Svet Ganov default: { 1053a091b79978caa9b5d58ae19f693279e5a717c2aDan Albert jniThrowExceptionFmt(env, "java/io/IOException", 1063a091b79978caa9b5d58ae19f693279e5a717c2aDan Albert "cannot create document. Error: %ld", error); 107fce84f035c35606c5707e735f503f7bdcfd5b2a1Svet Ganov } break; 108fce84f035c35606c5707e735f503f7bdcfd5b2a1Svet Ganov } 10962ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav destroyLibraryIfNeeded(); 11062ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav return -1; 11162ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav } 11262ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav 11362ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav return reinterpret_cast<jlong>(document); 11462ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav} 11562ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav 11662ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslavstatic void nativeClose(JNIEnv* env, jclass thiz, jlong documentPtr) { 11762ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr); 11862ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav FPDF_CloseDocument(document); 11962ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav destroyLibraryIfNeeded(); 12062ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav} 12162ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav 12262ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslavstatic jint nativeGetPageCount(JNIEnv* env, jclass thiz, jlong documentPtr) { 12362ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr); 12462ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav return FPDF_GetPageCount(document); 12562ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav} 12662ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav 12762ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslavstatic jint nativeRemovePage(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex) { 12862ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr); 12962ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav FPDFPage_Delete(document, pageIndex); 13062ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav return FPDF_GetPageCount(document); 13162ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav} 13262ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav 13362ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslavstruct PdfToFdWriter : FPDF_FILEWRITE { 13462ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav int dstFd; 13562ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav}; 13662ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav 13762ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslavstatic bool writeAllBytes(const int fd, const void* buffer, const size_t byteCount) { 13862ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav char* writeBuffer = static_cast<char*>(const_cast<void*>(buffer)); 13962ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav size_t remainingBytes = byteCount; 14062ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav while (remainingBytes > 0) { 14162ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav ssize_t writtenByteCount = write(fd, writeBuffer, remainingBytes); 14262ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav if (writtenByteCount == -1) { 14362ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav if (errno == EINTR) { 14462ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav continue; 14562ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav } 146121ab7001b3d818f7e7cf3cd4a95bcb3453b44e2Mark Salyzyn ALOGE("Error writing to buffer: %d", errno); 14762ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav return false; 14862ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav } 14962ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav remainingBytes -= writtenByteCount; 15062ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav writeBuffer += writtenByteCount; 15162ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav } 15262ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav return true; 15362ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav} 15462ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav 15562ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslavstatic int writeBlock(FPDF_FILEWRITE* owner, const void* buffer, unsigned long size) { 15662ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav const PdfToFdWriter* writer = reinterpret_cast<PdfToFdWriter*>(owner); 15762ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav const bool success = writeAllBytes(writer->dstFd, buffer, size); 15892ddfcfff5cec32456e2d1e0d96671f1eb0e2986Bernhard Rosenkränzer if (!success) { 15962ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav ALOGE("Cannot write to file descriptor. Error:%d", errno); 16062ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav return 0; 16162ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav } 16262ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav return 1; 16362ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav} 16462ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav 16562ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslavstatic void nativeWrite(JNIEnv* env, jclass thiz, jlong documentPtr, jint fd) { 16662ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr); 16762ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav PdfToFdWriter writer; 16862ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav writer.dstFd = fd; 16962ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav writer.WriteBlock = &writeBlock; 17062ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav const bool success = FPDF_SaveAsCopy(document, &writer, FPDF_NO_INCREMENTAL); 17162ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav if (!success) { 17246d8444631b4b1253a76bfcc78a29d26014d022fDan Albert jniThrowExceptionFmt(env, "java/io/IOException", 17346d8444631b4b1253a76bfcc78a29d26014d022fDan Albert "cannot write to fd. Error: %d", errno); 17462ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav destroyLibraryIfNeeded(); 17562ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav } 17662ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav} 17762ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav 178bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslavstatic void nativeSetTransformAndClip(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex, 179bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav jlong transformPtr, jint clipLeft, jint clipTop, jint clipRight, jint clipBottom) { 180bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr); 181bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav 182bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav CPDF_Page* page = (CPDF_Page*) FPDF_LoadPage(document, pageIndex); 183bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav if (!page) { 184bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav jniThrowException(env, "java/lang/IllegalStateException", 185bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav "cannot open page"); 186bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav return; 187bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav } 188bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav 189bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav double width = 0; 190bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav double height = 0; 191bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav 192bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav const int result = FPDF_GetPageSizeByIndex(document, pageIndex, &width, &height); 193bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav if (!result) { 194bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav jniThrowException(env, "java/lang/IllegalStateException", 195bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav "cannot get page size"); 196bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav return; 197bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav } 198bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav 19979bd8d48ad69c39834291809fe78ea478d067b68Philip P. Moltmann CFX_Matrix matrix; 200bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav 201bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav SkMatrix* skTransform = reinterpret_cast<SkMatrix*>(transformPtr); 202bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav 203bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav SkScalar transformValues[6]; 20471487eb0ceb2b7dea02649e78d99bb5952f5eaefMike Reed if (!skTransform->asAffine(transformValues)) { 20571487eb0ceb2b7dea02649e78d99bb5952f5eaefMike Reed jniThrowException(env, "java/lang/IllegalArgumentException", 20671487eb0ceb2b7dea02649e78d99bb5952f5eaefMike Reed "transform matrix has perspective. Only affine matrices are allowed."); 20771487eb0ceb2b7dea02649e78d99bb5952f5eaefMike Reed return; 20871487eb0ceb2b7dea02649e78d99bb5952f5eaefMike Reed } 209bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav 210bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav // PDF's coordinate system origin is left-bottom while in graphics it 211bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav // is the top-left. So, translate the PDF coordinates to ours. 212bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav matrix.Set(1, 0, 0, -1, 0, page->GetPageHeight()); 213bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav 214bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav // Apply the transformation what was created in our coordinates. 215bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav matrix.Concat(transformValues[SkMatrix::kAScaleX], transformValues[SkMatrix::kASkewY], 216bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav transformValues[SkMatrix::kASkewX], transformValues[SkMatrix::kAScaleY], 217bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav transformValues[SkMatrix::kATransX], transformValues[SkMatrix::kATransY]); 218bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav 219bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav // Translate the result back to PDF coordinates. 220bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav matrix.Concat(1, 0, 0, -1, 0, page->GetPageHeight()); 221bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav 222bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav FS_MATRIX transform = {matrix.a, matrix.b, matrix.c, matrix.d, matrix.e, matrix.f}; 223bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav FS_RECTF clip = {(float) clipLeft, (float) clipTop, (float) clipRight, (float) clipBottom}; 224bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav 225bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav FPDFPage_TransFormWithClip(page, &transform, &clip); 226bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav 227bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav FPDF_ClosePage(page); 228bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav} 229bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav 230bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslavstatic void nativeGetPageSize(JNIEnv* env, jclass thiz, jlong documentPtr, 231bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav jint pageIndex, jobject outSize) { 232bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr); 233bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav 234bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav FPDF_PAGE page = FPDF_LoadPage(document, pageIndex); 235bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav if (!page) { 236bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav jniThrowException(env, "java/lang/IllegalStateException", 237bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav "cannot open page"); 238bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav return; 239bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav } 240bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav 241bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav double width = 0; 242bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav double height = 0; 243bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav 244bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav const int result = FPDF_GetPageSizeByIndex(document, pageIndex, &width, &height); 245bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav if (!result) { 246bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav jniThrowException(env, "java/lang/IllegalStateException", 247bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav "cannot get page size"); 248bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav return; 249bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav } 250bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav 251bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav env->SetIntField(outSize, gPointClassInfo.x, width); 252bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav env->SetIntField(outSize, gPointClassInfo.y, height); 253bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav 254bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav FPDF_ClosePage(page); 255bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav} 256bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav 257bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslavstatic jboolean nativeScaleForPrinting(JNIEnv* env, jclass thiz, jlong documentPtr) { 258bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr); 259bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav FPDF_BOOL success = FPDF_VIEWERREF_GetPrintScaling(document); 260bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav return success ? JNI_TRUE : JNI_FALSE; 261bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav} 262bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav 263bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslavstatic bool nativeGetPageBox(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex, 264bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav PageBox pageBox, jobject outBox) { 265bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr); 266bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav 267bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav FPDF_PAGE page = FPDF_LoadPage(document, pageIndex); 268bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav if (!page) { 269bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav jniThrowException(env, "java/lang/IllegalStateException", 270bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav "cannot open page"); 271bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav return false; 272bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav } 273bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav 274bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav float left; 275bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav float top; 276bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav float right; 277bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav float bottom; 278bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav 279bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav const FPDF_BOOL success = (pageBox == PAGE_BOX_MEDIA) 280bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav ? FPDFPage_GetMediaBox(page, &left, &top, &right, &bottom) 281bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav : FPDFPage_GetCropBox(page, &left, &top, &right, &bottom); 282bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav 283bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav FPDF_ClosePage(page); 284bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav 285bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav if (!success) { 286bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav return false; 287bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav } 288bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav 289bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav env->SetIntField(outBox, gRectClassInfo.left, (int) left); 290bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav env->SetIntField(outBox, gRectClassInfo.top, (int) top); 291bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav env->SetIntField(outBox, gRectClassInfo.right, (int) right); 292bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav env->SetIntField(outBox, gRectClassInfo.bottom, (int) bottom); 293bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav 294bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav return true; 295bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav} 296bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav 297bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslavstatic jboolean nativeGetPageMediaBox(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex, 298bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav jobject outMediaBox) { 299bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav const bool success = nativeGetPageBox(env, thiz, documentPtr, pageIndex, PAGE_BOX_MEDIA, 300bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav outMediaBox); 301bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav return success ? JNI_TRUE : JNI_FALSE; 302bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav} 303bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav 304bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslavstatic jboolean nativeGetPageCropBox(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex, 305bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav jobject outMediaBox) { 306bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav const bool success = nativeGetPageBox(env, thiz, documentPtr, pageIndex, PAGE_BOX_CROP, 307bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav outMediaBox); 308bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav return success ? JNI_TRUE : JNI_FALSE; 309bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav} 310bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav 311bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslavstatic void nativeSetPageBox(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex, 312bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav PageBox pageBox, jobject box) { 313bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr); 314bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav 315bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav FPDF_PAGE page = FPDF_LoadPage(document, pageIndex); 316bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav if (!page) { 317bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav jniThrowException(env, "java/lang/IllegalStateException", 318bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav "cannot open page"); 319bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav return; 320bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav } 321bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav 322bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav const int left = env->GetIntField(box, gRectClassInfo.left); 323bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav const int top = env->GetIntField(box, gRectClassInfo.top); 324bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav const int right = env->GetIntField(box, gRectClassInfo.right); 325bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav const int bottom = env->GetIntField(box, gRectClassInfo.bottom); 326bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav 327bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav if (pageBox == PAGE_BOX_MEDIA) { 328bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav FPDFPage_SetMediaBox(page, left, top, right, bottom); 329bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav } else { 330bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav FPDFPage_SetCropBox(page, left, top, right, bottom); 331bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav } 332bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav 333bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav FPDF_ClosePage(page); 334bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav} 335bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav 336bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslavstatic void nativeSetPageMediaBox(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex, 337bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav jobject mediaBox) { 338bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav nativeSetPageBox(env, thiz, documentPtr, pageIndex, PAGE_BOX_MEDIA, mediaBox); 339bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav} 340bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav 341bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslavstatic void nativeSetPageCropBox(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex, 342bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav jobject mediaBox) { 343bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav nativeSetPageBox(env, thiz, documentPtr, pageIndex, PAGE_BOX_CROP, mediaBox); 344bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav} 345bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav 34676f6a86de25e1bf74717e047e55fd44b089673f3Daniel Micaystatic const JNINativeMethod gPdfEditor_Methods[] = { 34762ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav {"nativeOpen", "(IJ)J", (void*) nativeOpen}, 34862ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav {"nativeClose", "(J)V", (void*) nativeClose}, 34962ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav {"nativeGetPageCount", "(J)I", (void*) nativeGetPageCount}, 35062ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav {"nativeRemovePage", "(JI)I", (void*) nativeRemovePage}, 351bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav {"nativeWrite", "(JI)V", (void*) nativeWrite}, 352bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav {"nativeSetTransformAndClip", "(JIJIIII)V", (void*) nativeSetTransformAndClip}, 353bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav {"nativeGetPageSize", "(JILandroid/graphics/Point;)V", (void*) nativeGetPageSize}, 354bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav {"nativeScaleForPrinting", "(J)Z", (void*) nativeScaleForPrinting}, 355bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav {"nativeGetPageMediaBox", "(JILandroid/graphics/Rect;)Z", (void*) nativeGetPageMediaBox}, 356bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav {"nativeSetPageMediaBox", "(JILandroid/graphics/Rect;)V", (void*) nativeSetPageMediaBox}, 357bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav {"nativeGetPageCropBox", "(JILandroid/graphics/Rect;)Z", (void*) nativeGetPageCropBox}, 358bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav {"nativeSetPageCropBox", "(JILandroid/graphics/Rect;)V", (void*) nativeSetPageCropBox} 35962ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav}; 36062ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav 36162ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslavint register_android_graphics_pdf_PdfEditor(JNIEnv* env) { 3627d13d9db1ef90063cb542ccd6554042a6a3263b7Andreas Gampe const int result = RegisterMethodsOrDie( 36362ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav env, "android/graphics/pdf/PdfEditor", gPdfEditor_Methods, 36462ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav NELEM(gPdfEditor_Methods)); 365bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav 3667d13d9db1ef90063cb542ccd6554042a6a3263b7Andreas Gampe jclass pointClass = FindClassOrDie(env, "android/graphics/Point"); 3677d13d9db1ef90063cb542ccd6554042a6a3263b7Andreas Gampe gPointClassInfo.x = GetFieldIDOrDie(env, pointClass, "x", "I"); 3687d13d9db1ef90063cb542ccd6554042a6a3263b7Andreas Gampe gPointClassInfo.y = GetFieldIDOrDie(env, pointClass, "y", "I"); 369bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav 3707d13d9db1ef90063cb542ccd6554042a6a3263b7Andreas Gampe jclass rectClass = FindClassOrDie(env, "android/graphics/Rect"); 3717d13d9db1ef90063cb542ccd6554042a6a3263b7Andreas Gampe gRectClassInfo.left = GetFieldIDOrDie(env, rectClass, "left", "I"); 3727d13d9db1ef90063cb542ccd6554042a6a3263b7Andreas Gampe gRectClassInfo.top = GetFieldIDOrDie(env, rectClass, "top", "I"); 3737d13d9db1ef90063cb542ccd6554042a6a3263b7Andreas Gampe gRectClassInfo.right = GetFieldIDOrDie(env, rectClass, "right", "I"); 3747d13d9db1ef90063cb542ccd6554042a6a3263b7Andreas Gampe gRectClassInfo.bottom = GetFieldIDOrDie(env, rectClass, "bottom", "I"); 375bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav 376bec22beb99b279d381f720d761ca75fe3e7414dcSvetoslav return result; 37762ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav}; 37862ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav 37962ce332c141cf7bc7200c4c87d63e395874fc3ecSvetoslav}; 380