Home | History | Annotate | Download | only in pdf
      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 "CreateJavaOutputStreamAdaptor.h"
     23 
     24 #include "SkCanvas.h"
     25 #include "SkDocument.h"
     26 #include "SkPicture.h"
     27 #include "SkStream.h"
     28 #include "SkRect.h"
     29 
     30 namespace android {
     31 
     32 struct PageRecord {
     33 
     34     PageRecord(int width, int height, const SkRect& contentRect)
     35             : mPicture(new SkPicture()), mWidth(width), mHeight(height) {
     36         mContentRect = contentRect;
     37     }
     38 
     39     ~PageRecord() {
     40         mPicture->unref();
     41     }
     42 
     43     SkPicture* const mPicture;
     44     const int mWidth;
     45     const int mHeight;
     46     SkRect mContentRect;
     47 };
     48 
     49 class PdfDocument {
     50 public:
     51     PdfDocument() {
     52         mCurrentPage = NULL;
     53     }
     54 
     55     SkCanvas* startPage(int width, int height,
     56             int contentLeft, int contentTop, int contentRight, int contentBottom) {
     57         assert(mCurrentPage == NULL);
     58 
     59         SkRect contentRect = SkRect::MakeLTRB(
     60                 contentLeft, contentTop, contentRight, contentBottom);
     61         PageRecord* page = new PageRecord(width, height, contentRect);
     62         mPages.push_back(page);
     63         mCurrentPage = page;
     64 
     65         SkCanvas* canvas = page->mPicture->beginRecording(
     66                 contentRect.width(), contentRect.height(), 0);
     67 
     68         // We pass this canvas to Java where it is used to construct
     69         // a Java Canvas object which dereferences the pointer when it
     70         // is destroyed, so we have to bump up the reference count.
     71         canvas->ref();
     72 
     73         return canvas;
     74     }
     75 
     76     void finishPage() {
     77         assert(mCurrentPage != NULL);
     78         mCurrentPage->mPicture->endRecording();
     79         mCurrentPage = NULL;
     80     }
     81 
     82     void write(SkWStream* stream) {
     83         SkDocument* document = SkDocument::CreatePDF(stream);
     84         for (unsigned i = 0; i < mPages.size(); i++) {
     85             PageRecord* page =  mPages[i];
     86 
     87             SkCanvas* canvas = document->beginPage(page->mWidth, page->mHeight,
     88                     &(page->mContentRect));
     89 
     90             canvas->clipRect(page->mContentRect);
     91             canvas->translate(page->mContentRect.left(), page->mContentRect.top());
     92             canvas->drawPicture(*page->mPicture);
     93 
     94             document->endPage();
     95         }
     96         document->close();
     97     }
     98 
     99     void close() {
    100         for (unsigned i = 0; i < mPages.size(); i++) {
    101             delete mPages[i];
    102         }
    103         delete mCurrentPage;
    104         mCurrentPage = NULL;
    105     }
    106 
    107 private:
    108     ~PdfDocument() {
    109         close();
    110     }
    111 
    112     std::vector<PageRecord*> mPages;
    113     PageRecord* mCurrentPage;
    114 };
    115 
    116 static jint nativeCreateDocument(JNIEnv* env, jobject thiz) {
    117     return reinterpret_cast<jint>(new PdfDocument());
    118 }
    119 
    120 static jint nativeStartPage(JNIEnv* env, jobject thiz, jint documentPtr,
    121         jint pageWidth, jint pageHeight,
    122         jint contentLeft, jint contentTop, jint contentRight, jint contentBottom) {
    123     PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr);
    124     return reinterpret_cast<jint>(document->startPage(pageWidth, pageHeight,
    125             contentLeft, contentTop, contentRight, contentBottom));
    126 }
    127 
    128 static void nativeFinishPage(JNIEnv* env, jobject thiz, jint documentPtr) {
    129     PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr);
    130     document->finishPage();
    131 }
    132 
    133 static void nativeWriteTo(JNIEnv* env, jobject thiz, jint documentPtr, jobject out,
    134         jbyteArray chunk) {
    135     PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr);
    136     SkWStream* skWStream = CreateJavaOutputStreamAdaptor(env, out, chunk);
    137     document->write(skWStream);
    138     delete skWStream;
    139 }
    140 
    141 static void nativeClose(JNIEnv* env, jobject thiz, jint documentPtr) {
    142     PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr);
    143     document->close();
    144 }
    145 
    146 static JNINativeMethod gPdfDocument_Methods[] = {
    147     {"nativeCreateDocument", "()I", (void*) nativeCreateDocument},
    148     {"nativeStartPage", "(IIIIIII)I", (void*) nativeStartPage},
    149     {"nativeFinishPage", "(I)V", (void*) nativeFinishPage},
    150     {"nativeWriteTo", "(ILjava/io/OutputStream;[B)V", (void*) nativeWriteTo},
    151     {"nativeClose", "(I)V", (void*) nativeClose}
    152 };
    153 
    154 int register_android_graphics_pdf_PdfDocument(JNIEnv* env) {
    155     int result = android::AndroidRuntime::registerNativeMethods(
    156             env, "android/graphics/pdf/PdfDocument", gPdfDocument_Methods,
    157             NELEM(gPdfDocument_Methods));
    158     return result;
    159 }
    160 
    161 };
    162