[Pkg-javascript-commits] [pdf.js] 02/141: Doesn't traverse cyclic references in Dict.getAll; reduces empty-Dict garbage

David Prévot taffit at moszumanska.debian.org
Sat Apr 19 22:40:24 UTC 2014


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

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

commit 31f081ae173497af1c6a6fd6064703bc9e64c622
Author: Yury Delendik <ydelendik at mozilla.com>
Date:   Wed Mar 26 09:07:38 2014 -0500

    Doesn't traverse cyclic references in Dict.getAll; reduces empty-Dict garbage
---
 src/core/core.js          |  2 +-
 src/core/evaluator.js     | 26 ++++++++++------
 src/core/obj.js           | 75 ++++++++++++++++++++++++++++++++++++++++++++---
 src/core/parser.js        |  2 +-
 src/core/stream.js        |  2 +-
 src/shared/annotation.js  |  2 +-
 src/shared/fonts_utils.js |  2 +-
 7 files changed, 93 insertions(+), 18 deletions(-)

diff --git a/src/core/core.js b/src/core/core.js
index 8ac43c8..7138ce0 100644
--- a/src/core/core.js
+++ b/src/core/core.js
@@ -68,7 +68,7 @@ var Page = (function PageClosure() {
       // present, but can be empty. Some document omit it still. In this case
       // return an empty dictionary:
       if (value === undefined) {
-        value = new Dict();
+        value = Dict.empty;
       }
       return shadow(this, 'resources', value);
     },
diff --git a/src/core/evaluator.js b/src/core/evaluator.js
index 84a618a..d8ce942 100644
--- a/src/core/evaluator.js
+++ b/src/core/evaluator.js
@@ -48,6 +48,11 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
         return false;
       }
 
+      var processed = Object.create(null);
+      if (resources.objId) {
+        processed[resources.objId] = true;
+      }
+
       var nodes = [resources];
       while (nodes.length) {
         var node = nodes.shift();
@@ -75,10 +80,13 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
             continue;
           }
           var xResources = xObject.dict.get('Resources');
-          // Only add the resource if it's different from the current one,
-          // otherwise we can get stuck in an infinite loop.
-          if (isDict(xResources) && xResources !== node) {
+          // Checking objId to detect an infinite loop.
+          if (isDict(xResources) &&
+              (!xResources.objId || !processed[xResources.objId])) {
             nodes.push(xResources);
+            if (xResources.objId) {
+              processed[xResources.objId] = true;
+            }
           }
         }
       }
@@ -466,9 +474,9 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
 
       operatorList = (operatorList || new OperatorList());
 
-      resources = (resources || new Dict());
-      var xobjs = (resources.get('XObject') || new Dict());
-      var patterns = (resources.get('Pattern') || new Dict());
+      resources = (resources || Dict.empty);
+      var xobjs = (resources.get('XObject') || Dict.empty);
+      var patterns = (resources.get('Pattern') || Dict.empty);
       var preprocessor = new EvaluatorPreprocessor(stream, xref);
       if (evaluatorState) {
         preprocessor.setState(evaluatorState);
@@ -659,7 +667,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
         return self.loadFont(fontName, fontRef, xref, resources, null);
       }
 
-      resources = (xref.fetchIfRef(resources) || new Dict());
+      resources = (xref.fetchIfRef(resources) || Dict.empty);
       // The xobj is parsed iff it's needed, e.g. if there is a `DO` cmd.
       var xobjs = null;
       var xobjsCache = {};
@@ -753,7 +761,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
             }
 
             if (!xobjs) {
-              xobjs = (resources.get('XObject') || new Dict());
+              xobjs = (resources.get('XObject') || Dict.empty);
             }
 
             var name = args[0].name;
