Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 90242fe5 authored by Svetoslav's avatar Svetoslav Committed by Android (Google) Code Review
Browse files

Merge "Switch to the new Skia PDF generation APIs." into klp-dev

parents e81f9755 35aacf2e
Loading
Loading
Loading
Loading
+110 −34
Original line number Diff line number Diff line
@@ -17,62 +17,138 @@
#include "jni.h"
#include "GraphicsJNI.h"
#include <android_runtime/AndroidRuntime.h>
#include <vector>

#include "CreateJavaOutputStreamAdaptor.h"

#include "SkCanvas.h"
#include "SkPDFDevice.h"
#include "SkPDFDocument.h"
#include "SkDocument.h"
#include "SkPicture.h"
#include "SkStream.h"
#include "SkRect.h"
#include "SkSize.h"
#include "CreateJavaOutputStreamAdaptor.h"
#include "JNIHelp.h"

namespace android {

#define LOGD(x...) do { Log::Instance()->printf(Log::ELogD, x); } while(0)
struct PageRecord {

static jint nativeCreateDocument(JNIEnv* env, jobject clazz) {
    return reinterpret_cast<jint>(new SkPDFDocument());
    PageRecord(int width, int height, const SkRect& contentRect)
            : mPicture(new SkPicture()), mWidth(width), mHeight(height) {
        mContentRect = contentRect;
    }

static void nativeFinalize(JNIEnv* env, jobject thiz, jint documentPtr) {
    delete reinterpret_cast<SkPDFDocument*>(documentPtr);
    ~PageRecord() {
        mPicture->unref();
    }

static jint nativeCreatePage(JNIEnv* env, jobject thiz, jint pageWidth, jint pageHeight,
        jint contentLeft, jint contentTop, jint contentRight, jint contentBottom) {
    SkPicture* const mPicture;
    const int mWidth;
    const int mHeight;
    SkRect mContentRect;
};

class PdfDocument {
public:
    PdfDocument() {
        mCurrentPage = NULL;
    }

    SkCanvas* startPage(int width, int height,
            int contentLeft, int contentTop, int contentRight, int contentBottom) {
        assert(mCurrentPage == NULL);

    SkMatrix transformation;
    transformation.setTranslate(contentLeft, contentTop);
        SkRect contentRect = SkRect::MakeLTRB(
                contentLeft, contentTop, contentRight, contentBottom);
        PageRecord* page = new PageRecord(width, height, contentRect);
        mPages.push_back(page);
        mCurrentPage = page;

    SkISize skPageSize = SkISize::Make(pageWidth, pageHeight);
    SkISize skContentSize = SkISize::Make(contentRight - contentLeft, contentBottom - contentTop);
        SkCanvas* canvas = page->mPicture->beginRecording(
                contentRect.width(), contentRect.height(), 0);

    SkPDFDevice* skPdfDevice = new SkPDFDevice(skPageSize, skContentSize, transformation);
    return reinterpret_cast<jint>(new SkCanvas(skPdfDevice));
        // We pass this canvas to Java where it is used to construct
        // a Java Canvas object which dereferences the pointer when it
        // is destroyed, so we have to bump up the reference count.
        canvas->ref();

        return canvas;
    }

    void finishPage() {
        assert(mCurrentPage != NULL);
        mCurrentPage->mPicture->endRecording();
        mCurrentPage = NULL;
    }

static void nativeAppendPage(JNIEnv* env, jobject thiz, jint documentPtr, jint pagePtr) {
    SkCanvas* page = reinterpret_cast<SkCanvas*>(pagePtr);
    SkPDFDocument* document = reinterpret_cast<SkPDFDocument*>(documentPtr);
    SkPDFDevice* device = static_cast<SkPDFDevice*>(page->getDevice());
    document->appendPage(device);
    void write(SkWStream* stream) {
        SkDocument* document = SkDocument::CreatePDF(stream);
        for (unsigned i = 0; i < mPages.size(); i++) {
            PageRecord* page =  mPages[i];

            SkCanvas* canvas = document->beginPage(page->mWidth, page->mHeight,
                    &(page->mContentRect));

            canvas->clipRect(page->mContentRect);
            canvas->translate(page->mContentRect.left(), page->mContentRect.top());
            canvas->drawPicture(*page->mPicture);

            document->endPage();
        }
        document->close();
    }

static void nativeWriteTo(JNIEnv* env, jobject clazz, jint documentPtr,
        jobject out, jbyteArray chunk) {
    void close() {
        for (unsigned i = 0; i < mPages.size(); i++) {
            delete mPages[i];
        }
        delete mCurrentPage;
        mCurrentPage = NULL;
    }

private:
    ~PdfDocument() {
        close();
    }

    std::vector<PageRecord*> mPages;
    PageRecord* mCurrentPage;
};

static jint nativeCreateDocument(JNIEnv* env, jobject thiz) {
    return reinterpret_cast<jint>(new PdfDocument());
}

static jint nativeStartPage(JNIEnv* env, jobject thiz, jint documentPtr,
        jint pageWidth, jint pageHeight,
        jint contentLeft, jint contentTop, jint contentRight, jint contentBottom) {
    PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr);
    return reinterpret_cast<jint>(document->startPage(pageWidth, pageHeight,
            contentLeft, contentTop, contentRight, contentBottom));
}

static void nativeFinishPage(JNIEnv* env, jobject thiz, jint documentPtr) {
    PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr);
    document->finishPage();
}

static void nativeWriteTo(JNIEnv* env, jobject thiz, jint documentPtr, jobject out,
        jbyteArray chunk) {
    PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr);
    SkWStream* skWStream = CreateJavaOutputStreamAdaptor(env, out, chunk);
    SkPDFDocument* document = reinterpret_cast<SkPDFDocument*>(documentPtr);
    document->emitPDF(skWStream);
    document->write(skWStream);
    delete skWStream;
}

static void nativeClose(JNIEnv* env, jobject thiz, jint documentPtr) {
    PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr);
    document->close();
}

static JNINativeMethod gPdfDocument_Methods[] = {
    {"nativeCreateDocument", "()I", (void*) nativeCreateDocument},
    {"nativeFinalize", "(I)V", (void*) nativeFinalize},
    {"nativeCreatePage", "(IIIIII)I",
            (void*) nativeCreatePage},
    {"nativeAppendPage", "(II)V", (void*) nativeAppendPage},
    {"nativeWriteTo", "(ILjava/io/OutputStream;[B)V", (void*) nativeWriteTo}
    {"nativeStartPage", "(IIIIIII)I", (void*) nativeStartPage},
    {"nativeFinishPage", "(I)V", (void*) nativeFinishPage},
    {"nativeWriteTo", "(ILjava/io/OutputStream;[B)V", (void*) nativeWriteTo},
    {"nativeClose", "(I)V", (void*) nativeClose}
};

int register_android_graphics_pdf_PdfDocument(JNIEnv* env) {
+27 −20
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package android.graphics.pdf;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;

import dalvik.system.CloseGuard;
@@ -69,6 +70,12 @@ import java.util.List;
 */
public class PdfDocument {

    // TODO: We need a constructor that will take an OutputStream to
    // support online data serialization as opposed to the current
    // on demand one. The current approach is fine until Skia starts
    // to support online PDF generation at which point we need to
    // handle this.

    private final byte[] mChunk = new byte[4096];

    private final CloseGuard mCloseGuard = CloseGuard.get();
@@ -111,7 +118,7 @@ public class PdfDocument {
        if (pageInfo == null) {
            throw new IllegalArgumentException("page cannot be null");
        }
        Canvas canvas = new PdfCanvas(nativeCreatePage(pageInfo.mPageWidth,
        Canvas canvas = new PdfCanvas(nativeStartPage(mNativeDocument, pageInfo.mPageWidth,
                pageInfo.mPageHeight, pageInfo.mContentRect.left, pageInfo.mContentRect.top,
                pageInfo.mContentRect.right, pageInfo.mContentRect.bottom));
        mCurrentPage = new Page(canvas, pageInfo);
@@ -142,7 +149,7 @@ public class PdfDocument {
        }
        mPages.add(page.getInfo());
        mCurrentPage = null;
        nativeAppendPage(mNativeDocument, page.mCanvas.mNativeCanvas);
        nativeFinishPage(mNativeDocument);
        page.finish();
    }

@@ -204,7 +211,7 @@ public class PdfDocument {

    private void dispose() {
        if (mNativeDocument != 0) {
            nativeFinalize(mNativeDocument);
            nativeClose(mNativeDocument);
            mCloseGuard.close();
            mNativeDocument = 0;
        }
@@ -230,14 +237,14 @@ public class PdfDocument {

    private native int nativeCreateDocument();

    private native void nativeFinalize(int document);
    private native void nativeClose(int document);

    private native void nativeAppendPage(int document, int page);
    private native void nativeFinishPage(int document);

    private native void nativeWriteTo(int document, OutputStream out, byte[] chunk);

    private static native int nativeCreatePage(int pageWidth, int pageHeight, int contentLeft,
            int contentTop, int contentRight, int contentBottom);
    private static native int nativeStartPage(int documentPtr, int pageWidth, int pageHeight,
            int contentLeft, int contentTop, int contentRight, int contentBottom);

    private final class PdfCanvas extends Canvas {

@@ -392,28 +399,28 @@ public class PdfDocument {
         * Gets the {@link Canvas} of the page.
         *
         * <p>
         * <strong>Note: </strong> There are some draw operations that are
         * not yet supported by the canvas returned by this method. More
         * specifically:
         * <strong>Note: </strong> There are some draw operations that are not yet
         * supported by the canvas returned by this method. More specifically:
         * <ul>
         * <li>{@link Canvas#clipPath(android.graphics.Path)
         *     Canvas.clipPath(android.graphics.Path)}</li>
         * <li>All flavors of {@link Canvas#drawText(String, float, float,
         *     android.graphics.Paint) Canvas.drawText(String, float, float,
         *     android.graphics.Paint)}</li>
         * <li>All flavors of {@link Canvas#drawPosText(String, float[],
         *     android.graphics.Paint) Canvas.drawPosText(String, float[],
         *     android.graphics.Paint)}</li>
         * <li>Inverse path clipping performed via {@link Canvas#clipPath(android.graphics.Path,
         *     android.graphics.Region.Op) Canvas.clipPath(android.graphics.Path,
         *     android.graphics.Region.Op)} for {@link
         *     android.graphics.Region.Op#REVERSE_DIFFERENCE
         *     Region.Op#REVERSE_DIFFERENCE} operations.</li>
         * <li>{@link Canvas#drawVertices(android.graphics.Canvas.VertexMode, int,
         *     float[], int, float[], int, int[], int, short[], int, int,
         *     android.graphics.Paint) Canvas.drawVertices(
         *     android.graphics.Canvas.VertexMode, int, float[], int, float[],
         *     int, int[], int, short[], int, int, android.graphics.Paint)}</li>
         * <li>{@link android.graphics.PorterDuff.Mode#SRC_ATOP PorterDuff.Mode SRC},
         * <li>Color filters set via {@link Paint#setColorFilter(
         *     android.graphics.ColorFilter)}</li>
         * <li>Mask filters set via {@link Paint#setMaskFilter(
         *     android.graphics.MaskFilter)}</li>
         * <li>Some XFER modes such as
         *     {@link android.graphics.PorterDuff.Mode#SRC_ATOP PorterDuff.Mode SRC},
         *     {@link android.graphics.PorterDuff.Mode#DST_ATOP PorterDuff.DST_ATOP},
         *     {@link android.graphics.PorterDuff.Mode#XOR PorterDuff.XOR},
         *     {@link android.graphics.PorterDuff.Mode#ADD PorterDuff.ADD}</li>
         * <li>Perspective transforms</li>
         * </ul>
         *
         * @return The canvas if the page is not finished, null otherwise.