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
2235aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav#include "CreateJavaOutputStreamAdaptor.h"
23ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov
2435aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav#include "SkDocument.h"
2535aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav#include "SkPicture.h"
26b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips#include "SkPictureRecorder.h"
2735aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav#include "SkStream.h"
28ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov#include "SkRect.h"
29ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov
30dccca44ffda4836b56a21da95a046c9708ffd49csergeyv#include <hwui/Canvas.h>
31dccca44ffda4836b56a21da95a046c9708ffd49csergeyv
32ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganovnamespace android {
33ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov
3435aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslavstruct PageRecord {
356811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslav
3635aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    PageRecord(int width, int height, const SkRect& contentRect)
37b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips            : mPictureRecorder(new SkPictureRecorder())
38b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips            , mPicture(NULL)
39b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips            , mWidth(width)
40b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips            , mHeight(height) {
4135aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        mContentRect = contentRect;
4235aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    }
43ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov
4435aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    ~PageRecord() {
45b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips        delete mPictureRecorder;
46b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips        if (NULL != mPicture) {
47b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips            mPicture->unref();
48b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips        }
4935aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    }
50ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov
51b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips    SkPictureRecorder* mPictureRecorder;
52b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips    SkPicture* mPicture;
5335aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    const int mWidth;
5435aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    const int mHeight;
5535aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    SkRect mContentRect;
5635aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav};
5735aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav
5835aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslavclass PdfDocument {
5935aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslavpublic:
6035aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    PdfDocument() {
6135aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        mCurrentPage = NULL;
6235aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    }
6335aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav
6435aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    SkCanvas* startPage(int width, int height,
6535aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav            int contentLeft, int contentTop, int contentRight, int contentBottom) {
6635aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        assert(mCurrentPage == NULL);
6735aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav
6835aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        SkRect contentRect = SkRect::MakeLTRB(
6935aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav                contentLeft, contentTop, contentRight, contentBottom);
7035aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        PageRecord* page = new PageRecord(width, height, contentRect);
7135aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        mPages.push_back(page);
7235aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        mCurrentPage = page;
7335aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav
74b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips        SkCanvas* canvas = page->mPictureRecorder->beginRecording(
7571487eb0ceb2b7dea02649e78d99bb5952f5eaefMike Reed                SkRect::MakeWH(contentRect.width(), contentRect.height()));
7635aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav
7735aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        return canvas;
7835aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    }
79ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov
8035aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    void finishPage() {
8135aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        assert(mCurrentPage != NULL);
82b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips        assert(mCurrentPage->mPictureRecorder != NULL);
83b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips        assert(mCurrentPage->mPicture == NULL);
84b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips        mCurrentPage->mPicture = mCurrentPage->mPictureRecorder->endRecording();
85b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips        delete mCurrentPage->mPictureRecorder;
86b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips        mCurrentPage->mPictureRecorder = NULL;
8735aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        mCurrentPage = NULL;
8835aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    }
89ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov
9035aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    void write(SkWStream* stream) {
91424784d60e475cd1ce1d8168491f07a23f213109Hal Canary        SkAutoTUnref<SkDocument> document(SkDocument::CreatePDF(stream));
9235aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        for (unsigned i = 0; i < mPages.size(); i++) {
9335aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav            PageRecord* page =  mPages[i];
94ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov
9535aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav            SkCanvas* canvas = document->beginPage(page->mWidth, page->mHeight,
9635aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav                    &(page->mContentRect));
9735aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav
98b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips            canvas->drawPicture(page->mPicture);
9935aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav
10035aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav            document->endPage();
10135aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        }
10235aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        document->close();
10335aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    }
10435aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav
10535aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    void close() {
106b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips        assert(NULL == mCurrentPage);
10735aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        for (unsigned i = 0; i < mPages.size(); i++) {
10835aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav            delete mPages[i];
10935aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        }
11035aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    }
11135aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav
11235aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslavprivate:
11335aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    ~PdfDocument() {
11435aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        close();
11535aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    }
11635aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav
11735aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    std::vector<PageRecord*> mPages;
11835aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    PageRecord* mCurrentPage;
11935aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav};
12035aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav
121cdf34469b3a49b73ffa4ab2766b55d7c0946fab1Ashok Bhatstatic jlong nativeCreateDocument(JNIEnv* env, jobject thiz) {
122cdf34469b3a49b73ffa4ab2766b55d7c0946fab1Ashok Bhat    return reinterpret_cast<jlong>(new PdfDocument());
12335aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav}
12435aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav
125cdf34469b3a49b73ffa4ab2766b55d7c0946fab1Ashok Bhatstatic jlong nativeStartPage(JNIEnv* env, jobject thiz, jlong documentPtr,
12635aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        jint pageWidth, jint pageHeight,
12735aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        jint contentLeft, jint contentTop, jint contentRight, jint contentBottom) {
12835aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr);
1298872b38ef403cc2c44aca07d392f5e9426fd7f54Derek Sollenberger    SkCanvas* canvas = document->startPage(pageWidth, pageHeight,
1308872b38ef403cc2c44aca07d392f5e9426fd7f54Derek Sollenberger            contentLeft, contentTop, contentRight, contentBottom);
1318872b38ef403cc2c44aca07d392f5e9426fd7f54Derek Sollenberger    return reinterpret_cast<jlong>(Canvas::create_canvas(canvas));
132ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov}
133ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov
134cdf34469b3a49b73ffa4ab2766b55d7c0946fab1Ashok Bhatstatic void nativeFinishPage(JNIEnv* env, jobject thiz, jlong documentPtr) {
13535aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr);
13635aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    document->finishPage();
137ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov}
138ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov
139cdf34469b3a49b73ffa4ab2766b55d7c0946fab1Ashok Bhatstatic void nativeWriteTo(JNIEnv* env, jobject thiz, jlong documentPtr, jobject out,
14035aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        jbyteArray chunk) {
14135aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr);
142ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov    SkWStream* skWStream = CreateJavaOutputStreamAdaptor(env, out, chunk);
14335aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    document->write(skWStream);
144ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov    delete skWStream;
145ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov}
146ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov
147cdf34469b3a49b73ffa4ab2766b55d7c0946fab1Ashok Bhatstatic void nativeClose(JNIEnv* env, jobject thiz, jlong documentPtr) {
14835aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr);
14935aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    document->close();
15035aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav}
15135aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav
15276f6a86de25e1bf74717e047e55fd44b089673f3Daniel Micaystatic const JNINativeMethod gPdfDocument_Methods[] = {
153cdf34469b3a49b73ffa4ab2766b55d7c0946fab1Ashok Bhat    {"nativeCreateDocument", "()J", (void*) nativeCreateDocument},
154cdf34469b3a49b73ffa4ab2766b55d7c0946fab1Ashok Bhat    {"nativeStartPage", "(JIIIIII)J", (void*) nativeStartPage},
155cdf34469b3a49b73ffa4ab2766b55d7c0946fab1Ashok Bhat    {"nativeFinishPage", "(J)V", (void*) nativeFinishPage},
156cdf34469b3a49b73ffa4ab2766b55d7c0946fab1Ashok Bhat    {"nativeWriteTo", "(JLjava/io/OutputStream;[B)V", (void*) nativeWriteTo},
157cdf34469b3a49b73ffa4ab2766b55d7c0946fab1Ashok Bhat    {"nativeClose", "(J)V", (void*) nativeClose}
158ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov};
159ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov
1606811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslavint register_android_graphics_pdf_PdfDocument(JNIEnv* env) {
161ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe    return RegisterMethodsOrDie(
1626811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslav            env, "android/graphics/pdf/PdfDocument", gPdfDocument_Methods,
163ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov            NELEM(gPdfDocument_Methods));
164ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov}
165ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov
166ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov};
167