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 "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
31 namespace android {
32
33 struct PageRecord {
34
PageRecordandroid::PageRecord35 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
~PageRecordandroid::PageRecord43 ~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
57 class PdfDocument {
58 public:
PdfDocument()59 PdfDocument() {
60 mCurrentPage = NULL;
61 }
62
startPage(int width,int height,int contentLeft,int contentTop,int contentRight,int contentBottom)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 contentRect.width(), contentRect.height(), NULL, 0);
75
76 // We pass this canvas to Java where it is used to construct
77 // a Java Canvas object which dereferences the pointer when it
78 // is destroyed, so we have to bump up the reference count.
79 canvas->ref();
80
81 return canvas;
82 }
83
finishPage()84 void finishPage() {
85 assert(mCurrentPage != NULL);
86 assert(mCurrentPage->mPictureRecorder != NULL);
87 assert(mCurrentPage->mPicture == NULL);
88 mCurrentPage->mPicture = mCurrentPage->mPictureRecorder->endRecording();
89 delete mCurrentPage->mPictureRecorder;
90 mCurrentPage->mPictureRecorder = NULL;
91 mCurrentPage = NULL;
92 }
93
write(SkWStream * stream)94 void write(SkWStream* stream) {
95 SkDocument* document = SkDocument::CreatePDF(stream);
96 for (unsigned i = 0; i < mPages.size(); i++) {
97 PageRecord* page = mPages[i];
98
99 SkCanvas* canvas = document->beginPage(page->mWidth, page->mHeight,
100 &(page->mContentRect));
101
102 canvas->clipRect(page->mContentRect);
103 canvas->translate(page->mContentRect.left(), page->mContentRect.top());
104 canvas->drawPicture(page->mPicture);
105
106 document->endPage();
107 }
108 document->close();
109 }
110
close()111 void close() {
112 assert(NULL == mCurrentPage);
113 for (unsigned i = 0; i < mPages.size(); i++) {
114 delete mPages[i];
115 }
116 }
117
118 private:
~PdfDocument()119 ~PdfDocument() {
120 close();
121 }
122
123 std::vector<PageRecord*> mPages;
124 PageRecord* mCurrentPage;
125 };
126
nativeCreateDocument(JNIEnv * env,jobject thiz)127 static jlong nativeCreateDocument(JNIEnv* env, jobject thiz) {
128 return reinterpret_cast<jlong>(new PdfDocument());
129 }
130
nativeStartPage(JNIEnv * env,jobject thiz,jlong documentPtr,jint pageWidth,jint pageHeight,jint contentLeft,jint contentTop,jint contentRight,jint contentBottom)131 static jlong nativeStartPage(JNIEnv* env, jobject thiz, jlong documentPtr,
132 jint pageWidth, jint pageHeight,
133 jint contentLeft, jint contentTop, jint contentRight, jint contentBottom) {
134 PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr);
135 SkCanvas* canvas = document->startPage(pageWidth, pageHeight,
136 contentLeft, contentTop, contentRight, contentBottom);
137 return reinterpret_cast<jlong>(Canvas::create_canvas(canvas));
138 }
139
nativeFinishPage(JNIEnv * env,jobject thiz,jlong documentPtr)140 static void nativeFinishPage(JNIEnv* env, jobject thiz, jlong documentPtr) {
141 PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr);
142 document->finishPage();
143 }
144
nativeWriteTo(JNIEnv * env,jobject thiz,jlong documentPtr,jobject out,jbyteArray chunk)145 static void nativeWriteTo(JNIEnv* env, jobject thiz, jlong documentPtr, jobject out,
146 jbyteArray chunk) {
147 PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr);
148 SkWStream* skWStream = CreateJavaOutputStreamAdaptor(env, out, chunk);
149 document->write(skWStream);
150 delete skWStream;
151 }
152
nativeClose(JNIEnv * env,jobject thiz,jlong documentPtr)153 static void nativeClose(JNIEnv* env, jobject thiz, jlong documentPtr) {
154 PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr);
155 document->close();
156 }
157
158 static JNINativeMethod gPdfDocument_Methods[] = {
159 {"nativeCreateDocument", "()J", (void*) nativeCreateDocument},
160 {"nativeStartPage", "(JIIIIII)J", (void*) nativeStartPage},
161 {"nativeFinishPage", "(J)V", (void*) nativeFinishPage},
162 {"nativeWriteTo", "(JLjava/io/OutputStream;[B)V", (void*) nativeWriteTo},
163 {"nativeClose", "(J)V", (void*) nativeClose}
164 };
165
register_android_graphics_pdf_PdfDocument(JNIEnv * env)166 int register_android_graphics_pdf_PdfDocument(JNIEnv* env) {
167 int result = android::AndroidRuntime::registerNativeMethods(
168 env, "android/graphics/pdf/PdfDocument", gPdfDocument_Methods,
169 NELEM(gPdfDocument_Methods));
170 return result;
171 }
172
173 };
174