1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2010 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker *
4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker */
7*c8dee2aaSAndroid Build Coastguard Worker
8*c8dee2aaSAndroid Build Coastguard Worker #include "tools/viewer/TouchGesture.h"
9*c8dee2aaSAndroid Build Coastguard Worker
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkMatrix.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkDebug.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkFloatingPoint.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkTime.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "tools/timer/TimeUtils.h"
16*c8dee2aaSAndroid Build Coastguard Worker
17*c8dee2aaSAndroid Build Coastguard Worker #include <algorithm>
18*c8dee2aaSAndroid Build Coastguard Worker #include <cmath>
19*c8dee2aaSAndroid Build Coastguard Worker
20*c8dee2aaSAndroid Build Coastguard Worker #define DISCRETIZE_TRANSLATE_TO_AVOID_FLICKER true
21*c8dee2aaSAndroid Build Coastguard Worker
22*c8dee2aaSAndroid Build Coastguard Worker static const SkScalar MAX_FLING_SPEED = SkIntToScalar(1500);
23*c8dee2aaSAndroid Build Coastguard Worker
pin_max_fling(SkScalar speed)24*c8dee2aaSAndroid Build Coastguard Worker static SkScalar pin_max_fling(SkScalar speed) {
25*c8dee2aaSAndroid Build Coastguard Worker if (speed > MAX_FLING_SPEED) {
26*c8dee2aaSAndroid Build Coastguard Worker speed = MAX_FLING_SPEED;
27*c8dee2aaSAndroid Build Coastguard Worker }
28*c8dee2aaSAndroid Build Coastguard Worker return speed;
29*c8dee2aaSAndroid Build Coastguard Worker }
30*c8dee2aaSAndroid Build Coastguard Worker
getseconds()31*c8dee2aaSAndroid Build Coastguard Worker static double getseconds() {
32*c8dee2aaSAndroid Build Coastguard Worker return SkTime::GetMSecs() * 0.001;
33*c8dee2aaSAndroid Build Coastguard Worker }
34*c8dee2aaSAndroid Build Coastguard Worker
35*c8dee2aaSAndroid Build Coastguard Worker // returns +1 or -1, depending on the sign of x
36*c8dee2aaSAndroid Build Coastguard Worker // returns +1 if z is zero
SkScalarSignNonZero(SkScalar x)37*c8dee2aaSAndroid Build Coastguard Worker static SkScalar SkScalarSignNonZero(SkScalar x) {
38*c8dee2aaSAndroid Build Coastguard Worker SkScalar sign = SK_Scalar1;
39*c8dee2aaSAndroid Build Coastguard Worker if (x < 0) {
40*c8dee2aaSAndroid Build Coastguard Worker sign = -sign;
41*c8dee2aaSAndroid Build Coastguard Worker }
42*c8dee2aaSAndroid Build Coastguard Worker return sign;
43*c8dee2aaSAndroid Build Coastguard Worker }
44*c8dee2aaSAndroid Build Coastguard Worker
unit_axis_align(SkVector * unit)45*c8dee2aaSAndroid Build Coastguard Worker static void unit_axis_align(SkVector* unit) {
46*c8dee2aaSAndroid Build Coastguard Worker const SkScalar TOLERANCE = SkDoubleToScalar(0.15);
47*c8dee2aaSAndroid Build Coastguard Worker if (SkScalarAbs(unit->fX) < TOLERANCE) {
48*c8dee2aaSAndroid Build Coastguard Worker unit->fX = 0;
49*c8dee2aaSAndroid Build Coastguard Worker unit->fY = SkScalarSignNonZero(unit->fY);
50*c8dee2aaSAndroid Build Coastguard Worker } else if (SkScalarAbs(unit->fY) < TOLERANCE) {
51*c8dee2aaSAndroid Build Coastguard Worker unit->fX = SkScalarSignNonZero(unit->fX);
52*c8dee2aaSAndroid Build Coastguard Worker unit->fY = 0;
53*c8dee2aaSAndroid Build Coastguard Worker }
54*c8dee2aaSAndroid Build Coastguard Worker }
55*c8dee2aaSAndroid Build Coastguard Worker
reset(float sx,float sy)56*c8dee2aaSAndroid Build Coastguard Worker void TouchGesture::FlingState::reset(float sx, float sy) {
57*c8dee2aaSAndroid Build Coastguard Worker fActive = true;
58*c8dee2aaSAndroid Build Coastguard Worker fDirection.set(sx, sy);
59*c8dee2aaSAndroid Build Coastguard Worker fSpeed0 = SkPoint::Normalize(&fDirection);
60*c8dee2aaSAndroid Build Coastguard Worker fSpeed0 = pin_max_fling(fSpeed0);
61*c8dee2aaSAndroid Build Coastguard Worker fTime0 = getseconds();
62*c8dee2aaSAndroid Build Coastguard Worker
63*c8dee2aaSAndroid Build Coastguard Worker unit_axis_align(&fDirection);
64*c8dee2aaSAndroid Build Coastguard Worker // printf("---- speed %g dir %g %g\n", fSpeed0, fDirection.fX, fDirection.fY);
65*c8dee2aaSAndroid Build Coastguard Worker }
66*c8dee2aaSAndroid Build Coastguard Worker
evaluateMatrix(SkMatrix * matrix)67*c8dee2aaSAndroid Build Coastguard Worker bool TouchGesture::FlingState::evaluateMatrix(SkMatrix* matrix) {
68*c8dee2aaSAndroid Build Coastguard Worker if (!fActive) {
69*c8dee2aaSAndroid Build Coastguard Worker return false;
70*c8dee2aaSAndroid Build Coastguard Worker }
71*c8dee2aaSAndroid Build Coastguard Worker
72*c8dee2aaSAndroid Build Coastguard Worker const float t = (float)(getseconds() - fTime0);
73*c8dee2aaSAndroid Build Coastguard Worker const float MIN_SPEED = 2;
74*c8dee2aaSAndroid Build Coastguard Worker const float K0 = 5;
75*c8dee2aaSAndroid Build Coastguard Worker const float K1 = 0.02f;
76*c8dee2aaSAndroid Build Coastguard Worker const float speed = fSpeed0 * (std::exp(- K0 * t) - K1);
77*c8dee2aaSAndroid Build Coastguard Worker if (speed <= MIN_SPEED) {
78*c8dee2aaSAndroid Build Coastguard Worker fActive = false;
79*c8dee2aaSAndroid Build Coastguard Worker return false;
80*c8dee2aaSAndroid Build Coastguard Worker }
81*c8dee2aaSAndroid Build Coastguard Worker float dist = (fSpeed0 - speed) / K0;
82*c8dee2aaSAndroid Build Coastguard Worker
83*c8dee2aaSAndroid Build Coastguard Worker // printf("---- time %g speed %g dist %g\n", t, speed, dist);
84*c8dee2aaSAndroid Build Coastguard Worker float tx = fDirection.fX * dist;
85*c8dee2aaSAndroid Build Coastguard Worker float ty = fDirection.fY * dist;
86*c8dee2aaSAndroid Build Coastguard Worker if (DISCRETIZE_TRANSLATE_TO_AVOID_FLICKER) {
87*c8dee2aaSAndroid Build Coastguard Worker tx = (float)sk_float_round2int(tx);
88*c8dee2aaSAndroid Build Coastguard Worker ty = (float)sk_float_round2int(ty);
89*c8dee2aaSAndroid Build Coastguard Worker }
90*c8dee2aaSAndroid Build Coastguard Worker matrix->setTranslate(tx, ty);
91*c8dee2aaSAndroid Build Coastguard Worker // printf("---- evaluate (%g %g)\n", tx, ty);
92*c8dee2aaSAndroid Build Coastguard Worker
93*c8dee2aaSAndroid Build Coastguard Worker return true;
94*c8dee2aaSAndroid Build Coastguard Worker }
95*c8dee2aaSAndroid Build Coastguard Worker
96*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////
97*c8dee2aaSAndroid Build Coastguard Worker
98*c8dee2aaSAndroid Build Coastguard Worker static const TimeUtils::MSec MAX_DBL_TAP_INTERVAL = 300;
99*c8dee2aaSAndroid Build Coastguard Worker static const float MAX_DBL_TAP_DISTANCE = 100;
100*c8dee2aaSAndroid Build Coastguard Worker static const float MAX_JITTER_RADIUS = 2;
101*c8dee2aaSAndroid Build Coastguard Worker
102*c8dee2aaSAndroid Build Coastguard Worker // if true, then ignore the touch-move, 'cause its probably just jitter
close_enough_for_jitter(float x0,float y0,float x1,float y1)103*c8dee2aaSAndroid Build Coastguard Worker static bool close_enough_for_jitter(float x0, float y0, float x1, float y1) {
104*c8dee2aaSAndroid Build Coastguard Worker return std::fabs(x0 - x1) <= MAX_JITTER_RADIUS &&
105*c8dee2aaSAndroid Build Coastguard Worker std::fabs(y0 - y1) <= MAX_JITTER_RADIUS;
106*c8dee2aaSAndroid Build Coastguard Worker }
107*c8dee2aaSAndroid Build Coastguard Worker
108*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////
109*c8dee2aaSAndroid Build Coastguard Worker
TouchGesture()110*c8dee2aaSAndroid Build Coastguard Worker TouchGesture::TouchGesture() {
111*c8dee2aaSAndroid Build Coastguard Worker this->reset();
112*c8dee2aaSAndroid Build Coastguard Worker }
113*c8dee2aaSAndroid Build Coastguard Worker
~TouchGesture()114*c8dee2aaSAndroid Build Coastguard Worker TouchGesture::~TouchGesture() {
115*c8dee2aaSAndroid Build Coastguard Worker }
116*c8dee2aaSAndroid Build Coastguard Worker
resetTouchState()117*c8dee2aaSAndroid Build Coastguard Worker void TouchGesture::resetTouchState() {
118*c8dee2aaSAndroid Build Coastguard Worker fIsTransLimited = false;
119*c8dee2aaSAndroid Build Coastguard Worker fTouches.reset();
120*c8dee2aaSAndroid Build Coastguard Worker fState = kEmpty_State;
121*c8dee2aaSAndroid Build Coastguard Worker fLocalM.reset();
122*c8dee2aaSAndroid Build Coastguard Worker
123*c8dee2aaSAndroid Build Coastguard Worker fLastUpMillis = SkTime::GetMSecs() - 2*MAX_DBL_TAP_INTERVAL;
124*c8dee2aaSAndroid Build Coastguard Worker fLastUpP.set(0, 0);
125*c8dee2aaSAndroid Build Coastguard Worker }
126*c8dee2aaSAndroid Build Coastguard Worker
reset()127*c8dee2aaSAndroid Build Coastguard Worker void TouchGesture::reset() {
128*c8dee2aaSAndroid Build Coastguard Worker fGlobalM.reset();
129*c8dee2aaSAndroid Build Coastguard Worker this->resetTouchState();
130*c8dee2aaSAndroid Build Coastguard Worker }
131*c8dee2aaSAndroid Build Coastguard Worker
flushLocalM()132*c8dee2aaSAndroid Build Coastguard Worker void TouchGesture::flushLocalM() {
133*c8dee2aaSAndroid Build Coastguard Worker fGlobalM.postConcat(fLocalM);
134*c8dee2aaSAndroid Build Coastguard Worker fLocalM.reset();
135*c8dee2aaSAndroid Build Coastguard Worker }
136*c8dee2aaSAndroid Build Coastguard Worker
localM()137*c8dee2aaSAndroid Build Coastguard Worker const SkMatrix& TouchGesture::localM() {
138*c8dee2aaSAndroid Build Coastguard Worker if (fFlinger.isActive()) {
139*c8dee2aaSAndroid Build Coastguard Worker if (!fFlinger.evaluateMatrix(&fLocalM)) {
140*c8dee2aaSAndroid Build Coastguard Worker this->flushLocalM();
141*c8dee2aaSAndroid Build Coastguard Worker }
142*c8dee2aaSAndroid Build Coastguard Worker }
143*c8dee2aaSAndroid Build Coastguard Worker return fLocalM;
144*c8dee2aaSAndroid Build Coastguard Worker }
145*c8dee2aaSAndroid Build Coastguard Worker
appendNewRec(void * owner,float x,float y)146*c8dee2aaSAndroid Build Coastguard Worker void TouchGesture::appendNewRec(void* owner, float x, float y) {
147*c8dee2aaSAndroid Build Coastguard Worker Rec* rec = fTouches.append();
148*c8dee2aaSAndroid Build Coastguard Worker rec->fOwner = owner;
149*c8dee2aaSAndroid Build Coastguard Worker rec->fStartX = rec->fPrevX = rec->fLastX = x;
150*c8dee2aaSAndroid Build Coastguard Worker rec->fStartY = rec->fPrevY = rec->fLastY = y;
151*c8dee2aaSAndroid Build Coastguard Worker rec->fLastT = rec->fPrevT = static_cast<float>(SkTime::GetSecs());
152*c8dee2aaSAndroid Build Coastguard Worker }
153*c8dee2aaSAndroid Build Coastguard Worker
touchBegin(void * owner,float x,float y)154*c8dee2aaSAndroid Build Coastguard Worker void TouchGesture::touchBegin(void* owner, float x, float y) {
155*c8dee2aaSAndroid Build Coastguard Worker // SkDebugf("--- %d touchBegin %p %g %g\n", fTouches.count(), owner, x, y);
156*c8dee2aaSAndroid Build Coastguard Worker
157*c8dee2aaSAndroid Build Coastguard Worker int index = this->findRec(owner);
158*c8dee2aaSAndroid Build Coastguard Worker if (index >= 0) {
159*c8dee2aaSAndroid Build Coastguard Worker this->flushLocalM();
160*c8dee2aaSAndroid Build Coastguard Worker fTouches.removeShuffle(index);
161*c8dee2aaSAndroid Build Coastguard Worker SkDebugf("---- already exists, removing\n");
162*c8dee2aaSAndroid Build Coastguard Worker }
163*c8dee2aaSAndroid Build Coastguard Worker
164*c8dee2aaSAndroid Build Coastguard Worker if (fTouches.size() == 2) {
165*c8dee2aaSAndroid Build Coastguard Worker return;
166*c8dee2aaSAndroid Build Coastguard Worker }
167*c8dee2aaSAndroid Build Coastguard Worker
168*c8dee2aaSAndroid Build Coastguard Worker this->flushLocalM();
169*c8dee2aaSAndroid Build Coastguard Worker fFlinger.stop();
170*c8dee2aaSAndroid Build Coastguard Worker
171*c8dee2aaSAndroid Build Coastguard Worker this->appendNewRec(owner, x, y);
172*c8dee2aaSAndroid Build Coastguard Worker
173*c8dee2aaSAndroid Build Coastguard Worker switch (fTouches.size()) {
174*c8dee2aaSAndroid Build Coastguard Worker case 1:
175*c8dee2aaSAndroid Build Coastguard Worker fState = kTranslate_State;
176*c8dee2aaSAndroid Build Coastguard Worker break;
177*c8dee2aaSAndroid Build Coastguard Worker case 2:
178*c8dee2aaSAndroid Build Coastguard Worker this->startZoom();
179*c8dee2aaSAndroid Build Coastguard Worker break;
180*c8dee2aaSAndroid Build Coastguard Worker default:
181*c8dee2aaSAndroid Build Coastguard Worker break;
182*c8dee2aaSAndroid Build Coastguard Worker }
183*c8dee2aaSAndroid Build Coastguard Worker }
184*c8dee2aaSAndroid Build Coastguard Worker
findRec(void * owner) const185*c8dee2aaSAndroid Build Coastguard Worker int TouchGesture::findRec(void* owner) const {
186*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < fTouches.size(); i++) {
187*c8dee2aaSAndroid Build Coastguard Worker if (owner == fTouches[i].fOwner) {
188*c8dee2aaSAndroid Build Coastguard Worker return i;
189*c8dee2aaSAndroid Build Coastguard Worker }
190*c8dee2aaSAndroid Build Coastguard Worker }
191*c8dee2aaSAndroid Build Coastguard Worker return -1;
192*c8dee2aaSAndroid Build Coastguard Worker }
193*c8dee2aaSAndroid Build Coastguard Worker
center(float pos0,float pos1)194*c8dee2aaSAndroid Build Coastguard Worker static SkScalar center(float pos0, float pos1) {
195*c8dee2aaSAndroid Build Coastguard Worker return (pos0 + pos1) * 0.5f;
196*c8dee2aaSAndroid Build Coastguard Worker }
197*c8dee2aaSAndroid Build Coastguard Worker
startZoom()198*c8dee2aaSAndroid Build Coastguard Worker void TouchGesture::startZoom() {
199*c8dee2aaSAndroid Build Coastguard Worker fState = kZoom_State;
200*c8dee2aaSAndroid Build Coastguard Worker }
201*c8dee2aaSAndroid Build Coastguard Worker
updateZoom(float scale,float startX,float startY,float lastX,float lastY)202*c8dee2aaSAndroid Build Coastguard Worker void TouchGesture::updateZoom(float scale, float startX, float startY, float lastX, float lastY) {
203*c8dee2aaSAndroid Build Coastguard Worker fLocalM.setTranslate(-startX, -startY);
204*c8dee2aaSAndroid Build Coastguard Worker fLocalM.postScale(scale, scale);
205*c8dee2aaSAndroid Build Coastguard Worker fLocalM.postTranslate(lastX, lastY);
206*c8dee2aaSAndroid Build Coastguard Worker }
207*c8dee2aaSAndroid Build Coastguard Worker
endZoom()208*c8dee2aaSAndroid Build Coastguard Worker void TouchGesture::endZoom() {
209*c8dee2aaSAndroid Build Coastguard Worker this->flushLocalM();
210*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(kZoom_State == fState);
211*c8dee2aaSAndroid Build Coastguard Worker fState = kEmpty_State;
212*c8dee2aaSAndroid Build Coastguard Worker }
213*c8dee2aaSAndroid Build Coastguard Worker
touchMoved(void * owner,float x,float y)214*c8dee2aaSAndroid Build Coastguard Worker void TouchGesture::touchMoved(void* owner, float x, float y) {
215*c8dee2aaSAndroid Build Coastguard Worker // SkDebugf("--- %d touchMoved %p %g %g\n", fTouches.count(), owner, x, y);
216*c8dee2aaSAndroid Build Coastguard Worker
217*c8dee2aaSAndroid Build Coastguard Worker if (kEmpty_State == fState) {
218*c8dee2aaSAndroid Build Coastguard Worker return;
219*c8dee2aaSAndroid Build Coastguard Worker }
220*c8dee2aaSAndroid Build Coastguard Worker
221*c8dee2aaSAndroid Build Coastguard Worker int index = this->findRec(owner);
222*c8dee2aaSAndroid Build Coastguard Worker if (index < 0) {
223*c8dee2aaSAndroid Build Coastguard Worker SkDebugf("---- ignoring move without begin\n");
224*c8dee2aaSAndroid Build Coastguard Worker return;
225*c8dee2aaSAndroid Build Coastguard Worker }
226*c8dee2aaSAndroid Build Coastguard Worker
227*c8dee2aaSAndroid Build Coastguard Worker Rec& rec = fTouches[index];
228*c8dee2aaSAndroid Build Coastguard Worker
229*c8dee2aaSAndroid Build Coastguard Worker // not sure how valuable this is
230*c8dee2aaSAndroid Build Coastguard Worker if (fTouches.size() == 2) {
231*c8dee2aaSAndroid Build Coastguard Worker if (close_enough_for_jitter(rec.fLastX, rec.fLastY, x, y)) {
232*c8dee2aaSAndroid Build Coastguard Worker // SkDebugf("--- drop touchMove, within jitter tolerance %g %g\n", rec.fLastX - x, rec.fLastY - y);
233*c8dee2aaSAndroid Build Coastguard Worker return;
234*c8dee2aaSAndroid Build Coastguard Worker }
235*c8dee2aaSAndroid Build Coastguard Worker }
236*c8dee2aaSAndroid Build Coastguard Worker
237*c8dee2aaSAndroid Build Coastguard Worker rec.fPrevX = rec.fLastX; rec.fLastX = x;
238*c8dee2aaSAndroid Build Coastguard Worker rec.fPrevY = rec.fLastY; rec.fLastY = y;
239*c8dee2aaSAndroid Build Coastguard Worker rec.fPrevT = rec.fLastT;
240*c8dee2aaSAndroid Build Coastguard Worker rec.fLastT = static_cast<float>(SkTime::GetSecs());
241*c8dee2aaSAndroid Build Coastguard Worker
242*c8dee2aaSAndroid Build Coastguard Worker switch (fTouches.size()) {
243*c8dee2aaSAndroid Build Coastguard Worker case 1: {
244*c8dee2aaSAndroid Build Coastguard Worker float dx = rec.fLastX - rec.fStartX;
245*c8dee2aaSAndroid Build Coastguard Worker float dy = rec.fLastY - rec.fStartY;
246*c8dee2aaSAndroid Build Coastguard Worker dx = (float)sk_float_round2int(dx);
247*c8dee2aaSAndroid Build Coastguard Worker dy = (float)sk_float_round2int(dy);
248*c8dee2aaSAndroid Build Coastguard Worker fLocalM.setTranslate(dx, dy);
249*c8dee2aaSAndroid Build Coastguard Worker } break;
250*c8dee2aaSAndroid Build Coastguard Worker case 2: {
251*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(kZoom_State == fState);
252*c8dee2aaSAndroid Build Coastguard Worker const Rec& rec0 = fTouches[0];
253*c8dee2aaSAndroid Build Coastguard Worker const Rec& rec1 = fTouches[1];
254*c8dee2aaSAndroid Build Coastguard Worker
255*c8dee2aaSAndroid Build Coastguard Worker float scale = this->computePinch(rec0, rec1);
256*c8dee2aaSAndroid Build Coastguard Worker this->updateZoom(scale,
257*c8dee2aaSAndroid Build Coastguard Worker center(rec0.fStartX, rec1.fStartX),
258*c8dee2aaSAndroid Build Coastguard Worker center(rec0.fStartY, rec1.fStartY),
259*c8dee2aaSAndroid Build Coastguard Worker center(rec0.fLastX, rec1.fLastX),
260*c8dee2aaSAndroid Build Coastguard Worker center(rec0.fLastY, rec1.fLastY));
261*c8dee2aaSAndroid Build Coastguard Worker } break;
262*c8dee2aaSAndroid Build Coastguard Worker default:
263*c8dee2aaSAndroid Build Coastguard Worker break;
264*c8dee2aaSAndroid Build Coastguard Worker }
265*c8dee2aaSAndroid Build Coastguard Worker }
266*c8dee2aaSAndroid Build Coastguard Worker
touchEnd(void * owner)267*c8dee2aaSAndroid Build Coastguard Worker void TouchGesture::touchEnd(void* owner) {
268*c8dee2aaSAndroid Build Coastguard Worker // SkDebugf("--- %d touchEnd %p\n", fTouches.count(), owner);
269*c8dee2aaSAndroid Build Coastguard Worker
270*c8dee2aaSAndroid Build Coastguard Worker int index = this->findRec(owner);
271*c8dee2aaSAndroid Build Coastguard Worker if (index < 0) {
272*c8dee2aaSAndroid Build Coastguard Worker SkDebugf("--- not found\n");
273*c8dee2aaSAndroid Build Coastguard Worker return;
274*c8dee2aaSAndroid Build Coastguard Worker }
275*c8dee2aaSAndroid Build Coastguard Worker
276*c8dee2aaSAndroid Build Coastguard Worker const Rec& rec = fTouches[index];
277*c8dee2aaSAndroid Build Coastguard Worker if (this->handleDblTap(rec.fLastX, rec.fLastY)) {
278*c8dee2aaSAndroid Build Coastguard Worker return;
279*c8dee2aaSAndroid Build Coastguard Worker }
280*c8dee2aaSAndroid Build Coastguard Worker
281*c8dee2aaSAndroid Build Coastguard Worker // count() reflects the number before we removed the owner
282*c8dee2aaSAndroid Build Coastguard Worker switch (fTouches.size()) {
283*c8dee2aaSAndroid Build Coastguard Worker case 1: {
284*c8dee2aaSAndroid Build Coastguard Worker this->flushLocalM();
285*c8dee2aaSAndroid Build Coastguard Worker float dx = rec.fLastX - rec.fPrevX;
286*c8dee2aaSAndroid Build Coastguard Worker float dy = rec.fLastY - rec.fPrevY;
287*c8dee2aaSAndroid Build Coastguard Worker float dur = rec.fLastT - rec.fPrevT;
288*c8dee2aaSAndroid Build Coastguard Worker if (dur > 0) {
289*c8dee2aaSAndroid Build Coastguard Worker fFlinger.reset(dx / dur, dy / dur);
290*c8dee2aaSAndroid Build Coastguard Worker }
291*c8dee2aaSAndroid Build Coastguard Worker fState = kEmpty_State;
292*c8dee2aaSAndroid Build Coastguard Worker } break;
293*c8dee2aaSAndroid Build Coastguard Worker case 2:
294*c8dee2aaSAndroid Build Coastguard Worker this->endZoom();
295*c8dee2aaSAndroid Build Coastguard Worker break;
296*c8dee2aaSAndroid Build Coastguard Worker default:
297*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(kZoom_State == fState);
298*c8dee2aaSAndroid Build Coastguard Worker break;
299*c8dee2aaSAndroid Build Coastguard Worker }
300*c8dee2aaSAndroid Build Coastguard Worker
301*c8dee2aaSAndroid Build Coastguard Worker fTouches.removeShuffle(index);
302*c8dee2aaSAndroid Build Coastguard Worker
303*c8dee2aaSAndroid Build Coastguard Worker limitTrans();
304*c8dee2aaSAndroid Build Coastguard Worker }
305*c8dee2aaSAndroid Build Coastguard Worker
isFling(SkPoint * dir)306*c8dee2aaSAndroid Build Coastguard Worker bool TouchGesture::isFling(SkPoint* dir) {
307*c8dee2aaSAndroid Build Coastguard Worker if (fFlinger.isActive()) {
308*c8dee2aaSAndroid Build Coastguard Worker SkScalar speed;
309*c8dee2aaSAndroid Build Coastguard Worker fFlinger.get(dir, &speed);
310*c8dee2aaSAndroid Build Coastguard Worker if (speed > 1000) {
311*c8dee2aaSAndroid Build Coastguard Worker return true;
312*c8dee2aaSAndroid Build Coastguard Worker }
313*c8dee2aaSAndroid Build Coastguard Worker }
314*c8dee2aaSAndroid Build Coastguard Worker return false;
315*c8dee2aaSAndroid Build Coastguard Worker }
316*c8dee2aaSAndroid Build Coastguard Worker
computePinch(const Rec & rec0,const Rec & rec1)317*c8dee2aaSAndroid Build Coastguard Worker float TouchGesture::computePinch(const Rec& rec0, const Rec& rec1) {
318*c8dee2aaSAndroid Build Coastguard Worker double dx = rec0.fStartX - rec1.fStartX;
319*c8dee2aaSAndroid Build Coastguard Worker double dy = rec0.fStartY - rec1.fStartY;
320*c8dee2aaSAndroid Build Coastguard Worker double dist0 = sqrt(dx*dx + dy*dy);
321*c8dee2aaSAndroid Build Coastguard Worker
322*c8dee2aaSAndroid Build Coastguard Worker dx = rec0.fLastX - rec1.fLastX;
323*c8dee2aaSAndroid Build Coastguard Worker dy = rec0.fLastY - rec1.fLastY;
324*c8dee2aaSAndroid Build Coastguard Worker double dist1 = sqrt(dx*dx + dy*dy);
325*c8dee2aaSAndroid Build Coastguard Worker
326*c8dee2aaSAndroid Build Coastguard Worker double scale = dist1 / dist0;
327*c8dee2aaSAndroid Build Coastguard Worker return (float)scale;
328*c8dee2aaSAndroid Build Coastguard Worker }
329*c8dee2aaSAndroid Build Coastguard Worker
handleDblTap(float x,float y)330*c8dee2aaSAndroid Build Coastguard Worker bool TouchGesture::handleDblTap(float x, float y) {
331*c8dee2aaSAndroid Build Coastguard Worker bool found = false;
332*c8dee2aaSAndroid Build Coastguard Worker double now = SkTime::GetMSecs();
333*c8dee2aaSAndroid Build Coastguard Worker if (now - fLastUpMillis <= MAX_DBL_TAP_INTERVAL) {
334*c8dee2aaSAndroid Build Coastguard Worker if (SkPoint::Length(fLastUpP.fX - x,
335*c8dee2aaSAndroid Build Coastguard Worker fLastUpP.fY - y) <= MAX_DBL_TAP_DISTANCE) {
336*c8dee2aaSAndroid Build Coastguard Worker fFlinger.stop();
337*c8dee2aaSAndroid Build Coastguard Worker fLocalM.reset();
338*c8dee2aaSAndroid Build Coastguard Worker fGlobalM.reset();
339*c8dee2aaSAndroid Build Coastguard Worker fTouches.reset();
340*c8dee2aaSAndroid Build Coastguard Worker fState = kEmpty_State;
341*c8dee2aaSAndroid Build Coastguard Worker found = true;
342*c8dee2aaSAndroid Build Coastguard Worker }
343*c8dee2aaSAndroid Build Coastguard Worker }
344*c8dee2aaSAndroid Build Coastguard Worker
345*c8dee2aaSAndroid Build Coastguard Worker fLastUpMillis = now;
346*c8dee2aaSAndroid Build Coastguard Worker fLastUpP.set(x, y);
347*c8dee2aaSAndroid Build Coastguard Worker return found;
348*c8dee2aaSAndroid Build Coastguard Worker }
349*c8dee2aaSAndroid Build Coastguard Worker
setTransLimit(const SkRect & contentRect,const SkRect & windowRect,const SkMatrix & preTouchMatrix)350*c8dee2aaSAndroid Build Coastguard Worker void TouchGesture::setTransLimit(const SkRect& contentRect, const SkRect& windowRect,
351*c8dee2aaSAndroid Build Coastguard Worker const SkMatrix& preTouchMatrix) {
352*c8dee2aaSAndroid Build Coastguard Worker fIsTransLimited = true;
353*c8dee2aaSAndroid Build Coastguard Worker fContentRect = contentRect;
354*c8dee2aaSAndroid Build Coastguard Worker fWindowRect = windowRect;
355*c8dee2aaSAndroid Build Coastguard Worker fPreTouchM = preTouchMatrix;
356*c8dee2aaSAndroid Build Coastguard Worker }
357*c8dee2aaSAndroid Build Coastguard Worker
limitTrans()358*c8dee2aaSAndroid Build Coastguard Worker void TouchGesture::limitTrans() {
359*c8dee2aaSAndroid Build Coastguard Worker if (!fIsTransLimited) {
360*c8dee2aaSAndroid Build Coastguard Worker return;
361*c8dee2aaSAndroid Build Coastguard Worker }
362*c8dee2aaSAndroid Build Coastguard Worker
363*c8dee2aaSAndroid Build Coastguard Worker SkRect scaledContent = fContentRect;
364*c8dee2aaSAndroid Build Coastguard Worker fPreTouchM.mapRect(&scaledContent);
365*c8dee2aaSAndroid Build Coastguard Worker fGlobalM.mapRect(&scaledContent);
366*c8dee2aaSAndroid Build Coastguard Worker const SkScalar ZERO = 0;
367*c8dee2aaSAndroid Build Coastguard Worker
368*c8dee2aaSAndroid Build Coastguard Worker fGlobalM.postTranslate(ZERO, std::min(ZERO, fWindowRect.fBottom - scaledContent.fTop));
369*c8dee2aaSAndroid Build Coastguard Worker fGlobalM.postTranslate(ZERO, std::max(ZERO, fWindowRect.fTop - scaledContent.fBottom));
370*c8dee2aaSAndroid Build Coastguard Worker fGlobalM.postTranslate(std::min(ZERO, fWindowRect.fRight - scaledContent.fLeft), ZERO);
371*c8dee2aaSAndroid Build Coastguard Worker fGlobalM.postTranslate(std::max(ZERO, fWindowRect.fLeft - scaledContent.fRight), ZERO);
372*c8dee2aaSAndroid Build Coastguard Worker }
373