diff options
author | Svetoslav <svetoslavganov@google.com> | 2013-11-08 00:20:10 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2013-11-08 00:20:10 +0000 |
commit | 90242fe5581c8f665c09337a0971a7c3fc908f7c (patch) | |
tree | 2cbcc6d5f5ec60c53ecd34f72036c00bce6c03e5 | |
parent | e81f9755d914b5b87f18e5ed201a4903dc09baa6 (diff) | |
parent | 35aacf2eb325d24c67d01f4dbd706ed26ab9e8c3 (diff) | |
download | frameworks_base-90242fe5581c8f665c09337a0971a7c3fc908f7c.zip frameworks_base-90242fe5581c8f665c09337a0971a7c3fc908f7c.tar.gz frameworks_base-90242fe5581c8f665c09337a0971a7c3fc908f7c.tar.bz2 |
Merge "Switch to the new Skia PDF generation APIs." into klp-dev
-rw-r--r-- | core/jni/android/graphics/pdf/PdfDocument.cpp | 144 | ||||
-rw-r--r-- | graphics/java/android/graphics/pdf/PdfDocument.java | 47 |
2 files changed, 137 insertions, 54 deletions
diff --git a/core/jni/android/graphics/pdf/PdfDocument.cpp b/core/jni/android/graphics/pdf/PdfDocument.cpp index b57a0fe..6175a8f 100644 --- a/core/jni/android/graphics/pdf/PdfDocument.cpp +++ b/core/jni/android/graphics/pdf/PdfDocument.cpp @@ -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); + + SkRect contentRect = SkRect::MakeLTRB( + contentLeft, contentTop, contentRight, contentBottom); + PageRecord* page = new PageRecord(width, height, contentRect); + mPages.push_back(page); + mCurrentPage = page; + + SkCanvas* canvas = page->mPicture->beginRecording( + contentRect.width(), contentRect.height(), 0); + + // 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; + } - SkMatrix transformation; - transformation.setTranslate(contentLeft, contentTop); + void finishPage() { + assert(mCurrentPage != NULL); + mCurrentPage->mPicture->endRecording(); + mCurrentPage = NULL; + } - SkISize skPageSize = SkISize::Make(pageWidth, pageHeight); - SkISize skContentSize = SkISize::Make(contentRight - contentLeft, contentBottom - contentTop); + void write(SkWStream* stream) { + SkDocument* document = SkDocument::CreatePDF(stream); + for (unsigned i = 0; i < mPages.size(); i++) { + PageRecord* page = mPages[i]; - SkPDFDevice* skPdfDevice = new SkPDFDevice(skPageSize, skContentSize, transformation); - return reinterpret_cast<jint>(new SkCanvas(skPdfDevice)); + 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(); + } + + 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 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); +static void nativeFinishPage(JNIEnv* env, jobject thiz, jint documentPtr) { + PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr); + document->finishPage(); } -static void nativeWriteTo(JNIEnv* env, jobject clazz, jint documentPtr, - jobject out, jbyteArray chunk) { +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) { diff --git a/graphics/java/android/graphics/pdf/PdfDocument.java b/graphics/java/android/graphics/pdf/PdfDocument.java index 81e523d..29d14a2 100644 --- a/graphics/java/android/graphics/pdf/PdfDocument.java +++ b/graphics/java/android/graphics/pdf/PdfDocument.java @@ -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. |