PdfDocument.cpp revision ed6b9dff563c5e22f040ff37e12c0d771e0478ae
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 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 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 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 111 void close() { 112 assert(NULL == mCurrentPage); 113 for (unsigned i = 0; i < mPages.size(); i++) { 114 delete mPages[i]; 115 } 116 } 117 118private: 119 ~PdfDocument() { 120 close(); 121 } 122 123 std::vector<PageRecord*> mPages; 124 PageRecord* mCurrentPage; 125}; 126 127static jlong nativeCreateDocument(JNIEnv* env, jobject thiz) { 128 return reinterpret_cast<jlong>(new PdfDocument()); 129} 130 131static 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 140static void nativeFinishPage(JNIEnv* env, jobject thiz, jlong documentPtr) { 141 PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr); 142 document->finishPage(); 143} 144 145static 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 153static void nativeClose(JNIEnv* env, jobject thiz, jlong documentPtr) { 154 PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr); 155 document->close(); 156} 157 158static 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 166int register_android_graphics_pdf_PdfDocument(JNIEnv* env) { 167 return RegisterMethodsOrDie( 168 env, "android/graphics/pdf/PdfDocument", gPdfDocument_Methods, 169 NELEM(gPdfDocument_Methods)); 170} 171 172}; 173