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