[Pkg-javascript-commits] [pdf.js] 28/72: Use binary search in getVisibleElements()

David Prévot taffit at moszumanska.debian.org
Wed Mar 18 20:15:57 UTC 2015


This is an automated email from the git hooks/post-receive script.

taffit pushed a commit to branch master
in repository pdf.js.

commit a78bb6b946840a7095bce29af69a3f1c54781de8
Author: fkaelberer <l_l at gmx-topmail.de>
Date:   Fri Dec 26 17:43:13 2014 +0100

    Use binary search in getVisibleElements()
---
 test/unit/ui_utils_spec.js | 37 ++++++++++++++++++++++
 test/unit/unit_test.html   |  2 ++
 web/ui_utils.js            | 78 ++++++++++++++++++++++++++++++++++++----------
 3 files changed, 100 insertions(+), 17 deletions(-)

diff --git a/test/unit/ui_utils_spec.js b/test/unit/ui_utils_spec.js
new file mode 100644
index 0000000..757aef2
--- /dev/null
+++ b/test/unit/ui_utils_spec.js
@@ -0,0 +1,37 @@
+/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
+/* globals expect, it, describe, binarySearchFirstItem */
+
+'use strict';
+
+describe('ui_utils', function() {
+
+  describe('binary search', function() {
+    function isTrue(boolean) {
+      return boolean;
+    }
+    function isGreater3(number) {
+      return number > 3;
+    }
+
+    it('empty array', function() {
+      expect(binarySearchFirstItem([], isTrue)).toEqual(0);
+    });
+    it('single boolean entry', function() {
+      expect(binarySearchFirstItem([false], isTrue)).toEqual(1);
+      expect(binarySearchFirstItem([true], isTrue)).toEqual(0);
+    });
+    it('three boolean entries', function() {
+      expect(binarySearchFirstItem([true, true, true], isTrue)).toEqual(0);
+      expect(binarySearchFirstItem([false, true, true], isTrue)).toEqual(1);
+      expect(binarySearchFirstItem([false, false, true], isTrue)).toEqual(2);
+      expect(binarySearchFirstItem([false, false, false], isTrue)).toEqual(3);
+    });
+    it('three numeric entries', function() {
+      expect(binarySearchFirstItem([0, 1, 2], isGreater3)).toEqual(3);
+      expect(binarySearchFirstItem([2, 3, 4], isGreater3)).toEqual(2);
+      expect(binarySearchFirstItem([4, 5, 6], isGreater3)).toEqual(0);
+    });
+  });
+});
+
diff --git a/test/unit/unit_test.html b/test/unit/unit_test.html
index c8f59fc..9b43e01 100644
--- a/test/unit/unit_test.html
+++ b/test/unit/unit_test.html
@@ -40,6 +40,7 @@
   <script src="../../src/core/worker.js"></script>
   <script src="../../src/display/metadata.js"></script>
   <script src="../../src/core/jpg.js"></script>
+  <script src="../../web/ui_utils.js"></script>
   <script>PDFJS.workerSrc = '../../src/worker_loader.js';</script>
 
   <!-- include spec files here... -->
@@ -52,6 +53,7 @@
   <script src="parser_spec.js"></script>
   <script src="api_spec.js"></script>
   <script src="metadata_spec.js"></script>
+  <script src="ui_utils_spec.js"></script>
   <script src="util_spec.js"></script>
   <script src="cmap_spec.js"></script>
   <script>
diff --git a/web/ui_utils.js b/web/ui_utils.js
index 00eb25e..7e798e3 100644
--- a/web/ui_utils.js
+++ b/web/ui_utils.js
@@ -160,13 +160,10 @@ function watchScroll(viewAreaElement, callback) {
 
       var currentY = viewAreaElement.scrollTop;
       var lastY = state.lastY;
-      if (currentY > lastY) {
-        state.down = true;
-      } else if (currentY < lastY) {
-        state.down = false;
+      if (currentY !== lastY) {
+        state.down = currentY > lastY;
       }
       state.lastY = currentY;
-      // else do nothing and use previous value
       callback(state);
     });
   };
@@ -183,36 +180,83 @@ function watchScroll(viewAreaElement, callback) {
 }
 
 /**
+ * Use binary search to find the index of the first item in a given array which
+ * passes a given condition. The items are expected to be sorted in the sense
+ * that if the condition is true for one item in the array, then it is also true
+ * for all following items.
+ *
+ * @returns {Number} Index of the first array element to pass the test,
+ *                   or |items.length| if no such element exists.
+ */
+function binarySearchFirstItem(items, condition) {
+  var minIndex = 0;
+  var maxIndex = items.length - 1;
+
+  if (items.length === 0 || !condition(items[maxIndex])) {
+    return items.length;
+  }
+  if (condition(items[minIndex])) {
+    return minIndex;
+  }
+
+  while (minIndex < maxIndex) {
+    var currentIndex = (minIndex + maxIndex) >> 1;
+    var currentItem = items[currentIndex];
+    if (condition(currentItem)) {
+      maxIndex = currentIndex;
+    } else {
+      minIndex = currentIndex + 1;
+    }
+  }
+  return minIndex; /* === maxIndex */
+}
+
+/**
  * Generic helper to find out what elements are visible within a scroll pane.
  */
 function getVisibleElements(scrollEl, views, sortByVisibility) {
   var top = scrollEl.scrollTop, bottom = top + scrollEl.clientHeight;
   var left = scrollEl.scrollLeft, right = left + scrollEl.clientWidth;
 
-  var visible = [], view;
+  function isElementBottomBelowViewTop(view) {
+    var element = view.div;
+    var elementBottom =
+      element.offsetTop + element.clientTop + element.clientHeight;
+    return elementBottom > top;
+  }
+
+  var visible = [], view, element;
   var currentHeight, viewHeight, hiddenHeight, percentHeight;
   var currentWidth, viewWidth;
-  for (var i = 0, ii = views.length; i < ii; ++i) {
+  var firstVisibleElementInd = (views.length === 0) ? 0 :
+    binarySearchFirstItem(views, isElementBottomBelowViewTop);
+
+  for (var i = firstVisibleElementInd, ii = views.length; i < ii; i++) {
     view = views[i];
-    currentHeight = view.div.offsetTop + view.div.clientTop;
-    viewHeight = view.div.clientHeight;
-    if ((currentHeight + viewHeight) < top) {
-      continue;
-    }
+    element = view.div;
+    currentHeight = element.offsetTop + element.clientTop;
+    viewHeight = element.clientHeight;
+
     if (currentHeight > bottom) {
       break;
     }
-    currentWidth = view.div.offsetLeft + view.div.clientLeft;
-    viewWidth = view.div.clientWidth;
-    if ((currentWidth + viewWidth) < left || currentWidth > right) {
+
+    currentWidth = element.offsetLeft + element.clientLeft;
+    viewWidth = element.clientWidth;
+    if (currentWidth + viewWidth < left || currentWidth > right) {
       continue;
     }
     hiddenHeight = Math.max(0, top - currentHeight) +
       Math.max(0, currentHeight + viewHeight - bottom);
     percentHeight = ((viewHeight - hiddenHeight) * 100 / viewHeight) | 0;
 
-    visible.push({ id: view.id, x: currentWidth, y: currentHeight,
-      view: view, percent: percentHeight });
+    visible.push({
+      id: view.id,
+      x: currentWidth,
+      y: currentHeight,
+      view: view,
+      percent: percentHeight
+    });
   }
 
   var first = visible[0];

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/pdf.js.git



More information about the Pkg-javascript-commits mailing list