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