Improvements to the SampleApp (primarily Android).
authorScroggo <Scroggo@2bbb7eff-a529-9590-31e7-b0007b416f81>
Wed, 15 Jun 2011 16:49:08 +0000 (16:49 +0000)
committerScroggo <Scroggo@2bbb7eff-a529-9590-31e7-b0007b416f81>
Wed, 15 Jun 2011 16:49:08 +0000 (16:49 +0000)
Reviewed at http://codereview.appspot.com/4587042/

Android
- Added buttons for interaction without a keyboard.
- Added the ability to zoom in to a specific point (roughly).
- Added event handling (for showing a slideshow, for example).
- Allow changing screen orientation
- Updated README file, explaining how to build

Multiplatform changes
- Added SampleApp header file
- Remove FPS when turning off measure FPS mode

git-svn-id: http://skia.googlecode.com/svn/trunk@1596 2bbb7eff-a529-9590-31e7-b0007b416f81

android_sample/SampleApp/Android.mk
android_sample/SampleApp/AndroidManifest.xml
android_sample/SampleApp/README.txt
android_sample/SampleApp/jni/sample-jni.cpp
android_sample/SampleApp/res/menu/sample.xml
android_sample/SampleApp/res/values/strings.xml
android_sample/SampleApp/src/com/skia/sampleapp/SampleApp.java
android_sample/SampleApp/src/com/skia/sampleapp/SampleView.java
include/views/SkOSWindow_Android.h
samplecode/SampleApp.cpp
samplecode/SampleApp.h [new file with mode: 0644]

index 59f6993..f2fd860 100644 (file)
@@ -14,6 +14,8 @@ LOCAL_PACKAGE_NAME := SampleApp
 
 LOCAL_JNI_SHARED_LIBRARIES := libskia-sample
 
+LOCAL_PROGUARD_ENABLED := disabled
+
 include $(BUILD_PACKAGE)
 
 ######################################
@@ -37,6 +39,7 @@ LOCAL_C_INCLUDES += \
     external/skia/include/gpu \
     external/skia/src/core \
     external/skia/gpu/include \
+    frameworks/base/opengl/include/GLES2 \
     $(LOCAL_PATH)/jni
 
 LOCAL_SHARED_LIBRARIES := \
index 071ae03..5980d29 100644 (file)
@@ -22,6 +22,7 @@
                  android:debuggable="true">
         <activity android:name=".SampleApp"
                   android:theme="@android:style/Theme.Holo.Light"
+                  android:configChanges="orientation|screenSize"
                   android:label="@string/app_name">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
@@ -29,4 +30,4 @@
             </intent-filter>
         </activity>
     </application>
-</manifest> 
+</manifest>
index a7d8e54..31e6492 100644 (file)
@@ -1,25 +1,6 @@
 Building the sample app for Android using an Android tree:
 
-Copy this folder into an Android tree in packages/apps. In addition to jni,
-res, and src, there needs to be a fourth folder named "skia_extra".  This
-will include the skia files which are not part of an Android checkout. It
-should have three folders: include, samplecode, and src.
-
-skia/trunk/include/views -> skia_extra/include/views
-skia/trunk/include/xml -> skia_extra/include/xml
-
-skia/trunk/samplecode -> skia_extra/samplecode
-
-skia/trunk/src/views -> skia_extra/src/views
-skia/trunk/src/ports/SkXMLParser_empty.cpp -> skia_extra/src/ports/
-skia/trunk/src/xml -> skia_extra/src/xml
-
-skia/trunk/include/utils/android/AndroidKeyToSkKey.h -> jni/
-
-From packages/apps/SampleApp, type "mm" to build, and install the
-resulting apk.
-
-(It may be necessary to remove samples that do not build from
-skia_extra/samplecode/samplecode_files.mk)
+cd into external/skia/android_sample/SampleApp.
+Type "mm" to build, and install the resulting apk.
 
 TODO: Instructions for building from SDK/NDK
index 86d07a8..be4e4d4 100644 (file)
  *
  */
 
