Loading core/jni/android/graphics/pdf/PdfDocument.cpp +110 −34 Original line number Diff line number Diff line Loading @@ -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) { Loading graphics/java/android/graphics/pdf/PdfDocument.java +27 −20 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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(); Loading Loading @@ -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); Loading Loading @@ -142,7 +149,7 @@ public class PdfDocument { } mPages.add(page.getInfo()); mCurrentPage = null; nativeAppendPage(mNativeDocument, page.mCanvas.mNativeCanvas); nativeFinishPage(mNativeDocument); page.finish(); } Loading Loading @@ -204,7 +211,7 @@ public class PdfDocument { private void dispose() { if (mNativeDocument != 0) { nativeFinalize(mNativeDocument); nativeClose(mNativeDocument); mCloseGuard.close(); mNativeDocument = 0; } Loading @@ -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 { Loading Loading @@ -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. Loading Loading
core/jni/android/graphics/pdf/PdfDocument.cpp +110 −34 Original line number Diff line number Diff line Loading @@ -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) { Loading
graphics/java/android/graphics/pdf/PdfDocument.java +27 −20 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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(); Loading Loading @@ -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); Loading Loading @@ -142,7 +149,7 @@ public class PdfDocument { } mPages.add(page.getInfo()); mCurrentPage = null; nativeAppendPage(mNativeDocument, page.mCanvas.mNativeCanvas); nativeFinishPage(mNativeDocument); page.finish(); } Loading Loading @@ -204,7 +211,7 @@ public class PdfDocument { private void dispose() { if (mNativeDocument != 0) { nativeFinalize(mNativeDocument); nativeClose(mNativeDocument); mCloseGuard.close(); mNativeDocument = 0; } Loading @@ -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 { Loading Loading @@ -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. Loading