PdfDocument.cpp revision 71487eb0ceb2b7dea02649e78d99bb5952f5eaef
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 "core_jni_helpers.h"
20#include <vector>
21
22#include "Canvas.h"
23#include "CreateJavaOutputStreamAdaptor.h"
24
25#include "SkDocument.h"
26#include "SkPicture.h"
27#include "SkPictureRecorder.h"
28#include "SkStream.h"
29#include "SkRect.h"
30
31namespace android {
32
33struct PageRecord {
34
35    PageRecord(int width, int height, const SkRect& contentRect)
36            : mPictureRecorder(new SkPictureRecorder())
37            , mPicture(NULL)
38            , mWidth(width)
39            , mHeight(height) {
40        mContentRect = contentRect;
41    }
42
43    ~PageRecord() {
44        delete mPictureRecorder;
45        if (NULL != mPicture) {
46            mPicture->unref();
47        }
48    }
49
50    SkPictureRecorder* mPictureRecorder;
51    SkPicture* mPicture;
52    const int mWidth;
53    const int mHeight;
54    SkRect mContentRect;
55};
56
57class PdfDocument {
58public:
59    PdfDocument() {
60        mCurrentPage = NULL;
61    }
62
63    SkCanvas* startPage(int width, int height,
64            int contentLeft, int contentTop, int contentRight, int contentBottom) {
65        assert(mCurrentPage == NULL);
66
67        SkRect contentRect = SkRect::MakeLTRB(
68                contentLeft, contentTop, contentRight, contentBottom);
69        PageRecord* page = new PageRecord(width, height, contentRect);
70        mPages.push_back(page);
71        mCurrentPage = page;
72
73        SkCanvas* canvas = page->mPictureRecorder->beginRecording(
74                SkRect::MakeWH(contentRect.width(), contentRect.height()));
75
76        return canvas;
77    }
78
79    void finishPage() {
80        assert(mCurrentPage != NULL);
81        assert(mCurrentPage->mPictureRecorder != NULL);
82        assert(mCurrentPage->mPicture == NULL);
83        mCurrentPage->mPicture = mCurrentPage->mPictureRecorder->endRecording();
84        delete mCurrentPage->mPictureRecorder;
85        mCurrentPage->mPictureRecorder = NULL;
86        mCurrentPage = NULL;
87    }
88
89    void write(SkWStream* stream) {
90        SkDocument* document = SkDocument::CreatePDF(stream);
91        for (unsigned i = 0; i < mPages.size(); i++) {
92            PageRecord* page =  mPages[i];
93
94            SkCanvas* canvas = document->beginPage(page->mWidth, page->mHeight,
95                    &(page->mContentRect));
96
97            canvas->clipRect(page->mContentRect);
98            canvas->translate(page->mContentRect.left(), page->mContentRect.top());
99            canvas->drawPicture(page->mPicture);
100
101            document->endPage();
102        }
103        document->close();
104    }
105
106    void close() {
107        assert(NULL == mCurrentPage);
108        for (unsigned i = 0; i < mPages.size(); i++) {
109            delete mPages[i];
110        }
111    }
112
113private:
114    ~PdfDocument() {
115        close();
116    }
117
118    std::vector<PageRecord*> mPages;
119    PageRecord* mCurrentPage;
120};
121
122static jlong nativeCreateDocument(JNIEnv* env, jobject thiz) {
123    return reinterpret_cast<jlong>(new PdfDocument());
124}
125
126static jlong nativeStartPage(JNIEnv* env, jobject thiz, jlong documentPtr,
127        jint pageWidth, jint pageHeight,
128        jint contentLeft, jint contentTop, jint contentRight, jint contentBottom) {
129    PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr);
130    SkCanvas* canvas = document->startPage(pageWidth, pageHeight,
131            contentLeft, contentTop, contentRight, contentBottom);
132    return reinterpret_cast<jlong>(Canvas::create_canvas(canvas));
133}
134
135static void nativeFinishPage(JNIEnv* env, jobject thiz, jlong documentPtr) {
136    PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr);
137    document->finishPage();
138}
139
140static void nativeWriteTo(JNIEnv* env, jobject thiz, jlong documentPtr, jobject out,
141        jbyteArray chunk) {
142    PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr);
143    SkWStream* skWStream = CreateJavaOutputStreamAdaptor(env, out, chunk);
144    document->write(skWStream);
145    delete skWStream;
146}
147
148static void nativeClose(JNIEnv* env, jobject thiz, jlong documentPtr) {
149    PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr);
150    document->close();
151}
152
153static JNINativeMethod gPdfDocument_Methods[] = {
154    {"nativeCreateDocument", "()J", (void*) nativeCreateDocument},
155    {"nativeStartPage", "(JIIIIII)J", (void*) nativeStartPage},
156    {"nativeFinishPage", "(J)V", (void*) nativeFinishPage},
157    {"nativeWriteTo", "(JLjava/io/OutputStream;[B)V", (void*) nativeWriteTo},
158    {"nativeClose", "(J)V", (void*) nativeClose}
159};
160
161int register_android_graphics_pdf_PdfDocument(JNIEnv* env) {
162    return RegisterMethodsOrDie(
163            env, "android/graphics/pdf/PdfDocument", gPdfDocument_Methods,
164            NELEM(gPdfDocument_Methods));
165}
166
167};
168