-#include <jni.h>
-
+#include "GrContext.h"
+#include "SampleApp.h"
+#include "SkApplication.h"
 #include "SkCanvas.h"
+#include "SkDevice.h"
 #include "SkEvent.h"
+#include "SkGpuCanvas.h"
 #include "SkWindow.h"
-#include "SkApplication.h"
+
+#include <jni.h>
 #include "utils/android/AndroidKeyToSkKey.h"
 
-#include "SkDevice.h"
-#include "SkGpuCanvas.h"
-#include "GrContext.h"
 
 ///////////////////////////////////////////
 ///////////////// Globals /////////////////
@@ -35,23 +36,27 @@ struct ActivityGlue {
     JNIEnv* m_env;
     jweak m_obj;
     jmethodID m_setTitle;
+    jmethodID m_startTimer;
     ActivityGlue() {
         m_env = NULL;
         m_obj = NULL;
         m_setTitle = NULL;
+        m_startTimer = NULL;
     }
 } gActivityGlue;
 
 struct WindowGlue {
     jweak m_obj;
     jmethodID m_inval;
+    jmethodID m_queueSkEvent;
     WindowGlue() {
         m_obj = NULL;
         m_inval = NULL;
+        m_queueSkEvent = NULL;
     }
 } gWindowGlue;
 
-SkOSWindow* gWindow;
+SampleWindow* gWindow;
 
 ///////////////////////////////////////////
 ///////////// SkOSWindow impl /////////////
@@ -80,9 +85,25 @@ void SkOSWindow::onHandleInval(const SkIRect& rect)
 /////////////// SkEvent impl //////////////
 ///////////////////////////////////////////
 
-void SkEvent::SignalQueueTimer(SkMSec) {}
+void SkEvent::SignalQueueTimer(SkMSec ms)
+{
+    if (!gActivityGlue.m_env || !gActivityGlue.m_startTimer
+            || !gActivityGlue.m_obj || !ms) {
+        return;
+    }
+    gActivityGlue.m_env->CallVoidMethod(gActivityGlue.m_obj,
+            gActivityGlue.m_startTimer, ms);
+}
 
-void SkEvent::SignalNonEmptyQueue() {}
+void SkEvent::SignalNonEmptyQueue()
+{
+    if (!gActivityGlue.m_env || !gWindowGlue.m_queueSkEvent
+            || !gWindowGlue.m_obj) {
+        return;
+    }
+    gActivityGlue.m_env->CallVoidMethod(gWindowGlue.m_obj,
+            gWindowGlue.m_queueSkEvent);
+}
 
 ///////////////////////////////////////////
 ////////////////// JNI ////////////////////
@@ -113,8 +134,22 @@ JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_handleClick(
         JNIEnv* env, jobject thiz, jint x, jint y, jint state);
 JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_createOSWindow(
         JNIEnv* env, jobject thiz, jobject jsampleView);
+JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_setZoomCenter(
+        JNIEnv* env, jobject thiz, jfloat x, jfloat y);
 JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_zoom(
         JNIEnv* env, jobject thiz, jfloat factor);
+JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_nextSample(
+        JNIEnv* env, jobject thiz, jboolean fprevious);
+JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_toggleRendering(
+        JNIEnv* env, jobject thiz);
+JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_toggleSlideshow(
+        JNIEnv* env, jobject thiz);
+JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_toggleFps(
+        JNIEnv* env, jobject thiz);
+JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_processSkEvent(
+        JNIEnv* env, jobject thiz);
+JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_serviceQueueTimer(
+        JNIEnv* env, jobject thiz);
 };
 
 JNIEXPORT bool JNICALL Java_com_skia_sampleapp_SampleApp_handleKeyDown(
@@ -162,12 +197,14 @@ JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_updateSize(JNIEnv* env,
 JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_createOSWindow(
         JNIEnv* env, jobject thiz, jobject jsampleView)
 {
-    gWindow = create_sk_window(NULL);
-    // Only using a method on View.
-    jclass clazz = gActivityGlue.m_env->FindClass("android/opengl/GLSurfaceView");
+    gWindow = new SampleWindow(NULL);
+    jclass clazz = gActivityGlue.m_env->FindClass(
+            "com/skia/sampleapp/SampleView");
     gWindowGlue.m_obj = gActivityGlue.m_env->NewWeakGlobalRef(jsampleView);
-    gWindowGlue.m_inval = GetJMethod(gActivityGlue.m_env, clazz, "requestRender",
-            "()V");
+    gWindowGlue.m_inval = GetJMethod(gActivityGlue.m_env, clazz,
+            "requestRender", "()V");
+    gWindowGlue.m_queueSkEvent = GetJMethod(gActivityGlue.m_env, clazz,
+            "queueSkEvent", "()V");
     gActivityGlue.m_env->DeleteLocalRef(clazz);
 }
 
@@ -175,11 +212,12 @@ JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_init(JNIEnv* env,
         jobject thiz)
 {
     gActivityGlue.m_env = env;
-    // Only using a method on Activity.
-    jclass clazz = env->FindClass("android/app/Activity");
+    jclass clazz = env->FindClass("com/skia/sampleapp/SampleApp");
     gActivityGlue.m_obj = env->NewWeakGlobalRef(thiz);
     gActivityGlue.m_setTitle = GetJMethod(env, clazz, "setTitle",
             "(Ljava/lang/CharSequence;)V");
+    gActivityGlue.m_startTimer = GetJMethod(gActivityGlue.m_env, clazz,
+            "startTimer", "(I)V");
     env->DeleteLocalRef(clazz);
 
     application_init();
@@ -235,9 +273,56 @@ JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_draw(
     }
 }
 
+JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_setZoomCenter(
+        JNIEnv* env, jobject thiz, jfloat x, jfloat y)
+{
+    gWindow->setZoomCenter(x, y);
+}
+
 JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_zoom(
         JNIEnv* env, jobject thiz, jfloat factor)
 {
     gWindow->changeZoomLevel(factor);
 }
 
+JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_nextSample(
+        JNIEnv* env, jobject thiz, jboolean fprevious)
+{
+    if (fprevious) {
+        gWindow->previousSample();
+    } else {
+        gWindow->nextSample();
+    }
+}
+
+JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_toggleRendering(
+        JNIEnv* env, jobject thiz)
+{
+    gWindow->toggleRendering();
+}
+
+JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_toggleSlideshow(
+        JNIEnv* env, jobject thiz)
+{
+    gWindow->toggleSlideshow();
+}
+
+JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_toggleFps(
+        JNIEnv* env, jobject thiz)
+{
+    gWindow->toggleFPS();
+}
+
+JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_processSkEvent(
+        JNIEnv* env, jobject thiz)
+{
+    if (SkEvent::ProcessEvent()) {
+        SkEvent::SignalNonEmptyQueue();
+    }
+}
+
+JNIEXPORT void JNICALL Java_com_skia_sampleapp_SampleApp_serviceQueueTimer(
+        JNIEnv* env, jobject thiz)
+{
+    SkEvent::ServiceQueueTimer();
+}
index 49f7ebb..193f277 100644 (file)
 
 <menu xmlns:android="http://schemas.android.com/apk/res/android">
     <item
+        android:id="@+id/fps"
+        android:title="@string/fps"
+        android:showAsAction="always"
+        />
+    <item
+        android:id="@+id/toggle_rendering"
+        android:title="@string/toggle_rendering"
+        android:showAsAction="always"
+        />
+    <item
+        android:id="@+id/prev"
+        android:showAsAction="always"
+        android:icon="@*android:drawable/ic_btn_find_prev"
+        />
+    <item
         android:id="@+id/next"
         android:showAsAction="always"
         android:icon="@*android:drawable/ic_btn_find_next"
         android:id="@+id/overview"
         android:title="@string/overview"
         />
+    <item
+        android:id="@+id/slideshow"
+        android:title="@string/slideshow"
+        />
 <!--
         android:icon="@drawable/ic_menu_new_window"
 -->
index 72d3bc8..810ff41 100644 (file)
@@ -15,4 +15,8 @@
 -->
 <resources>
     <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>
 </resources>
index fe73360..b116010 100644 (file)
@@ -53,10 +53,9 @@ public class SampleApp extends Activity
         holder.addView(mView, new LinearLayout.LayoutParams(
                 ViewGroup.LayoutParams.MATCH_PARENT,
                 ViewGroup.LayoutParams.MATCH_PARENT));
-        
+
         mTitle.setVisibility(View.GONE);
         getActionBar().setDisplayShowHomeEnabled(false);
-        
     }
 
     @Override
@@ -87,11 +86,43 @@ public class SampleApp extends Activity
                     }
                 });
                 return true;
