Skip to content

Commit 90242fe

Browse files
sganovAndroid (Google) Code Review
authored andcommitted
Merge "Switch to the new Skia PDF generation APIs." into klp-dev
2 parents e81f975 + 35aacf2 commit 90242fe

2 files changed

Lines changed: 137 additions & 54 deletions

File tree

core/jni/android/graphics/pdf/PdfDocument.cpp

Lines changed: 110 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -17,62 +17,138 @@
1717
#include "jni.h"
1818
#include "GraphicsJNI.h"
1919
#include <android_runtime/AndroidRuntime.h>
20+
#include <vector>
21+
22+
#include "CreateJavaOutputStreamAdaptor.h"
2023

2124
#include "SkCanvas.h"
22-
#include "SkPDFDevice.h"
23-
#include "SkPDFDocument.h"
25+
#include "SkDocument.h"
26+
#include "SkPicture.h"
27+
#include "SkStream.h"
2428
#include "SkRect.h"
25-
#include "SkSize.h"
26-
#include "CreateJavaOutputStreamAdaptor.h"
27-
#include "JNIHelp.h"
2829

2930
namespace android {
3031

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

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

37-
static void nativeFinalize(JNIEnv* env, jobject thiz, jint documentPtr) {
38-
delete reinterpret_cast<SkPDFDocument*>(documentPtr);
39-
}
39+
~PageRecord() {
40+
mPicture->unref();
41+
}
4042

41-
static jint nativeCreatePage(JNIEnv* env, jobject thiz, jint pageWidth, jint pageHeight,
42-
jint contentLeft, jint contentTop, jint contentRight, jint contentBottom) {
43+
SkPicture* const mPicture;
44+
const int mWidth;
45+
const int mHeight;
46+
SkRect mContentRect;
47+
};
48+
49+
class PdfDocument {
50+
public:
51+
PdfDocument() {
52+
mCurrentPage = NULL;
53+
}
54+
55+
SkCanvas* startPage(int width, int height,
56+
int contentLeft, int contentTop, int contentRight, int contentBottom) {
57+
assert(mCurrentPage == NULL);
58+
59+
SkRect contentRect = SkRect::MakeLTRB(
60+
contentLeft, contentTop, contentRight, contentBottom);
61+
PageRecord* page = new PageRecord(width, height, contentRect);
62+
mPages.push_back(page);
63+
mCurrentPage = page;
64+
65+
SkCanvas* canvas = page->mPicture->beginRecording(
66+
contentRect.width(), contentRect.height(), 0);
67+
68+
// We pass this canvas to Java where it is used to construct
69+
// a Java Canvas object which dereferences the pointer when it
70+
// is destroyed, so we have to bump up the reference count.
71+
canvas->ref();
72+
73+
return canvas;
74+
}
4375

44-
SkMatrix transformation;
45-
transformation.setTranslate(contentLeft, contentTop);
76+
void finishPage() {
77+
assert(mCurrentPage != NULL);
78+
mCurrentPage->mPicture->endRecording();
79+
mCurrentPage = NULL;
80+
}
4681

47-
SkISize skPageSize = SkISize::Make(pageWidth, pageHeight);
48-
SkISize skContentSize = SkISize::Make(contentRight - contentLeft, contentBottom - contentTop);
82+
void write(SkWStream* stream) {
83+
SkDocument* document = SkDocument::CreatePDF(stream);
84+
for (unsigned i = 0; i < mPages.size(); i++) {
85+
PageRecord* page = mPages[i];
4986

50-
SkPDFDevice* skPdfDevice = new SkPDFDevice(skPageSize, skContentSize, transformation);
51-
return reinterpret_cast<jint>(new SkCanvas(skPdfDevice));
87+
SkCanvas* canvas = document->beginPage(page->mWidth, page->mHeight,
88+
&(page->mContentRect));
89+
90+
canvas->clipRect(page->mContentRect);
91+
canvas->translate(page->mContentRect.left(), page->mContentRect.top());
92+
canvas->drawPicture(*page->mPicture);
93+
94+
document->endPage();
95+
}
96+
document->close();
97+
}
98+
99+
void close() {
100+
for (unsigned i = 0; i < mPages.size(); i++) {
101+
delete mPages[i];
102+
}
103+
delete mCurrentPage;
104+
mCurrentPage = NULL;
105+
}
106+
107+
private:
108+
~PdfDocument() {
109+
close();
110+
}
111+
112+
std::vector<PageRecord*> mPages;
113+
PageRecord* mCurrentPage;
114+
};
115+
116+
static jint nativeCreateDocument(JNIEnv* env, jobject thiz) {
117+
return reinterpret_cast<jint>(new PdfDocument());
118+
}
119+
120+
static jint nativeStartPage(JNIEnv* env, jobject thiz, jint documentPtr,
121+
jint pageWidth, jint pageHeight,
122+
jint contentLeft, jint contentTop, jint contentRight, jint contentBottom) {
123+
PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr);
124+
return reinterpret_cast<jint>(document->startPage(pageWidth, pageHeight,
125+
contentLeft, contentTop, contentRight, contentBottom));
52126
}
53127