@@ -1147,7 +1155,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
         if (type.name == 'Type3') {
           // FontDescriptor is only required for Type3 fonts when the document
           // is a tagged pdf. Create a barbebones one to get by.
-          descriptor = new Dict();
+          descriptor = new Dict(null);
           descriptor.set('FontName', Name.get(type.name));
         } else {
           // Before PDF 1.5 if the font was one of the base 14 fonts, having a
diff --git a/src/core/obj.js b/src/core/obj.js
index f9f197b..ab4bb04 100644
--- a/src/core/obj.js
+++ b/src/core/obj.js
@@ -62,11 +62,30 @@ var Dict = (function DictClosure() {
     return nonSerializable; // creating closure on some variable
   };
 
+  var GETALL_DICTIONARY_TYPES_WHITELIST = {
+    'Background': true,
+    'ExtGState': true,
+    'Halftone': true,
+    'Layout': true,
+    'Mask': true,
+    'Pagination': true,
+    'Printing': true
+  };
+
+  function isRecursionAllowedFor(dict) {
+    if (!isName(dict.Type)) {
+      return true;
+    }
+    var dictType = dict.Type.name;
+    return GETALL_DICTIONARY_TYPES_WHITELIST[dictType] === true;
+  }
+
   // 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;
+    this.objId = null;
     this.__nonSerializable__ = nonSerializable; // disable cloning of the Dict
   }
 
@@ -130,10 +149,51 @@ var Dict = (function DictClosure() {
 
     // creates new map and dereferences all Refs
     getAll: function Dict_getAll() {
-      var all = {};
+      var all = Object.create(null);
+      var queue = null;
       for (var key in this.map) {
         var obj = this.get(key);
-        all[key] = (obj instanceof Dict ? obj.getAll() : obj);
+        if (obj instanceof Dict) {
+          if (isRecursionAllowedFor(obj)) {
+            (queue || (queue = [])).push({target: all, key: key, obj: obj});
+          } else {
+            all[key] = this.getRaw(key);
+          }
+        } else {
+          all[key] = obj;
+        }
+      }
+      if (!queue) {
+        return all;
+      }
+
+      // trying to take cyclic references into the account
+      var processed = Object.create(null);
+      while (queue.length > 0) {
+        var item = queue.shift();
+        var itemObj = item.obj;
+        var objId = itemObj.objId;
+        if (objId && objId in processed) {
+          item.target[item.key] = processed[objId];
+          continue;
+        }
+        var dereferenced = Object.create(null);
+        for (var key in itemObj.map) {
+          var obj = itemObj.get(key);
+          if (obj instanceof Dict) {
+            if (isRecursionAllowedFor(obj)) {
+              queue.push({target: dereferenced, key: key, obj: obj});
+            } else {
+              dereferenced[key] = itemObj.getRaw(key);
+            }
+          } else {
+            dereferenced[key] = obj;
+          }
+        }
+        if (objId) {
+          processed[objId] = dereferenced;
+        }
+        item.target[item.key] = dereferenced;
       }
       return all;
     },
@@ -153,6 +213,8 @@ var Dict = (function DictClosure() {
     }
   };
 
+  Dict.empty = new Dict(null);
+
   return Dict;
 })();
 
@@ -1061,10 +1123,15 @@ var XRef = (function XRefClosure() {
       }
 
       if (xrefEntry.uncompressed) {
-        return this.fetchUncompressed(ref, xrefEntry, suppressEncryption);
+        xrefEntry = this.fetchUncompressed(ref, xrefEntry, suppressEncryption);
       } else {
-        return this.fetchCompressed(xrefEntry, suppressEncryption);
+        xrefEntry = this.fetchCompressed(xrefEntry, suppressEncryption);
       }
+
+      if (isDict(xrefEntry)) {
+        xrefEntry.objId = 'R' + ref.num + '.' + ref.gen;
+      }
+      return xrefEntry;
     },
 
     fetchUncompressed: function XRef_fetchUncompressed(ref, xrefEntry,
diff --git a/src/core/parser.js b/src/core/parser.js
index aff4608..acdb46b 100644
--- a/src/core/parser.js
+++ b/src/core/parser.js
@@ -131,7 +131,7 @@ var Parser = (function ParserClosure() {
       var stream = lexer.stream;
 
       // parse dictionary
-      var dict = new Dict();
+      var dict = new Dict(null);
       while (!isCmd(this.buf1, 'ID') && !isEOF(this.buf1)) {
         if (!isName(this.buf1)) {
           error('Dictionary key must be a name object');
diff --git a/src/core/stream.js b/src/core/stream.js
index 0776c43..b2580f9 100644
--- a/src/core/stream.js
+++ b/src/core/stream.js
@@ -1744,7 +1744,7 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() {
     this.str = str;
     this.dict = str.dict;
 
-    params = params || new Dict();
+    params = params || Dict.empty;
 
     this.encoding = params.get('K') || 0;
     this.eoline = params.get('EndOfLine') || false;
diff --git a/src/shared/annotation.js b/src/shared/annotation.js
index 4d34edf..0f48f0f 100644
--- a/src/shared/annotation.js
+++ b/src/shared/annotation.js
@@ -378,7 +378,7 @@ var WidgetAnnotation = (function WidgetAnnotationClosure() {
     var fieldType = Util.getInheritableProperty(dict, 'FT');
     data.fieldType = isName(fieldType) ? fieldType.name : '';
     data.fieldFlags = Util.getInheritableProperty(dict, 'Ff') || 0;
-    this.fieldResources = Util.getInheritableProperty(dict, 'DR') || new Dict();
+    this.fieldResources = Util.getInheritableProperty(dict, 'DR') || Dict.empty;
 
     // Building the full field name by collecting the field and
     // its ancestors 'T' data and joining them using '.'.
diff --git a/src/shared/fonts_utils.js b/src/shared/fonts_utils.js
index bc2659a..a14d921 100644
--- a/src/shared/fonts_utils.js
+++ b/src/shared/fonts_utils.js
@@ -249,7 +249,7 @@ function readFontIndexData(aStream, aIsByte) {
 }
 
 var Type2Parser = function type2Parser(aFilePath) {
-  var font = new Dict();
+  var font = new Dict(null);
 
   var xhr = new XMLHttpRequest();
   xhr.open('GET', aFilePath, false);

-- 
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