PdfDocument.cpp revision cdf34469b3a49b73ffa4ab2766b55d7c0946fab1
1/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "jni.h"
18#include "GraphicsJNI.h"
19#include <android_runtime/AndroidRuntime.h>
20#include <vector>
21
22#include "CreateJavaOutputStreamAdaptor.h"
23
24#include "SkCanvas.h"
25#include "SkDocument.h"
26#include "SkPicture.h"
27#include "SkStream.h"
28#include "SkRect.h"
29
30namespace android {
31
32struct PageRecord {
33
34    PageRecord(int width, int height, const SkRect& contentRect)
35            : mPicture(new SkPicture()), mWidth(width), mHeight(height) {
36        mContentRect = contentRect;
37    }
38
39    ~PageRecord() {
40        mPicture->unref();
41    }
42
43    SkPicture* const mPicture;
44    const int mWidth;
45    const int mHeight;
46    SkRect mContentRect;
47};
48
49class PdfDocument {
50public:
51    PdfDocument() {
52        mCurrentPage = NULL;
53    }
54
55    SkCanvas* startPage(int width, int height,
56            int contentLeft, int contentTop, int contentRight, int contentBottom) {
57        assert(mCurrentPage == NULL);
58
59        SkRect contentRect = SkRect::MakeLTRB(
60                contentLeft, contentTop, contentRight, contentBottom);
61        PageRecord* page = new PageRecord(width, height, contentRect);
62        mPages.push_back(page);
63        mCurrentPage = page;
64
65        SkCanvas* canvas = page->mPicture->beginRecording(
66                contentRect.width(), contentRect.height(), 0);
67
68        // We pass this canvas to Java where it is used to construct
69        // a Java Canvas object which dereferences the pointer when it
70        // is destroyed, so we have to bump up the reference count.
71        canvas->ref();
72
73        return canvas;
74    }
75
76    void finishPage() {
77        assert(mCurrentPage != NULL);
78        mCurrentPage->mPicture->endRecording();
79        mCurrentPage = NULL;
80    }
81
82    void write(SkWStream* stream) {
83        SkDocument* document = SkDocument::CreatePDF(stream);
84        for (unsigned i = 0; i < mPages.size(); i++) {
85            PageRecord* page =  mPages[i];
86
87            SkCanvas* canvas = document->beginPage(page->mWidth, page->mHeight,
88                    &(page->mContentRect));
89
90            canvas->clipRect(page->mContentRect);
91            canvas->translate(page->mContentRect.left(), page->mContentRect.top());
92            canvas->drawPicture(*page->mPicture);
93
94            document->endPage();
95        }
96        document->close();
97    }
98
99    void close() {
100        for (unsigned i = 0; i < mPages.size(); i++) {
101            delete mPages[i];
102        }
103        delete mCurrentPage;
104        mCurrentPage = NULL;
105    }
106
107private:
108    ~PdfDocument() {
109        close();
110    }
111
112    std::vector<PageRecord*> mPages;
113    PageRecord* mCurrentPage;
114};
115
116static jlong nativeCreateDocument(JNIEnv* env, jobject thiz) {
117    return reinterpret_cast<jlong>(new PdfDocument());
118}
119
120static jlong nativeStartPage(JNIEnv* env, jobject thiz, jlong documentPtr,
121        jint pageWidth, jint pageHeight,
122        jint contentLeft, jint contentTop, jint contentRight, jint contentBottom) {
123    PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr);
124    return reinterpret_cast<jlong>(document->startPage(pageWidth, pageHeight,
125            contentLeft, contentTop, contentRight, contentBottom));
126}
127
128static void nativeFinishPage(JNIEnv* env, jobject thiz, jlong documentPtr) {
129    PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr);
130    document->finishPage();
131}
132
133static void nativeWriteTo(JNIEnv* env, jobject thiz, jlong documentPtr, jobject out,
134        jbyteArray chunk) {
135    PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr);
136    SkWStream* skWStream = CreateJavaOutputStreamAdaptor(env, out, chunk);
137    document->write(skWStream);
138    delete skWStream;
139}
140
141static void nativeClose(JNIEnv* env, jobject thiz, jlong documentPtr) {
142    PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr);
143    document->close();
144}
145
146static JNINativeMethod gPdfDocument_Methods[] = {
147    {"nativeCreateDocument", "()J", (void*) nativeCreateDocument},
148    {"nativeStartPage", "(JIIIIII)J", (void*) nativeStartPage},
149    {"nativeFinishPage", "(J)V", (void*) nativeFinishPage},
150    {"nativeWriteTo", "(JLjava/io/OutputStream;[B)V", (void*) nativeWriteTo},
151    {"nativeClose", "(J)V", (void*) nativeClose}
152};
153
154int register_android_graphics_pdf_PdfDocument(JNIEnv* env) {
155    int result = android::AndroidRuntime::registerNativeMethods(
156            env, "android/graphics/pdf/PdfDocument", gPdfDocument_Methods,
157            NELEM(gPdfDocument_Methods));
158    return result;
159}
160
161};
162