"use strict"; Services.scriptloader.loadSubScript( "chrome://mochitests/content/browser/gfx/layers/apz/test/mochitest/apz_test_utils.js", this ); Services.scriptloader.loadSubScript( "chrome://mochitests/content/browser/gfx/layers/apz/test/mochitest/apz_test_native_event_utils.js", this ); Services.scriptloader.loadSubScript( "chrome://mochikit/content/tests/SimpleTest/WindowSnapshot.js", this ); // usesFailurePatterns is defined in SimpleTest.js and used in // WindowSnapshot.js but SimpleTest.js can't be loaded in browser mochitests // (there's an equivalent script named browser-test.js for browser mochitests), // so we define usesFailurePatterns which just returns false to make functions // in WindowSnapshot.js work without loading SimpleTest.js. function usesFailurePatterns() { return false; } async function convertDataURLtoCanvas(aDataURL, aWidth, aHeight) { const canvas = document.createElementNS( "http://www.w3.org/1999/xhtml", "canvas" ); canvas.width = aWidth; canvas.height = aHeight; const image = new Image(); const ctx = canvas.getContext("2d"); const loadPromise = new Promise(resolve => image.addEventListener("load", resolve) ); image.src = aDataURL; await loadPromise; ctx.drawImage(image, 0, 0); return canvas; } add_task(async () => { function httpURL(filename) { let chromeURL = getRootDirectory(gTestPath) + filename; return chromeURL.replace( "chrome://mochitests/content/", "http://mochi.test:8888/" ); } const url = httpURL("helper_position_sticky_flicker.html"); const tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, url); const { rect, scrollbarWidth } = await SpecialPowers.spawn( tab.linkedBrowser, [], async () => { const sticky = content.document.getElementById("sticky"); // Get the area in the screen coords where the position:sticky element is. let stickyRect = sticky.getBoundingClientRect(); stickyRect.x += content.window.mozInnerScreenX; stickyRect.y += content.window.mozInnerScreenY; // generate some DIVs to make the page complex enough. for (let i = 1; i <= 120000; i++) { const div = content.document.createElement("div"); div.innerText = `${i}`; content.document.body.appendChild(div); } await content.wrappedJSObject.promiseApzFlushedRepaints(); await content.wrappedJSObject.waitUntilApzStable(); let w = {}, h = {}; SpecialPowers.DOMWindowUtils.getScrollbarSizes( content.document.documentElement, w, h ); // Reduce the scrollbar width from the sticky area. stickyRect.width -= w.value; return { rect: stickyRect, scrollbarWidth: w.value, }; } ); // Take a snapshot where the position:sticky element is initially painted. const referenceDataURL = await getSnapshot(rect); const referenceCanvas = await convertDataURLtoCanvas( referenceDataURL, rect.width, rect.height ); let mouseX = window.innerWidth - scrollbarWidth / 2; let mouseY = tab.linkedBrowser.getBoundingClientRect().y + 5; // Scroll fast to cause checkerboarding multiple times. const dragFinisher = await promiseNativeMouseDrag( window, mouseX, mouseY, 0, window.innerHeight, 100 ); // On debug builds there seems to be no chance that the content process gets // painted during above promiseNativeMouseDrag call, wait two frames to make // sure it happens so that this test is likely able to fail without proper // fix. if (AppConstants.DEBUG) { await SpecialPowers.spawn(tab.linkedBrowser, [], async () => { await content.wrappedJSObject.promiseFrame(content.window); await content.wrappedJSObject.promiseFrame(content.window); }); } // Take a snapshot again where the position:sticky element should be painted. const snapshotDataURL = await getSnapshot(rect); const snapshotCanvas = await convertDataURLtoCanvas( snapshotDataURL, rect.width, rect.height ); await dragFinisher(); const disablePixelAlignment = SpecialPowers.getBoolPref( "layout.disable-pixel-alignment" ); // With disabling pixel alignment, there appears 1px line glitch at the top of // the image, we allow it. const fuzz = disablePixelAlignment ? { maxDifference: 1, numDifferentPixels: rect.width } : null; assertSnapshots( snapshotCanvas, referenceCanvas, true /* expectEqual */, fuzz, "test case", "reference" ); BrowserTestUtils.removeTab(tab); });