PdfDocument.cpp revision ed6b9dff563c5e22f040ff37e12c0d771e0478ae
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"
19ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe#include "core_jni_helpers.h"
2035aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav#include <vector>
2135aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav
228872b38ef403cc2c44aca07d392f5e9426fd7f54Derek Sollenberger#include "Canvas.h"
2335aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav#include "CreateJavaOutputStreamAdaptor.h"
24ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov
2535aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav#include "SkDocument.h"
2635aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav#include "SkPicture.h"
27b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips#include "SkPictureRecorder.h"
2835aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav#include "SkStream.h"
29ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov#include "SkRect.h"
30ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov
31ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganovnamespace android {
32ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov
3335aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslavstruct PageRecord {
346811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslav
3535aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    PageRecord(int width, int height, const SkRect& contentRect)
36b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips            : mPictureRecorder(new SkPictureRecorder())
37b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips            , mPicture(NULL)
38b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips            , mWidth(width)
39b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips            , mHeight(height) {
4035aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        mContentRect = contentRect;
4135aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    }
42ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov
4335aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    ~PageRecord() {
44b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips        delete mPictureRecorder;
45b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips        if (NULL != mPicture) {
46b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips            mPicture->unref();
47b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips        }
4835aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    }
49ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov
50b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips    SkPictureRecorder* mPictureRecorder;
51b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips    SkPicture* mPicture;
5235aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    const int mWidth;
5335aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    const int mHeight;
5435aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    SkRect mContentRect;
5535aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav};
5635aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav
5735aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslavclass PdfDocument {
5835aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslavpublic:
5935aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    PdfDocument() {
6035aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        mCurrentPage = NULL;
6135aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    }
6235aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav
6335aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    SkCanvas* startPage(int width, int height,
6435aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav            int contentLeft, int contentTop, int contentRight, int contentBottom) {
6535aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        assert(mCurrentPage == NULL);
6635aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav
6735aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        SkRect contentRect = SkRect::MakeLTRB(
6835aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav                contentLeft, contentTop, contentRight, contentBottom);
6935aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        PageRecord* page = new PageRecord(width, height, contentRect);
7035aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        mPages.push_back(page);
7135aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        mCurrentPage = page;
7235aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav
73b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips        SkCanvas* canvas = page->mPictureRecorder->beginRecording(
74b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips                contentRect.width(), contentRect.height(), NULL, 0);
7535aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav
7635aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        // We pass this canvas to Java where it is used to construct
7735aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        // a Java Canvas object which dereferences the pointer when it
7835aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        // is destroyed, so we have to bump up the reference count.
7935aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        canvas->ref();
8035aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav
8135aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        return canvas;
8235aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    }
83ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov
8435aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    void finishPage() {
8535aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        assert(mCurrentPage != NULL);
86b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips        assert(mCurrentPage->mPictureRecorder != NULL);
87b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips        assert(mCurrentPage->mPicture == NULL);
88b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips        mCurrentPage->mPicture = mCurrentPage->mPictureRecorder->endRecording();
89b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips        delete mCurrentPage->mPictureRecorder;
90b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips        mCurrentPage->mPictureRecorder = NULL;
9135aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        mCurrentPage = NULL;
9235aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    }
93ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov
9435aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    void write(SkWStream* stream) {
9535aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        SkDocument* document = SkDocument::CreatePDF(stream);
9635aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        for (unsigned i = 0; i < mPages.size(); i++) {
9735aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav            PageRecord* page =  mPages[i];
98ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov
9935aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav            SkCanvas* canvas = document->beginPage(page->mWidth, page->mHeight,
10035aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav                    &(page->mContentRect));
10135aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav
10235aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav            canvas->clipRect(page->mContentRect);
10335aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav            canvas->translate(page->mContentRect.left(), page->mContentRect.top());
104b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips            canvas->drawPicture(page->mPicture);
10535aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav
10635aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav            document->endPage();
10735aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        }
10835aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        document->close();
10935aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    }
11035aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav
11135aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    void close() {
112b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips        assert(NULL == mCurrentPage);
11335aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        for (unsigned i = 0; i < mPages.size(); i++) {
11435aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav            delete mPages[i];
11535aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        }
11635aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    }
11735aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav
11835aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslavprivate:
11935aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    ~PdfDocument() {
12035aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        close();
12135aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    }
12235aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav
12335aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    std::vector<PageRecord*> mPages;
12435aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    PageRecord* mCurrentPage;
12535aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav};
12635aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav
127cdf34469b3a49b73ffa4ab2766b55d7c0946fab1Ashok Bhatstatic jlong nativeCreateDocument(JNIEnv* env, jobject thiz) {
128cdf34469b3a49b73ffa4ab2766b55d7c0946fab1Ashok Bhat    return reinterpret_cast<jlong>(new PdfDocument());
12935aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav}
13035aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav
131cdf34469b3a49b73ffa4ab2766b55d7c0946fab1Ashok Bhatstatic jlong nativeStartPage(JNIEnv* env, jobject thiz, jlong documentPtr,
13235aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        jint pageWidth, jint pageHeight,
13335aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        jint contentLeft, jint contentTop, jint contentRight, jint contentBottom) {
13435aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr);
1358872b38ef403cc2c44aca07d392f5e9426fd7f54Derek Sollenberger    SkCanvas* canvas = document->startPage(pageWidth, pageHeight,
1368872b38ef403cc2c44aca07d392f5e9426fd7f54Derek Sollenberger            contentLeft, contentTop, contentRight, contentBottom);
1378872b38ef403cc2c44aca07d392f5e9426fd7f54Derek Sollenberger    return reinterpret_cast<jlong>(Canvas::create_canvas(canvas));
138ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov}
139ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov
140cdf34469b3a49b73ffa4ab2766b55d7c0946fab1Ashok Bhatstatic void nativeFinishPage(JNIEnv* env, jobject thiz, jlong documentPtr) {
14135aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr);
14235aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    document->finishPage();
143ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov}
144ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov
145cdf34469b3a49b73ffa4ab2766b55d7c0946fab1Ashok Bhatstatic void nativeWriteTo(JNIEnv* env, jobject thiz, jlong documentPtr, jobject out,
14635aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        jbyteArray chunk) {
14735aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr);
148ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov    SkWStream* skWStream = CreateJavaOutputStreamAdaptor(env, out, chunk);
14935aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    document->write(skWStream);
150ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov    delete skWStream;
151ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov}
152ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov
153cdf34469b3a49b73ffa4ab2766b55d7c0946fab1Ashok Bhatstatic void nativeClose(JNIEnv* env, jobject thiz, jlong documentPtr) {
15435aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr);
15535aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    document->close();
15635aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav}
15735aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav
158ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganovstatic JNINativeMethod gPdfDocument_Methods[] = {
159cdf34469b3a49b73ffa4ab2766b55d7c0946fab1Ashok Bhat    {"nativeCreateDocument", "()J", (void*) nativeCreateDocument},
160cdf34469b3a49b73ffa4ab2766b55d7c0946fab1Ashok Bhat    {"nativeStartPage", "(JIIIIII)J", (void*) nativeStartPage},
161cdf34469b3a49b73ffa4ab2766b55d7c0946fab1Ashok Bhat    {"nativeFinishPage", "(J)V", (void*) nativeFinishPage},
162cdf34469b3a49b73ffa4ab2766b55d7c0946fab1Ashok Bhat    {"nativeWriteTo", "(JLjava/io/OutputStream;[B)V", (void*) nativeWriteTo},
163cdf34469b3a49b73ffa4ab2766b55d7c0946fab1Ashok Bhat    {"nativeClose", "(J)V", (void*) nativeClose}
164ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov};
165ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov
1666811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslavint register_android_graphics_pdf_PdfDocument(JNIEnv* env) {
167ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe    return RegisterMethodsOrDie(
1686811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslav            env, "android/graphics/pdf/PdfDocument", gPdfDocument_Methods,
169ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov            NELEM(gPdfDocument_Methods));
170ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov}
171ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov
172ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov};
173