summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSvetoslav <svetoslavganov@google.com>2013-11-06 18:22:13 -0800
committerSvetoslav Ganov <svetoslavganov@google.com>2013-11-07 14:15:19 -0800
commit35aacf2eb325d24c67d01f4dbd706ed26ab9e8c3 (patch)
tree659b0de968eb7d62a6e6aea8ac290b5d3ee3b3b0
parentc157cac9b2827a4eeb0ea29209fbb879a6076de4 (diff)
downloadframeworks_base-35aacf2eb325d24c67d01f4dbd706ed26ab9e8c3.zip
frameworks_base-35aacf2eb325d24c67d01f4dbd706ed26ab9e8c3.tar.gz
frameworks_base-35aacf2eb325d24c67d01f4dbd706ed26ab9e8c3.tar.bz2
Switch to the new Skia PDF generation APIs.
The new Skia PDF generation APIs are a small extension to the code that converts drawing commands to PDF (SkPDFDevice) and this new functionality is exposed via new APIs. This change switches to using these new APIs allowing us to capitalize on the new perspective support for PDF generation. bug:11561776 Change-Id: Ief61f7ff6a5a22c27d3acbe99a48910cb679f594
-rw-r--r--core/jni/android/graphics/pdf/PdfDocument.cpp144
-rw-r--r--graphics/java/android/graphics/pdf/PdfDocument.java47
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.