Index: Tools/Scripts/webkitpy/layout_tests/controllers/repaint_overlay.py |
diff --git a/Tools/Scripts/webkitpy/layout_tests/controllers/repaint_overlay.py b/Tools/Scripts/webkitpy/layout_tests/controllers/repaint_overlay.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..06521126bf3a8dd0c5a37bfabd8e340f6a2beb59 |
--- /dev/null |
+++ b/Tools/Scripts/webkitpy/layout_tests/controllers/repaint_overlay.py |
@@ -0,0 +1,204 @@ |
+# Copyright 2014 The Chromium Authors. All rights reserved. |
+# Use of this source code is governed by a BSD-style license that can be |
+# found in the LICENSE file. |
+ |
+import re |
+ |
+ |
+def result_contains_repaint_rects(text): |
+ return isinstance(text, str) and re.search('^\s*\(repaint rects$', text, re.MULTILINE) != None |
+ |
+ |
+def generate_repaint_overlay_html(test_name, actual_text, expected_text): |
+ if not result_contains_repaint_rects(expected_text): |
+ return '' |
+ |
+ def make_js_rect(input_str): |
+ rect_pattern = '\(rect\s+(\d+\.\d+)\s+(\d+\.\d+)\s+(\d+\.\d+)\s+(\d+\.\d+)\)' |
+ rects = [] |
+ for m in re.finditer(rect_pattern, input_str): |
+ rects.append('[' + ','.join(m.groups()) + ']') |
+ return '[' + ','.join(rects) + ']' |
+ |
+ # FIXME: Need to consider layer offset and transforms. |
+ expected_rects = make_js_rect(expected_text) |
+ actual_rects = make_js_rect(actual_text) |
+ |
+ return """<!DOCTYPE HTML> |
+<html> |
+<head> |
+<title>%(title)s</title> |
+<style> |
+ body { |
+ margin: 0; |
+ padding: 0; |
+ } |
+ iframe { |
+ position: absolute; |
+ top: 60px; |
+ left: 0; |
+ border: 0; |
+ z-index: -1; |
+ } |
+ canvas { |
+ position: absolute; |
+ top: 60px; |
+ left: 0; |
+ z-index: 1; |
+ } |
+ #actual { display: none; } |
+ #dump { |
+ position: absolute; |
+ top: 60px; |
+ left: 0; |
+ z-index: 2; |
+ display: none; |
+ } |
+</style> |
+</head> |
+<body> |
+Note: This version doesn't support transformation and layer offset yet.<br> |
+<label><input type="checkbox" checked onchange="toggle_test(this.checked)">Show test</label> |
+<label><input type="checkbox" checked onchange="toggle_diff_only(this.checked)">Show differences only</label> |
+<label><input type="checkbox" checked onchange="toggle_hide_duplicate_rects(this.checked)">Hide duplicate rects</label> |
+<label><input type="checkbox" onchange="toggle_print_rects(this.checked)">Dump rects</label> |
+<br> |
+<span id='type'>Expected Invalidations</span> |
+<div id=overlay> |
+ <canvas id='expected' width='2000' height='2000'></canvas> |
+ <canvas id='actual' width='2000' height='2000'></canvas> |
+ <pre id='dump'></pre> |
+</div> |
+<script> |
+var show_diff_only = true; |
+var hide_duplicate_rects = true; |
+ |
+function toggle_test(show_test) { |
+ iframe.style.display = show_test ? 'block' : 'none'; |
+} |
+ |
+function toggle_diff_only(new_show_diff_only) { |
+ show_diff_only = new_show_diff_only; |
+ draw_repaint_rects(); |
+} |
+ |
+function toggle_hide_duplicate_rects(new_hide_duplicate_rects) { |
+ hide_duplicate_rects = new_hide_duplicate_rects; |
+ draw_repaint_rects(); |
+} |
+ |
+function toggle_print_rects(dump_rects) { |
+ document.getElementById('dump').style.display = dump_rects ? 'block' : 'none'; |
+} |
+ |
+var original_expected_rects = %(expected_rects)s; |
+var original_actual_rects = %(actual_rects)s; |
+ |
+function rectsEqual(rect1, rect2) { |
+ return rect1[0] == rect2[0] && rect1[1] == rect2[1] && rect1[2] == rect2[2] && rect1[3] == rect2[3]; |
+} |
+ |
+function findDifference(rects1, rects2) { |
+ for (var i = rects1.length - 1; i >= 0; i--) { |
+ for (var k = rects2.length - 1; k >= 0; k--) { |
+ if (rectsEqual(rects1[i], rects2[k])) { |
+ rects1.splice(i, 1); |
+ rects2.splice(k, 1); |
+ break; |
+ } |
+ } |
+ } |
+} |
+ |
+function removeDuplicateRects(rects) { |
+ for (var i = rects.length - 1; i > 0; i--) { |
+ for (var k = i - 1; k >= 0; k--) { |
+ if (rectsEqual(rects[i], rects[k])) { |
+ rects.splice(i, 1); |
+ break; |
+ } |
+ } |
+ } |
+} |
+ |
+function draw_rects(context, rects) { |
+ context.clearRect(0, 0, 2000, 2000); |
+ for (var i = 0; i < rects.length; i++) { |
+ var rect = rects[i]; |
+ context.fillRect(rect[0], rect[1], rect[2], rect[3]); |
+ context.strokeRect(rect[0], rect[1], rect[2], rect[3]); |
+ } |
+} |
+ |
+var expected_canvas = document.getElementById('expected'); |
+var actual_canvas = document.getElementById('actual'); |
+ |
+function dump_rects(rects) { |
+ var result = ''; |
+ for (var i = 0; i < rects.length; i++) |
+ result += '(' + rects[i].toString() + ')\\n'; |
+ return result; |
+} |
+ |
+function draw_repaint_rects() { |
+ var expected_rects = original_expected_rects.slice(0); |
+ var actual_rects = original_actual_rects.slice(0); |
+ if (hide_duplicate_rects) { |
+ removeDuplicateRects(expected_rects); |
+ removeDuplicateRects(actual_rects); |
+ } |
+ |
+ if (show_diff_only) |
+ findDifference(expected_rects, actual_rects); |
+ |
+ document.getElementById('dump').textContent = |
+ 'Expected:\\n' + dump_rects(expected_rects) |
+ + '\\nActual:\\n' + dump_rects(actual_rects); |
+ |
+ var expected_ctx = expected_canvas.getContext("2d"); |
+ expected_ctx.lineWidth = 0.5; |
+ expected_ctx.strokeStyle = 'rgba(255, 0, 0, 1)'; |
+ expected_ctx.fillStyle = 'rgba(255, 0, 0, 0.25)'; |
+ draw_rects(expected_ctx, expected_rects); |
+ |
+ var actual_ctx = actual_canvas.getContext("2d"); |
+ actual_ctx.lineWidth = 1; |
+ actual_ctx.strokeStyle = 'rgba(0, 255, 0, 1)'; |
+ actual_ctx.fillStyle = 'rgba(0, 255, 0, 0.25)'; |
+ draw_rects(actual_ctx, actual_rects); |
+} |
+draw_repaint_rects(); |
+ |
+var path = decodeURIComponent(location.search).substr(1); |
+var iframe = document.createElement('iframe'); |
+iframe.id = 'test-frame'; |
+iframe.width = 800; |
+iframe.height = 600; |
+iframe.src = path; |
+ |
+var overlay = document.getElementById('overlay'); |
+overlay.appendChild(iframe); |
+ |
+var type = document.getElementById('type'); |
+var expected_showing = true; |
+function flip() { |
+ if (expected_showing) { |
+ type.textContent = 'Actual Invalidations'; |
+ expected_canvas.style.display = 'none'; |
+ actual_canvas.style.display = 'block'; |
+ } else { |
+ type.textContent = 'Expected Invalidations'; |
+ actual_canvas.style.display = 'none'; |
+ expected_canvas.style.display = 'block'; |
+ } |
+ expected_showing = !expected_showing |
+} |
+setInterval(flip, 3000); |
+</script> |
+</body> |
+</html> |
+""" % { |
+ 'title': test_name, |
+ 'expected_rects': expected_rects, |
+ 'actual_rects': actual_rects, |
+ } |