Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Asynchronous tests should manually call finishRepaintTest at the appropriate | 1 // Asynchronous tests should manually call finishRepaintTest at the appropriate |
| 2 // time. | 2 // time. |
| 3 window.testIsAsync = false; | 3 window.testIsAsync = false; |
| 4 window.outputRepaintRects = true; | 4 window.outputRepaintRects = true; |
| 5 window.generateMinimumRepaint = true; // See comments about 'Minimum repaint' be low. | |
|
enne (OOO)
2014/06/06 19:55:16
Default to false?
Xianzhu
2014/06/07 05:23:06
Sorry, I uploaded the version for local testing th
| |
| 5 | 6 |
| 6 function runRepaintTest() | 7 function runRepaintTest() |
| 7 { | 8 { |
| 8 if (!window.testRunner || !window.internals) { | 9 if (!window.testRunner || !window.internals) { |
| 9 setTimeout(repaintTest, 500); | 10 setTimeout(repaintTest, 500); |
| 10 return; | 11 return; |
| 11 } | 12 } |
| 12 | 13 |
| 13 // TODO(enne): this is a workaround for multiple svg onload events. | 14 // TODO(enne): this is a workaround for multiple svg onload events. |
| 14 // See: http://crbug.com/372946 | 15 // See: http://crbug.com/372946 |
| 15 if (window.hasRunRepaintTest) | 16 if (window.hasRunRepaintTest) |
| 16 return; | 17 return; |
| 17 window.hasRunRepaintTest = true; | 18 window.hasRunRepaintTest = true; |
| 18 | 19 |
| 19 if (window.enablePixelTesting) | 20 if (window.enablePixelTesting) |
| 20 testRunner.dumpAsTextWithPixelResults(); | 21 testRunner.dumpAsTextWithPixelResults(); |
| 21 else | 22 else |
| 22 testRunner.dumpAsText(); | 23 testRunner.dumpAsText(); |
| 23 | 24 |
| 24 // All repaint tests are asynchronous. | 25 // All repaint tests are asynchronous. |
| 25 testRunner.waitUntilDone(); | 26 testRunner.waitUntilDone(); |
| 26 | 27 |
| 27 testRunner.displayAsyncThen(function() { | 28 function continueRepaintTest() |
| 29 { | |
| 28 window.internals.startTrackingRepaints(document); | 30 window.internals.startTrackingRepaints(document); |
| 29 repaintTest(); | 31 repaintTest(); |
| 30 if (!window.testIsAsync) | 32 if (!window.testIsAsync) |
| 31 finishRepaintTest(); | 33 finishRepaintTest(); |
| 32 }); | 34 } |
| 35 | |
| 36 if (window.generateMinimumRepaint) { | |
| 37 testRunner.capturePixelsAsyncThen(function(width, height, snapshot) { | |
| 38 window.widthBeforeRepaint = width; | |
| 39 window.heightBeforeRepaint = height; | |
| 40 window.snapshotBeforeRepaint = snapshot; | |
| 41 continueRepaintTest(); | |
| 42 }); | |
| 43 } else { | |
| 44 testRunner.displayAsyncThen(continueRepaintTest); | |
| 45 }; | |
| 33 } | 46 } |
| 34 | 47 |
| 35 function runRepaintAndPixelTest() | 48 function runRepaintAndPixelTest() |
| 36 { | 49 { |
| 37 window.enablePixelTesting = true; | 50 window.enablePixelTesting = true; |
| 38 runRepaintTest(); | 51 runRepaintTest(); |
| 39 } | 52 } |
| 40 | 53 |
| 41 function forceStyleRecalc() | 54 function forceStyleRecalc() |
| 42 { | 55 { |
| 43 if (document.body) | 56 if (document.body) |
| 44 document.body.offsetTop; | 57 document.body.offsetTop; |
| 45 else if (document.documentElement) | 58 else if (document.documentElement) |
| 46 document.documentElement.offsetTop; | 59 document.documentElement.offsetTop; |
| 47 } | 60 } |
| 48 | 61 |
| 49 function finishRepaintTest() | 62 function finishRepaintTest() |
| 50 { | 63 { |
| 51 // Force a style recalc. | 64 // Force a style recalc. |
| 52 forceStyleRecalc(); | 65 forceStyleRecalc(); |
| 53 | 66 |
| 54 var repaintRects = window.internals.layerTreeAsText(document, window.interna ls.LAYER_TREE_INCLUDES_REPAINT_RECTS); | 67 var repaintRects = window.internals.layerTreeAsText(document, window.interna ls.LAYER_TREE_INCLUDES_REPAINT_RECTS); |
| 55 | 68 |
| 56 internals.stopTrackingRepaints(document); | 69 internals.stopTrackingRepaints(document); |
| 57 | 70 |
| 58 // Play nice with JS tests which may want to print out assert results. | 71 function repaintTestDone() |
| 59 if (window.isJsTest) | 72 { |
| 60 window.outputRepaintRects = false; | 73 // Play nice with JS tests which may want to print out assert results. |
| 74 if (window.isJsTest) | |
| 75 window.outputRepaintRects = false; | |
| 61 | 76 |
| 62 if (window.outputRepaintRects) | 77 if (window.outputRepaintRects) |
| 63 testRunner.setCustomTextOutput(repaintRects); | 78 testRunner.setCustomTextOutput(repaintRects); |
| 64 | 79 |
| 65 if (window.afterTest) | 80 if (window.afterTest) |
| 66 window.afterTest(); | 81 window.afterTest(); |
| 67 | 82 |
| 68 // Play nice with async JS tests which want to notifyDone themselves. | 83 // Play nice with async JS tests which want to notifyDone themselves. |
| 69 if (!window.jsTestIsAsync) | 84 if (!window.jsTestIsAsync) |
| 70 testRunner.notifyDone(); | 85 testRunner.notifyDone(); |
| 86 } | |
| 87 | |
| 88 if (window.generateMinimumRepaint) { | |
| 89 internals.forceFullRepaint(document); | |
| 90 testRunner.capturePixelsAsyncThen(function(width, height, snapshot) { | |
| 91 if (window.outputRepaintRects) { | |
| 92 var minimumRepaint = computeMinimumRepaint(width, height, snapsh ot); | |
| 93 if (minimumRepaint.length) | |
| 94 repaintRects += '\nMinimum repaint:\n' + JSON.stringify(mini mumRepaint, null, 2); | |
| 95 } | |
| 96 repaintTestDone(); | |
| 97 }); | |
| 98 } else { | |
| 99 repaintTestDone(); | |
| 100 } | |
| 71 } | 101 } |
| 102 | |
| 103 // Minimum repaint | |
| 104 // | |
| 105 // Definitions | |
| 106 // - minimum-repaint = region(diff(snapshot-before-repaintTest, | |
| 107 // snapshot-after-repaintTest-and-full-repaint)) | |
| 108 // It includes all pixels that should be changed after repaintTest. | |
| 109 // - actual-repaint = repaint rects recorded during repaintTest() and | |
| 110 // forceStyleRecalc(). | |
| 111 // - potential-under-repaint = subtract(minimum-repaint, actual-repaint) | |
| 112 // Potential-under-repaint will be shown in layout test overlay in black if | |
| 113 // any minimum-repaint region is not covered by actual-repaint. | |
| 114 // | |
| 115 // Potential-under-repaints don't always mean bug: | |
| 116 // - Some know visualization issues (crbug.com/381221) may cause false | |
| 117 // under-repaint; | |
| 118 // - Screen updates caused by composited layer re-compositing may not need | |
| 119 // repaint. | |
| 120 // | |
| 121 // How to use | |
| 122 // 1. Set window.generateMinimumRepaint to true in some repaint test or change | |
| 123 // this script to force window.generateMinimumRepaint to true. | |
| 124 // 2. Run layout tests. Repaint tests will result text diffs, which is because | |
| 125 // of the minimum repaint output in the actual results and doesn't mean the | |
| 126 // tests failed. | |
| 127 // 3. In layout test result page, click 'overlay' link or expand the test to | |
| 128 // see the 'overlay' pane. | |
| 129 // 4. Click 'Highlight under-repaint' button. You'll see black region if there | |
| 130 // is any under-repaint. | |
| 131 // | |
| 132 // Known issues | |
| 133 // crbug.com/381221 | |
| 134 | |
| 135 function computeMinimumRepaint(width, height, snapshot) | |
| 136 { | |
| 137 var result = []; | |
| 138 if (width > widthBeforeRepaint) { | |
| 139 result.push([widthBeforeRepaint, 0, width - widthBeforeRepaint, Math.max (height, heightBeforeRepaint)]); | |
| 140 width = widthBeforeRepaint; | |
| 141 } | |
| 142 if (height > heightBeforeRepaint) { | |
| 143 result.push([0, heightBeforeRepaint, width, height - heightBeforeRepaint ]); | |
| 144 height = heightBeforeRepaint; | |
| 145 } | |
| 146 | |
| 147 var dataBefore = new Uint32Array(snapshotBeforeRepaint); | |
| 148 var dataAfter = new Uint32Array(snapshot); | |
| 149 var rectsMayContinue = []; | |
| 150 var index = 0; | |
| 151 for (var y = 0; y < height; ++y) { | |
| 152 var x = 0; | |
| 153 var rectsMayContinueIndex = 0; | |
| 154 var nextRectsMayContinue = []; | |
| 155 while (true) { | |
| 156 while (x < width && dataBefore[index] == dataAfter[index]) { | |
| 157 ++x; | |
| 158 ++index; | |
| 159 } | |
| 160 xBegin = x; | |
| 161 while (x < width && dataBefore[index] != dataAfter[index]) { | |
| 162 ++x; | |
| 163 ++index; | |
| 164 } | |
| 165 xEnd = x; | |
| 166 | |
| 167 var xWidth = xEnd - xBegin; | |
| 168 if (!xWidth) | |
| 169 break; | |
| 170 | |
| 171 var rectMayContinue = rectsMayContinue[rectsMayContinueIndex]; | |
| 172 while (rectMayContinue && rectMayContinue[0] < xBegin) | |
| 173 rectMayContinue = rectsMayContinue[++rectsMayContinueIndex]; | |
| 174 | |
| 175 if (rectMayContinue && rectMayContinue[0] == xBegin && rectMayContin ue[2] == xWidth) { | |
| 176 ++rectMayContinue[3]; | |
| 177 nextRectsMayContinue.push(rectMayContinue); | |
| 178 } else { | |
| 179 var newRect = [xBegin, y, xWidth, 1]; | |
| 180 nextRectsMayContinue.push(newRect); | |
| 181 result.push(newRect); | |
| 182 } | |
| 183 } | |
| 184 rectsMayContinue = nextRectsMayContinue; | |
| 185 } | |
| 186 return result; | |
| 187 } | |
| OLD | NEW |