1 2/* 3 * Copyright 2011 Skia 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8#include "com_skia_SkiaSampleRenderer.h" 9 10#include "SampleApp.h" 11#include "SkApplication.h" 12#include "SkCanvas.h" 13#include "SkDevice.h" 14#include "SkEvent.h" 15#include "SkWindow.h" 16 17#include <jni.h> 18#include "AndroidKeyToSkKey.h" 19 20 21/////////////////////////////////////////// 22///////////////// Globals ///////////////// 23/////////////////////////////////////////// 24 25struct ActivityGlue { 26 JNIEnv* m_env; 27 jweak m_obj; 28 jmethodID m_setTitle; 29 jmethodID m_setSlideList; 30 jmethodID m_addToDownloads; 31 ActivityGlue() { 32 m_env = NULL; 33 m_obj = NULL; 34 m_setTitle = NULL; 35 m_setSlideList = NULL; 36 m_addToDownloads = NULL; 37 } 38} gActivityGlue; 39 40struct WindowGlue { 41 jweak m_obj; 42 jmethodID m_inval; 43 jmethodID m_queueSkEvent; 44 jmethodID m_startTimer; 45 jmethodID m_getMSAASampleCount; 46 WindowGlue() { 47 m_obj = NULL; 48 m_inval = NULL; 49 m_queueSkEvent = NULL; 50 m_startTimer = NULL; 51 m_getMSAASampleCount = NULL; 52 } 53} gWindowGlue; 54 55SampleWindow* gWindow; 56 57/////////////////////////////////////////// 58///////////// SkOSWindow impl ///////////// 59/////////////////////////////////////////// 60 61bool SkOSWindow::attach(SkBackEndTypes /* attachType */, int /*msaaSampleCount*/, AttachmentInfo* info) 62{ 63 JNIEnv* env = gActivityGlue.m_env; 64 if (!env || !gWindowGlue.m_getMSAASampleCount || !gWindowGlue.m_obj) { 65 return false; 66 } 67 if (env->IsSameObject(gWindowGlue.m_obj, NULL)) { 68 SkDebugf("ERROR: The JNI WeakRef to the Window is invalid"); 69 return false; 70 } 71 info->fSampleCount = env->CallIntMethod(gWindowGlue.m_obj, gWindowGlue.m_getMSAASampleCount); 72 73 // This is the value requested in SkiaSampleView.java. 74 info->fStencilBits = 8; 75 return true; 76} 77 78void SkOSWindow::onSetTitle(const char title[]) 79{ 80 JNIEnv* env = gActivityGlue.m_env; 81 if (!env) { 82 return; 83 } 84 if (env->IsSameObject(gActivityGlue.m_obj, NULL)) { 85 SkDebugf("ERROR: The JNI WeakRef to the Activity is invalid"); 86 return; 87 } 88 89 jstring string = env->NewStringUTF(title); 90 env->CallVoidMethod(gActivityGlue.m_obj, gActivityGlue.m_setTitle, string); 91 env->DeleteLocalRef(string); 92} 93 94void SkOSWindow::onHandleInval(const SkIRect& rect) 95{ 96 JNIEnv* env = gActivityGlue.m_env; 97 if (!env || !gWindowGlue.m_inval || !gWindowGlue.m_obj) { 98 return; 99 } 100 if (env->IsSameObject(gWindowGlue.m_obj, NULL)) { 101 SkDebugf("ERROR: The JNI WeakRef to the Window is invalid"); 102 return; 103 } 104 env->CallVoidMethod(gWindowGlue.m_obj, gWindowGlue.m_inval); 105} 106 107void SkOSWindow::onPDFSaved(const char title[], const char desc[], 108 const char path[]) 109{ 110 JNIEnv* env = gActivityGlue.m_env; 111 if (!env || !gActivityGlue.m_addToDownloads || !gActivityGlue.m_obj) { 112 return; 113 } 114 if (env->IsSameObject(gActivityGlue.m_obj, NULL)) { 115 SkDebugf("ERROR: The JNI WeakRef to the Activity is invalid"); 116 return; 117 } 118 119 jstring jtitle = env->NewStringUTF(title); 120 jstring jdesc = env->NewStringUTF(desc); 121 jstring jpath = env->NewStringUTF(path); 122 123 env->CallVoidMethod(gActivityGlue.m_obj, gActivityGlue.m_addToDownloads, 124 jtitle, jdesc, jpath); 125 126 env->DeleteLocalRef(jtitle); 127 env->DeleteLocalRef(jdesc); 128 env->DeleteLocalRef(jpath); 129} 130 131/////////////////////////////////////////// 132/////////////// SkEvent impl ////////////// 133/////////////////////////////////////////// 134 135void SkEvent::SignalQueueTimer(SkMSec ms) 136{ 137 JNIEnv* env = gActivityGlue.m_env; 138 if (!env || !gWindowGlue.m_startTimer || !gWindowGlue.m_obj || !ms) { 139 return; 140 } 141 if (env->IsSameObject(gWindowGlue.m_obj, NULL)) { 142 SkDebugf("ERROR: The JNI WeakRef to the Window is invalid"); 143 return; 144 } 145 env->CallVoidMethod(gWindowGlue.m_obj, 146 gWindowGlue.m_startTimer, ms); 147} 148 149void SkEvent::SignalNonEmptyQueue() 150{ 151 JNIEnv* env = gActivityGlue.m_env; 152 if (!env || !gWindowGlue.m_queueSkEvent || !gWindowGlue.m_obj) { 153 return; 154 } 155 if (env->IsSameObject(gWindowGlue.m_obj, NULL)) { 156 SkDebugf("ERROR: The JNI WeakRef to the Window is invalid"); 157 return; 158 } 159 env->CallVoidMethod(gWindowGlue.m_obj, gWindowGlue.m_queueSkEvent); 160} 161 162/////////////////////////////////////////// 163////////////////// JNI //////////////////// 164/////////////////////////////////////////// 165 166static jmethodID GetJMethod(JNIEnv* env, jclass clazz, const char name[], 167 const char signature[]) 168{ 169 jmethodID m = env->GetMethodID(clazz, name, signature); 170 if (!m) SkDebugf("Could not find Java method %s\n", name); 171 return m; 172} 173 174JNIEXPORT void JNICALL Java_com_skia_SkiaSampleRenderer_init(JNIEnv* env, 175 jobject thiz, jobject jsampleActivity, jstring cmdLineFlags, jint msaaSampleCount) 176{ 177 // setup jni hooks to the java activity 178 gActivityGlue.m_env = env; 179 jclass clazz = env->FindClass("com/skia/SkiaSampleActivity"); 180 gActivityGlue.m_obj = env->NewWeakGlobalRef(jsampleActivity); 181 gActivityGlue.m_setTitle = GetJMethod(env, clazz, "setTitle", "(Ljava/lang/CharSequence;)V"); 182 gActivityGlue.m_setSlideList = GetJMethod(env, clazz, "setSlideList", "([Ljava/lang/String;)V"); 183 gActivityGlue.m_addToDownloads = GetJMethod(env, clazz, "addToDownloads", 184 "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); 185 env->DeleteLocalRef(clazz); 186 187 // setup jni hooks to the java renderer 188 clazz = env->FindClass("com/skia/SkiaSampleRenderer"); 189 gWindowGlue.m_obj = env->NewWeakGlobalRef(thiz); 190 gWindowGlue.m_inval = GetJMethod(env, clazz, "requestRender", "()V"); 191 gWindowGlue.m_queueSkEvent = GetJMethod(env, clazz, "queueSkEvent", "()V"); 192 gWindowGlue.m_startTimer = GetJMethod(env, clazz, "startTimer", "(I)V"); 193 gWindowGlue.m_getMSAASampleCount = GetJMethod(env, clazz, "getMSAASampleCount", "()I"); 194 env->DeleteLocalRef(clazz); 195 196 application_init(); 197 198 const char* flags = env->GetStringUTFChars(cmdLineFlags, JNI_FALSE); 199 SkTArray<SkString> flagEntries; 200 SkStrSplit(flags, " ", &flagEntries); 201 202 SkTArray<const char*> args; 203 args.push_back("SampleApp"); 204 for (int i = 0; i < flagEntries.count(); i++) { 205 SkDebugf(flagEntries[i].c_str()); 206 args.push_back(flagEntries[i].c_str()); 207 } 208 209 SkString msaaSampleCountString; 210 if (msaaSampleCount > 0) { 211 args.push_back("--msaa"); 212 msaaSampleCountString.appendS32(static_cast<uint32_t>(msaaSampleCount)); 213 args.push_back(msaaSampleCountString.c_str()); 214 } 215 216 if (gWindow) { 217 SkDebugf("The sample window already exists."); 218 } else { 219 gWindow = new SampleWindow(NULL, args.count(), const_cast<char**>(args.begin()), NULL); 220 } 221 222 // cleanup the command line flags 223 env->ReleaseStringUTFChars(cmdLineFlags, flags); 224 225 // send the list of slides up to the activity 226 const int slideCount = gWindow->sampleCount(); 227 jobjectArray slideList = env->NewObjectArray(slideCount, env->FindClass("java/lang/String"), env->NewStringUTF("")); 228 for (int i = 0; i < slideCount; i++) { 229 jstring slideTitle = env->NewStringUTF(gWindow->getSampleTitle(i).c_str()); 230 env->SetObjectArrayElement(slideList, i, slideTitle); 231 env->DeleteLocalRef(slideTitle); 232 } 233 env->CallVoidMethod(gActivityGlue.m_obj, gActivityGlue.m_setSlideList, slideList); 234 env->DeleteLocalRef(slideList); 235} 236 237JNIEXPORT void JNICALL Java_com_skia_SkiaSampleRenderer_term(JNIEnv* env, 238 jobject thiz) 239{ 240 delete gWindow; 241 gWindow = NULL; 242 application_term(); 243 if (gWindowGlue.m_obj) { 244 env->DeleteWeakGlobalRef(gWindowGlue.m_obj); 245 gWindowGlue.m_obj = NULL; 246 } 247 if (gActivityGlue.m_obj) { 248 env->DeleteWeakGlobalRef(gActivityGlue.m_obj); 249 gActivityGlue.m_obj = NULL; 250 } 251} 252 253JNIEXPORT void JNICALL Java_com_skia_SkiaSampleRenderer_draw( 254 JNIEnv* env, jobject thiz) 255{ 256 if (!gWindow) return; 257 gWindow->update(NULL); 258} 259 260JNIEXPORT void JNICALL Java_com_skia_SkiaSampleRenderer_updateSize(JNIEnv* env, 261 jobject thiz, jint w, jint h) 262{ 263 gWindow->resize(w, h); 264} 265 266JNIEXPORT void JNICALL Java_com_skia_SkiaSampleRenderer_handleClick(JNIEnv* env, 267 jobject thiz, jint owner, jfloat x, jfloat y, jint jstate) 268{ 269 SkView::Click::State state; 270 switch(jstate) { 271 case 0: // MotionEvent.ACTION_DOWN 272 state = SkView::Click::kDown_State; 273 break; 274 case 1: // MotionEvent.ACTION_UP 275 case 3: // MotionEvent.ACTION_CANCEL 276 state = SkView::Click::kUp_State; 277 break; 278 case 2: // MotionEvent.ACTION_MOVE 279 state = SkView::Click::kMoved_State; 280 break; 281 default: 282 SkDebugf("motion event ignored\n"); 283 return; 284 } 285 gWindow->handleClick(x, y, state, reinterpret_cast<void*>(owner)); 286} 287 288JNIEXPORT void JNICALL Java_com_skia_SkiaSampleRenderer_nextSample( 289 JNIEnv* env, jobject thiz) 290{ 291 gWindow->nextSample(); 292} 293 294JNIEXPORT void JNICALL Java_com_skia_SkiaSampleRenderer_previousSample( 295 JNIEnv* env, jobject thiz) 296{ 297 gWindow->previousSample(); 298} 299 300JNIEXPORT void JNICALL Java_com_skia_SkiaSampleRenderer_goToSample( 301 JNIEnv* env, jobject thiz, jint position) 302{ 303 gWindow->goToSample(position); 304} 305 306JNIEXPORT void JNICALL Java_com_skia_SkiaSampleRenderer_toggleRenderingMode( 307 JNIEnv* env, jobject thiz) 308{ 309 gWindow->toggleRendering(); 310} 311 312JNIEXPORT void JNICALL Java_com_skia_SkiaSampleRenderer_showOverview( 313 JNIEnv* env, jobject thiz) 314{ 315 gWindow->showOverview(); 316} 317 318JNIEXPORT void JNICALL Java_com_skia_SkiaSampleRenderer_toggleSlideshow( 319 JNIEnv* env, jobject thiz) 320{ 321 gWindow->toggleSlideshow(); 322} 323 324JNIEXPORT void JNICALL Java_com_skia_SkiaSampleRenderer_toggleFPS( 325 JNIEnv* env, jobject thiz) 326{ 327 gWindow->toggleFPS(); 328} 329 330JNIEXPORT void JNICALL Java_com_skia_SkiaSampleRenderer_toggleTiling( 331 JNIEnv* env, jobject thiz) 332{ 333 gWindow->handleChar('t'); 334} 335 336JNIEXPORT void JNICALL Java_com_skia_SkiaSampleRenderer_toggleBBox( 337 JNIEnv* env, jobject thiz) 338{ 339 gWindow->handleChar('b'); 340} 341 342JNIEXPORT void JNICALL Java_com_skia_SkiaSampleRenderer_processSkEvent( 343 JNIEnv* env, jobject thiz) 344{ 345 if (SkEvent::ProcessEvent()) { 346 SkEvent::SignalNonEmptyQueue(); 347 } 348} 349 350JNIEXPORT void JNICALL Java_com_skia_SkiaSampleRenderer_serviceQueueTimer( 351 JNIEnv* env, jobject thiz) 352{ 353 SkEvent::ServiceQueueTimer(); 354} 355 356JNIEXPORT void JNICALL Java_com_skia_SkiaSampleRenderer_saveToPDF( 357 JNIEnv* env, jobject thiz) 358{ 359 gWindow->saveToPdf(); 360} 361 362JNIEXPORT void JNICALL Java_com_skia_SkiaSampleRenderer_postInval( 363 JNIEnv* env, jobject thiz) 364{ 365 gWindow->postInvalDelay(); 366} 367