external/skia/src/core \
external/skia/gpu/include \
frameworks/base/opengl/include/GLES2 \
+ external/skia/include/pdf \
$(LOCAL_PATH)/jni
LOCAL_SHARED_LIBRARIES := \
LOCAL_SRC_FILES := \
../../src/ports/SkXMLParser_empty.cpp \
+ ../../src/pdf/SkPDFCatalog.cpp \
+ ../../src/pdf/SkPDFDevice.cpp \
+ ../../src/pdf/SkPDFDocument.cpp \
+ ../../src/pdf/SkPDFFont.cpp \
+ ../../src/pdf/SkPDFFormXObject.cpp \
+ ../../src/pdf/SkPDFGraphicState.cpp \
+ ../../src/pdf/SkPDFImage.cpp \
+ ../../src/pdf/SkPDFPage.cpp \
+ ../../src/pdf/SkPDFShader.cpp \
+ ../../src/pdf/SkPDFStream.cpp \
+ ../../src/pdf/SkPDFTypes.cpp \
+ ../../src/pdf/SkPDFUtils.cpp \
jni/sample-jni.cpp
include external/skia/src/views/views_files.mk
package="com.skia.sampleapp"
android:versionCode="1"
android:versionName="1.0">
+ <!-- Needed to save a file to the file system. -->
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+ <!-- Needed to add to the download manager. -->
+ <uses-permission android:name="android.permission.INTERNET" />
<uses-sdk android:minSdkVersion="3" />
<application android:label="@string/app_name"
android:debuggable="true">
jweak m_obj;
jmethodID m_setTitle;
jmethodID m_startTimer;
+ jmethodID m_addToDownloads;
ActivityGlue() {
m_env = NULL;
m_obj = NULL;
m_setTitle = NULL;
m_startTimer = NULL;
+ m_addToDownloads = NULL;
}
} gActivityGlue;
gActivityGlue.m_env->CallVoidMethod(gWindowGlue.m_obj, gWindowGlue.m_inval);
}
+void SkOSWindow::onPDFSaved(const char title[], const char desc[],
+ const char path[])
+{
+ if (gActivityGlue.m_env) {
+ JNIEnv* env = gActivityGlue.m_env;
+ jstring jtitle = env->NewStringUTF(title);
+ jstring jdesc = env->NewStringUTF(desc);
+ jstring jpath = env->NewStringUTF(path);
+
+ env->CallVoidMethod(gActivityGlue.m_obj, gActivityGlue.m_addToDownloads,
+ jtitle, jdesc, jpath);
+
+ env->DeleteLocalRef(jtitle);
+ env->DeleteLocalRef(jdesc);
+ env->DeleteLocalRef(jpath);
+ }
+}
+
///////////////////////////////////////////
/////////////// SkEvent impl //////////////
///////////////////////////////////////////
JNIEnv* env, jobject thiz);
JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_serviceQueueTimer(
JNIEnv* env, jobject thiz);
+JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_saveToPdf(
+ JNIEnv* env, jobject thiz);
};
JNIEXPORT bool JNICALL Java_com_skia_sampleapp_SampleApp_handleKeyDown(
gActivityGlue.m_obj = env->NewWeakGlobalRef(thiz);
gActivityGlue.m_setTitle = GetJMethod(env, clazz, "setTitle",
"(Ljava/lang/CharSequence;)V");
+ gActivityGlue.m_addToDownloads = GetJMethod(env, clazz, "addToDownloads",
+ "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
gActivityGlue.m_startTimer = GetJMethod(gActivityGlue.m_env, clazz,
"startTimer", "(I)V");
env->DeleteLocalRef(clazz);
{
SkEvent::ServiceQueueTimer();
}
+
+JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_saveToPdf(
+ JNIEnv* env, jobject thiz)
+{
+ gWindow->saveToPdf();
+}
android:id="@+id/slideshow"
android:title="@string/slideshow"
/>
-<!--
- android:icon="@drawable/ic_menu_new_window"
--->
+ <item
+ android:id="@+id/save_to_pdf"
+ android:title="@string/save_to_pdf"
+ />
</menu>
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name">SampleApp</string>
<string name="overview">Overview</string>
<string name="toggle_rendering">Toggle rendering</string>
<string name="slideshow">Slideshow</string>
<string name="fps">FPS</string>
+ <string name="file_saved"><xliff:g id="title">%s1</xliff:g> saved!</string>
+ <string name="failed">PDF creation failed</string>
+ <string name="save_to_pdf">Save as PDF</string>
</resources>
package com.skia.sampleapp;
import android.app.Activity;
+import android.app.DownloadManager;
import android.content.Context;
import android.graphics.Canvas;
import android.opengl.GLSurfaceView;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
+import android.widget.Toast;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
+import java.io.File;
+
public class SampleApp extends Activity
{
private TextView mTitle;
}
});
return true;
+ case R.id.save_to_pdf:
+ mView.queueEvent(new Runnable() {
+ @Override
+ public void run() {
+ saveToPdf();
+ }
+ });
+ return true;
+
default:
return false;
}
}
private static final int SET_TITLE = 1;
+ private static final int TOAST_DOWNLOAD = 2;
private Handler mHandler = new Handler() {
@Override
mTitle.setText((String) msg.obj);
SampleApp.this.getActionBar().setSubtitle((String) msg.obj);
break;
+ case TOAST_DOWNLOAD:
+ Toast.makeText(SampleApp.this, (String) msg.obj,
+ Toast.LENGTH_SHORT).show();
+ break;
default:
break;
}
// Called by JNI
@SuppressWarnings("unused")
+ private void addToDownloads(final String title, final String desc,
+ final String path) {
+ File file = new File(path);
+ final long length = file.exists() ? file.length() : 0;
+ if (length == 0) {
+ String failed = getString(R.string.failed);
+ mHandler.obtainMessage(TOAST_DOWNLOAD, failed).sendToTarget();
+ return;
+ }
+ String toast = getString(R.string.file_saved).replace("%s", title);
+ mHandler.obtainMessage(TOAST_DOWNLOAD, toast).sendToTarget();
+ final DownloadManager manager = (DownloadManager) getSystemService(
+ Context.DOWNLOAD_SERVICE);
+ new Thread("Add pdf to downloads") {
+ @Override
+ public void run() {
+ manager.addCompletedDownload(title, desc, true,
+ "application/pdf", path, length, true);
+ }
+ }.start();
+ }
+
+ // Called by JNI
+ @SuppressWarnings("unused")
private void startTimer(int ms) {
// After the delay, queue an event to the Renderer's thread
// to handle the event on the timer queue
native void toggleFps();
native void processSkEvent();
native void serviceQueueTimer();
+ native void saveToPdf();
static {
System.loadLibrary("skia-sample");
'experimental.gyp:experimental',
'gpu.gyp:gr',
'gpu.gyp:skgr',
+ 'pdf.gyp:pdf',
],
'conditions' : [
[ 'OS == "linux" or OS == "freebsd" or OS == "openbsd" or OS == "solaris"', {
void detachGL() {}
void presentGL() {}
+ virtual void onPDFSaved(const char title[], const char desc[],
+ const char path[]);
+
protected:
// overrides from SkWindow
virtual void onHandleInval(const SkIRect&);
void preConcat(const SkMatrix&);
void postConcat(const SkMatrix&);
+ virtual void onPDFSaved(const char title[], const char desc[],
+ const char path[]) {}
protected:
virtual bool onEvent(const SkEvent&);
virtual bool onDispatchClick(int x, int y, Click::State);
#include "GrGLInterface.h"
+#include "SkPDFDevice.h"
+#include "SkPDFDocument.h"
+#include "SkStream.h"
+
#define TEST_GPIPEx
#ifdef TEST_GPIPE
fZoomLevel = 0;
fZoomScale = SK_Scalar1;
+ fSaveToPdf = false;
+ fPdfCanvas = NULL;
+
// this->setConfig(SkBitmap::kRGB_565_Config);
this->setConfig(SkBitmap::kARGB_8888_Config);
this->setVisibleP(true);
SampleWindow::~SampleWindow() {
delete fPicture;
delete fGpuCanvas;
+ delete fPdfCanvas;
if (NULL != fGrContext) {
fGrContext->unref();
}
} else {
this->INHERITED::draw(canvas);
}
- if (fShowZoomer && fCanvasType != kGPU_CanvasType) {
+ if (fShowZoomer && fCanvasType != kGPU_CanvasType && !fSaveToPdf) {
// In the GPU case, INHERITED::draw calls beforeChildren, which
// creates an SkGpuCanvas. All further draw calls are directed
// at that canvas, which is deleted in afterChildren (which is
}
}
+void SampleWindow::saveToPdf()
+{
+ fSaveToPdf = true;
+ this->inval(NULL);
+}
+
SkCanvas* SampleWindow::beforeChildren(SkCanvas* canvas) {
if (kGPU_CanvasType != fCanvasType) {
#ifdef SK_SUPPORT_GL
#endif
}
- switch (fCanvasType) {
- case kRaster_CanvasType:
- canvas = this->INHERITED::beforeChildren(canvas);
- break;
- case kPicture_CanvasType:
- fPicture = new SkPicture;
- canvas = fPicture->beginRecording(9999, 9999);
- break;
- case kGPU_CanvasType: {
- if (make3DReady()) {
- SkDevice* device = canvas->getDevice();
- const SkBitmap& bitmap = device->accessBitmap(true);
-
- GrRenderTarget* renderTarget;
-
- GrPlatformSurfaceDesc desc;
- desc.reset();
- desc.fSurfaceType = kRenderTarget_GrPlatformSurfaceType;
- desc.fWidth = bitmap.width();
- desc.fHeight = bitmap.height();
- desc.fConfig = kRGBA_8888_GrPixelConfig;
- desc.fStencilBits = 8;
- GrGLint buffer;
- GR_GL_GetIntegerv(GR_GL_FRAMEBUFFER_BINDING, &buffer);
- desc.fPlatformRenderTarget = buffer;
-
- renderTarget = static_cast<GrRenderTarget*>(
- fGrContext->createPlatformSurface(desc));
- fGpuCanvas = new SkGpuCanvas(fGrContext, renderTarget);
- renderTarget->unref();
-
- device = new SkGpuDevice(fGrContext, renderTarget);
- fGpuCanvas->setDevice(device)->unref();
-
- fGpuCanvas->concat(canvas->getTotalMatrix());
- canvas = fGpuCanvas;
-
- } else {
+ if (fSaveToPdf) {
+ const SkBitmap& bmp = canvas->getDevice()->accessBitmap(false);
+ SkISize size = SkISize::Make(bmp.width(), bmp.height());
+ SkPDFDevice* pdfDevice = new SkPDFDevice(size, size,
+ canvas->getTotalMatrix());
+ fPdfCanvas = new SkCanvas(pdfDevice);
+ pdfDevice->unref();
+ canvas = fPdfCanvas;
+ } else {
+ switch (fCanvasType) {
+ case kRaster_CanvasType:
canvas = this->INHERITED::beforeChildren(canvas);
+ break;
+ case kPicture_CanvasType:
+ fPicture = new SkPicture;
+ canvas = fPicture->beginRecording(9999, 9999);
+ break;
+ case kGPU_CanvasType: {
+ if (make3DReady()) {
+ SkDevice* device = canvas->getDevice();
+ const SkBitmap& bitmap = device->accessBitmap(true);
+
+ GrRenderTarget* renderTarget;
+
+ GrPlatformSurfaceDesc desc;
+ desc.reset();
+ desc.fSurfaceType = kRenderTarget_GrPlatformSurfaceType;
+ desc.fWidth = bitmap.width();
+ desc.fHeight = bitmap.height();
+ desc.fConfig = kRGBA_8888_GrPixelConfig;
+ desc.fStencilBits = 8;
+ GrGLint buffer;
+ GR_GL_GetIntegerv(GR_GL_FRAMEBUFFER_BINDING, &buffer);
+ desc.fPlatformRenderTarget = buffer;
+
+ renderTarget = static_cast<GrRenderTarget*>(
+ fGrContext->createPlatformSurface(desc));
+ fGpuCanvas = new SkGpuCanvas(fGrContext, renderTarget);
+ renderTarget->unref();
+
+ device = new SkGpuDevice(fGrContext, renderTarget);
+ fGpuCanvas->setDevice(device)->unref();
+
+ fGpuCanvas->concat(canvas->getTotalMatrix());
+ canvas = fGpuCanvas;
+
+ } else {
+ canvas = this->INHERITED::beforeChildren(canvas);
+ }
+ break;
}
- break;
}
}
}
void SampleWindow::afterChildren(SkCanvas* orig) {
+ if (fSaveToPdf) {
+ fSaveToPdf = false;
+ if (fShowZoomer) {
+ showZoomer(fPdfCanvas);
+ }
+ SkString name;
+ name.printf("%s.pdf", this->getTitle());
+ SkPDFDocument doc;
+ SkPDFDevice* device = static_cast<SkPDFDevice*>(fPdfCanvas->getDevice());
+ doc.appendPage(device);
+#ifdef ANDROID
+ name.prepend("/sdcard/");
+#endif
+ SkFILEWStream stream(name.c_str());
+ if (stream.isValid()) {
+ doc.emitPDF(&stream);
+ const char* desc = "File saved from Skia SampleApp";
+ this->onPDFSaved(this->getTitle(), desc, name.c_str());
+ }
+ delete fPdfCanvas;
+ fPdfCanvas = NULL;
+
+ // We took over the draw calls in order to create the PDF, so we need
+ // to redraw.
+ this->inval(NULL);
+ return;
+ }
+
if (fRequestGrabImage) {
fRequestGrabImage = false;
case 'd':
SkGraphics::SetFontCacheUsed(0);
return true;
+ case 'e':
+ this->saveToPdf();
+ break;
case 'f':
this->toggleFPS();
break;
bool previousSample();
bool handleTouch(int ownerId, float x, float y,
SkView::Click::State state);
+ void saveToPdf();
protected:
virtual void onDraw(SkCanvas* canvas);
};
CanvasType fCanvasType;
+ bool fSaveToPdf;
+ SkCanvas* fPdfCanvas;
+
bool fUseClip;
bool fNClip;
bool fRepeatDrawing;