Bug 786898 part.1 Set overflowDelta 0 if the delta is unused by overflow-x: hidden; or overflow-y: hidden; but an ancestor is scrollable along the axis r=smaug

This commit is contained in:
Masayuki Nakano 2012-09-04 17:39:28 +09:00
parent 1acbd32c7a
commit 2cf554452a
2 changed files with 79 additions and 34 deletions

View File

@ -2504,7 +2504,8 @@ nsEventStateManager::DispatchLegacyMouseScrollEvents(nsIFrame* aTargetFrame,
// Ignore mouse wheel transaction for computing legacy mouse wheel
// events' delta value.
nsIScrollableFrame* scrollTarget =
ComputeScrollTarget(aTargetFrame, aEvent, false);
ComputeScrollTarget(aTargetFrame, aEvent,
COMPUTE_LEGACY_MOUSE_SCROLL_EVENT_TARGET);
nsIFrame* scrollFrame = do_QueryFrame(scrollTarget);
nsPresContext* pc =
@ -2688,9 +2689,9 @@ nsEventStateManager::SendPixelScrollEvent(nsIFrame* aTargetFrame,
nsIScrollableFrame*
nsEventStateManager::ComputeScrollTarget(nsIFrame* aTargetFrame,
widget::WheelEvent* aEvent,
bool aForDefaultAction)
ComputeScrollTargetOptions aOptions)
{
if (aForDefaultAction) {
if (aOptions & PREFER_MOUSE_WHEEL_TRANSACTION) {
// 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. nsMouseWheelTransaction tracks the frame currently being
@ -2717,18 +2718,23 @@ nsEventStateManager::ComputeScrollTarget(nsIFrame* aTargetFrame,
return nullptr;
}
bool checkIfScrollableX =
aEvent->deltaX && (aOptions & PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_X_AXIS);
bool checkIfScrollableY =
aEvent->deltaY && (aOptions & PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_Y_AXIS);
nsIScrollableFrame* frameToScroll = nullptr;
for (nsIFrame* scrollFrame = aTargetFrame; scrollFrame;
scrollFrame = GetParentFrameToScroll(scrollFrame)) {
nsIFrame* scrollFrame =
!(aOptions & START_FROM_PARENT) ? aTargetFrame :
GetParentFrameToScroll(aTargetFrame);
for (; scrollFrame; scrollFrame = GetParentFrameToScroll(scrollFrame)) {
// Check whether the frame wants to provide us with a scrollable view.
frameToScroll = scrollFrame->GetScrollTargetFrame();
if (!frameToScroll) {
continue;
}
// At computing scroll target for legacy mouse events, we should return
// first scrollable element even when it's not scrollable to the direction.
if (!aForDefaultAction) {
if (!checkIfScrollableX && !checkIfScrollableY) {
return frameToScroll;
}
@ -2736,8 +2742,8 @@ nsEventStateManager::ComputeScrollTarget(nsIFrame* aTargetFrame,
bool hiddenForV = (NS_STYLE_OVERFLOW_HIDDEN == ss.mVertical);
bool hiddenForH = (NS_STYLE_OVERFLOW_HIDDEN == ss.mHorizontal);
if ((hiddenForV && hiddenForH) ||
(aEvent->deltaY && !aEvent->deltaX && hiddenForV) ||
(aEvent->deltaX && !aEvent->deltaY && hiddenForH)) {
(checkIfScrollableY && !checkIfScrollableX && hiddenForV) ||
(checkIfScrollableX && !checkIfScrollableY && hiddenForH)) {
continue;
}
@ -2763,8 +2769,9 @@ nsEventStateManager::ComputeScrollTarget(nsIFrame* aTargetFrame,
nsIFrame* newFrame = nsLayoutUtils::GetCrossDocParentFrame(
aTargetFrame->PresContext()->FrameManager()->GetRootFrame());
return newFrame ?
ComputeScrollTarget(newFrame, aEvent, aForDefaultAction) : nullptr;
aOptions =
static_cast<ComputeScrollTargetOptions>(aOptions & ~START_FROM_PARENT);
return newFrame ? ComputeScrollTarget(newFrame, aEvent, aOptions) : nullptr;
}
nsSize
@ -2908,18 +2915,17 @@ nsEventStateManager::DoScrollText(nsIScrollableFrame* aScrollableFrame,
return;
}
// XXX When the scroll target came from the wheel transaction manager, there
// may be another scrollable element in its ancestors. Then, probably we
// shouldn't set overflowDelta even if the event doesn't cause scroll
// actually because the non-zero overflowDelta could cause another action
// such as "back" or "forward" in the history.
nsIntPoint overflow;
aScrollableFrame->ScrollBy(actualDevPixelScrollAmount,
nsIScrollableFrame::DEVICE_PIXELS,
mode, &overflow, origin);
if (isDeltaModePixel) {
if (!scrollFrameWeak.IsAlive()) {
// If the scroll causes changing the layout, we can think that the event
// has been completely consumed by the content. Then, users probably don't
// want additional action.
aEvent->overflowDeltaX = aEvent->overflowDeltaY = 0;
} else if (isDeltaModePixel) {
aEvent->overflowDeltaX = overflow.x;
aEvent->overflowDeltaY = overflow.y;
} else {
@ -2931,19 +2937,30 @@ nsEventStateManager::DoScrollText(nsIScrollableFrame* aScrollableFrame,
// If CSS overflow properties caused not to scroll, the overflowDelta* values
// should be same as delta* values since they may be used as gesture event by
// widget.
if (overflowStyle.mHorizontal == NS_STYLE_OVERFLOW_HIDDEN) {
aEvent->overflowDeltaX = aEvent->deltaX;
}
if (overflowStyle.mVertical == NS_STYLE_OVERFLOW_HIDDEN) {
aEvent->overflowDeltaY = aEvent->deltaY;
// widget. However, if there is another scrollable element in the ancestor
// along the axis, probably users don't want the operation to cause
// additional action such as moving history. In such case, overflowDelta
// values should stay zero.
if (scrollFrameWeak.IsAlive()) {
if (aEvent->deltaX &&
overflowStyle.mHorizontal == NS_STYLE_OVERFLOW_HIDDEN &&
!ComputeScrollTarget(scrollFrame, aEvent,
COMPUTE_SCROLLABLE_ANCESTOR_ALONG_X_AXIS)) {
aEvent->overflowDeltaX = aEvent->deltaX;
}
if (aEvent->deltaY &&
overflowStyle.mVertical == NS_STYLE_OVERFLOW_HIDDEN &&
!ComputeScrollTarget(scrollFrame, aEvent,
COMPUTE_SCROLLABLE_ANCESTOR_ALONG_Y_AXIS)) {
aEvent->overflowDeltaY = aEvent->deltaY;
}
}
NS_ASSERTION(aEvent->overflowDeltaX == 0 ||
(aEvent->overflowDeltaX > 0) == (actualDevPixelScrollAmount.x > 0),
(aEvent->overflowDeltaX > 0) == (aEvent->deltaX > 0),
"The sign of overflowDeltaX is different from the scroll direction");
NS_ASSERTION(aEvent->overflowDeltaY == 0 ||
(aEvent->overflowDeltaY > 0) == (actualDevPixelScrollAmount.y > 0),
(aEvent->overflowDeltaY > 0) == (aEvent->deltaY > 0),
"The sign of overflowDeltaY is different from the scroll direction");
WheelPrefs::GetInstance()->CancelApplyingUserPrefsFromOverflowDelta(aEvent);
@ -3272,7 +3289,8 @@ nsEventStateManager::PostHandleEvent(nsPresContext* aPresContext,
// For scrolling of default action, we should honor the mouse wheel
// transaction.
nsIScrollableFrame* scrollTarget =
ComputeScrollTarget(aTargetFrame, wheelEvent, true);
ComputeScrollTarget(aTargetFrame, wheelEvent,
COMPUTE_DEFAULT_ACTION_TARGET);
wheelEvent->overflowDeltaX = wheelEvent->deltaX;
wheelEvent->overflowDeltaY = wheelEvent->deltaY;
WheelPrefs::GetInstance()->
@ -5171,7 +5189,8 @@ nsEventStateManager::DeltaAccumulator::InitLineOrPageDelta(
// of default action. The transaction should be used only for the default
// action.
nsIScrollableFrame* scrollTarget =
aESM->ComputeScrollTarget(aTargetFrame, aEvent, false);
aESM->ComputeScrollTarget(aTargetFrame, aEvent,
COMPUTE_LEGACY_MOUSE_SCROLL_EVENT_TARGET);
nsIFrame* frame = do_QueryFrame(scrollTarget);
nsPresContext* pc =
frame ? frame->PresContext() : aTargetFrame->PresContext();

View File

@ -468,15 +468,41 @@ protected:
*
* @param aTargetFrame The event target of the wheel event.
* @param aEvent The handling mouse wheel event.
* @param aForDefaultAction Whether this uses wheel transaction or not.
* If true, returns the latest scrolled frame if
* there is it. Otherwise, the nearest ancestor
* scrollable frame from aTargetFrame.
* @param aOptions The options for finding the scroll target.
* Callers should use COMPUTE_*.
* @return The scrollable frame which should be scrolled.
*/
// These flags are used in ComputeScrollTarget(). Callers should use
// COMPUTE_*.
enum
{
PREFER_MOUSE_WHEEL_TRANSACTION = 1,
PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_X_AXIS = 2,
PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_Y_AXIS = 4,
START_FROM_PARENT = 8
};
enum ComputeScrollTargetOptions
{
// At computing scroll target for legacy mouse events, we should return
// first scrollable element even when it's not scrollable to the direction.
COMPUTE_LEGACY_MOUSE_SCROLL_EVENT_TARGET = 0,
// Default action prefers the scrolled element immediately before if it's
// still under the mouse cursor. Otherwise, it prefers the nearest
// scrollable ancestor which will be scrolled actually.
COMPUTE_DEFAULT_ACTION_TARGET =
(PREFER_MOUSE_WHEEL_TRANSACTION |
PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_X_AXIS |
PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_Y_AXIS),
// Look for the nearest scrollable ancestor which can be scrollable with
// aEvent.
COMPUTE_SCROLLABLE_ANCESTOR_ALONG_X_AXIS =
(PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_X_AXIS | START_FROM_PARENT),
COMPUTE_SCROLLABLE_ANCESTOR_ALONG_Y_AXIS =
(PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_Y_AXIS | START_FROM_PARENT)
};
nsIScrollableFrame* ComputeScrollTarget(nsIFrame* aTargetFrame,
mozilla::widget::WheelEvent* aEvent,
bool aForDefaultAction);
ComputeScrollTargetOptions aOptions);
/**
* GetScrollAmount() returns the scroll amount in app uints of one line or