+            case R.id.prev:
+                mView.queueEvent(new Runnable() {
+                    @Override
+                    public void run() {
+                        nextSample(true);
+                    }
+                });
+                return true;
             case R.id.next:
                 mView.queueEvent(new Runnable() {
                     @Override
                     public void run() {
-                        handleKeyDown(KeyEvent.KEYCODE_DPAD_RIGHT, 0);
+                        nextSample(false);
+                    }
+                });
+                return true;
+            case R.id.toggle_rendering:
+                mView.queueEvent(new Runnable() {
+                    @Override
+                    public void run() {
+                        toggleRendering();
+                    }
+                });
+                return true;
+            case R.id.slideshow:
+                mView.queueEvent(new Runnable() {
+                    @Override
+                    public void run() {
+                        toggleSlideshow();
+                    }
+                });
+                return true;
+            case R.id.fps:
+                mView.queueEvent(new Runnable() {
+                    @Override
+                    public void run() {
+                        toggleFps();
                     }
                 });
                 return true;
@@ -118,7 +149,6 @@ public class SampleApp extends Activity
                         handleKeyDown(keycode, uni);
                     }
                 });
-                
                 return true;
             case KeyEvent.ACTION_UP:
                 mView.queueEvent(new Runnable() {
@@ -134,7 +164,7 @@ public class SampleApp extends Activity
     }
 
     private static final int SET_TITLE = 1;
-    
+
     private Handler mHandler = new Handler() {
         @Override
         public void handleMessage(Message msg) {
@@ -148,22 +178,47 @@ public class SampleApp extends Activity
             }
         }
     };
-    
+
     @Override
     public void setTitle(CharSequence title) {
         mHandler.obtainMessage(SET_TITLE, title).sendToTarget();
     }
 
+    // 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
+        mHandler.postDelayed(new Runnable() {
+            @Override
+            public void run() {
+                mView.queueEvent(new Runnable() {
+                    @Override
+                    public void run() {
+                        serviceQueueTimer();
+                    }
+                });
+            }
+        }, ms);
+    }
+
     native void draw();
     native void init();
     native void term();
     // Currently depends on init having already been called.
-    native void createOSWindow(GLSurfaceView view);
+    native void createOSWindow(SampleView view);
     native void updateSize(int w, int h);
     native void handleClick(int x, int y, int state);
     native boolean handleKeyDown(int key, int uni);
     native boolean handleKeyUp(int key);
     native void zoom(float factor);
+    native void setZoomCenter(float x, float y);
+    native void nextSample(boolean previous);
+    native void toggleRendering();
+    native void toggleSlideshow();
+    native void toggleFps();
+    native void processSkEvent();
+    native void serviceQueueTimer();
 
     static {
         System.loadLibrary("skia-sample");
index 0d76dce..5ea36a8 100644 (file)
@@ -33,9 +33,10 @@ import javax.microedition.khronos.egl.EGLConfig;
 import javax.microedition.khronos.opengles.GL10;
 
 public class SampleView extends GLSurfaceView implements OnScaleGestureListener {
-    
+
     private final SampleApp mApp;
     private ScaleGestureDetector mDetector;
+
     public SampleView(SampleApp app) {
         super(app);
         mApp = app;
@@ -46,6 +47,17 @@ public class SampleView extends GLSurfaceView implements OnScaleGestureListener
         mDetector = new ScaleGestureDetector(app, this);
     }
 
+    // Called by JNI
+    @SuppressWarnings("unused")
+    private void queueSkEvent() {
+        queueEvent(new Runnable() {
+            @Override
+            public void run() {
+                mApp.processSkEvent();
+            }
+        });
+    }
+
     @Override
     public boolean onTouchEvent(MotionEvent event) {
         mDetector.onTouchEvent(event);
@@ -62,23 +74,33 @@ public class SampleView extends GLSurfaceView implements OnScaleGestureListener
                mApp.handleClick(x, y, action);
            }
         });
