Bug 1501062 - Set the visible region on scrollthumb WebRenderLayerScrollData items. r=botond

This field is used by APZ to implement the feature where the scrollbar snaps
back to the starting position if the mouse gets too far away.
This commit is contained in:
Kartikaya Gupta 2018-10-29 15:40:09 -04:00
Родитель ee8ccacb05
Коммит c277149ab9
5 изменённых файлов: 112 добавлений и 1 удалений

Просмотреть файл

@ -351,6 +351,8 @@ function moveMouseAndScrollWheelOver(element, dx, dy, testDriver, waitForScroll
// processed by the widget code can be detected by listening for the mousemove // processed by the widget code can be detected by listening for the mousemove
// events in the caller, or for some other event that is triggered by the // events in the caller, or for some other event that is triggered by the
// mousemove, such as the scroll event resulting from the scrollbar drag. // mousemove, such as the scroll event resulting from the scrollbar drag.
// Note: helper_scrollbar_snap_bug1501062.html contains a copy of this code
// with modifications. Fixes here should be copied there if appropriate.
function* dragVerticalScrollbar(element, testDriver, distance = 20, increment = 5) { function* dragVerticalScrollbar(element, testDriver, distance = 20, increment = 5) {
var boundingClientRect = element.getBoundingClientRect(); var boundingClientRect = element.getBoundingClientRect();
var verticalScrollbarWidth = boundingClientRect.width - element.clientWidth; var verticalScrollbarWidth = boundingClientRect.width - element.clientWidth;

Просмотреть файл

@ -0,0 +1,99 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width; initial-scale=1.0">
<title>Exercising the slider.snapMultiplier code</title>
<script type="application/javascript" src="apz_test_native_event_utils.js"></script>
<script type="application/javascript" src="apz_test_utils.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/paint_listener.js"></script>
</head>
<body>
<div id="scrollable" style="width: 300px; height: 300px; overflow: auto">
<div id="filler" style="height: 2000px; background-image: linear-gradient(red,blue)"></div>
</div>
</body>
<script type="text/javascript">
function* test(testDriver) {
// Note that this pref is a read-once-on-startup pref so we can't change it
// and have the change take effect. Instead we just use the value to determine
// what the expected behaviour is.
var snapMultiplier = SpecialPowers.getIntPref("slider.snapMultiplier");
// Much of the code below is "inlined" from dragVerticalScrollbar. Reusing
// that code was nontrivial given the modifications we needed to make, and
// would have increased the complexity of that helper function more than I'd
// like. However if any bugfixes are made to that function this code might
// need to be updated as well.
var scrollableDiv = document.getElementById('scrollable');
var boundingClientRect = scrollableDiv.getBoundingClientRect();
var verticalScrollbarWidth = boundingClientRect.width - scrollableDiv.clientWidth;
if (verticalScrollbarWidth == 0) {
ok(true, "No scrollbar, can't do this test");
return;
}
// register a scroll listener for the initial drag
scrollableDiv.addEventListener('scroll', () => setTimeout(testDriver, 0), {once: true});
var upArrowHeight = verticalScrollbarWidth; // assume square scrollbar buttons
var mouseX = scrollableDiv.clientWidth + (verticalScrollbarWidth / 2);
var mouseY = upArrowHeight + 5; // start dragging somewhere in the thumb
dump("Starting drag at " + mouseX + ", " + mouseY + " from top-left of #" + scrollableDiv.id + "\n");
// Move the mouse to the scrollbar thumb and drag it down
yield synthesizeNativeMouseEvent(scrollableDiv, mouseX, mouseY, nativeMouseMoveEventMsg(), testDriver);
yield synthesizeNativeMouseEvent(scrollableDiv, mouseX, mouseY, nativeMouseDownEventMsg(), testDriver);
// drag down by 100 pixels
mouseY += 100;
yield synthesizeNativeMouseEvent(scrollableDiv, mouseX, mouseY, nativeMouseMoveEventMsg(), testDriver);
// wait here until the scroll event listener is triggered.
yield;
var savedScrollPos = scrollableDiv.scrollTop;
ok(savedScrollPos > 0, "Scrolled to " + savedScrollPos);
// register a new scroll event listener. The next mousemove below will either
// trigger the snapback behaviour (if snapMultiplier > 0) or trigger a vertical
// scroll (if snapMultiplier == 0) because of the x- and y-coordinates we move
// the mouse to. This allows us to wait for a scroll event in either case.
// If we only triggered the snapback case then waiting for the scroll to
// "not happen" in the other case would be more error-prone.
scrollableDiv.addEventListener('scroll', () => setTimeout(testDriver, 0), {once: true});
// Add 2 to snapMultipler just to make sure we get far enough away from the scrollbar
var snapBackDistance = (snapMultiplier + 2) * verticalScrollbarWidth;
yield synthesizeNativeMouseEvent(scrollableDiv, mouseX + snapBackDistance, mouseY + 10, nativeMouseMoveEventMsg(), testDriver);
// wait here until the scroll happens
yield;
if (snapMultiplier > 0) {
ok(scrollableDiv.scrollTop == 0, "Scroll position snapped back to " + scrollableDiv.scrollTop);
} else {
ok(scrollableDiv.scrollTop > savedScrollPos, "Scroll position increased to " + scrollableDiv.scrollTop);
}
// Now we move the mouse back to the old position to ensure the scroll position
// gets restored properly
scrollableDiv.addEventListener('scroll', () => setTimeout(testDriver, 0), {once: true});
yield synthesizeNativeMouseEvent(scrollableDiv, mouseX, mouseY, nativeMouseMoveEventMsg(), testDriver);
// wait here until the scroll happens
yield;
ok(scrollableDiv.scrollTop == savedScrollPos, "Scroll position was restored to " + scrollableDiv.scrollTop);
// Release mouse and ensure the scroll position stuck
yield synthesizeNativeMouseEvent(scrollableDiv, mouseX, mouseY, nativeMouseUpEventMsg(), testDriver);
// Flush everything just to be safe
yield flushApzRepaints(testDriver);
ok(scrollableDiv.scrollTop == savedScrollPos, "Final scroll position was " + scrollableDiv.scrollTop);
}
waitUntilApzStable()
.then(runContinuation(test))
.then(subtestDone);
</script>
</html>

Просмотреть файл

@ -25,7 +25,10 @@ var subtests = [
// Test for scrollbar-dragging on a scrollframe inside an SVGEffects // Test for scrollbar-dragging on a scrollframe inside an SVGEffects
{'file': 'helper_bug1331693.html'}, {'file': 'helper_bug1331693.html'},
// Test for scrollbar-dragging on a transformed scrollframe inside a fixed-pos item // Test for scrollbar-dragging on a transformed scrollframe inside a fixed-pos item
{'file': 'helper_bug1462961.html'} {'file': 'helper_bug1462961.html'},
// Scrollbar dragging where we exercise the snapback behaviour by moving the
// mouse away from the scrollbar during drag
{'file': 'helper_scrollbar_snap_bug1501062.html'}
]; ];
if (isApzEnabled()) { if (isApzEnabled()) {

Просмотреть файл

@ -74,6 +74,7 @@ public:
void SetEventRegionsOverride(const EventRegionsOverride& aOverride) { mEventRegionsOverride = aOverride; } void SetEventRegionsOverride(const EventRegionsOverride& aOverride) { mEventRegionsOverride = aOverride; }
EventRegionsOverride GetEventRegionsOverride() const { return mEventRegionsOverride; } EventRegionsOverride GetEventRegionsOverride() const { return mEventRegionsOverride; }
void SetVisibleRegion(const LayerIntRegion& aRegion) { mVisibleRegion = aRegion; }
const LayerIntRegion& GetVisibleRegion() const { return mVisibleRegion; } const LayerIntRegion& GetVisibleRegion() const { return mVisibleRegion; }
void SetReferentId(LayersId aReferentId) { mReferentId = Some(aReferentId); } void SetReferentId(LayersId aReferentId) { mReferentId = Some(aReferentId); }
Maybe<LayersId> GetReferentId() const { return mReferentId; } Maybe<LayersId> GetReferentId() const { return mReferentId; }

Просмотреть файл

@ -7118,6 +7118,12 @@ nsDisplayOwnLayer::UpdateScrollData(
aLayerData->SetScrollbarData(mScrollbarData); aLayerData->SetScrollbarData(mScrollbarData);
if (IsScrollThumbLayer()) { if (IsScrollThumbLayer()) {
aLayerData->SetScrollbarAnimationId(mWrAnimationId); aLayerData->SetScrollbarAnimationId(mWrAnimationId);
LayoutDeviceRect bounds = LayoutDeviceIntRect::FromAppUnits(
mBounds, mFrame->PresContext()->AppUnitsPerDevPixel());
// Assume a resolution of 1.0 for now because this is a WebRender codepath
// and we don't really handle resolution on the Gecko side
LayerIntRect layerBounds = RoundedOut(bounds * LayoutDeviceToLayerScale(1.0f));
aLayerData->SetVisibleRegion(LayerIntRegion(layerBounds));
} }
} }
} }