54-
static void nativeAppendPage(JNIEnv* env, jobject thiz, jint documentPtr, jint pagePtr) {
55-
SkCanvas* page = reinterpret_cast<SkCanvas*>(pagePtr);
56-
SkPDFDocument* document = reinterpret_cast<SkPDFDocument*>(documentPtr);
57-
SkPDFDevice* device = static_cast<SkPDFDevice*>(page->getDevice());
58-
document->appendPage(device);
128+
static void nativeFinishPage(JNIEnv* env, jobject thiz, jint documentPtr) {
129+
PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr);
130+
document->finishPage();
59131
}
60132

61-
static void nativeWriteTo(JNIEnv* env, jobject clazz, jint documentPtr,
62-
jobject out, jbyteArray chunk) {
133+
static void nativeWriteTo(JNIEnv* env, jobject thiz, jint documentPtr, jobject out,
134+
jbyteArray chunk) {
135+
PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr);
63136
SkWStream* skWStream = CreateJavaOutputStreamAdaptor(env, out, chunk);
64-
SkPDFDocument* document = reinterpret_cast<SkPDFDocument*>(documentPtr);
65-
document->emitPDF(skWStream);
137+
document->write(skWStream);
66138
delete skWStream;
67139
}
68140

141+
static void nativeClose(JNIEnv* env, jobject thiz, jint documentPtr) {
142+
PdfDocument* document = reinterpret_cast<PdfDocument*>(documentPtr);
143+
document->close();
144+
}
145+
69146
static JNINativeMethod gPdfDocument_Methods[] = {
70147
{"nativeCreateDocument", "()I", (void*) nativeCreateDocument},
71-
{"nativeFinalize", "(I)V", (void*) nativeFinalize},
72-
{"nativeCreatePage", "(IIIIII)I",
73-
(void*) nativeCreatePage},
74-
{"nativeAppendPage", "(II)V", (void*) nativeAppendPage},
75-
{"nativeWriteTo", "(ILjava/io/OutputStream;[B)V", (void*) nativeWriteTo}
148+
{"nativeStartPage", "(IIIIIII)I", (void*) nativeStartPage},
149+
{"nativeFinishPage", "(I)V", (void*) nativeFinishPage},
150+
{"nativeWriteTo", "(ILjava/io/OutputStream;[B)V", (void*) nativeWriteTo},
151+
{"nativeClose", "(I)V", (void*) nativeClose}
76152
};
77153