-        
+
         return true;
     }
+
     // ScaleGestureDetector.OnScaleGestureListener implementation
     @Override
     public boolean onScaleBegin(ScaleGestureDetector detector) {
+        final float x = detector.getFocusX();
+        final float y = detector.getFocusY();
+        queueEvent(new Runnable() {
+            @Override
+            public void run() {
+                mApp.setZoomCenter(x, y);
+            }
+        });
         return true;
     }
 
     @Override
     public boolean onScale(ScaleGestureDetector detector) {
         if (detector.getScaleFactor() != 1) {
-            final float difference = detector.getCurrentSpan() - detector.getPreviousSpan();
+            final float difference = detector.getCurrentSpan()
+                    - detector.getPreviousSpan();
             queueEvent(new Runnable() {
                 @Override
                 public void run() {
-                    mApp.zoom(difference * .03f);
+                    mApp.zoom(difference * .01f);
                 }
             });
 
@@ -96,11 +118,11 @@ public class SampleView extends GLSurfaceView implements OnScaleGestureListener
         public void onDrawFrame(GL10 gl) {
             mApp.draw();
         }
-        
+
         public void onSurfaceChanged(GL10 gl, int width, int height) {
             mApp.updateSize(width, height);
         }
-        
+
         public void onSurfaceCreated(GL10 gl, EGLConfig config) {
             gl.glClearStencil(0);
             gl.glClear(gl.GL_STENCIL_BUFFER_BIT);
@@ -108,4 +130,4 @@ public class SampleView extends GLSurfaceView implements OnScaleGestureListener
             mApp.createOSWindow(SampleView.this);
         }
     }
-}
\ No newline at end of file
+}
index 569f3f7..e547609 100644 (file)
@@ -18,9 +18,8 @@
 #define SkOSWindow_Android_DEFINED
 
 #include "SkWindow.h"
-#include "SkEvent.h"
 
