Pause diff rendering on window scroll

Bug: Issue 4364
Change-Id: If1bc1560fa98b170e776fd0afd9782d8ca38e769
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-processor/gr-diff-processor.js b/polygerrit-ui/app/elements/diff/gr-diff-processor/gr-diff-processor.js
index 2a1e880..2dd4c91 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-processor/gr-diff-processor.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-processor/gr-diff-processor.js
@@ -78,6 +78,22 @@
       },
 
       _nextStepHandle: Number,
+      _isScrolling: Boolean,
+    },
+
+    attached: function() {
+      this.listen(window, 'scroll', '_handleWindowScroll');
+    },
+
+    detached: function() {
+      this.unlisten(window, 'scroll', '_handleWindowScroll');
+    },
+
+    _handleWindowScroll: function() {
+      this._isScrolling = true;
+      this.debounce('resetIsScrolling', function() {
+        this._isScrolling = false;
+      }, 50);
     },
 
     /**
@@ -100,6 +116,11 @@
 
         var currentBatch = 0;
         var nextStep = function() {
+
+          if (this._isScrolling) {
+            this.async(nextStep, 100);
+            return;
+          }
           // If we are done, resolve the promise.
           if (state.sectionIndex >= content.length) {
             resolve(this.groups);
@@ -201,11 +222,11 @@
     /**
      * Take rows of a shared diff section and produce an array of corresponding
      * (potentially collapsed) groups.
-     * @param  {Array<String>} rows
-     * @param  {Number} context
-     * @param  {Number} startLineNumLeft
-     * @param  {Number} startLineNumRight
-     * @param  {String} opt_sectionEnd String representing whether this is the
+     * @param {Array<String>} rows
+     * @param {Number} context
+     * @param {Number} startLineNumLeft
+     * @param {Number} startLineNumRight
+     * @param {String} opt_sectionEnd String representing whether this is the
      *     first section or the last section or neither. Use the values 'first',
      *     'last' and null respectively.
      * @return {Array<GrDiffGroup>}
@@ -264,10 +285,10 @@
     /**
      * Take the rows of a delta diff section and produce the corresponding
      * group.
-     * @param  {Array<String>} rowsAdded
-     * @param  {Array<String>} rowsRemoved
-     * @param  {Number} startLineNumLeft
-     * @param  {Number} startLineNumRight
+     * @param {Array<String>} rowsAdded
+     * @param {Array<String>} rowsRemoved
+     * @param {Number} startLineNumLeft
+     * @param {Number} startLineNumRight
      * @return {GrDiffGroup}
      */
     _deltaGroupFromRows: function(rowsAdded, rowsRemoved, startLineNumLeft,
@@ -325,7 +346,7 @@
      * In order to show comments out of the bounds of the selected context,
      * treat them as separate chunks within the model so that the content (and
      * context surrounding it) renders correctly.
-     * @param  {Object} content The diff content object.
+     * @param {Object} content The diff content object.
      * @return {Object} A new diff content object with regions split up.
      */
     _splitCommonGroupsWithComments: function(content) {
@@ -477,8 +498,8 @@
     /**
      * Given an array and a size, return an array of arrays where no inner array
      * is larger than that size, preserving the original order.
-     * @param  {!Array<T>}
-     * @param  {number}
+     * @param {!Array<T>} array
+     * @param {number} size
      * @return {!Array<!Array<T>>}
      * @template T
      */
@@ -489,7 +510,7 @@
       var head = array.slice(0, array.length - size);
       var tail = array.slice(array.length - size);
 
-      return this._breakdown(head, size).concat([tail])
+      return this._breakdown(head, size).concat([tail]);
     },
   });
 })();
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-processor/gr-diff-processor_test.html b/polygerrit-ui/app/elements/diff/gr-diff-processor/gr-diff-processor_test.html
index 9d687ac..4f8c532 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-processor/gr-diff-processor_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-processor/gr-diff-processor_test.html
@@ -40,6 +40,15 @@
         'fugit assum per.';
 
     var element;
+    var sandbox;
+
+    setup(function() {
+      sandbox = sinon.sandbox.create();
+    });
+
+    teardown(function() {
+      sandbox.restore();
+    });
 
     suite('not logged in', function() {
 
@@ -409,6 +418,23 @@
         ]);
       });
 
+      test('scrolling pauses rendering', function() {
+        var contentRow = {
+          ab: [
+            '<!DOCTYPE html>',
+            '<meta charset="utf-8">',
+          ]
+        };
+        var content = _.times(200, _.constant(contentRow));
+        sandbox.stub(element, 'async');
+        element._isScrolling = true;
+        element.process(content);
+        assert.equal(element.groups.length, 1);
+        element._isScrolling = false;
+        element.process(content);
+        assert.equal(element.groups.length, 33);
+      });
+
       suite('gr-diff-processor helpers', function() {
         var rows;
 
@@ -512,15 +538,6 @@
       });
 
       suite('_breakdown*', function() {
-        var sandbox;
-        setup(function() {
-          sandbox = sinon.sandbox.create();
-        });
-
-        teardown(function() {
-          sandbox.restore();
-        });
-
         test('_breakdownGroup ignores shared groups', function() {
           sandbox.stub(element, '_breakdown');
           var chunk = {ab: ['blah', 'blah', 'blah']};