From 42911f1fc975b6f87a39ddb7bf66dc44dfeae37d Mon Sep 17 00:00:00 2001
From: Yury Delendik <ydelendik@mozilla.com>
Date: Sat, 14 Apr 2012 13:54:31 -0700
Subject: [PATCH] Async getAnnotations(); hide map and xref for Dict

---
 src/api.js       | 19 ++++++++++++--
 src/evaluator.js |  2 +-
 src/obj.js       | 64 +++++++++++++++++++++++++-----------------------
 src/worker.js    | 16 ++++++++----
 4 files changed, 63 insertions(+), 38 deletions(-)

diff --git a/src/api.js b/src/api.js
index f1baefade..479134bd2 100644
--- a/src/api.js
+++ b/src/api.js
@@ -102,9 +102,12 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
       return new PDFJS.PageViewport(this.view, scale, rotate, 0, 0);
     },
     getAnnotations: function() {
+      if (this.annotationsPromise)
+        return this.annotationsPromise;
+
       var promise = new PDFJS.Promise();
-      var annotations = this.pageInfo.annotations;
-      promise.resolve(annotations);
+      this.annotationsPromise = promise;
+      this.transport.getAnnotations(this.pageInfo.pageIndex);
       return promise;
     },
     render: function(renderContext) {
@@ -209,6 +212,7 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
           gfx.executeOperatorList(operatorList, startIdx, next, stepper);
         if (startIdx == length) {
           gfx.endDrawing();
+          delete this.operatorList;
           stats.timeEnd('Rendering');
           stats.timeEnd('Overall');
           if (callback) callback();
@@ -342,6 +346,12 @@ var WorkerTransport = (function WorkerTransportClosure() {
         promise.resolve(page);
       }, this);
 
+      messageHandler.on('GetAnnotations', function transportAnnotations(data) {
+        var annotations = data.annotations;
+        var promise = this.pageCache[data.pageIndex].annotationsPromise;
+        promise.resolve(annotations);
+      }, this);
+
       messageHandler.on('RenderPage', function transportRender(data) {
         var page = this.pageCache[data.pageIndex];
         var depFonts = data.depFonts;
@@ -440,6 +450,11 @@ var WorkerTransport = (function WorkerTransportClosure() {
       this.pagePromises[pageIndex] = promise;
       this.messageHandler.send('GetPageRequest', { pageIndex: pageIndex });
       return promise;
+    },
+
+    getAnnotations: function WorkerTransport_getAnnotations(pageIndex) {
+      this.messageHandler.send('GetAnnotationsRequest',
+        { pageIndex: pageIndex });
     }
   };
   return WorkerTransport;
diff --git a/src/evaluator.js b/src/evaluator.js
index 350ab20b2..50274a9ed 100644
--- a/src/evaluator.js
+++ b/src/evaluator.js
@@ -466,7 +466,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
           args = [];
         } else if (obj != null) {
           assertWellFormed(args.length <= 33, 'Too many arguments');
-          args.push(obj);
+          args.push(obj instanceof Dict ? obj.getAll() : obj);
         }
       }
 
diff --git a/src/obj.js b/src/obj.js
index 200b40a7f..c905a7dc5 100644
--- a/src/obj.js
+++ b/src/obj.js
@@ -37,51 +37,55 @@ var Dict = (function DictClosure() {
   // xref is optional
   function Dict(xref) {
     // Map should only be used internally, use functions below to access.
-    this.map = Object.create(null);
-    this.xref = xref;
-  }
+    var map = Object.create(null);
+
+    this.assignXref = function Dict_assingXref(newXref) {
+      xref = newXref;
+    };
 
-  Dict.prototype = {
     // automatically dereferences Ref objects
-    get: function Dict_get(key1, key2, key3) {
+    this.get = function Dict_get(key1, key2, key3) {
       var value;
-      var xref = this.xref;
-      if (typeof (value = this.map[key1]) != 'undefined' || key1 in this.map ||
+      if (typeof (value = map[key1]) != 'undefined' || key1 in map ||
           typeof key2 == 'undefined') {
-        return xref ? this.xref.fetchIfRef(value) : value;
+        return xref ? xref.fetchIfRef(value) : value;
       }
-      if (typeof (value = this.map[key2]) != 'undefined' || key2 in this.map ||
+      if (typeof (value = map[key2]) != 'undefined' || key2 in map ||
           typeof key3 == 'undefined') {
-        return xref ? this.xref.fetchIfRef(value) : value;
+        return xref ? xref.fetchIfRef(value) : value;
       }
-      value = this.map[key3] || null;
-      return xref ? this.xref.fetchIfRef(value) : value;
-    },
+      value = map[key3] || null;
+      return xref ? xref.fetchIfRef(value) : value;
+    };
+
     // no dereferencing
-    getRaw: function Dict_getRaw(key) {
-      return this.map[key];
-    },
+    this.getRaw = function Dict_getRaw(key) {
+      return map[key];
+    };
+
     // creates new map and dereferences all Refs
-    getAll: function Dict_getAll() {
+    this.getAll = function Dict_getAll() {
       var all = {};
-      for (var key in this.map)
-        all[key] = this.get(key);
+      for (var key in map) {
+        var obj = this.get(key);
+        all[key] = obj instanceof Dict ? obj.getAll() : obj;
+      }
       return all;
-    },
+    };
 
-    set: function Dict_set(key, value) {
-      this.map[key] = value;
-    },
+    this.set = function Dict_set(key, value) {
+      map[key] = value;
+    };
 
-    has: function Dict_has(key) {
-      return key in this.map;
-    },
+    this.has = function Dict_has(key) {
+      return key in map;
+    };
 
-    forEach: function Dict_forEach(callback) {
-      for (var key in this.map) {
+    this.forEach = function Dict_forEach(callback) {
+      for (var key in map) {
         callback(key, this.get(key));
       }
-    }
+    };
   };
 
   return Dict;
@@ -299,7 +303,7 @@ var XRef = (function XRefClosure() {
     this.entries = [];
     this.xrefstms = {};
     var trailerDict = this.readXRef(startXRef);
-    trailerDict.xref = this;
+    trailerDict.assignXref(this);
     this.trailer = trailerDict;
     // prepare the XRef cache
     this.cache = [];
diff --git a/src/worker.js b/src/worker.js
index 5cecc6cf2..25f3f52cd 100644
--- a/src/worker.js
+++ b/src/worker.js
@@ -100,20 +100,27 @@ var WorkerMessageHandler = {
       handler.send('GetDoc', {pdfInfo: doc});
     });
 
-    handler.on('GetPageRequest', function wphSetupTest(data) {
+    handler.on('GetPageRequest', function wphSetupGetPage(data) {
       var pageNumber = data.pageIndex + 1;
       var pdfPage = pdfModel.getPage(pageNumber);
       var page = {
         pageIndex: data.pageIndex,
         rotate: pdfPage.rotate,
         ref: pdfPage.ref,
-        view: pdfPage.view,
-        annotations: pdfPage.getAnnotations()
+        view: pdfPage.view
       };
       handler.send('GetPage', {pageInfo: page});
     });
 
-    handler.on('RenderPageRequest', function wphSetupPageRequest(data) {
+    handler.on('GetAnnotationsRequest', function wphSetupGetAnnotations(data) {
+      var pdfPage = pdfModel.getPage(data.pageIndex + 1);
+      handler.send('GetAnnotations', {
+        pageIndex: data.pageIndex,
+        annotations: pdfPage.getAnnotations()
+      });
+    });
+
+    handler.on('RenderPageRequest', function wphSetupRenderPage(data) {
       var pageNum = data.pageIndex + 1;
 
 
@@ -170,7 +177,6 @@ var WorkerMessageHandler = {
           fonts[dep] = true;
         }
       }
-
       handler.send('RenderPage', {
         pageIndex: data.pageIndex,
         operatorList: operatorList,