1ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov/* 2ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov * Copyright (C) 2013 The Android Open Source Project 3ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov * 4ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov * Licensed under the Apache License, Version 2.0 (the "License"); 5ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov * you may not use this file except in compliance with the License. 6ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov * You may obtain a copy of the License at 7ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov * 8ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov * http://www.apache.org/licenses/LICENSE-2.0 9ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov * 10ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov * Unless required by applicable law or agreed to in writing, software 11ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov * distributed under the License is distributed on an "AS IS" BASIS, 12ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov * See the License for the specific language governing permissions and 14ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov * limitations under the License. 15ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov */ 16ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov 17ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov#include "jni.h" 18ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov#include "GraphicsJNI.h" 19ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov#include <android_runtime/AndroidRuntime.h> 2035aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav#include <vector> 2135aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav 2235aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav#include "CreateJavaOutputStreamAdaptor.h" 23ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov 24ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov#include "SkCanvas.h" 2535aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav#include "SkDocument.h" 2635aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav#include "SkPicture.h" 2735aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav#include "SkStream.h" 28ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov#include "SkRect.h" 29ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov 30ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganovnamespace android { 31ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov 3235aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslavstruct PageRecord { 336811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslav 3435aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav PageRecord(int width, int height, const SkRect& contentRect) 3535aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav : mPicture(new SkPicture()), mWidth(width), mHeight(height) { 3635aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav mContentRect = contentRect; 3735aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav } 38ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov 3935aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav ~PageRecord() { 4035aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav mPicture->unref(); 4135aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav } 42ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov 4335aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav SkPicture* const mPicture; 4435aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav const int mWidth; 4535aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav const int mHeight; 4635aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav SkRect mContentRect; 4735aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav}; 4835aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav 4935aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslavclass PdfDocument { 5035aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslavpublic: 5135aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav PdfDocument() { 5235aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav mCurrentPage = NULL; 5335aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav } 5435aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav 5535aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav SkCanvas* startPage(int width, int height, 5635aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav int contentLeft, int contentTop, int contentRight, int contentBottom) { 5735aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav assert(mCurrentPage == NULL); 5835aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav 5935aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav SkRect contentRect = SkRect::MakeLTRB( 6035aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav contentLeft, contentTop, contentRight, contentBottom); 6135aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav PageRecord* page = new PageRecord(width, height, contentRect); 6235aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav mPages.push_back(page); 6335aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav mCurrentPage = page; 6435aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav 6535aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav SkCanvas* canvas = page->mPicture->beginRecording( 6635aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav contentRect.width(), contentRect.height(), 0); 6735aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav 6835aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav // We pass this canvas to Java where it is used to construct 6935aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav // a Java Canvas object which dereferences the pointer when it 7035aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav // is destroyed, so we have to bump up the reference count. 7135aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav canvas->ref(); 7235aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav 7335aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav return canvas; 7435aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav } 75ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov 7635aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav void finishPage() { 7735aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav assert(mCurrentPage != NULL); 7835aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav mCurrentPage->mPicture->endRecording(); 7935aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav mCurrentPage = NULL; 8035aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav } 81ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov 8235aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav void write(SkWStream* stream) { 8335aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav SkDocument* document = SkDocument::CreatePDF(stream); 8435aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav for (unsigned i = 0; i < mPages.size(); i++) { 8535aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav PageRecord* page = mPages[i]; 86ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov 8735aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav SkCanvas* canvas = document->beginPage(page->mWidth, page->mHeight, 8835aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav &(page->mContentRect)); 8935aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav 9035aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav canvas->clipRect(page->mContentRect); 9135aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav canvas->translate(page->mContentRect.left(), page->mContentRect.top()); 9235aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav canvas->drawPicture(*page->mPicture); 9335aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav 9435aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav document->endPage(); 9535aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav } 9635aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav document->close(); 9735aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav } 9835aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav 9935aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav void close() { 10035aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav for (unsigned i = 0; i < mPages.size(); i++) { 10135aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav delete mPages[i]; 10235aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav } 10335aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav delete mCurrentPage; 10435aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav mCurrentPage = NULL; 10535aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav } 10635aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav 10735aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslavprivate: 10835aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav ~PdfDocument() { 10935aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav close(); 11035aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav } 11135aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav 11235aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav std::vector<PageRecord*> mPages; 11335aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav PageRecord* mCurrentPage; 11435aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav}; 11535aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav 11635aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslavstatic jint nativeCreateDocument(JNIEnv* env, jobject thiz) { 11735aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav return reinterpret_cast<jint>(new PdfDocument()); 11835aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav} 11935aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav 12035aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslavstatic jint nativeStartPage(JNIEnv* env, jobject thiz, jint documentPtr, 12135aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav jint pageWidth, jint pageHeight, 12235aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav jint contentLeft, jint contentTop, jint contentRight, jint contentBottom) { 12335aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr); 12435aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav return reinterpret_cast<jint>(document->startPage(pageWidth, pageHeight, 12535aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav contentLeft, contentTop, contentRight, contentBottom)); 126ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov} 127ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov 12835aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslavstatic void nativeFinishPage(JNIEnv* env, jobject thiz, jint documentPtr) { 12935aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr); 13035aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav document->finishPage(); 131ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov} 132ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov 13335aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslavstatic void nativeWriteTo(JNIEnv* env, jobject thiz, jint documentPtr, jobject out, 13435aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav jbyteArray chunk) { 13535aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr); 136ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov SkWStream* skWStream = CreateJavaOutputStreamAdaptor(env, out, chunk); 13735aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav document->write(skWStream); 138ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov delete skWStream; 139ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov} 140ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov 14135aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslavstatic void nativeClose(JNIEnv* env, jobject thiz, jint documentPtr) { 14235aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr); 14335aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav document->close(); 14435aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav} 14535aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav 146ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganovstatic JNINativeMethod gPdfDocument_Methods[] = { 147ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov {"nativeCreateDocument", "()I", (void*) nativeCreateDocument}, 14835aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav {"nativeStartPage", "(IIIIIII)I", (void*) nativeStartPage}, 14935aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav {"nativeFinishPage", "(I)V", (void*) nativeFinishPage}, 15035aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav {"nativeWriteTo", "(ILjava/io/OutputStream;[B)V", (void*) nativeWriteTo}, 15135aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav {"nativeClose", "(I)V", (void*) nativeClose} 152ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov}; 153ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov 1546811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslavint register_android_graphics_pdf_PdfDocument(JNIEnv* env) { 155ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov int result = android::AndroidRuntime::registerNativeMethods( 1566811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslav env, "android/graphics/pdf/PdfDocument", gPdfDocument_Methods, 157ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov NELEM(gPdfDocument_Methods)); 158ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov return result; 159ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov} 160ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov 161ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov}; 162