1ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov/* 2ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov * Copyright (C) 2013 The Android Open Source Project 3ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov * 4ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov * Licensed under the Apache License, Version 2.0 (the "License"); 5ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov * you may not use this file except in compliance with the License. 6ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov * You may obtain a copy of the License at 7ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov * 8ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov * http://www.apache.org/licenses/LICENSE-2.0 9ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov * 10ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov * Unless required by applicable law or agreed to in writing, software 11ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov * distributed under the License is distributed on an "AS IS" BASIS, 12ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov * See the License for the specific language governing permissions and 14ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov * limitations under the License. 15ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov */ 16ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov 17ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov#include "jni.h" 18ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov#include "GraphicsJNI.h" 19ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe#include "core_jni_helpers.h" 2035aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav#include <vector> 2135aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav 2235aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav#include "CreateJavaOutputStreamAdaptor.h" 23ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov 24ea70d22dc8dc5d61f075edf6d03f86f6a68169cdMatt Sarett#include "SkColorSpaceXformCanvas.h" 2535aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav#include "SkDocument.h" 2635aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav#include "SkPicture.h" 27b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips#include "SkPictureRecorder.h" 2835aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav#include "SkStream.h" 29ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov#include "SkRect.h" 30ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov 31dccca44ffda4836b56a21da95a046c9708ffd49csergeyv#include <hwui/Canvas.h> 32dccca44ffda4836b56a21da95a046c9708ffd49csergeyv 33ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganovnamespace android { 34ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov 3535aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslavstruct PageRecord { 366811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslav 3735aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav PageRecord(int width, int height, const SkRect& contentRect) 38b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips : mPictureRecorder(new SkPictureRecorder()) 39b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips , mPicture(NULL) 40b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips , mWidth(width) 41b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips , mHeight(height) { 4235aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav mContentRect = contentRect; 4335aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav } 44ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov 4535aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav ~PageRecord() { 46b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips delete mPictureRecorder; 47b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips if (NULL != mPicture) { 48b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips mPicture->unref(); 49b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips } 5035aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav } 51ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov 52b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips SkPictureRecorder* mPictureRecorder; 53b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips SkPicture* mPicture; 5435aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav const int mWidth; 5535aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav const int mHeight; 5635aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav SkRect mContentRect; 5735aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav}; 5835aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav 5935aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslavclass PdfDocument { 6035aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslavpublic: 6135aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav PdfDocument() { 6235aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav mCurrentPage = NULL; 6335aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav } 6435aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav 6535aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav SkCanvas* startPage(int width, int height, 6635aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav int contentLeft, int contentTop, int contentRight, int contentBottom) { 6735aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav assert(mCurrentPage == NULL); 6835aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav 6935aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav SkRect contentRect = SkRect::MakeLTRB( 7035aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav contentLeft, contentTop, contentRight, contentBottom); 7135aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav PageRecord* page = new PageRecord(width, height, contentRect); 7235aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav mPages.push_back(page); 7335aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav mCurrentPage = page; 7435aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav 75b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips SkCanvas* canvas = page->mPictureRecorder->beginRecording( 7671487eb0ceb2b7dea02649e78d99bb5952f5eaefMike Reed SkRect::MakeWH(contentRect.width(), contentRect.height())); 7735aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav 7835aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav return canvas; 7935aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav } 80ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov 8135aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav void finishPage() { 8235aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav assert(mCurrentPage != NULL); 83b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips assert(mCurrentPage->mPictureRecorder != NULL); 84b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips assert(mCurrentPage->mPicture == NULL); 85260ab726486317496bc12a57d599ea96dcde3284Mike Reed mCurrentPage->mPicture = mCurrentPage->mPictureRecorder->finishRecordingAsPicture().release(); 86b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips delete mCurrentPage->mPictureRecorder; 87b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips mCurrentPage->mPictureRecorder = NULL; 8835aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav mCurrentPage = NULL; 8935aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav } 90ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov 9135aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav void write(SkWStream* stream) { 924cb7bb53f987ccfccbd786aef378d87bea41fe1fHal Canary sk_sp<SkDocument> document = SkDocument::MakePDF(stream); 9335aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav for (unsigned i = 0; i < mPages.size(); i++) { 9435aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav PageRecord* page = mPages[i]; 95ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov 9635aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav SkCanvas* canvas = document->beginPage(page->mWidth, page->mHeight, 9735aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav &(page->mContentRect)); 98ea70d22dc8dc5d61f075edf6d03f86f6a68169cdMatt Sarett std::unique_ptr<SkCanvas> toSRGBCanvas = 99ea70d22dc8dc5d61f075edf6d03f86f6a68169cdMatt Sarett SkCreateColorSpaceXformCanvas(canvas, SkColorSpace::MakeSRGB()); 10035aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav 101ea70d22dc8dc5d61f075edf6d03f86f6a68169cdMatt Sarett toSRGBCanvas->drawPicture(page->mPicture); 10235aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav 10335aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav document->endPage(); 10435aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav } 10535aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav document->close(); 10635aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav } 10735aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav 10835aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav void close() { 109b59508fce51b23f0201f4dcba7e4f18bab4f9d1aRobert Phillips assert(NULL == mCurrentPage); 11035aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav for (unsigned i = 0; i < mPages.size(); i++) { 11135aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav delete mPages[i]; 11235aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav } 11335aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav } 11435aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav 11535aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslavprivate: 11635aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav ~PdfDocument() { 11735aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav close(); 11835aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav } 11935aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav 12035aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav std::vector<PageRecord*> mPages; 12135aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav PageRecord* mCurrentPage; 12235aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav}; 12335aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav 124cdf34469b3a49b73ffa4ab2766b55d7c0946fab1Ashok Bhatstatic jlong nativeCreateDocument(JNIEnv* env, jobject thiz) { 125cdf34469b3a49b73ffa4ab2766b55d7c0946fab1Ashok Bhat return reinterpret_cast<jlong>(new PdfDocument()); 12635aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav} 12735aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav 128cdf34469b3a49b73ffa4ab2766b55d7c0946fab1Ashok Bhatstatic jlong nativeStartPage(JNIEnv* env, jobject thiz, jlong documentPtr, 12935aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav jint pageWidth, jint pageHeight, 13035aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav jint contentLeft, jint contentTop, jint contentRight, jint contentBottom) { 13135aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr); 1328872b38ef403cc2c44aca07d392f5e9426fd7f54Derek Sollenberger SkCanvas* canvas = document->startPage(pageWidth, pageHeight, 1338872b38ef403cc2c44aca07d392f5e9426fd7f54Derek Sollenberger contentLeft, contentTop, contentRight, contentBottom); 134ea70d22dc8dc5d61f075edf6d03f86f6a68169cdMatt Sarett return reinterpret_cast<jlong>(Canvas::create_canvas(canvas, Canvas::XformToSRGB::kDefer)); 135ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov} 136ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov 137cdf34469b3a49b73ffa4ab2766b55d7c0946fab1Ashok Bhatstatic void nativeFinishPage(JNIEnv* env, jobject thiz, jlong documentPtr) { 13835aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr); 13935aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav document->finishPage(); 140ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov} 141ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov 142cdf34469b3a49b73ffa4ab2766b55d7c0946fab1Ashok Bhatstatic void nativeWriteTo(JNIEnv* env, jobject thiz, jlong documentPtr, jobject out, 14335aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav jbyteArray chunk) { 14435aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr); 145ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov SkWStream* skWStream = CreateJavaOutputStreamAdaptor(env, out, chunk); 14635aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav document->write(skWStream); 147ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov delete skWStream; 148ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov} 149ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov 150cdf34469b3a49b73ffa4ab2766b55d7c0946fab1Ashok Bhatstatic void nativeClose(JNIEnv* env, jobject thiz, jlong documentPtr) { 15135aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr); 15235aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav document->close(); 15335aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav} 15435aacf2eb325d24c67d01f4dbd706ed26ab9e8c3Svetoslav 15576f6a86de25e1bf74717e047e55fd44b089673f3Daniel Micaystatic const JNINativeMethod gPdfDocument_Methods[] = { 156cdf34469b3a49b73ffa4ab2766b55d7c0946fab1Ashok Bhat {"nativeCreateDocument", "()J", (void*) nativeCreateDocument}, 157cdf34469b3a49b73ffa4ab2766b55d7c0946fab1Ashok Bhat {"nativeStartPage", "(JIIIIII)J", (void*) nativeStartPage}, 158cdf34469b3a49b73ffa4ab2766b55d7c0946fab1Ashok Bhat {"nativeFinishPage", "(J)V", (void*) nativeFinishPage}, 159cdf34469b3a49b73ffa4ab2766b55d7c0946fab1Ashok Bhat {"nativeWriteTo", "(JLjava/io/OutputStream;[B)V", (void*) nativeWriteTo}, 160cdf34469b3a49b73ffa4ab2766b55d7c0946fab1Ashok Bhat {"nativeClose", "(J)V", (void*) nativeClose} 161ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov}; 162ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov 1636811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslavint register_android_graphics_pdf_PdfDocument(JNIEnv* env) { 164ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe return RegisterMethodsOrDie( 1656811f4e92cbb64e72a0d13eb9b99b5894bd59c76Svetoslav env, "android/graphics/pdf/PdfDocument", gPdfDocument_Methods, 166ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov NELEM(gPdfDocument_Methods)); 167ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov} 168ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov 169ff4adde5737be08d3e2d03fbe588c591d27d4a74Svetoslav Ganov}; 170