-class GrContext;
+class SkIRect;
 
 class SkOSWindow : public SkWindow {
 public:
@@ -29,10 +28,7 @@ public:
     bool attachGL() { return true; }
     void detachGL() {}
     void presentGL() {}
-    virtual bool drawsToHardware() { return false; }
-    virtual bool setGrContext(GrContext*) { return false; }
-    virtual GrContext* getGrContext() { return NULL; }
-    virtual void changeZoomLevel(float delta) {}
+
 protected:
     // overrides from SkWindow
     virtual void onHandleInval(const SkIRect&);
index aba105b..c457ef6 100644 (file)
@@ -1,3 +1,5 @@
+#include "SampleApp.h"
+
 #include "SkCanvas.h"
 #include "SkDevice.h"
 #include "SkGpuCanvas.h"
 
 #include "SampleCode.h"
 #include "GrContext.h"
-#include "SkTouchGesture.h"
 #include "SkTypeface.h"
 
+#ifdef ANDROID
+    #include "gl2.h"
+#endif
+
 #define TEST_GPIPEx
 
 #ifdef  TEST_GPIPE
@@ -111,12 +116,6 @@ enum FlipAxisEnum {
     kFlipAxis_Y = (1 << 1)
 };
 
-enum SkTriState {
-    kFalse_SkTriState,
-    kTrue_SkTriState,
-    kUnknown_SkTriState,
-};
-
 static SkTriState cycle_tristate(SkTriState state) {
     static const SkTriState gCycle[] = {
         /* kFalse_SkTriState   -> */  kUnknown_SkTriState,
@@ -244,121 +243,12 @@ static SkView* curr_view(SkWindow* wind) {
     return iter.next();
 }
 
-class SampleWindow : public SkOSWindow {
-    SkTDArray<SkViewFactory> fSamples;
-public:
-    SampleWindow(void* hwnd);
-    virtual ~SampleWindow();
-
-    virtual void draw(SkCanvas* canvas);
-#ifdef ANDROID
-    virtual bool drawsToHardware() { return fCanvasType == kGPU_CanvasType; }
-    virtual bool setGrContext(GrContext*);
-    virtual GrContext* getGrContext();
-#endif
-
-protected:
-    virtual void onDraw(SkCanvas* canvas);
-    virtual bool onHandleKey(SkKey key);
-    virtual bool onHandleChar(SkUnichar);
-    virtual void onSizeChange();
-
-    virtual SkCanvas* beforeChildren(SkCanvas*);
-    virtual void afterChildren(SkCanvas*);
-    virtual void beforeChild(SkView* child, SkCanvas* canvas);
-    virtual void afterChild(SkView* child, SkCanvas* canvas);
-
-    virtual bool onEvent(const SkEvent& evt);
-    virtual bool onQuery(SkEvent* evt);
-
-    virtual bool onDispatchClick(int x, int y, Click::State);
-    virtual bool onClick(Click* click);
-    virtual Click* onFindClickHandler(SkScalar x, SkScalar y);
-
-#if 0
-    virtual bool handleChar(SkUnichar uni);
-    virtual bool handleEvent(const SkEvent& evt);
-    virtual bool handleKey(SkKey key);
-    virtual bool handleKeyUp(SkKey key);
-    virtual bool onHandleKeyUp(SkKey key);
-#endif
-
-private:
-    int fCurrIndex;
-
-    SkPicture* fPicture;
-    SkGpuCanvas* fGpuCanvas;
-    GrContext* fGrContext;
-    SkPath fClipPath;
-
-    SkTouchGesture fGesture;
-    SkScalar fZoomLevel;
-    SkScalar fZoomScale;
-
-    enum CanvasType {
-        kRaster_CanvasType,
-        kPicture_CanvasType,
-        kGPU_CanvasType
-    };
-    CanvasType fCanvasType;
-
-    bool fUseClip;
-    bool fNClip;
-    bool fRepeatDrawing;
-    bool fAnimating;
-    bool fRotate;
-    bool fScale;
-    bool fRequestGrabImage;
-    bool fUsePipe;
-    bool fMeasureFPS;
-    SkMSec fMeasureFPS_Time;
-
-    // The following are for the 'fatbits' drawing
-    // Latest position of the mouse.
-    int fMouseX, fMouseY;
-    int fFatBitsScale;
-    // Used by the text showing position and color values.
-    SkTypeface* fTypeface;
-    bool fShowZoomer;
-
-    SkTriState fLCDState;
-    SkTriState fAAState;
-    SkTriState fFilterState;
-    SkTriState fHintingState;
-    unsigned   fFlipAxis;
-
-    int fScrollTestX, fScrollTestY;
-
-    bool make3DReady();
-#ifdef ANDROID
-    virtual
-#endif
-    void changeZoomLevel(float delta);
-
-    void loadView(SkView*);
-    void updateTitle();
-    bool nextSample();
-
-    void toggleZoomer();
-    bool zoomIn();
-    bool zoomOut();
-    void updatePointer(int x, int y);
-    void showZoomer(SkCanvas* canvas);
-
-    void postAnimatingEvent() {
-        if (fAnimating) {
-            SkEvent* evt = new SkEvent(ANIMATING_EVENTTYPE);
-            evt->post(this->getSinkID(), ANIMATING_DELAY);
-        }
-    }
-
-
-    static CanvasType cycle_canvastype(CanvasType);
-
-    typedef SkOSWindow INHERITED;
-};
+void SampleWindow::setZoomCenter(float x, float y)
+{
+    fZoomCenterX = SkFloatToScalar(x);
+    fZoomCenterY = SkFloatToScalar(y);
+}
 
-#ifdef ANDROID
 bool SampleWindow::setGrContext(GrContext* context)
 {
     if (fGrContext) {
@@ -373,7 +263,6 @@ GrContext* SampleWindow::getGrContext()
 {
     return fGrContext;
 }
-#endif
 
 bool SampleWindow::zoomIn()
 {
@@ -577,8 +466,8 @@ void SampleWindow::draw(SkCanvas* canvas) {
     gAnimTimePrev = gAnimTime;
     gAnimTime = SkTime::GetMSecs();
 
-    SkScalar cx = SkScalarHalf(this->width());
-    SkScalar cy = SkScalarHalf(this->height());
+    SkScalar cx = fZoomCenterX;
+    SkScalar cy = fZoomCenterY;
 
     if (fZoomLevel) {
         SkMatrix m;
@@ -970,12 +859,25 @@ void SampleWindow::changeZoomLevel(float delta) {
     this->inval(NULL);
 }
 
+bool SampleWindow::previousSample() {
+    fCurrIndex = (fCurrIndex - 1) % fSamples.count();
+    this->loadView(fSamples[fCurrIndex]());
+    return true;
+}
+
 bool SampleWindow::nextSample() {
     fCurrIndex = (fCurrIndex + 1) % fSamples.count();
     this->loadView(fSamples[fCurrIndex]());
     return true;
 }
 
+void SampleWindow::postAnimatingEvent() {
+    if (fAnimating) {
+        SkEvent* evt = new SkEvent(ANIMATING_EVENTTYPE);
+        evt->post(this->getSinkID(), ANIMATING_DELAY);
+    }
+}
+
 bool SampleWindow::onEvent(const SkEvent& evt) {
     if (evt.isType(ANIMATING_EVENTTYPE)) {
         if (fAnimating) {
@@ -1072,9 +974,7 @@ bool SampleWindow::onHandleChar(SkUnichar uni) {
 
     switch (uni) {
         case 'a':
-            fAnimating = !fAnimating;
-            this->postAnimatingEvent();
-            this->updateTitle();
+            this->toggleSlideshow();
             return true;
         case 'b':
             fAAState = cycle_tristate(fAAState);
@@ -1090,8 +990,7 @@ bool SampleWindow::onHandleChar(SkUnichar uni) {
             SkGraphics::SetFontCacheUsed(0);
             return true;
         case 'f':
-            fMeasureFPS = !fMeasureFPS;
-            this->inval(NULL);
+            this->toggleFPS();
             break;
         case 'g':
             fRequestGrabImage = true;
@@ -1153,6 +1052,24 @@ bool SampleWindow::onHandleChar(SkUnichar uni) {
     return this->INHERITED::onHandleChar(uni);
 }
 
+void SampleWindow::toggleFPS() {
+    fMeasureFPS = !fMeasureFPS;
+    this->inval(NULL);
+    this->updateTitle();
+}
+
+void SampleWindow::toggleSlideshow() {
+    fAnimating = !fAnimating;
+    this->postAnimatingEvent();
+    this->updateTitle();
+}
+
+void SampleWindow::toggleRendering() {
+    fCanvasType = cycle_canvastype(fCanvasType);
+    this->updateTitle();
+    this->inval(NULL);
+}
+
 #include "SkDumpCanvas.h"
 
 bool SampleWindow::onHandleKey(SkKey key) {
@@ -1174,9 +1091,7 @@ bool SampleWindow::onHandleKey(SkKey key) {
             }
             break;
         case kLeft_SkKey:
-            fCanvasType = cycle_canvastype(fCanvasType);
-            this->updateTitle();
-            this->inval(NULL);
+            toggleRendering();
             return true;
         case kUp_SkKey:
             if (USE_ARROWS_FOR_ZOOM) {
@@ -1405,6 +1320,15 @@ void SampleWindow::onSizeChange() {
 #endif
     }
 
+    fZoomCenterX = SkScalarHalf(this->width());
+    fZoomCenterY = SkScalarHalf(this->height());
+
+    if (fGrContext) {
+        glViewport(0, 0, SkScalarRound(this->width()),
+                SkScalarRound(this->height()));
+        fGrContext->resetContext();
+    }
+
     this->updateTitle();    // to refresh our config
 }
 
diff --git a/samplecode/SampleApp.h b/samplecode/SampleApp.h
new file mode 100644 (file)
index 0000000..37a3d09
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2011 Skia
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SampleWindow_DEFINED
+#define SampleWindow_DEFINED
+
+#include "SkWindow.h"
+
+#include "SampleCode.h"
+#include "SkPath.h"
+#include "SkScalar.h"
+#include "SkTDArray.h"
+#include "SkTouchGesture.h"
+#include "SkWindow.h"
+
+class GrContext;
+
+class SkEvent;
+class SkCanvas;
+class SkGpuCanvas;
+class SkPicture;
+class SkTypeface;
+
+enum SkTriState {
+    kFalse_SkTriState,
+    kTrue_SkTriState,
+    kUnknown_SkTriState,
+};
+
+class SampleWindow : public SkOSWindow {
+    SkTDArray<SkViewFactory> fSamples;
+public:
+    SampleWindow(void* hwnd);
+    virtual ~SampleWindow();
+
+    virtual void draw(SkCanvas* canvas);
+
+    void toggleRendering();
+    void toggleSlideshow();
+    void toggleFPS();
+    bool drawsToHardware() { return fCanvasType == kGPU_CanvasType; }
+    bool setGrContext(GrContext*);
+    GrContext* getGrContext();
+    void setZoomCenter(float x, float y);
+    void changeZoomLevel(float delta);
+    bool nextSample();
+    bool previousSample();
+
+protected:
+    virtual void onDraw(SkCanvas* canvas);
+    virtual bool onHandleKey(SkKey key);
+    virtual bool onHandleChar(SkUnichar);
+    virtual void onSizeChange();
+
+    virtual SkCanvas* beforeChildren(SkCanvas*);
+    virtual void afterChildren(SkCanvas*);
+    virtual void beforeChild(SkView* child, SkCanvas* canvas);
+    virtual void afterChild(SkView* child, SkCanvas* canvas);
+
+    virtual bool onEvent(const SkEvent& evt);
+    virtual bool onQuery(SkEvent* evt);
+
+    virtual bool onDispatchClick(int x, int y, Click::State);
+    virtual bool onClick(Click* click);
+    virtual Click* onFindClickHandler(SkScalar x, SkScalar y);
+
+private:
+    int fCurrIndex;
+
+    SkPicture* fPicture;
+    SkGpuCanvas* fGpuCanvas;
+    GrContext* fGrContext;
+    SkPath fClipPath;
+
+    SkTouchGesture fGesture;
+    SkScalar fZoomLevel;
+    SkScalar fZoomScale;
+
+    enum CanvasType {
+        kRaster_CanvasType,
+        kPicture_CanvasType,
+        kGPU_CanvasType
+    };
+    CanvasType fCanvasType;
+
+    bool fUseClip;
+    bool fNClip;
+    bool fRepeatDrawing;
+    bool fAnimating;
+    bool fRotate;
+    bool fScale;
+    bool fRequestGrabImage;
+    bool fUsePipe;
+    bool fMeasureFPS;
+    SkMSec fMeasureFPS_Time;
+
+    // The following are for the 'fatbits' drawing
+    // Latest position of the mouse.
+    int fMouseX, fMouseY;
+    int fFatBitsScale;
+    // Used by the text showing position and color values.
+    SkTypeface* fTypeface;
+    bool fShowZoomer;
+
+    SkTriState fLCDState;
+    SkTriState fAAState;
+    SkTriState fFilterState;
+    SkTriState fHintingState;
+    unsigned   fFlipAxis;
+
+    int fScrollTestX, fScrollTestY;
+    SkScalar fZoomCenterX, fZoomCenterY;
+
+    bool make3DReady();
+
+    void loadView(SkView*);
+    void updateTitle();
+
+    void toggleZoomer();
+    bool zoomIn();
+    bool zoomOut();
+    void updatePointer(int x, int y);
+    void showZoomer(SkCanvas* canvas);
+
+    void postAnimatingEvent();
+
+    static CanvasType cycle_canvastype(CanvasType);
+
+    typedef SkOSWindow INHERITED;
+};
+
+#endif