browser_bug1701027-1.js (5934B)
1 /* This test is based on 2 https://searchfox.org/mozilla-central/rev/e082df56bbfeaff0f388e7da9da401ff414df18f/gfx/layers/apz/test/mochitest/browser_test_select_zoom.js 3 */ 4 5 // In order for this test to test the original bug we need: 6 // 1) At least e10s enabled so that apz is enabled so we can create an 7 // nsDisplayAsyncZoom item 8 // (the insertion of this item without marking the required frame modified 9 // is what causes the bug in the retained display list merging) 10 // 2) a root content document, again so that we can create a nsDisplayAsyncZoom 11 // item 12 // 3) the root content document cannot have a display port to start 13 // (if it has a display port then it gets a nsDisplayAsyncZoom, but we need 14 // that to be created after the anonymous content we insert into the 15 // document) 16 // Point 3) requires the root content document to be in the parent process, 17 // since if it is in a content process it will get a displayport for being at 18 // the root of a process. 19 // Creating an in-process root content document I think is not possible in 20 // mochitest-plain. mochitest-chrome does not have e10s enabled. So this has to 21 // be a mochitest-browser-chrome test. 22 23 // Outline of this test: 24 // Open a new tab with a pretty simple content file, that is not scrollable 25 // Use the anonymous content api to insert into that content doc 26 // Send a mouse click over the content doc 27 // The click hits fixed pos content. 28 // This sets a displayport on the root scroll frame of the content doc. 29 // (This is because we call GetAsyncScrollableAncestorFrame in 30 // PrepareForSetTargetAPZCNotification 31 // https://searchfox.org/mozilla-central/rev/e082df56bbfeaff0f388e7da9da401ff414df18f/gfx/layers/apz/util/APZCCallbackHelper.cpp#624 32 // which passes the SCROLLABLE_FIXEDPOS_FINDS_ROOT flag 33 // https://searchfox.org/mozilla-central/rev/e082df56bbfeaff0f388e7da9da401ff414df18f/layout/base/nsLayoutUtils.cpp#2884 34 // so starting from fixed pos content means we always find the root scroll 35 // frame, whereas if we started from non-fixed content we'd walk pass the root 36 // scroll frame becase it isn't scrollable.) 37 // Then we have to be careful not to do anything that causes a full display 38 // list rebuild. 39 // And finally we change the color of the fixed element which covers the whole 40 // viewport which causes us to do a partial display list update including the 41 // anonymous content, which hits the assert we are aiming to test. 42 43 add_task(async function () { 44 function getChromeURL(filename) { 45 let chromeURL = getRootDirectory(gTestPath) + filename; 46 return chromeURL; 47 } 48 49 // We need this otherwise there is a burst animation on the new tab when it 50 // loads and that somehow scrolls a scroll frame, which makes it active, 51 // which makes the scrolled frame an AGR, which means we have multiple AGRs 52 // (the display port makes the root scroll frame active and an AGR) so we hit 53 // this 54 // https://searchfox.org/mozilla-central/rev/e082df56bbfeaff0f388e7da9da401ff414df18f/layout/painting/RetainedDisplayListBuilder.cpp#1179 55 // and are forced to do a full display list rebuild and that prevents us from 56 // testing the original bug. 57 await SpecialPowers.pushPrefEnv({ 58 set: [["ui.prefersReducedMotion", 1]], 59 }); 60 61 const pageUrl = getChromeURL("helper_bug1701027-1.html"); 62 let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, pageUrl); 63 64 const [theX, theY] = await SpecialPowers.spawn( 65 tab.linkedBrowser, 66 [], 67 async () => { 68 content.document.body.offsetWidth; 69 70 await new Promise(r => content.window.requestAnimationFrame(r)); 71 72 const rect = content.document 73 .getElementById("fd") 74 .getBoundingClientRect(); 75 const x = content.window.mozInnerScreenX + rect.left + rect.width / 2; 76 const y = content.window.mozInnerScreenY + rect.top + rect.height / 2; 77 78 let doc = SpecialPowers.wrap(content.document); 79 var bq = doc.createElement("blockquote"); 80 bq.textContent = "This blockquote text."; 81 var div = doc.createElement("div"); 82 div.textContent = " This div text."; 83 bq.appendChild(div); 84 var ac = doc.insertAnonymousContent(bq); 85 content.document.body.offsetWidth; 86 87 await new Promise(r => content.window.requestAnimationFrame(r)); 88 await new Promise(r => content.window.requestAnimationFrame(r)); 89 90 return [x, y]; 91 } 92 ); 93 94 // We intentionally turn off a11y_checks, because the following click 95 // is targeting test content that's not meant to be interactive and 96 // is not expected to be accessible: 97 AccessibilityUtils.setEnv({ 98 mustHaveAccessibleRule: false, 99 }); 100 EventUtils.synthesizeNativeMouseEvent({ 101 type: "click", 102 target: window.document.documentElement, 103 screenX: theX, 104 screenY: theY, 105 }); 106 107 await new Promise(resolve => setTimeout(resolve, 0)); 108 await SpecialPowers.spawn(tab.linkedBrowser, [], async () => { 109 await new Promise(r => content.window.requestAnimationFrame(r)); 110 await new Promise(r => content.window.requestAnimationFrame(r)); 111 }); 112 113 await SpecialPowers.spawn(tab.linkedBrowser, [], async () => { 114 content.document.getElementById("fd").style.backgroundColor = "blue"; 115 }); 116 117 await new Promise(resolve => setTimeout(resolve, 0)); 118 await SpecialPowers.spawn(tab.linkedBrowser, [], async () => { 119 await new Promise(r => content.window.requestAnimationFrame(r)); 120 await new Promise(r => content.window.requestAnimationFrame(r)); 121 }); 122 123 await SpecialPowers.spawn(tab.linkedBrowser, [], async () => { 124 content.document.getElementById("fd").style.backgroundColor = "red"; 125 }); 126 127 await new Promise(resolve => setTimeout(resolve, 0)); 128 await SpecialPowers.spawn(tab.linkedBrowser, [], async () => { 129 await new Promise(r => content.window.requestAnimationFrame(r)); 130 await new Promise(r => content.window.requestAnimationFrame(r)); 131 }); 132 133 BrowserTestUtils.removeTab(tab); 134 135 ok(true, "didn't crash"); 136 });