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
24ea70d22dc8dc5d61f075edf6d03f86f6a68169cdMatt Sarett#include "SkColorSpaceXformCanvas.h"
2535aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav#include "SkDocument.h"
2635aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav#include "SkPicture.h"
27b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips#include "SkPictureRecorder.h"
2835aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav#include "SkStream.h"
29ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov#include "SkRect.h"
30ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov
31dccca44ffda4836b56a21da95a046c9708ffd49csergeyv#include <hwui/Canvas.h>
32dccca44ffda4836b56a21da95a046c9708ffd49csergeyv
33ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganovnamespace android {
34ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov
3535aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslavstruct PageRecord {
366811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslav
3735aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    PageRecord(int width, int height, const SkRect& contentRect)
38b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips            : mPictureRecorder(new SkPictureRecorder())
39b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips            , mPicture(NULL)
40b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips            , mWidth(width)
41b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips            , mHeight(height) {
4235aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        mContentRect = contentRect;
4335aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    }
44ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov
4535aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    ~PageRecord() {
46b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips        delete mPictureRecorder;
47b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips        if (NULL != mPicture) {
48b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips            mPicture->unref();
49b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips        }
5035aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    }
51ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov
52b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips    SkPictureRecorder* mPictureRecorder;
53b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips    SkPicture* mPicture;
5435aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    const int mWidth;
5535aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    const int mHeight;
5635aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    SkRect mContentRect;
5735aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav};
5835aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav
5935aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslavclass PdfDocument {
6035aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslavpublic:
6135aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    PdfDocument() {
6235aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        mCurrentPage = NULL;
6335aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    }
6435aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav
6535aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    SkCanvas* startPage(int width, int height,
6635aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav            int contentLeft, int contentTop, int contentRight, int contentBottom) {
6735aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        assert(mCurrentPage == NULL);
6835aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav
6935aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        SkRect contentRect = SkRect::MakeLTRB(
7035aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav                contentLeft, contentTop, contentRight, contentBottom);
7135aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        PageRecord* page = new PageRecord(width, height, contentRect);
7235aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        mPages.push_back(page);
7335aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        mCurrentPage = page;
7435aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav
75b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips        SkCanvas* canvas = page->mPictureRecorder->beginRecording(
7671487eb0ceb2b7dea02649e78d99bb5952f5eaefMike Reed                SkRect::MakeWH(contentRect.width(), contentRect.height()));
7735aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav
7835aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        return canvas;
7935aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    }
80ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov
8135aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    void finishPage() {
8235aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        assert(mCurrentPage != NULL);
83b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips        assert(mCurrentPage->mPictureRecorder != NULL);
84b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips        assert(mCurrentPage->mPicture == NULL);
85260ab726486317496bc12a57d599ea96dcde3284Mike Reed        mCurrentPage->mPicture = mCurrentPage->mPictureRecorder->finishRecordingAsPicture().release();
86b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips        delete mCurrentPage->mPictureRecorder;
87b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips        mCurrentPage->mPictureRecorder = NULL;
8835aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        mCurrentPage = NULL;
8935aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    }
90ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov
9135aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    void write(SkWStream* stream) {
924cb7bb53f987ccfccbd786aef378d87bea41fe1fHal Canary        sk_sp<SkDocument> document = SkDocument::MakePDF(stream);
9335aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        for (unsigned i = 0; i < mPages.size(); i++) {
9435aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav            PageRecord* page =  mPages[i];
95ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov
9635aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav            SkCanvas* canvas = document->beginPage(page->mWidth, page->mHeight,
9735aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav                    &(page->mContentRect));
98ea70d22dc8dc5d61f075edf6d03f86f6a68169cdMatt Sarett            std::unique_ptr<SkCanvas> toSRGBCanvas =
99ea70d22dc8dc5d61f075edf6d03f86f6a68169cdMatt Sarett                    SkCreateColorSpaceXformCanvas(canvas, SkColorSpace::MakeSRGB());
10035aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav
101ea70d22dc8dc5d61f075edf6d03f86f6a68169cdMatt Sarett            toSRGBCanvas->drawPicture(page->mPicture);
10235aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav
10335aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav            document->endPage();
10435aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        }
10535aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        document->close();
10635aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    }
10735aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav
10835aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    void close() {
109b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips        assert(NULL == mCurrentPage);
11035aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        for (unsigned i = 0; i < mPages.size(); i++) {
11135aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav            delete mPages[i];
11235aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        }
11335aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    }
11435aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav
11535aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslavprivate:
11635aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    ~PdfDocument() {
11735aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        close();
11835aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    }
11935aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav
12035aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    std::vector<PageRecord*> mPages;
12135aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    PageRecord* mCurrentPage;
12235aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav};
12335aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav
124cdf34469b3a49b73ffa4ab2766b55d7c0946fab1Ashok Bhatstatic jlong nativeCreateDocument(JNIEnv* env, jobject thiz) {
125cdf34469b3a49b73ffa4ab2766b55d7c0946fab1Ashok Bhat    return reinterpret_cast<jlong>(new PdfDocument());
12635aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav}
12735aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav
128cdf34469b3a49b73ffa4ab2766b55d7c0946fab1Ashok Bhatstatic jlong nativeStartPage(JNIEnv* env, jobject thiz, jlong documentPtr,
12935aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        jint pageWidth, jint pageHeight,
13035aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        jint contentLeft, jint contentTop, jint contentRight, jint contentBottom) {
13135aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr);
1328872b38ef403cc2c44aca07d392f5e9426fd7f54Derek Sollenberger    SkCanvas* canvas = document->startPage(pageWidth, pageHeight,
1338872b38ef403cc2c44aca07d392f5e9426fd7f54Derek Sollenberger            contentLeft, contentTop, contentRight, contentBottom);
134ea70d22dc8dc5d61f075edf6d03f86f6a68169cdMatt Sarett    return reinterpret_cast<jlong>(Canvas::create_canvas(canvas, Canvas::XformToSRGB::kDefer));
135ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov}
136ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov
137cdf34469b3a49b73ffa4ab2766b55d7c0946fab1Ashok Bhatstatic void nativeFinishPage(JNIEnv* env, jobject thiz, jlong documentPtr) {
13835aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr);
13935aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    document->finishPage();
140ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov}
141ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov
142cdf34469b3a49b73ffa4ab2766b55d7c0946fab1Ashok Bhatstatic void nativeWriteTo(JNIEnv* env, jobject thiz, jlong documentPtr, jobject out,
14335aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav        jbyteArray chunk) {
14435aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr);
145ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov    SkWStream* skWStream = CreateJavaOutputStreamAdaptor(env, out, chunk);
14635aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    document->write(skWStream);
147ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov    delete skWStream;
148ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov}
149ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov
150cdf34469b3a49b73ffa4ab2766b55d7c0946fab1Ashok Bhatstatic void nativeClose(JNIEnv* env, jobject thiz, jlong documentPtr) {
15135aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr);
15235aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav    document->close();
15335aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav}
15435aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav
15576f6a86de25e1bf74717e047e55fd44b089673f3Daniel Micaystatic const JNINativeMethod gPdfDocument_Methods[] = {
156cdf34469b3a49b73ffa4ab2766b55d7c0946fab1Ashok Bhat    {"nativeCreateDocument", "()J", (void*) nativeCreateDocument},
157cdf34469b3a49b73ffa4ab2766b55d7c0946fab1Ashok Bhat    {"nativeStartPage", "(JIIIIII)J", (void*) nativeStartPage},
158cdf34469b3a49b73ffa4ab2766b55d7c0946fab1Ashok Bhat    {"nativeFinishPage", "(J)V", (void*) nativeFinishPage},
159cdf34469b3a49b73ffa4ab2766b55d7c0946fab1Ashok Bhat    {"nativeWriteTo", "(JLjava/io/OutputStream;[B)V", (void*) nativeWriteTo},
160cdf34469b3a49b73ffa4ab2766b55d7c0946fab1Ashok Bhat    {"nativeClose", "(J)V", (void*) nativeClose}
161ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov};
162ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov
1636811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslavint register_android_graphics_pdf_PdfDocument(JNIEnv* env) {
164ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe    return RegisterMethodsOrDie(
1656811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslav            env, "android/graphics/pdf/PdfDocument", gPdfDocument_Methods,
166ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov            NELEM(gPdfDocument_Methods));
167ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov}
168ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov
169ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov};
170