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