diff options
author | liyuqian <liyuqian@google.com> | 2016-05-17 12:44:20 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-05-17 12:44:20 -0700 |
commit | d3cdbcad65673596ae37e65fec842d8d4d81c5a7 (patch) | |
tree | f7b71e933a44a18e17af1d93d996ac4b2d0c4f59 | |
parent | 1483d0f73ea484bf582b81f031222082f33d6d35 (diff) |
Implement touch control
BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1982643004
Review-Url: https://codereview.chromium.org/1982643004
-rw-r--r-- | gyp/viewer.gyp | 2 | ||||
-rw-r--r-- | platform_tools/android/apps/viewer/src/main/java/org/skia/viewer/ViewerActivity.java | 11 | ||||
-rw-r--r-- | tools/viewer/Viewer.cpp | 42 | ||||
-rw-r--r-- | tools/viewer/Viewer.h | 6 | ||||
-rw-r--r-- | tools/viewer/sk_app/Window.cpp | 10 | ||||
-rw-r--r-- | tools/viewer/sk_app/Window.h | 14 | ||||
-rw-r--r-- | tools/viewer/sk_app/android/Window_android.cpp | 4 | ||||
-rw-r--r-- | tools/viewer/sk_app/android/surface_glue_android.cpp | 42 | ||||
-rw-r--r-- | tools/viewer/sk_app/android/surface_glue_android.h | 15 |
9 files changed, 127 insertions, 19 deletions
diff --git a/gyp/viewer.gyp b/gyp/viewer.gyp index d8082ef949..84daa8d4c5 100644 --- a/gyp/viewer.gyp +++ b/gyp/viewer.gyp @@ -18,6 +18,7 @@ 'include_dirs': [ '../bench', '../gm', + '../include/views', '../include/private', '../src/core', '../src/effects', @@ -28,6 +29,7 @@ ], 'sources': [ '../gm/gm.cpp', + '../src/views/SkTouchGesture.cpp', '<!@(python find.py ../tools/viewer "*.cpp")', ], 'dependencies': [ diff --git a/platform_tools/android/apps/viewer/src/main/java/org/skia/viewer/ViewerActivity.java b/platform_tools/android/apps/viewer/src/main/java/org/skia/viewer/ViewerActivity.java index d6fe710aeb..49f711d517 100644 --- a/platform_tools/android/apps/viewer/src/main/java/org/skia/viewer/ViewerActivity.java +++ b/platform_tools/android/apps/viewer/src/main/java/org/skia/viewer/ViewerActivity.java @@ -32,6 +32,7 @@ public class ViewerActivity private native void onSurfaceChanged(long handle, Surface surface); private native void onSurfaceDestroyed(long handle); private native void onKeyPressed(long handle, int keycode); + private native void onTouched(long handle, int owner, int state, float x, float y); @Override public boolean onCreateOptionsMenu(Menu menu) { @@ -96,6 +97,14 @@ public class ViewerActivity @Override public boolean onTouch(View v, MotionEvent event) { - return false; // TODO pass the touch event to native code + int count = event.getPointerCount(); + for (int i = 0; i < count; i++) { + final float x = event.getX(i); + final float y = event.getY(i); + final int owner = event.getPointerId(i); + int action = event.getAction() & MotionEvent.ACTION_MASK; + onTouched(mApplication.getNativeHandle(), owner, action, x, y); + } + return true; } } diff --git a/tools/viewer/Viewer.cpp b/tools/viewer/Viewer.cpp index 644dd22e5e..7f18652c2c 100644 --- a/tools/viewer/Viewer.cpp +++ b/tools/viewer/Viewer.cpp @@ -28,6 +28,13 @@ static void on_paint_handler(SkCanvas* canvas, void* userData) { return vv->onPaint(canvas); } +static bool on_touch_handler(int owner, Window::InputState state, float x, float y, void* userData) +{ + Viewer* viewer = reinterpret_cast<Viewer*>(userData); + + return viewer->onTouch(owner, state, x, y); +} + DEFINE_bool2(fullscreen, f, true, "Run fullscreen."); DEFINE_string(key, "", "Space-separated key/value pairs to add to JSON identifying this builder."); DEFINE_string2(match, m, nullptr, @@ -71,6 +78,7 @@ Viewer::Viewer(int argc, char** argv, void* platformData) // register callbacks fCommands.attach(fWindow); fWindow->registerPaintFunc(on_paint_handler, this); + fWindow->registerTouchFunc(on_touch_handler, this); // add key-bindings fCommands.addCommand('s', "Overlays", "Toggle stats display", [this]() { @@ -134,7 +142,6 @@ Viewer::Viewer(int argc, char** argv, void* platformData) // set up first frame fCurrentSlide = 0; setupCurrentSlide(-1); - updateMatrix(); fWindow->show(); } @@ -228,10 +235,9 @@ void Viewer::changeZoomLevel(float delta) { } else { fZoomScale = SK_Scalar1; } - this->updateMatrix(); } -void Viewer::updateMatrix(){ +SkMatrix Viewer::computeMatrix() { SkMatrix m; m.reset(); @@ -247,12 +253,10 @@ void Viewer::updateMatrix(){ m.postTranslate(cx, cy); } - // TODO: add gesture support - // Apply any gesture matrix - //m.preConcat(fGesture.localM()); - //m.preConcat(fGesture.globalM()); + m.preConcat(fGesture.localM()); + m.preConcat(fGesture.globalM()); - fLocalMatrix = m; + return m; } void Viewer::onPaint(SkCanvas* canvas) { @@ -273,7 +277,7 @@ void Viewer::onPaint(SkCanvas* canvas) { matrix.setRectToRect(slideBounds, contentRect, SkMatrix::kCenter_ScaleToFit); canvas->concat(matrix); } - canvas->concat(fLocalMatrix); + canvas->concat(computeMatrix()); fSlides[fCurrentSlide]->draw(canvas); canvas->restoreToCount(count); @@ -284,6 +288,26 @@ void Viewer::onPaint(SkCanvas* canvas) { fCommands.drawHelp(canvas); } +bool Viewer::onTouch(int owner, Window::InputState state, float x, float y) { + void* castedOwner = reinterpret_cast<void*>(owner); + switch (state) { + case Window::kUp_InputState: { + fGesture.touchEnd(castedOwner); + break; + } + case Window::kDown_InputState: { + fGesture.touchBegin(castedOwner, x, y); + break; + } + case Window::kMove_InputState: { + fGesture.touchMoved(castedOwner, x, y); + break; + } + } + fWindow->inval(); + return true; +} + void Viewer::drawStats(SkCanvas* canvas) { static const float kPixelPerMS = 2.0f; static const int kDisplayWidth = 130; diff --git a/tools/viewer/Viewer.h b/tools/viewer/Viewer.h index 3579e4d296..c785cff78e 100644 --- a/tools/viewer/Viewer.h +++ b/tools/viewer/Viewer.h @@ -24,6 +24,7 @@ public: void onPaint(SkCanvas* canvas); void onIdle(double ms) override; + bool onTouch(int owner, sk_app::Window::InputState state, float x, float y); private: void initSlides(); @@ -33,7 +34,7 @@ private: void drawStats(SkCanvas* canvas); void changeZoomLevel(float delta); - void updateMatrix(); + SkMatrix computeMatrix(); sk_app::Window* fWindow; @@ -50,13 +51,14 @@ private: sk_app::Window::BackendType fBackendType; // transform data - SkMatrix fLocalMatrix; SkScalar fZoomCenterX; SkScalar fZoomCenterY; SkScalar fZoomLevel; SkScalar fZoomScale; sk_app::CommandSet fCommands; + + SkTouchGesture fGesture; }; diff --git a/tools/viewer/sk_app/Window.cpp b/tools/viewer/sk_app/Window.cpp index dc0bf995d0..0a7bcf8a70 100644 --- a/tools/viewer/sk_app/Window.cpp +++ b/tools/viewer/sk_app/Window.cpp @@ -27,11 +27,17 @@ static bool default_mouse_func(int x, int y, Window::InputState state, uint32_t return false; } +static bool default_touch_func(int owner, Window::InputState state, float x, float y, + void* userData) { + return false; +} + static void default_paint_func(SkCanvas*, void* userData) {} Window::Window() : fCharFunc(default_char_func) , fKeyFunc(default_key_func) , fMouseFunc(default_mouse_func) + , fTouchFunc(default_touch_func) , fPaintFunc(default_paint_func) { } @@ -52,6 +58,10 @@ bool Window::onMouse(int x, int y, InputState state, uint32_t modifiers) { return fMouseFunc(x, y, state, modifiers, fMouseUserData); } +bool Window::onTouch(int owner, InputState state, float x, float y) { + return fTouchFunc(owner, state, x, y, fTouchUserData); +} + void Window::onPaint() { sk_sp<SkSurface> backbuffer = fWindowContext->getBackbufferSurface(); if (backbuffer) { diff --git a/tools/viewer/sk_app/Window.h b/tools/viewer/sk_app/Window.h index 5b41f87f07..63d5e19e55 100644 --- a/tools/viewer/sk_app/Window.h +++ b/tools/viewer/sk_app/Window.h @@ -9,8 +9,9 @@ #define Window_DEFINED #include "DisplayParams.h" -#include "SkTypes.h" #include "SkRect.h" +#include "SkTouchGesture.h" +#include "SkTypes.h" class SkCanvas; @@ -104,6 +105,7 @@ public: typedef bool(*OnCharFunc)(SkUnichar c, uint32_t modifiers, void* userData); typedef bool(*OnKeyFunc)(Key key, InputState state, uint32_t modifiers, void* userData); typedef bool(*OnMouseFunc)(int x, int y, InputState state, uint32_t modifiers, void* userData); + typedef bool(*OnTouchFunc)(int owner, InputState state, float x, float y, void* userData); typedef void(*OnPaintFunc)(SkCanvas*, void* userData); void registerCharFunc(OnCharFunc func, void* userData) { @@ -126,9 +128,15 @@ public: fPaintUserData = userData; } + void registerTouchFunc(OnTouchFunc func, void* userData) { + fTouchFunc = func; + fTouchUserData = userData; + } + bool onChar(SkUnichar c, uint32_t modifiers); bool onKey(Key key, InputState state, uint32_t modifiers); bool onMouse(int x, int y, InputState state, uint32_t modifiers); + bool onTouch(int owner, InputState state, float x, float y); // multi-owner = multi-touch void onPaint(); void onResize(uint32_t width, uint32_t height); @@ -150,10 +158,12 @@ protected: void* fKeyUserData; OnMouseFunc fMouseFunc; void* fMouseUserData; + OnTouchFunc fTouchFunc; + void* fTouchUserData; OnPaintFunc fPaintFunc; void* fPaintUserData; - WindowContext* fWindowContext; + WindowContext* fWindowContext = nullptr; }; } // namespace sk_app diff --git a/tools/viewer/sk_app/android/Window_android.cpp b/tools/viewer/sk_app/android/Window_android.cpp index 21998d5b41..106c40b7b0 100644 --- a/tools/viewer/sk_app/android/Window_android.cpp +++ b/tools/viewer/sk_app/android/Window_android.cpp @@ -64,6 +64,8 @@ void Window_android::onDisplayDestroyed() { detach(); } -void Window_android::inval() { fSkiaAndroidApp->postMessage(Message(kContentInvalidated)); } +void Window_android::inval() { + fSkiaAndroidApp->inval(); +} } // namespace sk_app diff --git a/tools/viewer/sk_app/android/surface_glue_android.cpp b/tools/viewer/sk_app/android/surface_glue_android.cpp index 3d8617f0aa..e8715582c0 100644 --- a/tools/viewer/sk_app/android/surface_glue_android.cpp +++ b/tools/viewer/sk_app/android/surface_glue_android.cpp @@ -13,6 +13,7 @@ #include <unistd.h> #include <unordered_map> +#include <android/input.h> #include <android/keycodes.h> #include <android/looper.h> #include <android/native_window_jni.h> @@ -31,6 +32,15 @@ static const std::unordered_map<int, Window::Key> ANDROID_TO_WINDOW_KEYMAP({ {AKEYCODE_SOFT_RIGHT, Window::Key::kRight} }); +static const std::unordered_map<int, Window::InputState> ANDROID_TO_WINDOW_STATEMAP({ + {AMOTION_EVENT_ACTION_DOWN, Window::kDown_InputState}, + {AMOTION_EVENT_ACTION_POINTER_DOWN, Window::kDown_InputState}, + {AMOTION_EVENT_ACTION_UP, Window::kUp_InputState}, + {AMOTION_EVENT_ACTION_POINTER_UP, Window::kUp_InputState}, + {AMOTION_EVENT_ACTION_MOVE, Window::kMove_InputState}, + {AMOTION_EVENT_ACTION_CANCEL, Window::kUp_InputState}, +}); + SkiaAndroidApp::SkiaAndroidApp(JNIEnv* env, jobject androidApp) { env->GetJavaVM(&fJavaVM); fAndroidApp = env->NewGlobalRef(androidApp); @@ -76,6 +86,14 @@ void SkiaAndroidApp::readMessage(Message* message) const { SkASSERT(readSize == sizeof(Message)); } +void SkiaAndroidApp::inval() { + SkAutoMutexAcquire ama(fMutex); + if (!fIsContentInvalidated) { + postMessage(Message(kContentInvalidated)); + fIsContentInvalidated = true; + } +} + int SkiaAndroidApp::message_callback(int fd, int events, void* data) { auto skiaAndroidApp = (SkiaAndroidApp*)data; Message message; @@ -90,6 +108,8 @@ int SkiaAndroidApp::message_callback(int fd, int events, void* data) { return 0; } case kContentInvalidated: { + SkAutoMutexAcquire ama(skiaAndroidApp->fMutex); + skiaAndroidApp->fIsContentInvalidated = false; skiaAndroidApp->paintIfNeeded(); break; } @@ -121,13 +141,20 @@ int SkiaAndroidApp::message_callback(int fd, int events, void* data) { break; } case kKeyPressed: { - auto it = ANDROID_TO_WINDOW_KEYMAP.find(message.keycode); + auto it = ANDROID_TO_WINDOW_KEYMAP.find(message.fKeycode); SkASSERT(it != ANDROID_TO_WINDOW_KEYMAP.end()); // No modifier is supported so far skiaAndroidApp->fWindow->onKey(it->second, Window::kDown_InputState, 0); skiaAndroidApp->fWindow->onKey(it->second, Window::kUp_InputState, 0); break; } + case kTouched: { + auto it = ANDROID_TO_WINDOW_STATEMAP.find(message.fTouchState); + SkASSERT(it != ANDROID_TO_WINDOW_STATEMAP.end()); + skiaAndroidApp->fWindow->onTouch(message.fTouchOwner, it->second, message.fTouchX, + message.fTouchY); + break; + } default: { // do nothing } @@ -203,7 +230,18 @@ extern "C" JNIEXPORT void JNICALL Java_org_skia_viewer_ViewerActivity_onKeyPress jint keycode) { auto skiaAndroidApp = (SkiaAndroidApp*)handle; Message message(kKeyPressed); - message.keycode = keycode; + message.fKeycode = keycode; + skiaAndroidApp->postMessage(message); +} + +extern "C" JNIEXPORT void JNICALL Java_org_skia_viewer_ViewerActivity_onTouched( + JNIEnv* env, jobject activity, jlong handle, jint owner, jfloat x, jfloat y, jint state) { + auto skiaAndroidApp = (SkiaAndroidApp*)handle; + Message message(kTouched); + message.fTouchOwner = owner; + message.fTouchState = state; + message.fTouchX = x; + message.fTouchY = y; skiaAndroidApp->postMessage(message); } diff --git a/tools/viewer/sk_app/android/surface_glue_android.h b/tools/viewer/sk_app/android/surface_glue_android.h index 1ce06674b9..7ffba3080a 100644 --- a/tools/viewer/sk_app/android/surface_glue_android.h +++ b/tools/viewer/sk_app/android/surface_glue_android.h @@ -12,6 +12,7 @@ #include <android/native_window_jni.h> +#include "../private/SkMutex.h" #include "../Application.h" #include "../Window.h" @@ -24,13 +25,16 @@ enum MessageType { kSurfaceDestroyed, kDestroyApp, kContentInvalidated, - kKeyPressed + kKeyPressed, + kTouched }; struct Message { MessageType fType = kUndefined; ANativeWindow* fNativeWindow = nullptr; - int keycode = 0; + int fKeycode = 0; + int fTouchOwner, fTouchState; + float fTouchX, fTouchY; Message() {} Message(MessageType t) : fType(t) {} @@ -49,6 +53,10 @@ struct SkiaAndroidApp { // This must be called in SkiaAndroidApp's own pthread because the JNIEnv is thread sensitive void setTitle(const char* title) const; + + // This posts a kContentInvalidated message if there's no such message currently in the queue + void inval(); + private: pthread_t fThread; ANativeWindow* fNativeWindow; @@ -57,6 +65,9 @@ private: JNIEnv* fPThreadEnv; jmethodID fSetTitleMethodID; + bool fIsContentInvalidated = false; // use this to avoid duplicate invalidate events + SkMutex fMutex; + // This must be called in SkiaAndroidApp's own pthread because the JNIEnv is thread sensitive ~SkiaAndroidApp(); |