78154
int register_android_graphics_pdf_PdfDocument(JNIEnv* env) {

graphics/java/android/graphics/pdf/PdfDocument.java

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import android.graphics.Bitmap;
2020
import android.graphics.Canvas;
21+
import android.graphics.Paint;
2122
import android.graphics.Rect;
2223

2324
import dalvik.system.CloseGuard;
@@ -69,6 +70,12 @@
6970
*/
7071
public class PdfDocument {
7172

73+
// TODO: We need a constructor that will take an OutputStream to
74+
// support online data serialization as opposed to the current
75+
// on demand one. The current approach is fine until Skia starts
76+
// to support online PDF generation at which point we need to
77+
// handle this.
78+
7279
private final byte[] mChunk = new byte[4096];
7380

7481
private final CloseGuard mCloseGuard = CloseGuard.get();
@@ -111,7 +118,7 @@ public Page startPage(PageInfo pageInfo) {
111118
if (pageInfo == null) {
112119
throw new IllegalArgumentException("page cannot be null");
113120
}
114-
Canvas canvas = new PdfCanvas(nativeCreatePage(pageInfo.mPageWidth,
121+
Canvas canvas = new PdfCanvas(nativeStartPage(mNativeDocument, pageInfo.mPageWidth,
115122
pageInfo.mPageHeight, pageInfo.mContentRect.left, pageInfo.mContentRect.top,
116123
pageInfo.mContentRect.right, pageInfo.mContentRect.bottom));
117124
mCurrentPage = new Page(canvas, pageInfo);
@@ -142,7 +149,7 @@ public void finishPage(Page page) {
142149
}
143150
mPages.add(page.getInfo());
144151
mCurrentPage = null;
145-
nativeAppendPage(mNativeDocument, page.mCanvas.mNativeCanvas);
152+
nativeFinishPage(mNativeDocument);
146153
page.finish();
147154
}
148155

@@ -204,7 +211,7 @@ protected void finalize() throws Throwable {
204211

205212
private void dispose() {
206213
if (mNativeDocument != 0) {
207-
nativeFinalize(mNativeDocument);
214+
nativeClose(mNativeDocument);
208215
mCloseGuard.close();
209216
mNativeDocument = 0;
210217
}
@@ -230,14 +237,14 @@ private void throwIfCurrentPageNotFinished() {
230237

231238
private native int nativeCreateDocument();
232239

233-
private native void nativeFinalize(int document);
240+
private native void nativeClose(int document);
234241

235-
private native void nativeAppendPage(int document, int page);
242+
private native void nativeFinishPage(int document);
236243

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

239-
private static native int nativeCreatePage(int pageWidth, int pageHeight, int contentLeft,
240-
int contentTop, int contentRight, int contentBottom);
246+
private static native int nativeStartPage(int documentPtr, int pageWidth, int pageHeight,
247+
int contentLeft, int contentTop, int contentRight, int contentBottom);
241248

242249
private final class PdfCanvas extends Canvas {
243250

@@ -392,28 +399,28 @@ private Page(Canvas canvas, PageInfo pageInfo) {
392399
* Gets the {@link Canvas} of the page.
393400
*
394401
* <p>
395-
* <strong>Note: </strong> There are some draw operations that are
396-
* not yet supported by the canvas returned by this method. More
397-
* specifically:
402+
* <strong>Note: </strong> There are some draw operations that are not yet
403+
* supported by the canvas returned by this method. More specifically:
398404
* <ul>
399-
* <li>{@link Canvas#clipPath(android.graphics.Path)
400-
* Canvas.clipPath(android.graphics.Path)}</li>
401-
* <li>All flavors of {@link Canvas#drawText(String, float, float,
402-
* android.graphics.Paint) Canvas.drawText(String, float, float,
403-
* android.graphics.Paint)}</li>
404-
* <li>All flavors of {@link Canvas#drawPosText(String, float[],
405-
* android.graphics.Paint) Canvas.drawPosText(String, float[],
406-
* android.graphics.Paint)}</li>
405+
* <li>Inverse path clipping performed via {@link Canvas#clipPath(android.graphics.Path,
406+
* android.graphics.Region.Op) Canvas.clipPath(android.graphics.Path,
407+
* android.graphics.Region.Op)} for {@link
408+
* android.graphics.Region.Op#REVERSE_DIFFERENCE
409+
* Region.Op#REVERSE_DIFFERENCE} operations.</li>
407410
* <li>{@link Canvas#drawVertices(android.graphics.Canvas.VertexMode, int,
408411
* float[], int, float[], int, int[], int, short[], int, int,
409412
* android.graphics.Paint) Canvas.drawVertices(
410413
* android.graphics.Canvas.VertexMode, int, float[], int, float[],
411414
* int, int[], int, short[], int, int, android.graphics.Paint)}</li>
412-
* <li>{@link android.graphics.PorterDuff.Mode#SRC_ATOP PorterDuff.Mode SRC},
415+
* <li>Color filters set via {@link Paint#setColorFilter(
416+
* android.graphics.ColorFilter)}</li>
417+
* <li>Mask filters set via {@link Paint#setMaskFilter(
418+
* android.graphics.MaskFilter)}</li>
419+
* <li>Some XFER modes such as
420+
* {@link android.graphics.PorterDuff.Mode#SRC_ATOP PorterDuff.Mode SRC},
413421
* {@link android.graphics.PorterDuff.Mode#DST_ATOP PorterDuff.DST_ATOP},
414422
* {@link android.graphics.PorterDuff.Mode#XOR PorterDuff.XOR},
415423
* {@link android.graphics.PorterDuff.Mode#ADD PorterDuff.ADD}</li>
416-
* <li>Perspective transforms</li>
417424
* </ul>
418425
*
419426
* @return The canvas if the page is not finished, null otherwise.

0 commit comments

Comments
 (0)