child-document-raf-order.html (4609B)
1 <!DOCTYPE HTML> 2 <meta charset=UTF-8> 3 <title>Ordering of steps in "Update the Rendering" - child document requestAnimationFrame order</title> 4 <link rel="help" href="https://html.spec.whatwg.org/multipage/webappapis.html#update-the-rendering"> 5 <link rel="author" title="L. David Baron" href="https://dbaron.org/"> 6 <link rel="author" title="Mozilla" href="https://mozilla.org/"> 7 <script src="/resources/testharness.js"></script> 8 <script src="/resources/testharnessreport.js"></script> 9 10 <div id=log></div> 11 12 <!-- 13 14 This test tests the interaction of just two substeps of the "Update the 15 rendering" steps in 16 https://html.spec.whatwg.org/multipage/webappapis.html#update-the-rendering 17 18 These are: 19 20 1. Let docs be the list of Document objects associated with the event 21 loop in question, sorted arbitrarily except that the following 22 conditions must be met: 23 24 - Any Document B that is nested through a Document A must be listed 25 after A in the list. 26 27 - If there are two documents A and B whose browsing contexts are 28 both nested browsing contexts and their browsing context 29 containers are both elements in the same Document C, then the 30 order of A and B in the list must match the relative tree order of 31 their respective browsing context containers in C. 32 33 In the steps below that iterate over docs, each Document must be 34 processed in the order it is found in the list. 35 36 and later: 37 38 10. For each fully active Document in docs, run the animation frame 39 callbacks for that Document, passing in now as the timestamp. 40 41 42 It tests this by setting up a tree of three documents, two children and 43 one parent, and testing for the relative order of the animation frame 44 callbacks for each. 45 46 --> 47 48 <script> 49 50 // Split array into chunks of len. 51 function chunk (arr, len) { 52 var chunks = [], 53 i = 0, 54 n = arr.length; 55 while (i < n) { 56 chunks.push(arr.slice(i, i += len)); 57 } 58 return chunks; 59 } 60 61 async_test(function (t) { 62 step_timeout(setup, 0); 63 64 let first_frame, second_frame; 65 66 let notification_sequence = []; 67 68 function setup() { 69 // Start by creating two iframes. To test (a little bit) the rule 70 // about iteration being in document order, insert them in the reverse 71 // order of creation. 72 let body = document.body; 73 function make_iframe() { 74 let iframe = document.createElement("iframe"); 75 iframe.setAttribute("srcdoc", "<body onload='parent.child_ready()'>"); 76 iframe.setAttribute("width", "30"); 77 iframe.setAttribute("height", "15"); 78 return iframe; 79 } 80 second_frame = make_iframe(); 81 body.prepend(second_frame); 82 first_frame = make_iframe(); 83 body.prepend(first_frame); 84 85 let children_waiting = 2; 86 window.child_ready = function() { 87 if (--children_waiting == 0) { 88 // Call requestAnimationFrame in neither the order nor the reverse 89 // of the order in which we expect to be called (which is parent, 90 // first, second). 91 first_frame.contentWindow.requestAnimationFrame(first_child_raf); 92 second_frame.contentWindow.requestAnimationFrame(second_child_raf); 93 window.requestAnimationFrame(parent_raf); 94 } 95 }; 96 } 97 98 let parent_raf = t.step_func(function() { 99 notification_sequence.push("parent_raf"); 100 101 // Request another notification to help ensure we're getting expected behavior. 102 window.requestAnimationFrame(parent_raf); 103 }); 104 105 let first_child_raf = t.step_func(function() { 106 notification_sequence.push("first_child_raf"); 107 108 // Request another notification to help ensure we're getting expected behavior. 109 first_frame.contentWindow.requestAnimationFrame(first_child_raf); 110 }); 111 112 let second_child_raf = t.step_func(function() { 113 notification_sequence.push("second_child_raf"); 114 115 // Request another notification to help ensure we're getting expected behavior. 116 second_frame.contentWindow.requestAnimationFrame(second_child_raf); 117 118 step_timeout(finish, 0); 119 }); 120 121 let finish = t.step_func(function() { 122 123 // The test requests rafs recursively, 124 // but since all three rafs run as part of the same "update the rendering" task, 125 // they should always come in a triplet. 126 assert_equals(notification_sequence.length % 3, 0); 127 128 let chunks = chunk(notification_sequence, 3); 129 for (var i = 0; i < chunks.length; i++) { 130 // Assert correct ordering per triplet of rafs. 131 assert_array_equals(chunks[i], 132 ["parent_raf", "first_child_raf", "second_child_raf"], 133 "expected order of notifications"); 134 } 135 136 t.done(); 137 }); 138 }); 139 140 </script>