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