Bug 801101 Allow to scoll over one page scroll with mouse wheel if delta mulitipliers are large enough r=smaug

This commit is contained in:
Masayuki Nakano 2012-10-31 08:22:23 +09:00
parent e33e735f92
commit 4b818b7598
3 changed files with 305 additions and 6 deletions

View File

@ -2886,17 +2886,20 @@ nsEventStateManager::DoScrollText(nsIScrollableFrame* aScrollableFrame,
return;
}
// We shouldn't scroll more one page at once.
// We shouldn't scroll more one page at once except when over one page scroll
// is allowed for the event.
nsSize pageSize = aScrollableFrame->GetPageScrollAmount();
nsIntSize devPixelPageSize(pc->AppUnitsToDevPixels(pageSize.width),
pc->AppUnitsToDevPixels(pageSize.height));
if (NS_ABS(actualDevPixelScrollAmount.x) > devPixelPageSize.width) {
if (!WheelPrefs::GetInstance()->IsOverOnePageScrollAllowedX(aEvent) &&
NS_ABS(actualDevPixelScrollAmount.x) > devPixelPageSize.width) {
actualDevPixelScrollAmount.x =
(actualDevPixelScrollAmount.x >= 0) ? devPixelPageSize.width :
-devPixelPageSize.width;
}
if (NS_ABS(actualDevPixelScrollAmount.y) > devPixelPageSize.height) {
if (!WheelPrefs::GetInstance()->IsOverOnePageScrollAllowedY(aEvent) &&
NS_ABS(actualDevPixelScrollAmount.y) > devPixelPageSize.height) {
actualDevPixelScrollAmount.y =
(actualDevPixelScrollAmount.y >= 0) ? devPixelPageSize.height :
-devPixelPageSize.height;
@ -5543,3 +5546,23 @@ nsEventStateManager::WheelPrefs::NeedToComputeLineOrPageDelta(
return (mMultiplierX[index] != 1.0 && mMultiplierX[index] != -1.0) ||
(mMultiplierY[index] != 1.0 && mMultiplierY[index] != -1.0);
}
bool
nsEventStateManager::WheelPrefs::IsOverOnePageScrollAllowedX(
widget::WheelEvent* aEvent)
{
Index index = GetIndexFor(aEvent);
Init(index);
return NS_ABS(mMultiplierX[index]) >=
MIN_MULTIPLIER_VALUE_ALLOWING_OVER_ONE_PAGE_SCROLL;
}
bool
nsEventStateManager::WheelPrefs::IsOverOnePageScrollAllowedY(
widget::WheelEvent* aEvent)
{
Index index = GetIndexFor(aEvent);
Init(index);
return NS_ABS(mMultiplierY[index]) >=
MIN_MULTIPLIER_VALUE_ALLOWING_OVER_ONE_PAGE_SCROLL;
}

View File

@ -368,6 +368,13 @@ protected:
*/
bool NeedToComputeLineOrPageDelta(mozilla::widget::WheelEvent* aEvent);
/**
* IsOverOnePageScrollAllowed*() checks whether wheel scroll amount should
* be rounded down to the page width/height (false) or not (true).
*/
bool IsOverOnePageScrollAllowedX(mozilla::widget::WheelEvent* aEvent);
bool IsOverOnePageScrollAllowedY(mozilla::widget::WheelEvent* aEvent);
private:
WheelPrefs();
~WheelPrefs();
@ -409,6 +416,15 @@ protected:
void Reset();
/**
* If the abosolute values of mMultiplierX and/or mMultiplierY are equals or
* larger than this value, the computed scroll amount isn't rounded down to
* the page width or height.
*/
enum {
MIN_MULTIPLIER_VALUE_ALLOWING_OVER_ONE_PAGE_SCROLL = 1000
};
bool mInit[COUNT_OF_MULTIPLIERS];
double mMultiplierX[COUNT_OF_MULTIPLIERS];
double mMultiplierY[COUNT_OF_MULTIPLIERS];

View File

@ -1135,7 +1135,7 @@ function doTestZoom(aSettings, aCallback)
doNextTest();
}
function doTestZoomedScroll()
function doTestZoomedScroll(aCallback)
{
function testZoomedPixelScroll()
{
@ -1262,6 +1262,8 @@ function doTestZoomedScroll()
window.removeEventListener("MozMousePixelScroll", handler, true);
synthesizeKey("0", { accelKey: true });
SimpleTest.executeSoon(aCallback);
}, 20);
}, 20);
}, 20);
@ -1274,6 +1276,261 @@ function doTestZoomedScroll()
testZoomedPixelScroll();
}
function doTestWholeScroll(aCallback)
{
SpecialPowers.setIntPref("mousewheel.default.delta_multiplier_x", 99999999);
SpecialPowers.setIntPref("mousewheel.default.delta_multiplier_y", 99999999);
const kTests = [
{ description: "try whole-scroll to top (line)",
prepare: function () {
gScrollableElement.scrollTop = 1000;
gScrollableElement.scrollLeft = 1000;
},
event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
deltaX: 0.0, deltaY: -1.0,
lineOrPageDeltaX: 0, lineOrPageDeltaY: -1 },
expectedScrollTop: 0,
expectedScrollLeft: 1000
},
{ description: "try whole-scroll to top when scrollTop is already top-most (line)",
event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
deltaX: 0.0, deltaY: -1.0,
lineOrPageDeltaX: 0, lineOrPageDeltaY: -1 },
expectedScrollTop: 0,
expectedScrollLeft: 1000
},
{ description: "try whole-scroll to bottom (line)",
prepare: function () {
gScrollableElement.scrollTop = 1000;
gScrollableElement.scrollLeft = 1000;
},
event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
deltaX: 0.0, deltaY: 1.0,
lineOrPageDeltaX: 0, lineOrPageDeltaY: 1 },
expectedScrollTop: gScrollableElement.scrollTopMax,
expectedScrollLeft: 1000
},
{ description: "try whole-scroll to bottom when scrollTop is already bottom-most (line)",
event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
deltaX: 0, deltaY: 1.0,
lineOrPageDeltaX: 0, lineOrPageDeltaY: 1 },
expectedScrollTop: gScrollableElement.scrollTopMax,
expectedScrollLeft: 1000
},
{ description: "try whole-scroll to left (line)",
prepare: function () {
gScrollableElement.scrollTop = 1000;
gScrollableElement.scrollLeft = 1000;
},
event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
deltaX: -1.0, deltaY: 0.0,
lineOrPageDeltaX: -1, lineOrPageDeltaY: 0 },
expectedScrollTop: 1000,
expectedScrollLeft: 0
},
{ description: "try whole-scroll to left when scrollLeft is already left-most (line)",
event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
deltaX: -1.0, deltaY: 0,
lineOrPageDeltaX: -1, lineOrPageDeltaY: 0 },
expectedScrollTop: 1000,
expectedScrollLeft: 0
},
{ description: "try whole-scroll to right (line)",
prepare: function () {
gScrollableElement.scrollTop = 1000;
gScrollableElement.scrollLeft = 1000;
},
event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
deltaX: 1.0, deltaY: 0.0,
lineOrPageDeltaX: 1, lineOrPageDeltaY: 0 },
expectedScrollTop: 1000,
expectedScrollLeft: gScrollableElement.scrollLeftMax
},
{ description: "try whole-scroll to right when scrollLeft is already right-most (line)",
event: { deltaMode: WheelEvent.DOM_DELTA_LINE,
deltaX: 1.0, deltaY: 0.0,
lineOrPageDeltaX: 1, lineOrPageDeltaY: 0 },
expectedScrollTop: 1000,
expectedScrollLeft: gScrollableElement.scrollLeftMax
},
{ description: "try whole-scroll to top (pixel)",
prepare: function () {
gScrollableElement.scrollTop = 1000;
gScrollableElement.scrollLeft = 1000;
},
event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
deltaX: 0.0, deltaY: -1.0,
lineOrPageDeltaX: 0, lineOrPageDeltaY: 0 },
expectedScrollTop: 0,
expectedScrollLeft: 1000
},
{ description: "try whole-scroll to top when scrollTop is already top-most (pixel)",
event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
deltaX: 0.0, deltaY: -1.0,
lineOrPageDeltaX: 0, lineOrPageDeltaY: 0 },
expectedScrollTop: 0,
expectedScrollLeft: 1000
},
{ description: "try whole-scroll to bottom (pixel)",
prepare: function () {
gScrollableElement.scrollTop = 1000;
gScrollableElement.scrollLeft = 1000;
},
event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
deltaX: 0.0, deltaY: 1.0,
lineOrPageDeltaX: 0, lineOrPageDeltaY: 0 },
expectedScrollTop: gScrollableElement.scrollTopMax,
expectedScrollLeft: 1000
},
{ description: "try whole-scroll to bottom when scrollTop is already bottom-most (pixel)",
event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
deltaX: 0, deltaY: 1.0,
lineOrPageDeltaX: 0, lineOrPageDeltaY: 0 },
expectedScrollTop: gScrollableElement.scrollTopMax,
expectedScrollLeft: 1000
},
{ description: "try whole-scroll to left (pixel)",
prepare: function () {
gScrollableElement.scrollTop = 1000;
gScrollableElement.scrollLeft = 1000;
},
event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
deltaX: -1.0, deltaY: 0.0,
lineOrPageDeltaX: 0, lineOrPageDeltaY: 0 },
expectedScrollTop: 1000,
expectedScrollLeft: 0
},
{ description: "try whole-scroll to left when scrollLeft is already left-most (pixel)",
event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
deltaX: -1.0, deltaY: 0,
lineOrPageDeltaX: 0, lineOrPageDeltaY: 0 },
expectedScrollTop: 1000,
expectedScrollLeft: 0
},
{ description: "try whole-scroll to right (pixel)",
prepare: function () {
gScrollableElement.scrollTop = 1000;
gScrollableElement.scrollLeft = 1000;
},
event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
deltaX: 1.0, deltaY: 0.0,
lineOrPageDeltaX: 0, lineOrPageDeltaY: 0 },
expectedScrollTop: 1000,
expectedScrollLeft: gScrollableElement.scrollLeftMax
},
{ description: "try whole-scroll to right when scrollLeft is already right-most (pixel)",
event: { deltaMode: WheelEvent.DOM_DELTA_PIXEL,
deltaX: 1.0, deltaY: 0.0,
lineOrPageDeltaX: 0, lineOrPageDeltaY: 0 },
expectedScrollTop: 1000,
expectedScrollLeft: gScrollableElement.scrollLeftMax
},
{ description: "try whole-scroll to top (page)",
prepare: function () {
gScrollableElement.scrollTop = 1000;
gScrollableElement.scrollLeft = 1000;
},
event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
deltaX: 0.0, deltaY: -1.0,
lineOrPageDeltaX: 0, lineOrPageDeltaY: -1 },
expectedScrollTop: 0,
expectedScrollLeft: 1000
},
{ description: "try whole-scroll to top when scrollTop is already top-most (page)",
event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
deltaX: 0.0, deltaY: -1.0,
lineOrPageDeltaX: 0, lineOrPageDeltaY: -1 },
expectedScrollTop: 0,
expectedScrollLeft: 1000
},
{ description: "try whole-scroll to bottom (page)",
prepare: function () {
gScrollableElement.scrollTop = 1000;
gScrollableElement.scrollLeft = 1000;
},
event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
deltaX: 0.0, deltaY: 1.0,
lineOrPageDeltaX: 0, lineOrPageDeltaY: 1 },
expectedScrollTop: gScrollableElement.scrollTopMax,
expectedScrollLeft: 1000
},
{ description: "try whole-scroll to bottom when scrollTop is already bottom-most (page)",
event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
deltaX: 0, deltaY: 1.0,
lineOrPageDeltaX: 0, lineOrPageDeltaY: 1 },
expectedScrollTop: gScrollableElement.scrollTopMax,
expectedScrollLeft: 1000
},
{ description: "try whole-scroll to left (page)",
prepare: function () {
gScrollableElement.scrollTop = 1000;
gScrollableElement.scrollLeft = 1000;
},
event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
deltaX: -1.0, deltaY: 0.0,
lineOrPageDeltaX: -1, lineOrPageDeltaY: 0 },
expectedScrollTop: 1000,
expectedScrollLeft: 0
},
{ description: "try whole-scroll to left when scrollLeft is already left-most (page)",
event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
deltaX: -1.0, deltaY: 0,
lineOrPageDeltaX: -1, lineOrPageDeltaY: 0 },
expectedScrollTop: 1000,
expectedScrollLeft: 0
},
{ description: "try whole-scroll to right (page)",
prepare: function () {
gScrollableElement.scrollTop = 1000;
gScrollableElement.scrollLeft = 1000;
},
event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
deltaX: 1.0, deltaY: 0.0,
lineOrPageDeltaX: 1, lineOrPageDeltaY: 0 },
expectedScrollTop: 1000,
expectedScrollLeft: gScrollableElement.scrollLeftMax
},
{ description: "try whole-scroll to right when scrollLeft is already right-most (page)",
event: { deltaMode: WheelEvent.DOM_DELTA_PAGE,
deltaX: 1.0, deltaY: 0.0,
lineOrPageDeltaX: 1, lineOrPageDeltaY: 0 },
expectedScrollTop: 1000,
expectedScrollLeft: gScrollableElement.scrollLeftMax
},
];
var index = 0;
function doIt()
{
const kTest = kTests[index];
if (kTest.prepare) {
kTest.prepare();
}
synthesizeWheel(gScrollableElement, 10, 10, kTest.event);
hitEventLoop(function () {
is(gScrollableElement.scrollTop, kTest.expectedScrollTop,
"doTestWholeScroll, " + kTest.description + ": unexpected scrollTop");
is(gScrollableElement.scrollLeft, kTest.expectedScrollLeft,
"doTestWholeScroll, " + kTest.description + ": unexpected scrollLeft");
if (++index == kTests.length) {
SpecialPowers.clearUserPref("mousewheel.default.delta_multiplier_x");
SpecialPowers.clearUserPref("mousewheel.default.delta_multiplier_y");
SpecialPowers.clearUserPref("mousewheel.default.delta_multiplier_z");
SimpleTest.executeSoon(aCallback);
} else {
doIt();
}
}, 20);
}
doIt();
}
function runTests()
{
SpecialPowers.setBoolPref("general.smoothScroll", false);
@ -1313,8 +1570,11 @@ function runTests()
doTestZoom(kSettings[index], function() {
if (++index == kSettings.length) {
setDeltaMultiplierSettings(kSettings[0]);
doTestZoomedScroll();
finishTests();
doTestZoomedScroll(function() {
doTestWholeScroll(function() {
finishTests();
});
});
} else {
doTest();
}