1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/widget/windows/nsWinGesture.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,595 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +/* 1.10 + * nsWinGesture - Touch input handling for tablet displays. 1.11 + */ 1.12 + 1.13 +#include "nscore.h" 1.14 +#include "nsWinGesture.h" 1.15 +#include "nsUXThemeData.h" 1.16 +#include "nsIDOMSimpleGestureEvent.h" 1.17 +#include "nsIDOMWheelEvent.h" 1.18 +#include "mozilla/Constants.h" 1.19 +#include "mozilla/MouseEvents.h" 1.20 +#include "mozilla/Preferences.h" 1.21 +#include "mozilla/TouchEvents.h" 1.22 + 1.23 +using namespace mozilla; 1.24 +using namespace mozilla::widget; 1.25 + 1.26 +#ifdef PR_LOGGING 1.27 +extern PRLogModuleInfo* gWindowsLog; 1.28 +#endif 1.29 + 1.30 +const wchar_t nsWinGesture::kGestureLibraryName[] = L"user32.dll"; 1.31 +HMODULE nsWinGesture::sLibraryHandle = nullptr; 1.32 +nsWinGesture::GetGestureInfoPtr nsWinGesture::getGestureInfo = nullptr; 1.33 +nsWinGesture::CloseGestureInfoHandlePtr nsWinGesture::closeGestureInfoHandle = nullptr; 1.34 +nsWinGesture::GetGestureExtraArgsPtr nsWinGesture::getGestureExtraArgs = nullptr; 1.35 +nsWinGesture::SetGestureConfigPtr nsWinGesture::setGestureConfig = nullptr; 1.36 +nsWinGesture::GetGestureConfigPtr nsWinGesture::getGestureConfig = nullptr; 1.37 +nsWinGesture::BeginPanningFeedbackPtr nsWinGesture::beginPanningFeedback = nullptr; 1.38 +nsWinGesture::EndPanningFeedbackPtr nsWinGesture::endPanningFeedback = nullptr; 1.39 +nsWinGesture::UpdatePanningFeedbackPtr nsWinGesture::updatePanningFeedback = nullptr; 1.40 + 1.41 +nsWinGesture::RegisterTouchWindowPtr nsWinGesture::registerTouchWindow = nullptr; 1.42 +nsWinGesture::UnregisterTouchWindowPtr nsWinGesture::unregisterTouchWindow = nullptr; 1.43 +nsWinGesture::GetTouchInputInfoPtr nsWinGesture::getTouchInputInfo = nullptr; 1.44 +nsWinGesture::CloseTouchInputHandlePtr nsWinGesture::closeTouchInputHandle = nullptr; 1.45 + 1.46 +static bool gEnableSingleFingerPanEvents = false; 1.47 + 1.48 +nsWinGesture::nsWinGesture() : 1.49 + mPanActive(false), 1.50 + mFeedbackActive(false), 1.51 + mXAxisFeedback(false), 1.52 + mYAxisFeedback(false), 1.53 + mPanInertiaActive(false) 1.54 +{ 1.55 + (void)InitLibrary(); 1.56 + mPixelScrollOverflow = 0; 1.57 +} 1.58 + 1.59 +/* Load and shutdown */ 1.60 + 1.61 +bool nsWinGesture::InitLibrary() 1.62 +{ 1.63 + if (getGestureInfo) { 1.64 + return true; 1.65 + } else if (sLibraryHandle) { 1.66 + return false; 1.67 + } 1.68 + 1.69 + sLibraryHandle = ::LoadLibraryW(kGestureLibraryName); 1.70 + HMODULE hTheme = nsUXThemeData::GetThemeDLL(); 1.71 + 1.72 + // gesture interfaces 1.73 + if (sLibraryHandle) { 1.74 + getGestureInfo = (GetGestureInfoPtr)GetProcAddress(sLibraryHandle, "GetGestureInfo"); 1.75 + closeGestureInfoHandle = (CloseGestureInfoHandlePtr)GetProcAddress(sLibraryHandle, "CloseGestureInfoHandle"); 1.76 + getGestureExtraArgs = (GetGestureExtraArgsPtr)GetProcAddress(sLibraryHandle, "GetGestureExtraArgs"); 1.77 + setGestureConfig = (SetGestureConfigPtr)GetProcAddress(sLibraryHandle, "SetGestureConfig"); 1.78 + getGestureConfig = (GetGestureConfigPtr)GetProcAddress(sLibraryHandle, "GetGestureConfig"); 1.79 + registerTouchWindow = (RegisterTouchWindowPtr)GetProcAddress(sLibraryHandle, "RegisterTouchWindow"); 1.80 + unregisterTouchWindow = (UnregisterTouchWindowPtr)GetProcAddress(sLibraryHandle, "UnregisterTouchWindow"); 1.81 + getTouchInputInfo = (GetTouchInputInfoPtr)GetProcAddress(sLibraryHandle, "GetTouchInputInfo"); 1.82 + closeTouchInputHandle = (CloseTouchInputHandlePtr)GetProcAddress(sLibraryHandle, "CloseTouchInputHandle"); 1.83 + } 1.84 + 1.85 + if (!getGestureInfo || !closeGestureInfoHandle || !getGestureExtraArgs || 1.86 + !setGestureConfig || !getGestureConfig) { 1.87 + getGestureInfo = nullptr; 1.88 + closeGestureInfoHandle = nullptr; 1.89 + getGestureExtraArgs = nullptr; 1.90 + setGestureConfig = nullptr; 1.91 + getGestureConfig = nullptr; 1.92 + return false; 1.93 + } 1.94 + 1.95 + if (!registerTouchWindow || !unregisterTouchWindow || !getTouchInputInfo || !closeTouchInputHandle) { 1.96 + registerTouchWindow = nullptr; 1.97 + unregisterTouchWindow = nullptr; 1.98 + getTouchInputInfo = nullptr; 1.99 + closeTouchInputHandle = nullptr; 1.100 + } 1.101 + 1.102 + // panning feedback interfaces 1.103 + if (hTheme) { 1.104 + beginPanningFeedback = (BeginPanningFeedbackPtr)GetProcAddress(hTheme, "BeginPanningFeedback"); 1.105 + endPanningFeedback = (EndPanningFeedbackPtr)GetProcAddress(hTheme, "EndPanningFeedback"); 1.106 + updatePanningFeedback = (UpdatePanningFeedbackPtr)GetProcAddress(hTheme, "UpdatePanningFeedback"); 1.107 + } 1.108 + 1.109 + if (!beginPanningFeedback || !endPanningFeedback || !updatePanningFeedback) { 1.110 + beginPanningFeedback = nullptr; 1.111 + endPanningFeedback = nullptr; 1.112 + updatePanningFeedback = nullptr; 1.113 + } 1.114 + 1.115 + // Check to see if we want single finger gesture input. Only do this once 1.116 + // for the app so we don't have to look it up on every window create. 1.117 + gEnableSingleFingerPanEvents = 1.118 + Preferences::GetBool("gestures.enable_single_finger_input", false); 1.119 + 1.120 + return true; 1.121 +} 1.122 + 1.123 +#define GCOUNT 5 1.124 + 1.125 +bool nsWinGesture::SetWinGestureSupport(HWND hWnd, 1.126 + WidgetGestureNotifyEvent::ePanDirection aDirection) 1.127 +{ 1.128 + if (!getGestureInfo) 1.129 + return false; 1.130 + 1.131 + GESTURECONFIG config[GCOUNT]; 1.132 + 1.133 + memset(&config, 0, sizeof(config)); 1.134 + 1.135 + config[0].dwID = GID_ZOOM; 1.136 + config[0].dwWant = GC_ZOOM; 1.137 + config[0].dwBlock = 0; 1.138 + 1.139 + config[1].dwID = GID_ROTATE; 1.140 + config[1].dwWant = GC_ROTATE; 1.141 + config[1].dwBlock = 0; 1.142 + 1.143 + config[2].dwID = GID_PAN; 1.144 + config[2].dwWant = GC_PAN|GC_PAN_WITH_INERTIA| 1.145 + GC_PAN_WITH_GUTTER; 1.146 + config[2].dwBlock = GC_PAN_WITH_SINGLE_FINGER_VERTICALLY| 1.147 + GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY; 1.148 + 1.149 + if (gEnableSingleFingerPanEvents) { 1.150 + 1.151 + if (aDirection == WidgetGestureNotifyEvent::ePanVertical || 1.152 + aDirection == WidgetGestureNotifyEvent::ePanBoth) 1.153 + { 1.154 + config[2].dwWant |= GC_PAN_WITH_SINGLE_FINGER_VERTICALLY; 1.155 + config[2].dwBlock -= GC_PAN_WITH_SINGLE_FINGER_VERTICALLY; 1.156 + } 1.157 + 1.158 + if (aDirection == WidgetGestureNotifyEvent::ePanHorizontal || 1.159 + aDirection == WidgetGestureNotifyEvent::ePanBoth) 1.160 + { 1.161 + config[2].dwWant |= GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY; 1.162 + config[2].dwBlock -= GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY; 1.163 + } 1.164 + 1.165 + } 1.166 + 1.167 + config[3].dwWant = GC_TWOFINGERTAP; 1.168 + config[3].dwID = GID_TWOFINGERTAP; 1.169 + config[3].dwBlock = 0; 1.170 + 1.171 + config[4].dwWant = GC_PRESSANDTAP; 1.172 + config[4].dwID = GID_PRESSANDTAP; 1.173 + config[4].dwBlock = 0; 1.174 + 1.175 + return SetGestureConfig(hWnd, GCOUNT, (PGESTURECONFIG)&config); 1.176 +} 1.177 + 1.178 +/* Helpers */ 1.179 + 1.180 +bool nsWinGesture::IsAvailable() 1.181 +{ 1.182 + return getGestureInfo != nullptr; 1.183 +} 1.184 + 1.185 +bool nsWinGesture::RegisterTouchWindow(HWND hWnd) 1.186 +{ 1.187 + if (!registerTouchWindow) 1.188 + return false; 1.189 + 1.190 + return registerTouchWindow(hWnd, TWF_WANTPALM); 1.191 +} 1.192 + 1.193 +bool nsWinGesture::UnregisterTouchWindow(HWND hWnd) 1.194 +{ 1.195 + if (!unregisterTouchWindow) 1.196 + return false; 1.197 + 1.198 + return unregisterTouchWindow(hWnd); 1.199 +} 1.200 + 1.201 +bool nsWinGesture::GetTouchInputInfo(HTOUCHINPUT hTouchInput, uint32_t cInputs, PTOUCHINPUT pInputs) 1.202 +{ 1.203 + if (!getTouchInputInfo) 1.204 + return false; 1.205 + 1.206 + return getTouchInputInfo(hTouchInput, cInputs, pInputs, sizeof(TOUCHINPUT)); 1.207 +} 1.208 + 1.209 +bool nsWinGesture::CloseTouchInputHandle(HTOUCHINPUT hTouchInput) 1.210 +{ 1.211 + if (!closeTouchInputHandle) 1.212 + return false; 1.213 + 1.214 + return closeTouchInputHandle(hTouchInput); 1.215 +} 1.216 + 1.217 +bool nsWinGesture::GetGestureInfo(HGESTUREINFO hGestureInfo, PGESTUREINFO pGestureInfo) 1.218 +{ 1.219 + if (!getGestureInfo || !hGestureInfo || !pGestureInfo) 1.220 + return false; 1.221 + 1.222 + ZeroMemory(pGestureInfo, sizeof(GESTUREINFO)); 1.223 + pGestureInfo->cbSize = sizeof(GESTUREINFO); 1.224 + 1.225 + return getGestureInfo(hGestureInfo, pGestureInfo); 1.226 +} 1.227 + 1.228 +bool nsWinGesture::CloseGestureInfoHandle(HGESTUREINFO hGestureInfo) 1.229 +{ 1.230 + if (!getGestureInfo || !hGestureInfo) 1.231 + return false; 1.232 + 1.233 + return closeGestureInfoHandle(hGestureInfo); 1.234 +} 1.235 + 1.236 +bool nsWinGesture::GetGestureExtraArgs(HGESTUREINFO hGestureInfo, UINT cbExtraArgs, PBYTE pExtraArgs) 1.237 +{ 1.238 + if (!getGestureInfo || !hGestureInfo || !pExtraArgs) 1.239 + return false; 1.240 + 1.241 + return getGestureExtraArgs(hGestureInfo, cbExtraArgs, pExtraArgs); 1.242 +} 1.243 + 1.244 +bool nsWinGesture::SetGestureConfig(HWND hWnd, UINT cIDs, PGESTURECONFIG pGestureConfig) 1.245 +{ 1.246 + if (!getGestureInfo || !pGestureConfig) 1.247 + return false; 1.248 + 1.249 + return setGestureConfig(hWnd, 0, cIDs, pGestureConfig, sizeof(GESTURECONFIG)); 1.250 +} 1.251 + 1.252 +bool nsWinGesture::GetGestureConfig(HWND hWnd, DWORD dwFlags, PUINT pcIDs, PGESTURECONFIG pGestureConfig) 1.253 +{ 1.254 + if (!getGestureInfo || !pGestureConfig) 1.255 + return false; 1.256 + 1.257 + return getGestureConfig(hWnd, 0, dwFlags, pcIDs, pGestureConfig, sizeof(GESTURECONFIG)); 1.258 +} 1.259 + 1.260 +bool nsWinGesture::BeginPanningFeedback(HWND hWnd) 1.261 +{ 1.262 + if (!beginPanningFeedback) 1.263 + return false; 1.264 + 1.265 + return beginPanningFeedback(hWnd); 1.266 +} 1.267 + 1.268 +bool nsWinGesture::EndPanningFeedback(HWND hWnd) 1.269 +{ 1.270 + if (!beginPanningFeedback) 1.271 + return false; 1.272 + 1.273 + return endPanningFeedback(hWnd, TRUE); 1.274 +} 1.275 + 1.276 +bool nsWinGesture::UpdatePanningFeedback(HWND hWnd, LONG offsetX, LONG offsetY, BOOL fInInertia) 1.277 +{ 1.278 + if (!beginPanningFeedback) 1.279 + return false; 1.280 + 1.281 + return updatePanningFeedback(hWnd, offsetX, offsetY, fInInertia); 1.282 +} 1.283 + 1.284 +bool nsWinGesture::IsPanEvent(LPARAM lParam) 1.285 +{ 1.286 + GESTUREINFO gi; 1.287 + 1.288 + ZeroMemory(&gi,sizeof(GESTUREINFO)); 1.289 + gi.cbSize = sizeof(GESTUREINFO); 1.290 + 1.291 + BOOL result = GetGestureInfo((HGESTUREINFO)lParam, &gi); 1.292 + if (!result) 1.293 + return false; 1.294 + 1.295 + if (gi.dwID == GID_PAN) 1.296 + return true; 1.297 + 1.298 + return false; 1.299 +} 1.300 + 1.301 +/* Gesture event processing */ 1.302 + 1.303 +bool 1.304 +nsWinGesture::ProcessGestureMessage(HWND hWnd, WPARAM wParam, LPARAM lParam, 1.305 + WidgetSimpleGestureEvent& evt) 1.306 +{ 1.307 + GESTUREINFO gi; 1.308 + 1.309 + ZeroMemory(&gi,sizeof(GESTUREINFO)); 1.310 + gi.cbSize = sizeof(GESTUREINFO); 1.311 + 1.312 + BOOL result = GetGestureInfo((HGESTUREINFO)lParam, &gi); 1.313 + if (!result) 1.314 + return false; 1.315 + 1.316 + // The coordinates of this event 1.317 + nsPointWin coord; 1.318 + coord = gi.ptsLocation; 1.319 + coord.ScreenToClient(hWnd); 1.320 + 1.321 + evt.refPoint.x = coord.x; 1.322 + evt.refPoint.y = coord.y; 1.323 + 1.324 + // Multiple gesture can occur at the same time so gesture state 1.325 + // info can't be shared. 1.326 + switch(gi.dwID) 1.327 + { 1.328 + case GID_BEGIN: 1.329 + case GID_END: 1.330 + // These should always fall through to DefWndProc 1.331 + return false; 1.332 + break; 1.333 + 1.334 + case GID_ZOOM: 1.335 + { 1.336 + if (gi.dwFlags & GF_BEGIN) { 1.337 + // Send a zoom start event 1.338 + 1.339 + // The low 32 bits are the distance in pixels. 1.340 + mZoomIntermediate = (float)gi.ullArguments; 1.341 + 1.342 + evt.message = NS_SIMPLE_GESTURE_MAGNIFY_START; 1.343 + evt.delta = 0.0; 1.344 + } 1.345 + else if (gi.dwFlags & GF_END) { 1.346 + // Send a zoom end event, the delta is the change 1.347 + // in touch points. 1.348 + evt.message = NS_SIMPLE_GESTURE_MAGNIFY; 1.349 + // (positive for a "zoom in") 1.350 + evt.delta = -1.0 * (mZoomIntermediate - (float)gi.ullArguments); 1.351 + mZoomIntermediate = (float)gi.ullArguments; 1.352 + } 1.353 + else { 1.354 + // Send a zoom intermediate event, the delta is the change 1.355 + // in touch points. 1.356 + evt.message = NS_SIMPLE_GESTURE_MAGNIFY_UPDATE; 1.357 + // (positive for a "zoom in") 1.358 + evt.delta = -1.0 * (mZoomIntermediate - (float)gi.ullArguments); 1.359 + mZoomIntermediate = (float)gi.ullArguments; 1.360 + } 1.361 + } 1.362 + break; 1.363 + 1.364 + case GID_ROTATE: 1.365 + { 1.366 + // Send a rotate start event 1.367 + double radians = 0.0; 1.368 + 1.369 + // On GF_BEGIN, ullArguments contains the absolute rotation at the 1.370 + // start of the gesture. In later events it contains the offset from 1.371 + // the start angle. 1.372 + if (gi.ullArguments != 0) 1.373 + radians = GID_ROTATE_ANGLE_FROM_ARGUMENT(gi.ullArguments); 1.374 + 1.375 + double degrees = -1 * radians * (180/M_PI); 1.376 + 1.377 + if (gi.dwFlags & GF_BEGIN) { 1.378 + // At some point we should pass the initial angle in 1.379 + // along with delta. It's useful. 1.380 + degrees = mRotateIntermediate = 0.0; 1.381 + } 1.382 + 1.383 + evt.direction = 0; 1.384 + evt.delta = degrees - mRotateIntermediate; 1.385 + mRotateIntermediate = degrees; 1.386 + 1.387 + if (evt.delta > 0) 1.388 + evt.direction = nsIDOMSimpleGestureEvent::ROTATION_COUNTERCLOCKWISE; 1.389 + else if (evt.delta < 0) 1.390 + evt.direction = nsIDOMSimpleGestureEvent::ROTATION_CLOCKWISE; 1.391 + 1.392 + if (gi.dwFlags & GF_BEGIN) 1.393 + evt.message = NS_SIMPLE_GESTURE_ROTATE_START; 1.394 + else if (gi.dwFlags & GF_END) 1.395 + evt.message = NS_SIMPLE_GESTURE_ROTATE; 1.396 + else 1.397 + evt.message = NS_SIMPLE_GESTURE_ROTATE_UPDATE; 1.398 + } 1.399 + break; 1.400 + 1.401 + case GID_TWOFINGERTAP: 1.402 + { 1.403 + // Normally maps to "restore" from whatever you may have recently changed. A simple 1.404 + // double click. 1.405 + evt.message = NS_SIMPLE_GESTURE_TAP; 1.406 + evt.clickCount = 1; 1.407 + } 1.408 + break; 1.409 + 1.410 + case GID_PRESSANDTAP: 1.411 + { 1.412 + // Two finger right click. Defaults to right click if it falls through. 1.413 + evt.message = NS_SIMPLE_GESTURE_PRESSTAP; 1.414 + evt.clickCount = 1; 1.415 + } 1.416 + break; 1.417 + } 1.418 + 1.419 + return true; 1.420 +} 1.421 + 1.422 +bool 1.423 +nsWinGesture::ProcessPanMessage(HWND hWnd, WPARAM wParam, LPARAM lParam) 1.424 +{ 1.425 + GESTUREINFO gi; 1.426 + 1.427 + ZeroMemory(&gi,sizeof(GESTUREINFO)); 1.428 + gi.cbSize = sizeof(GESTUREINFO); 1.429 + 1.430 + BOOL result = GetGestureInfo((HGESTUREINFO)lParam, &gi); 1.431 + if (!result) 1.432 + return false; 1.433 + 1.434 + // The coordinates of this event 1.435 + nsPointWin coord; 1.436 + coord = mPanRefPoint = gi.ptsLocation; 1.437 + // We want screen coordinates in our local offsets as client coordinates will change 1.438 + // when feedback is taking place. Gui events though require client coordinates. 1.439 + mPanRefPoint.ScreenToClient(hWnd); 1.440 + 1.441 + switch(gi.dwID) 1.442 + { 1.443 + case GID_BEGIN: 1.444 + case GID_END: 1.445 + // These should always fall through to DefWndProc 1.446 + return false; 1.447 + break; 1.448 + 1.449 + // Setup pixel scroll events for both axis 1.450 + case GID_PAN: 1.451 + { 1.452 + if (gi.dwFlags & GF_BEGIN) { 1.453 + mPanIntermediate = coord; 1.454 + mPixelScrollDelta = 0; 1.455 + mPanActive = true; 1.456 + mPanInertiaActive = false; 1.457 + } 1.458 + else { 1.459 + 1.460 +#ifdef DBG_jimm 1.461 + int32_t deltaX = mPanIntermediate.x - coord.x; 1.462 + int32_t deltaY = mPanIntermediate.y - coord.y; 1.463 + PR_LOG(gWindowsLog, PR_LOG_ALWAYS, 1.464 + ("coordX=%d coordY=%d deltaX=%d deltaY=%d x:%d y:%d\n", coord.x, 1.465 + coord.y, deltaX, deltaY, mXAxisFeedback, mYAxisFeedback)); 1.466 +#endif 1.467 + 1.468 + mPixelScrollDelta.x = mPanIntermediate.x - coord.x; 1.469 + mPixelScrollDelta.y = mPanIntermediate.y - coord.y; 1.470 + mPanIntermediate = coord; 1.471 + 1.472 + if (gi.dwFlags & GF_INERTIA) 1.473 + mPanInertiaActive = true; 1.474 + 1.475 + if (gi.dwFlags & GF_END) { 1.476 + mPanActive = false; 1.477 + mPanInertiaActive = false; 1.478 + PanFeedbackFinalize(hWnd, true); 1.479 + } 1.480 + } 1.481 + } 1.482 + break; 1.483 + } 1.484 + return true; 1.485 +} 1.486 + 1.487 +inline bool TestTransition(int32_t a, int32_t b) 1.488 +{ 1.489 + // If a is zero, overflow is zero, implying the cursor has moved back to the start position. 1.490 + // If b is zero, cached overscroll is zero, implying feedback just begun. 1.491 + if (a == 0 || b == 0) return true; 1.492 + // Test for different signs. 1.493 + return (a < 0) == (b < 0); 1.494 +} 1.495 + 1.496 +void 1.497 +nsWinGesture::UpdatePanFeedbackX(HWND hWnd, int32_t scrollOverflow, bool& endFeedback) 1.498 +{ 1.499 + // If scroll overflow was returned indicating we panned past the bounds of 1.500 + // the scrollable view port, start feeback. 1.501 + if (scrollOverflow != 0) { 1.502 + if (!mFeedbackActive) { 1.503 + BeginPanningFeedback(hWnd); 1.504 + mFeedbackActive = true; 1.505 + } 1.506 + endFeedback = false; 1.507 + mXAxisFeedback = true; 1.508 + return; 1.509 + } 1.510 + 1.511 + if (mXAxisFeedback) { 1.512 + int32_t newOverflow = mPixelScrollOverflow.x - mPixelScrollDelta.x; 1.513 + 1.514 + // Detect a reverse transition past the starting drag point. This tells us the user 1.515 + // has panned all the way back so we can stop providing feedback for this axis. 1.516 + if (!TestTransition(newOverflow, mPixelScrollOverflow.x) || newOverflow == 0) 1.517 + return; 1.518 + 1.519 + // Cache the total over scroll in pixels. 1.520 + mPixelScrollOverflow.x = newOverflow; 1.521 + endFeedback = false; 1.522 + } 1.523 +} 1.524 + 1.525 +void 1.526 +nsWinGesture::UpdatePanFeedbackY(HWND hWnd, int32_t scrollOverflow, bool& endFeedback) 1.527 +{ 1.528 + // If scroll overflow was returned indicating we panned past the bounds of 1.529 + // the scrollable view port, start feeback. 1.530 + if (scrollOverflow != 0) { 1.531 + if (!mFeedbackActive) { 1.532 + BeginPanningFeedback(hWnd); 1.533 + mFeedbackActive = true; 1.534 + } 1.535 + endFeedback = false; 1.536 + mYAxisFeedback = true; 1.537 + return; 1.538 + } 1.539 + 1.540 + if (mYAxisFeedback) { 1.541 + int32_t newOverflow = mPixelScrollOverflow.y - mPixelScrollDelta.y; 1.542 + 1.543 + // Detect a reverse transition past the starting drag point. This tells us the user 1.544 + // has panned all the way back so we can stop providing feedback for this axis. 1.545 + if (!TestTransition(newOverflow, mPixelScrollOverflow.y) || newOverflow == 0) 1.546 + return; 1.547 + 1.548 + // Cache the total over scroll in pixels. 1.549 + mPixelScrollOverflow.y = newOverflow; 1.550 + endFeedback = false; 1.551 + } 1.552 +} 1.553 + 1.554 +void 1.555 +nsWinGesture::PanFeedbackFinalize(HWND hWnd, bool endFeedback) 1.556 +{ 1.557 + if (!mFeedbackActive) 1.558 + return; 1.559 + 1.560 + if (endFeedback) { 1.561 + mFeedbackActive = false; 1.562 + mXAxisFeedback = false; 1.563 + mYAxisFeedback = false; 1.564 + mPixelScrollOverflow = 0; 1.565 + EndPanningFeedback(hWnd); 1.566 + return; 1.567 + } 1.568 + 1.569 + UpdatePanningFeedback(hWnd, mPixelScrollOverflow.x, mPixelScrollOverflow.y, mPanInertiaActive); 1.570 +} 1.571 + 1.572 +bool 1.573 +nsWinGesture::PanDeltaToPixelScroll(WidgetWheelEvent& aWheelEvent) 1.574 +{ 1.575 + aWheelEvent.deltaX = aWheelEvent.deltaY = aWheelEvent.deltaZ = 0.0; 1.576 + aWheelEvent.lineOrPageDeltaX = aWheelEvent.lineOrPageDeltaY = 0; 1.577 + 1.578 + aWheelEvent.refPoint.x = mPanRefPoint.x; 1.579 + aWheelEvent.refPoint.y = mPanRefPoint.y; 1.580 + aWheelEvent.deltaMode = nsIDOMWheelEvent::DOM_DELTA_PIXEL; 1.581 + aWheelEvent.scrollType = WidgetWheelEvent::SCROLL_SYNCHRONOUSLY; 1.582 + aWheelEvent.isPixelOnlyDevice = true; 1.583 + 1.584 + aWheelEvent.overflowDeltaX = 0.0; 1.585 + aWheelEvent.overflowDeltaY = 0.0; 1.586 + 1.587 + // Don't scroll the view if we are currently at a bounds, or, if we are 1.588 + // panning back from a max feedback position. This keeps the original drag point 1.589 + // constant. 1.590 + if (!mXAxisFeedback) { 1.591 + aWheelEvent.deltaX = mPixelScrollDelta.x; 1.592 + } 1.593 + if (!mYAxisFeedback) { 1.594 + aWheelEvent.deltaY = mPixelScrollDelta.y; 1.595 + } 1.596 + 1.597 + return (aWheelEvent.deltaX != 0 || aWheelEvent.deltaY != 0); 1.598 +}