async function testScrollBehaviorInterruption() {
// Take control of refresh driver
SpecialPowers.DOMWindowUtils.advanceTimeAndRefresh(0);
await promiseApzFlushedRepaints();
window.scrollTo(10, 9);
ok(window.scrollX == 10 && window.scrollY == 9, "instant scroll-behavior must be synchronous when setting initial position");
window.scrollTo(15, 16);
ok(window.scrollX == 15 && window.scrollY == 16, "instant scroll-behavior must be synchronous when setting new position");
window.scrollTo({left: 100, top: 200, behavior: 'smooth'});
ok(window.scrollX == 15 && window.scrollY == 16, "smooth scroll-behavior must be asynchronous");
ok(window.scrollX == 50 && window.scrollY == 52, "smooth scroll-behavior animation must stop after being interrupted");
// Release control of refresh driver
SpecialPowers.DOMWindowUtils.restoreNormalRefresh();
await promiseApzFlushedRepaints();
}
async function testScrollBehaviorFramerate() {
/**
* CSSOM-View scroll-behavior smooth scroll animations must produce the
* same results indendently of frame-rate:
*
* - Reference samples of scroll position for each frame are captured from
* a smooth scroll at 120fps for variations in X-Distance, Y-Distance.
* - Test samples are captured from an animation with the same parameters
* at varying framerates.
* - Variance in position at each sampled interval is compared to the
* 120fps reference. To pass the test, the position of each test
* sample must match the reference position with a tolerance of one test
* sample frame's range of motion. This range of motion is calculated
* by the position delta of the reference samples one test frame duration
* before and after.
* - The duration of the reference sample animation and the test sample
* animation must match within 1 frame to pass the test.
* - The simulation driving the animation must converge and stop on the
* destination position for the test to pass.
*/
// Use 120hz for reference samples var referenceFrameRate = 120;
for (var deltaIndex = 0; deltaIndex < deltas.length; deltaIndex++) { var deltaX = deltas[deltaIndex].x; var deltaY = deltas[deltaIndex].y;
// startX and startY must be at least as big as the greatest negative
// number in the deltas array in order to prevent the animation from
// being interrupted by scroll range boundaries. var startX = 1000; var startY = 1000; var endX = startX + deltaX; var endY = startY + deltaY; var referenceTimeStep = Math.floor(1000 / referenceFrameRate);
let refSamples = await sampleAnimation(startX, startY, endX, endY,
referenceTimeStep);
var referenceDuration = refSamples.length * referenceTimeStep; // ms
for (var frameRateIndex = 0; frameRateIndex < frameRates.length; frameRateIndex++) { var frameRate = frameRates[frameRateIndex];
var testTimeStep = Math.floor(1000 / frameRate);
let testSamples = await sampleAnimation(startX, startY, endX, endY,
testTimeStep); var testDuration = testSamples.length * testTimeStep; // ms
// Variance in duration of animation must be accurate to within one
// frame interval var durationVariance = Math.max(0, Math.abs(testDuration - referenceDuration) - testTimeStep);
is(durationVariance, 0, 'Smooth scroll animation duration must not '
+ 'be framerate dependent at deltaX: ' + deltaX + ', deltaY: '
+ deltaY + ', frameRate: ' + frameRate + 'fps');
var maxVariance = 0;
testSamples.forEach(function(sample, sampleIndex) {
var testToRef = refSamples.length / testSamples.length; var refIndexThisFrame = clamp(Math.floor(sampleIndex * testToRef),
0, refSamples.length - 1); var refIndexPrevFrame = clamp(Math.floor((sampleIndex - 1) * testToRef),
0, refSamples.length - 1); var refIndexNextFrame = clamp(Math.floor((sampleIndex + 1) * testToRef),
0, refSamples.length - 1);
var refSampleThisFrame = refSamples[refIndexThisFrame]; var refSamplePrevFrame = refSamples[refIndexPrevFrame]; var refSampleNextFrame = refSamples[refIndexNextFrame];
var refXMin = Math.min(refSamplePrevFrame[0],
refSampleThisFrame[0],
refSampleNextFrame[0]);
var refYMin = Math.min(refSamplePrevFrame[1],
refSampleThisFrame[1],
refSampleNextFrame[1]);
var refXMax = Math.max(refSamplePrevFrame[0],
refSampleThisFrame[0],
refSampleNextFrame[0]);
var refYMax = Math.max(refSamplePrevFrame[1],
refSampleThisFrame[1],
refSampleNextFrame[1]);
// Varience is expected to be at most 1 pixel beyond the range,
// due to integer rounding of pixel position. var positionTolerance = 1; // 1 pixel
is(maxVariance, 0, 'Smooth scroll animated position must not be '
+ 'framerate dependent at deltaX: ' + deltaX + ', deltaY: '
+ deltaY + ', frameRate: ' + frameRate + 'fps');
}
await promiseApzFlushedRepaints();
}
}
async function sampleAnimation(startX, startY, endX, endY, timeStep) {
// The animation must be stopped at the destination position for
// minStoppedFrames consecutive frames to detect that the animation has
// completed. var minStoppedFrames = 15; // 15 frames
// In case the simulation fails to converge, the test will time out after
// processing maxTime milliseconds of animation. var maxTime = 10000; // 10 seconds
var positionSamples = [];
var frameCountAtDestination = 0;
// Take control of refresh driver so we can synthesize
// various frame rates
SpecialPowers.DOMWindowUtils.advanceTimeAndRefresh(0);
await promiseApzFlushedRepaints();
isnot(frameCountAtDestination, 0, 'Smooth scrolls must always end at their destination '
+ 'unless they are interrupted, at deltaX: '
+ (endX - startX) + ', deltaY: ' + (endY - startY));
window.scrollTo(0, 0);
// Release control of refresh driver
SpecialPowers.DOMWindowUtils.restoreNormalRefresh();
await promiseApzFlushedRepaints();
// We must not include the duplicated frames at the animation
// destination as the tests are dependant on the total duration of
// the animation to be accurate.
positionSamples.splice(1 - minStoppedFrames,
minStoppedFrames - 1);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.