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

Commit 765c9dfd authored by Svetoslav's avatar Svetoslav Committed by Android Git Automerger
Browse files

am ebd616e8: am 134631b9: am 90242fe5: Merge "Switch to the new Skia PDF...

am ebd616e8: am 134631b9: am 90242fe5: Merge "Switch to the new Skia PDF generation APIs." into klp-dev

* commit 'ebd616e8':
  Switch to the new Skia PDF generation APIs.
parents e7dda40c ebd616e8
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.