Bug 485101 - Implement panning feedback for touch enabled displays with win7. r+sr=smaug r=blassey.

This commit is contained in:
Jim Mathies 2009-05-19 21:05:59 -05:00
parent 1df3c7cf23
commit b7f1e1335d
9 changed files with 367 additions and 85 deletions

View File

@ -2879,13 +2879,14 @@ nsEventStateManager::SendPixelScrollEvent(nsIFrame* aTargetFrame,
nsresult
nsEventStateManager::DoScrollText(nsPresContext* aPresContext,
nsIFrame* aTargetFrame,
nsInputEvent* aEvent,
PRInt32 aNumLines,
PRBool aScrollHorizontal,
nsMouseScrollEvent* aMouseEvent,
ScrollQuantity aScrollQuantity)
{
nsIScrollableView* scrollView = nsnull;
nsIFrame* scrollFrame = aTargetFrame;
PRInt32 numLines = aMouseEvent->delta;
PRBool isHorizontal = aMouseEvent->scrollFlags & nsMouseScrollEvent::kIsHorizontal;
aMouseEvent->scrollOverflow = 0;
// If the user recently scrolled with the mousewheel, then they probably want
// to scroll the same view as before instead of the view under the cursor.
@ -2899,7 +2900,7 @@ nsEventStateManager::DoScrollText(nsPresContext* aPresContext,
if (lastScrollFrame) {
nsIScrollableViewProvider* svp = do_QueryFrame(lastScrollFrame);
if (svp && (scrollView = svp->GetScrollableView())) {
nsMouseWheelTransaction::UpdateTransaction(aNumLines, aScrollHorizontal);
nsMouseWheelTransaction::UpdateTransaction(numLines, isHorizontal);
// When the scroll event will not scroll any views, UpdateTransaction
// fired MozMouseScrollFailed event which is for automated testing.
// In the event handler, the target frame might be destroyed. Then,
@ -2928,7 +2929,7 @@ nsEventStateManager::DoScrollText(nsPresContext* aPresContext,
nsPresContext::ScrollbarStyles ss =
nsLayoutUtils::ScrollbarStylesOfView(scrollView);
if (NS_STYLE_OVERFLOW_HIDDEN ==
(aScrollHorizontal ? ss.mHorizontal : ss.mVertical)) {
(isHorizontal ? ss.mHorizontal : ss.mVertical)) {
continue;
}
@ -2937,10 +2938,10 @@ nsEventStateManager::DoScrollText(nsPresContext* aPresContext,
scrollView->GetLineHeight(&lineHeight);
if (lineHeight != 0) {
if (CanScrollOn(scrollView, aNumLines, aScrollHorizontal)) {
if (CanScrollOn(scrollView, numLines, isHorizontal)) {
passToParent = PR_FALSE;
nsMouseWheelTransaction::BeginTransaction(scrollFrame,
aNumLines, aScrollHorizontal);
numLines, isHorizontal);
}
// Comboboxes need special care.
@ -2973,13 +2974,13 @@ nsEventStateManager::DoScrollText(nsPresContext* aPresContext,
if (lineHeight) {
nsSize pageScrollDistances(0, 0);
scrollView->GetPageScrollDistances(&pageScrollDistances);
nscoord pageScroll = aScrollHorizontal ?
nscoord pageScroll = isHorizontal ?
pageScrollDistances.width : pageScrollDistances.height;
if (PR_ABS(aNumLines) * lineHeight > pageScroll) {
if (PR_ABS(numLines) * lineHeight > pageScroll) {
nscoord maxLines = (pageScroll / lineHeight);
if (maxLines >= 1) {
aNumLines = ((aNumLines < 0) ? -1 : 1) * maxLines;
numLines = ((numLines < 0) ? -1 : 1) * maxLines;
} else {
aScrollQuantity = eScrollByPage;
}
@ -2988,34 +2989,52 @@ nsEventStateManager::DoScrollText(nsPresContext* aPresContext,
}
PRInt32 scrollX = 0;
PRInt32 scrollY = aNumLines;
PRInt32 scrollY = numLines;
if (aScrollQuantity == eScrollByPage)
scrollY = (scrollY > 0) ? 1 : -1;
if (aScrollHorizontal) {
if (isHorizontal) {
scrollX = scrollY;
scrollY = 0;
}
if (aScrollQuantity == eScrollByPage)
scrollView->ScrollByPages(scrollX, scrollY, NS_VMREFRESH_SMOOTHSCROLL);
else if (aScrollQuantity == eScrollByPixel)
scrollView->ScrollByPixels(scrollX, scrollY, NS_VMREFRESH_DEFERRED);
PRBool noDefer = aMouseEvent->scrollFlags & nsMouseScrollEvent::kNoDefer;
PRInt32 overflowX = 0, overflowY = 0;
if (aScrollQuantity == eScrollByPage) {
scrollView->ScrollByPages(scrollX, scrollY,
(noDefer ? NS_VMREFRESH_IMMEDIATE : NS_VMREFRESH_SMOOTHSCROLL));
}
else if (aScrollQuantity == eScrollByPixel) {
scrollView->ScrollByPixels(scrollX, scrollY, overflowX, overflowY,
(noDefer ? NS_VMREFRESH_IMMEDIATE : NS_VMREFRESH_DEFERRED));
}
else {
scrollView->ScrollByLinesWithOverflow(scrollX, scrollY, overflowX, overflowY,
(noDefer ? NS_VMREFRESH_IMMEDIATE : NS_VMREFRESH_SMOOTHSCROLL));
}
if (isHorizontal)
aMouseEvent->scrollOverflow = overflowX;
else
scrollView->ScrollByLines(scrollX, scrollY, NS_VMREFRESH_SMOOTHSCROLL);
aMouseEvent->scrollOverflow = overflowY;
return NS_OK;
}
if (passToParent) {
nsresult rv;
nsIFrame* newFrame = nsnull;
nsCOMPtr<nsPresContext> newPresContext;
rv = GetParentScrollingView(aEvent, aPresContext, newFrame,
rv = GetParentScrollingView(aMouseEvent, aPresContext, newFrame,
*getter_AddRefs(newPresContext));
if (NS_SUCCEEDED(rv) && newFrame)
return DoScrollText(newPresContext, newFrame, aEvent, aNumLines,
aScrollHorizontal, aScrollQuantity);
return DoScrollText(newPresContext, newFrame, aMouseEvent, aScrollQuantity);
}
aMouseEvent->scrollOverflow = numLines;
return NS_OK;
}
@ -3275,39 +3294,23 @@ nsEventStateManager::PostHandleEvent(nsPresContext* aPresContext,
switch (action) {
case MOUSE_SCROLL_N_LINES:
{
DoScrollText(presContext, aTargetFrame, msEvent, msEvent->delta,
!!(msEvent->scrollFlags & nsMouseScrollEvent::kIsHorizontal),
eScrollByLine);
}
DoScrollText(presContext, aTargetFrame, msEvent, eScrollByLine);
break;
case MOUSE_SCROLL_PAGE:
{
DoScrollText(presContext, aTargetFrame, msEvent, msEvent->delta,
!!(msEvent->scrollFlags & nsMouseScrollEvent::kIsHorizontal),
eScrollByPage);
}
DoScrollText(presContext, aTargetFrame, msEvent, eScrollByPage);
break;
case MOUSE_SCROLL_PIXELS:
{
DoScrollText(presContext, aTargetFrame, msEvent, msEvent->delta,
!!(msEvent->scrollFlags & nsMouseScrollEvent::kIsHorizontal),
eScrollByPixel);
}
DoScrollText(presContext, aTargetFrame, msEvent, eScrollByPixel);
break;
case MOUSE_SCROLL_HISTORY:
{
DoScrollHistory(msEvent->delta);
}
DoScrollHistory(msEvent->delta);
break;
case MOUSE_SCROLL_ZOOM:
{
DoScrollZoom(aTargetFrame, msEvent->delta);
}
DoScrollZoom(aTargetFrame, msEvent->delta);
break;
default: // Including -1 (do nothing)

View File

@ -312,9 +312,7 @@ protected:
} ScrollQuantity;
nsresult DoScrollText(nsPresContext* aPresContext,
nsIFrame* aTargetFrame,
nsInputEvent* aEvent,
PRInt32 aNumLines,
PRBool aScrollHorizontal,
nsMouseScrollEvent* aMouseEvent,
ScrollQuantity aScrollQuantity);
void DoScrollHistory(PRInt32 direction);
void DoScrollZoom(nsIFrame *aTargetFrame, PRInt32 adjustment);

View File

@ -147,6 +147,20 @@ public:
*/
NS_IMETHOD ScrollByLines(PRInt32 aNumLinesX, PRInt32 aNumLinexY,
PRUint32 aUpdateFlags = 0) = 0;
/**
* Identical to ScrollByLines while also returning overscroll values.
* @param aNumLinesX number of lines to scroll the view horizontally
* @param aNumLinesY number of lines to scroll the view vertically
* @param aOverflowX returns the number of pixels that could not
* be scrolled due to scroll bounds.
* @param aOverflowY returns the number of pixels that could not
* be scrolled due to scroll bounds.
* @param aUpdateFlags indicate smooth or async scrolling
* @return error status
*/
NS_IMETHOD ScrollByLinesWithOverflow(PRInt32 aNumLinesX, PRInt32 aNumLinexY,
PRInt32& aOverflowX, PRInt32& aOverflowY,
PRUint32 aUpdateFlags = 0) = 0;
/**
* Get the desired size of a page scroll in each dimension.
@ -181,12 +195,17 @@ public:
* Scroll the view left or right by aNumLinesX pixels. Positive values move
* right. Scroll the view up or down by aNumLinesY pixels. Positive values
* move down. Prevents scrolling off the end of the view.
* @param aNumLinesX number of lines to scroll the view horizontally
* @param aNumLinesY number of lines to scroll the view vertically
* @param aUpdateFlags indicate smooth or async scrolling
* @param aNumPixelsX number of pixels to scroll the view horizontally
* @param aNumPixelsY number of pixels to scroll the view vertically
* @param aOverflowX returns the number of pixels that could not
* be scrolled due to scroll bounds.
* @param aOverflowY returns the number of pixels that could not
* be scrolled due to scroll bounds.
* @param aUpdateFlags indicate smooth, async, or immediate scrolling
* @return error status
*/
NS_IMETHOD ScrollByPixels(PRInt32 aNumPixelsX, PRInt32 aNumPixelsY,
PRInt32& aOverflowX, PRInt32& aOverflowY,
PRUint32 aUpdateFlags = 0) = 0;
/**

View File

@ -208,7 +208,7 @@ static void ComputeVelocities(PRInt32 aCurVelocity, nscoord aCurPos, nscoord aDs
}
static nsresult ClampScrollValues(nscoord& aX, nscoord& aY, nsScrollPortView* aThis) {
// make sure the new position in in bounds
// make sure the new position is in bounds
nsView* scrolledView = aThis->GetScrolledView();
if (!scrolledView) return NS_ERROR_FAILURE;
@ -396,7 +396,44 @@ NS_IMETHODIMP nsScrollPortView::GetLineHeight(nscoord *aHeight)
return NS_OK;
}
NS_IMETHODIMP nsScrollPortView::ScrollByLines(PRInt32 aNumLinesX, PRInt32 aNumLinesY,
nsresult
nsScrollPortView::CalcScrollOverflow(nscoord aX, nscoord aY,
PRInt32& aPixelOverflowX, PRInt32& aPixelOverflowY)
{
// make sure the new position is in bounds
nsView* scrolledView = GetScrolledView();
if (!scrolledView) return NS_ERROR_FAILURE;
nsRect scrolledRect;
scrolledView->GetDimensions(scrolledRect);
nsSize portSize;
this->GetDimensions(portSize);
nscoord maxX = scrolledRect.XMost() - portSize.width;
nscoord maxY = scrolledRect.YMost() - portSize.height;
nsCOMPtr<nsIDeviceContext> dev;
mViewManager->GetDeviceContext(*getter_AddRefs(dev));
float p2a = (float)dev->AppUnitsPerDevPixel();
if (maxX != 0 && aX > maxX)
aPixelOverflowX = NSAppUnitsToIntPixels(aX - maxX, p2a);
if (maxY != 0 && aY > maxY)
aPixelOverflowY = NSAppUnitsToIntPixels(aY - maxY, p2a);
if (maxX != 0 && aX < scrolledRect.x)
aPixelOverflowX = NSAppUnitsToIntPixels(scrolledRect.x - aX, p2a);
if (maxY != 0 && aY < scrolledRect.y)
aPixelOverflowY = NSAppUnitsToIntPixels(scrolledRect.y - aY, p2a);
return NS_OK;
}
NS_IMETHODIMP nsScrollPortView::ScrollByLines(PRInt32 aNumLinesX,
PRInt32 aNumLinesY,
PRUint32 aUpdateFlags)
{
nscoord dx = mLineHeight*aNumLinesX;
@ -405,6 +442,20 @@ NS_IMETHODIMP nsScrollPortView::ScrollByLines(PRInt32 aNumLinesX, PRInt32 aNumLi
return ScrollTo(mDestinationX + dx, mDestinationY + dy, aUpdateFlags);
}
NS_IMETHODIMP nsScrollPortView::ScrollByLinesWithOverflow(PRInt32 aNumLinesX,
PRInt32 aNumLinesY,
PRInt32& aOverflowX,
PRInt32& aOverflowY,
PRUint32 aUpdateFlags)
{
nscoord dx = mLineHeight*aNumLinesX;
nscoord dy = mLineHeight*aNumLinesY;
CalcScrollOverflow(mDestinationX + dx, mDestinationY + dy, aOverflowX, aOverflowY);
return ScrollTo(mDestinationX + dx, mDestinationY + dy, aUpdateFlags);
}
NS_IMETHODIMP nsScrollPortView::GetPageScrollDistances(nsSize *aDistances)
{
nsSize size;
@ -451,6 +502,8 @@ NS_IMETHODIMP nsScrollPortView::ScrollByWhole(PRBool aTop,
NS_IMETHODIMP nsScrollPortView::ScrollByPixels(PRInt32 aNumPixelsX,
PRInt32 aNumPixelsY,
PRInt32& aOverflowX,
PRInt32& aOverflowY,
PRUint32 aUpdateFlags)
{
nsCOMPtr<nsIDeviceContext> dev;
@ -460,6 +513,8 @@ NS_IMETHODIMP nsScrollPortView::ScrollByPixels(PRInt32 aNumPixelsX,
nscoord dx = NSIntPixelsToAppUnits(aNumPixelsX, p2a);
nscoord dy = NSIntPixelsToAppUnits(aNumPixelsY, p2a);
CalcScrollOverflow(mDestinationX + dx, mDestinationY + dy, aOverflowX, aOverflowY);
return ScrollTo(mDestinationX + dx, mDestinationY + dy, aUpdateFlags);
}
@ -614,7 +669,7 @@ NS_IMETHODIMP nsScrollPortView::ScrollToImpl(nscoord aX, nscoord aY)
aX = NSIntPixelsToAppUnits(xPixels, p2a);
aY = NSIntPixelsToAppUnits(yPixels, p2a);
// do nothing if the we aren't scrolling.
// do nothing if we aren't scrolling.
// this needs to be rechecked because of the clamping and
// rounding
if (aX == mOffsetX && aY == mOffsetY) {

View File

@ -73,11 +73,15 @@ public:
NS_IMETHOD GetLineHeight(nscoord *aHeight);
NS_IMETHOD ScrollByLines(PRInt32 aNumLinesX, PRInt32 aNumLinesY,
PRUint32 aUpdateFlags = 0);
NS_IMETHOD ScrollByLinesWithOverflow(PRInt32 aNumLinesX, PRInt32 aNumLinesY,
PRInt32& aOverflowX, PRInt32& aOverflowY,
PRUint32 aUpdateFlags = 0);
NS_IMETHOD GetPageScrollDistances(nsSize *aDistances);
NS_IMETHOD ScrollByPages(PRInt32 aNumPagesX, PRInt32 aNumPagesY,
PRUint32 aUpdateFlags = 0);
NS_IMETHOD ScrollByWhole(PRBool aTop, PRUint32 aUpdateFlags = 0);
NS_IMETHOD ScrollByPixels(PRInt32 aNumPixelsX, PRInt32 aNumPixelsY,
PRInt32& aOverflowX, PRInt32& aOverflowY,
PRUint32 aUpdateFlags = 0);
NS_IMETHOD CanScroll(PRBool aHorizontal, PRBool aForward, PRBool &aResult);
@ -107,6 +111,7 @@ protected:
//private
void Scroll(nsView *aScrolledView, nsPoint aTwipsDelta, nsIntPoint aPixDelta, nscoord aP2A);
PRBool CannotBitBlt(nsView* aScrolledView);
nsresult CalcScrollOverflow(nscoord aX, nscoord aY, PRInt32& aOverflowX, PRInt32& aOverflowY);
nscoord mOffsetX, mOffsetY;
nscoord mDestinationX, mDestinationY;

View File

@ -1061,21 +1061,24 @@ public:
// When kHasPixels is set, the event is guaranteed to
// be followed up by an event that contains pixel
// scrolling information.
kNoLines = 1 << 4 // Marks pixel scroll events that will not be
kNoLines = 1 << 4, // Marks pixel scroll events that will not be
// followed by a line scroll events. EventStateManager
// will compute the appropriate height/width based on
// view lineHeight and generate line scroll events
// as needed.
kNoDefer = 1 << 5 // For scrollable views, indicates scroll should not
// occur asynchronously.
};
nsMouseScrollEvent(PRBool isTrusted, PRUint32 msg, nsIWidget *w)
: nsMouseEvent_base(isTrusted, msg, w, NS_MOUSE_SCROLL_EVENT),
scrollFlags(0), delta(0)
scrollFlags(0), delta(0), scrollOverflow(0)
{
}
PRInt32 scrollFlags;
PRInt32 delta;
PRInt32 scrollOverflow;
};
class nsQueryContentEvent : public nsGUIEvent

View File

@ -52,18 +52,27 @@
#endif
const PRUnichar nsWinGesture::kGestureLibraryName[] = L"user32.dll";
const PRUnichar nsWinGesture::kThemeLibraryName[] = L"uxtheme.dll";
HMODULE nsWinGesture::sLibraryHandle = nsnull;
nsWinGesture::GetGestureInfoPtr nsWinGesture::getGestureInfo = nsnull;
nsWinGesture::CloseGestureInfoHandlePtr nsWinGesture::closeGestureInfoHandle = nsnull;
nsWinGesture::GetGestureExtraArgsPtr nsWinGesture::getGestureExtraArgs = nsnull;
nsWinGesture::SetGestureConfigPtr nsWinGesture::setGestureConfig = nsnull;
nsWinGesture::GetGestureConfigPtr nsWinGesture::getGestureConfig = nsnull;
nsWinGesture::BeginPanningFeedbackPtr nsWinGesture::beginPanningFeedback = nsnull;
nsWinGesture::EndPanningFeedbackPtr nsWinGesture::endPanningFeedback = nsnull;
nsWinGesture::UpdatePanningFeedbackPtr nsWinGesture::updatePanningFeedback = nsnull;
static PRBool gEnableSingleFingerPanEvents = PR_FALSE;
nsWinGesture::nsWinGesture() :
mAvailable(PR_FALSE)
mFeedbackActive(PR_FALSE),
mXAxisFeedback(PR_FALSE),
mYAxisFeedback(PR_FALSE),
mPanActive(PR_FALSE),
mPanInertiaActive(PR_FALSE)
{
(void)InitLibrary();
mPixelScrollOverflow = 0;
}
nsWinGesture::~nsWinGesture()
@ -79,13 +88,15 @@ PRBool nsWinGesture::InitLibrary()
return PR_FALSE;
#else
if (getGestureInfo) {
mAvailable = PR_TRUE;
return PR_TRUE;
} else if (sLibraryHandle) {
return PR_FALSE;
}
sLibraryHandle = ::LoadLibraryW(kGestureLibraryName);
HMODULE hTheme = ::LoadLibraryW(kThemeLibraryName);
// gesture interfaces
if (sLibraryHandle) {
getGestureInfo = (GetGestureInfoPtr)GetProcAddress(sLibraryHandle, "GetGestureInfo");
closeGestureInfoHandle = (CloseGestureInfoHandlePtr)GetProcAddress(sLibraryHandle, "CloseGestureInfoHandle");
@ -95,17 +106,27 @@ PRBool nsWinGesture::InitLibrary()
}
if (!getGestureInfo || !closeGestureInfoHandle || !getGestureExtraArgs ||
!setGestureConfig || !getGestureConfig) {
!setGestureConfig || !getGestureConfig) {
getGestureInfo = nsnull;
closeGestureInfoHandle = nsnull;
getGestureExtraArgs = nsnull;
setGestureConfig = nsnull;
getGestureConfig = nsnull;
return PR_FALSE;
}
mAvailable = PR_TRUE;
// panning feedback interfaces
if (hTheme) {
beginPanningFeedback = (BeginPanningFeedbackPtr)GetProcAddress(hTheme, "BeginPanningFeedback");
endPanningFeedback = (EndPanningFeedbackPtr)GetProcAddress(hTheme, "EndPanningFeedback");
updatePanningFeedback = (UpdatePanningFeedbackPtr)GetProcAddress(hTheme, "UpdatePanningFeedback");
}
if (!beginPanningFeedback || !endPanningFeedback || !updatePanningFeedback) {
beginPanningFeedback = nsnull;
endPanningFeedback = nsnull;
updatePanningFeedback = nsnull;
}
// Check to see if we want single finger gesture input. Only do this once
// for the app so we don't have to look it up on every window create.
@ -127,14 +148,15 @@ PRBool nsWinGesture::InitLibrary()
void nsWinGesture::ShutdownLibrary()
{
mAvailable = PR_FALSE;
getGestureInfo = nsnull;
beginPanningFeedback = nsnull;
}
#define GCOUNT 5
PRBool nsWinGesture::InitWinGestureSupport(HWND hWnd)
{
if (!mAvailable)
if (!getGestureInfo)
return PR_FALSE;
GESTURECONFIG config[GCOUNT];
@ -168,8 +190,8 @@ PRBool nsWinGesture::InitWinGestureSupport(HWND hWnd)
config[3].dwID = GID_TWOFINGERTAP;
config[3].dwBlock = 0;
config[4].dwWant = GC_ROLLOVER;
config[4].dwID = GID_ROLLOVER;
config[4].dwWant = GC_PRESSANDTAP;
config[4].dwID = GID_PRESSANDTAP;
config[4].dwBlock = 0;
return SetGestureConfig(hWnd, GCOUNT, (PGESTURECONFIG)&config);
@ -179,12 +201,12 @@ PRBool nsWinGesture::InitWinGestureSupport(HWND hWnd)
PRBool nsWinGesture::IsAvailable()
{
return mAvailable;
return getGestureInfo != nsnull;
}
PRBool nsWinGesture::GetGestureInfo(HGESTUREINFO hGestureInfo, PGESTUREINFO pGestureInfo)
{
if (!mAvailable || !hGestureInfo || !pGestureInfo)
if (!getGestureInfo || !hGestureInfo || !pGestureInfo)
return PR_FALSE;
ZeroMemory(pGestureInfo, sizeof(GESTUREINFO));
@ -195,7 +217,7 @@ PRBool nsWinGesture::GetGestureInfo(HGESTUREINFO hGestureInfo, PGESTUREINFO pGes
PRBool nsWinGesture::CloseGestureInfoHandle(HGESTUREINFO hGestureInfo)
{
if (!mAvailable || !hGestureInfo)
if (!getGestureInfo || !hGestureInfo)
return PR_FALSE;
return closeGestureInfoHandle(hGestureInfo);
@ -203,7 +225,7 @@ PRBool nsWinGesture::CloseGestureInfoHandle(HGESTUREINFO hGestureInfo)
PRBool nsWinGesture::GetGestureExtraArgs(HGESTUREINFO hGestureInfo, UINT cbExtraArgs, PBYTE pExtraArgs)
{
if (!mAvailable || !hGestureInfo || !pExtraArgs)
if (!getGestureInfo || !hGestureInfo || !pExtraArgs)
return PR_FALSE;
return getGestureExtraArgs(hGestureInfo, cbExtraArgs, pExtraArgs);
@ -211,7 +233,7 @@ PRBool nsWinGesture::GetGestureExtraArgs(HGESTUREINFO hGestureInfo, UINT cbExtra
PRBool nsWinGesture::SetGestureConfig(HWND hWnd, UINT cIDs, PGESTURECONFIG pGestureConfig)
{
if (!mAvailable || !pGestureConfig)
if (!getGestureInfo || !pGestureConfig)
return PR_FALSE;
return setGestureConfig(hWnd, 0, cIDs, pGestureConfig, sizeof(GESTURECONFIG));
@ -219,12 +241,36 @@ PRBool nsWinGesture::SetGestureConfig(HWND hWnd, UINT cIDs, PGESTURECONFIG pGest
PRBool nsWinGesture::GetGestureConfig(HWND hWnd, DWORD dwFlags, PUINT pcIDs, PGESTURECONFIG pGestureConfig)
{
if (!mAvailable || !pGestureConfig)
if (!getGestureInfo || !pGestureConfig)
return PR_FALSE;
return getGestureConfig(hWnd, 0, dwFlags, pcIDs, pGestureConfig, sizeof(GESTURECONFIG));
}
PRBool nsWinGesture::BeginPanningFeedback(HWND hWnd)
{
if (!beginPanningFeedback)
return PR_FALSE;
return beginPanningFeedback(hWnd);
}
PRBool nsWinGesture::EndPanningFeedback(HWND hWnd)
{
if (!beginPanningFeedback)
return PR_FALSE;
return endPanningFeedback(hWnd, TRUE);
}
PRBool nsWinGesture::UpdatePanningFeedback(HWND hWnd, LONG offsetX, LONG offsetY, BOOL fInInertia)
{
if (!beginPanningFeedback)
return PR_FALSE;
return updatePanningFeedback(hWnd, offsetX, offsetY, fInInertia);
}
PRBool nsWinGesture::IsPanEvent(LPARAM lParam)
{
GESTUREINFO gi;
@ -341,9 +387,9 @@ nsWinGesture::ProcessGestureMessage(HWND hWnd, WPARAM wParam, LPARAM lParam, nsS
}
break;
case GID_ROLLOVER:
case GID_PRESSANDTAP:
{
// Two finger drum roll. Defaults to right click if it falls through.
// Two finger right click. Defaults to right click if it falls through.
evt.message = NS_SIMPLE_GESTURE_PRESSTAP;
}
break;
@ -366,8 +412,10 @@ nsWinGesture::ProcessPanMessage(HWND hWnd, WPARAM wParam, LPARAM lParam)
// The coordinates of this event
nsPointWin coord;
coord = gi.ptsLocation;
coord.ScreenToClient(hWnd);
coord = mPanRefPoint = gi.ptsLocation;
// We want screen coordinates in our local offsets as client coordinates will change
// when feedback is taking place. Gui events though require client coordinates.
mPanRefPoint.ScreenToClient(hWnd);
switch(gi.dwID)
{
@ -383,10 +431,30 @@ nsWinGesture::ProcessPanMessage(HWND hWnd, WPARAM wParam, LPARAM lParam)
if (gi.dwFlags & GF_BEGIN) {
mPanIntermediate = coord;
mPixelScrollDelta = 0;
} else {
mPanActive = PR_TRUE;
mPanInertiaActive = PR_FALSE;
}
else {
#ifdef DBG_jimm
PRInt32 deltaX = mPanIntermediate.x - coord.x;
PRInt32 deltaY = mPanIntermediate.y - coord.y;
printf("coordX=%d coordY=%d deltaX=%d deltaY=%d x:%d y:%d\n", coord.x,
coord.y, deltaX, deltaY, mXAxisFeedback, mYAxisFeedback);
#endif
mPixelScrollDelta.x = mPanIntermediate.x - coord.x;
mPixelScrollDelta.y = mPanIntermediate.y - coord.y;
mPanIntermediate = coord;
if (gi.dwFlags & GF_INERTIA)
mPanInertiaActive = PR_TRUE;
if (gi.dwFlags & GF_END) {
mPanActive = PR_FALSE;
mPanInertiaActive = PR_FALSE;
PanFeedbackFinalize(hWnd, PR_TRUE);
}
}
}
break;
@ -394,15 +462,112 @@ nsWinGesture::ProcessPanMessage(HWND hWnd, WPARAM wParam, LPARAM lParam)
return PR_TRUE;
}
inline PRBool TestTransition(PRInt32 a, PRInt32 b)
{
// If a is zero, overflow is zero, implying the cursor has moved back to the start position.
// If b is zero, cached overscroll is zero, implying feedback just begun.
if (a == 0 || b == 0) return PR_TRUE;
// Test for different signs.
return (a < 0) == (b < 0);
}
void
nsWinGesture::UpdatePanFeedbackX(HWND hWnd, nsMouseScrollEvent& evt, PRBool& endFeedback)
{
// If scroll overflow was returned indicating we panned past the bounds of
// the scrollable view port, start feeback.
if (evt.scrollOverflow != 0) {
if (!mFeedbackActive) {
BeginPanningFeedback(hWnd);
mFeedbackActive = PR_TRUE;
}
endFeedback = PR_FALSE;
mXAxisFeedback = PR_TRUE;
return;
}
if (mXAxisFeedback) {
PRInt32 newOverflow = mPixelScrollOverflow.x - mPixelScrollDelta.x;
// Detect a reverse transition past the starting drag point. This tells us the user
// has panned all the way back so we can stop providing feedback for this axis.
if (!TestTransition(newOverflow, mPixelScrollOverflow.x) || newOverflow == 0)
return;
// Cache the total over scroll in pixels.
mPixelScrollOverflow.x = newOverflow;
endFeedback = PR_FALSE;
}
}
void
nsWinGesture::UpdatePanFeedbackY(HWND hWnd, nsMouseScrollEvent& evt, PRBool& endFeedback)
{
// If scroll overflow was returned indicating we panned past the bounds of
// the scrollable view port, start feeback.
if (evt.scrollOverflow != 0) {
if (!mFeedbackActive) {
BeginPanningFeedback(hWnd);
mFeedbackActive = PR_TRUE;
}
endFeedback = PR_FALSE;
mYAxisFeedback = PR_TRUE;
return;
}
if (mYAxisFeedback) {
PRInt32 newOverflow = mPixelScrollOverflow.y - mPixelScrollDelta.y;
// Detect a reverse transition past the starting drag point. This tells us the user
// has panned all the way back so we can stop providing feedback for this axis.
if (!TestTransition(newOverflow, mPixelScrollOverflow.y) || newOverflow == 0)
return;
// Cache the total over scroll in pixels.
mPixelScrollOverflow.y = newOverflow;
endFeedback = PR_FALSE;
}
}
void
nsWinGesture::PanFeedbackFinalize(HWND hWnd, PRBool endFeedback)
{
if (!mFeedbackActive)
return;
if (endFeedback) {
mFeedbackActive = PR_FALSE;
mXAxisFeedback = PR_FALSE;
mYAxisFeedback = PR_FALSE;
mPixelScrollOverflow = 0;
EndPanningFeedback(hWnd);
return;
}
UpdatePanningFeedback(hWnd, mPixelScrollOverflow.x, mPixelScrollOverflow.y, mPanInertiaActive);
}
PRBool
nsWinGesture::PanDeltaToPixelScrollX(nsMouseScrollEvent& evt)
{
evt.delta = 0;
evt.scrollOverflow = 0;
// Don't scroll the view if we are currently at a bounds, or, if we are
// panning back from a max feedback position. This keeps the original drag point
// constant.
if (mXAxisFeedback)
return PR_FALSE;
if (mPixelScrollDelta.x != 0)
{
evt.scrollFlags = nsMouseScrollEvent::kIsHorizontal|nsMouseScrollEvent::kHasPixels|nsMouseScrollEvent::kNoLines;
evt.scrollFlags = nsMouseScrollEvent::kIsHorizontal|
nsMouseScrollEvent::kHasPixels|
nsMouseScrollEvent::kNoLines|
nsMouseScrollEvent::kNoDefer;
evt.delta = mPixelScrollDelta.x;
evt.refPoint.x = mPanIntermediate.x;
evt.refPoint.y = mPanIntermediate.y;
evt.refPoint.x = mPanRefPoint.x;
evt.refPoint.y = mPanRefPoint.y;
return PR_TRUE;
}
return PR_FALSE;
@ -411,12 +576,24 @@ nsWinGesture::PanDeltaToPixelScrollX(nsMouseScrollEvent& evt)
PRBool
nsWinGesture::PanDeltaToPixelScrollY(nsMouseScrollEvent& evt)
{
evt.delta = 0;
evt.scrollOverflow = 0;
// Don't scroll the view if we are currently at a bounds, or, if we are
// panning back from a max feedback position. This keeps the original drag point
// constant.
if (mYAxisFeedback)
return PR_FALSE;
if (mPixelScrollDelta.y != 0)
{
evt.scrollFlags = nsMouseScrollEvent::kIsVertical|nsMouseScrollEvent::kHasPixels|nsMouseScrollEvent::kNoLines;
evt.scrollFlags = nsMouseScrollEvent::kIsVertical|
nsMouseScrollEvent::kHasPixels|
nsMouseScrollEvent::kNoLines|
nsMouseScrollEvent::kNoDefer;
evt.delta = mPixelScrollDelta.y;
evt.refPoint.x = mPanIntermediate.x;
evt.refPoint.y = mPanIntermediate.y;
evt.refPoint.x = mPanRefPoint.x;
evt.refPoint.y = mPanRefPoint.y;
return PR_TRUE;
}
return PR_FALSE;

View File

@ -44,7 +44,6 @@
#include "nsPoint.h"
#include "nsGUIEvent.h"
#if !defined(NTDDI_WIN7) || NTDDI_VERSION < NTDDI_WIN7
DECLARE_HANDLE(HGESTUREINFO);
@ -131,7 +130,7 @@ typedef struct tagGESTURENOTIFYSTRUCT {
#define GC_TWOFINGERTAP 0x00000001
#define GC_ROLLOVER 0x00000001
#define GC_PRESSANDTAP 0x00000001
/*
* Gesture IDs
@ -142,7 +141,7 @@ typedef struct tagGESTURENOTIFYSTRUCT {
#define GID_PAN 4
#define GID_ROTATE 5
#define GID_TWOFINGERTAP 6
#define GID_ROLLOVER 7
#define GID_PRESSANDTAP 7
// Maximum number of gestures that can be included
// in a single call to SetGestureConfig / GetGestureConfig
@ -204,6 +203,9 @@ public:
PRBool ProcessPanMessage(HWND hWnd, WPARAM wParam, LPARAM lParam);
PRBool PanDeltaToPixelScrollX(nsMouseScrollEvent& evt);
PRBool PanDeltaToPixelScrollY(nsMouseScrollEvent& evt);
void UpdatePanFeedbackX(HWND hWnd, nsMouseScrollEvent& evt, PRBool& endFeedback);
void UpdatePanFeedbackY(HWND hWnd, nsMouseScrollEvent& evt, PRBool& endFeedback);
void PanFeedbackFinalize(HWND hWnd, PRBool endFeedback);
public:
// Helpers
@ -212,6 +214,9 @@ public:
PRBool GetGestureExtraArgs(HGESTUREINFO hGestureInfo, UINT cbExtraArgs, PBYTE pExtraArgs);
PRBool SetGestureConfig(HWND hWnd, UINT cIDs, PGESTURECONFIG pGestureConfig);
PRBool GetGestureConfig(HWND hWnd, DWORD dwFlags, PUINT pcIDs, PGESTURECONFIG pGestureConfig);
PRBool BeginPanningFeedback(HWND hWnd);
PRBool EndPanningFeedback(HWND hWnd);
PRBool UpdatePanningFeedback(HWND hWnd, LONG offsetX, LONG offsetY, BOOL fInInertia);
protected:
@ -222,6 +227,9 @@ private:
typedef BOOL (WINAPI * GetGestureExtraArgsPtr)(HGESTUREINFO hGestureInfo, UINT cbExtraArgs, PBYTE pExtraArgs);
typedef BOOL (WINAPI * SetGestureConfigPtr)(HWND hwnd, DWORD dwReserved, UINT cIDs, PGESTURECONFIG pGestureConfig, UINT cbSize);
typedef BOOL (WINAPI * GetGestureConfigPtr)(HWND hwnd, DWORD dwReserved, DWORD dwFlags, PUINT pcIDs, PGESTURECONFIG pGestureConfig, UINT cbSize);
typedef BOOL (WINAPI * BeginPanningFeedbackPtr)(HWND hWnd);
typedef BOOL (WINAPI * EndPanningFeedbackPtr)(HWND hWnd, BOOL fAnimateBack);
typedef BOOL (WINAPI * UpdatePanningFeedbackPtr)(HWND hWnd, LONG offsetX, LONG offsetY, BOOL fInInertia);
// Static function pointers
static GetGestureInfoPtr getGestureInfo;
@ -229,6 +237,9 @@ private:
static GetGestureExtraArgsPtr getGestureExtraArgs;
static SetGestureConfigPtr setGestureConfig;
static GetGestureConfigPtr getGestureConfig;
static BeginPanningFeedbackPtr beginPanningFeedback;
static EndPanningFeedbackPtr endPanningFeedback;
static UpdatePanningFeedbackPtr updatePanningFeedback;
// Delay load info
PRBool InitLibrary();
@ -236,12 +247,18 @@ private:
static HMODULE sLibraryHandle;
static const PRUnichar kGestureLibraryName[];
static const PRUnichar kThemeLibraryName[];
PRBool mAvailable;
// Pan state
// Pan and feedback state
nsPointWin mPanIntermediate;
nsPointWin mPanRefPoint;
nsPointWin mPixelScrollDelta;
PRPackedBool mPanActive;
PRPackedBool mFeedbackActive;
PRPackedBool mXAxisFeedback;
PRPackedBool mYAxisFeedback;
PRPackedBool mPanInertiaActive;
nsPointWin mPixelScrollOverflow;
// Zoom state
double mZoomIntermediate;

View File

@ -5221,13 +5221,18 @@ PRBool nsWindow::ProcessGestureMessage(WPARAM wParam, LPARAM lParam)
event.button = 0;
event.time = ::GetMessageTime();
PRBool endFeedback = PR_TRUE;
if (mGesture.PanDeltaToPixelScrollX(event)) {
DispatchEvent(&event, status);
}
mGesture.UpdatePanFeedbackX(mWnd, event, endFeedback);
if (mGesture.PanDeltaToPixelScrollY(event)) {
DispatchEvent(&event, status);
}
mGesture.UpdatePanFeedbackY(mWnd, event, endFeedback);
mGesture.PanFeedbackFinalize(mWnd, endFeedback);
mGesture.CloseGestureInfoHandle((HGESTUREINFO)lParam);
return PR_TRUE;