|
|
@ -50,6 +50,7 @@ var stringToUTF8String = sharedUtil.stringToUTF8String; |
|
|
|
var warn = sharedUtil.warn; |
|
|
|
var warn = sharedUtil.warn; |
|
|
|
var createValidAbsoluteUrl = sharedUtil.createValidAbsoluteUrl; |
|
|
|
var createValidAbsoluteUrl = sharedUtil.createValidAbsoluteUrl; |
|
|
|
var Util = sharedUtil.Util; |
|
|
|
var Util = sharedUtil.Util; |
|
|
|
|
|
|
|
var Dict = corePrimitives.Dict; |
|
|
|
var Ref = corePrimitives.Ref; |
|
|
|
var Ref = corePrimitives.Ref; |
|
|
|
var RefSet = corePrimitives.RefSet; |
|
|
|
var RefSet = corePrimitives.RefSet; |
|
|
|
var RefSetCache = corePrimitives.RefSetCache; |
|
|
|
var RefSetCache = corePrimitives.RefSetCache; |
|
|
@ -70,10 +71,11 @@ var Catalog = (function CatalogClosure() { |
|
|
|
this.pdfManager = pdfManager; |
|
|
|
this.pdfManager = pdfManager; |
|
|
|
this.xref = xref; |
|
|
|
this.xref = xref; |
|
|
|
this.catDict = xref.getCatalogObj(); |
|
|
|
this.catDict = xref.getCatalogObj(); |
|
|
|
this.fontCache = new RefSetCache(); |
|
|
|
|
|
|
|
this.builtInCMapCache = Object.create(null); |
|
|
|
|
|
|
|
assert(isDict(this.catDict), 'catalog object is not a dictionary'); |
|
|
|
assert(isDict(this.catDict), 'catalog object is not a dictionary'); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this.fontCache = new RefSetCache(); |
|
|
|
|
|
|
|
this.builtInCMapCache = Object.create(null); |
|
|
|
|
|
|
|
this.pageKidsCountCache = new RefSetCache(); |
|
|
|
// TODO refactor to move getPage() to the PDFDocument.
|
|
|
|
// TODO refactor to move getPage() to the PDFDocument.
|
|
|
|
this.pageFactory = pageFactory; |
|
|
|
this.pageFactory = pageFactory; |
|
|
|
this.pagePromises = []; |
|
|
|
this.pagePromises = []; |
|
|
@ -421,6 +423,8 @@ var Catalog = (function CatalogClosure() { |
|
|
|
}, |
|
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
cleanup: function Catalog_cleanup() { |
|
|
|
cleanup: function Catalog_cleanup() { |
|
|
|
|
|
|
|
this.pageKidsCountCache.clear(); |
|
|
|
|
|
|
|
|
|
|
|
var promises = []; |
|
|
|
var promises = []; |
|
|
|
this.fontCache.forEach(function (promise) { |
|
|
|
this.fontCache.forEach(function (promise) { |
|
|
|
promises.push(promise); |
|
|
|
promises.push(promise); |
|
|
@ -453,17 +457,30 @@ var Catalog = (function CatalogClosure() { |
|
|
|
getPageDict: function Catalog_getPageDict(pageIndex) { |
|
|
|
getPageDict: function Catalog_getPageDict(pageIndex) { |
|
|
|
var capability = createPromiseCapability(); |
|
|
|
var capability = createPromiseCapability(); |
|
|
|
var nodesToVisit = [this.catDict.getRaw('Pages')]; |
|
|
|
var nodesToVisit = [this.catDict.getRaw('Pages')]; |
|
|
|
var currentPageIndex = 0; |
|
|
|
var count, currentPageIndex = 0; |
|
|
|
var xref = this.xref; |
|
|
|
var xref = this.xref, pageKidsCountCache = this.pageKidsCountCache; |
|
|
|
|
|
|
|
|
|
|
|
function next() { |
|
|
|
function next() { |
|
|
|
while (nodesToVisit.length) { |
|
|
|
while (nodesToVisit.length) { |
|
|
|
var currentNode = nodesToVisit.pop(); |
|
|
|
var currentNode = nodesToVisit.pop(); |
|
|
|
|
|
|
|
|
|
|
|
if (isRef(currentNode)) { |
|
|
|
if (isRef(currentNode)) { |
|
|
|
|
|
|
|
count = pageKidsCountCache.get(currentNode); |
|
|
|
|
|
|
|
// Skip nodes where the page can't be.
|
|
|
|
|
|
|
|
if (count > 0 && currentPageIndex + count < pageIndex) { |
|
|
|
|
|
|
|
currentPageIndex += count; |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
xref.fetchAsync(currentNode).then(function (obj) { |
|
|
|
xref.fetchAsync(currentNode).then(function (obj) { |
|
|
|
if (isDict(obj, 'Page') || (isDict(obj) && !obj.has('Kids'))) { |
|
|
|
if (isDict(obj, 'Page') || (isDict(obj) && !obj.has('Kids'))) { |
|
|
|
if (pageIndex === currentPageIndex) { |
|
|
|
if (pageIndex === currentPageIndex) { |
|
|
|
|
|
|
|
// Cache the Page reference, since it can *greatly* improve
|
|
|
|
|
|
|
|
// performance by reducing redundant lookups in long documents
|
|
|
|
|
|
|
|
// where all nodes are found at *one* level of the tree.
|
|
|
|
|
|
|
|
if (currentNode && !pageKidsCountCache.has(currentNode)) { |
|
|
|
|
|
|
|
pageKidsCountCache.put(currentNode, 1); |
|
|
|
|
|
|
|
} |
|
|
|
capability.resolve([obj, currentNode]); |
|
|
|
capability.resolve([obj, currentNode]); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
currentPageIndex++; |
|
|
|
currentPageIndex++; |
|
|
@ -481,7 +498,13 @@ var Catalog = (function CatalogClosure() { |
|
|
|
assert(isDict(currentNode), |
|
|
|
assert(isDict(currentNode), |
|
|
|
'page dictionary kid reference points to wrong type of object'); |
|
|
|
'page dictionary kid reference points to wrong type of object'); |
|
|
|
|
|
|
|
|
|
|
|
var count = currentNode.get('Count'); |
|
|
|
count = currentNode.get('Count'); |
|
|
|
|
|
|
|
// Cache the Kids count, since it can reduce redundant lookups in long
|
|
|
|
|
|
|
|
// documents where all nodes are found at *one* level of the tree.
|
|
|
|
|
|
|
|
var objId = currentNode.objId; |
|
|
|
|
|
|
|
if (objId && !pageKidsCountCache.has(objId)) { |
|
|
|
|
|
|
|
pageKidsCountCache.put(objId, count); |
|
|
|
|
|
|
|
} |
|
|
|
// Skip nodes where the page can't be.
|
|
|
|
// Skip nodes where the page can't be.
|
|
|
|
if (currentPageIndex + count <= pageIndex) { |
|
|
|
if (currentPageIndex + count <= pageIndex) { |
|
|
|
currentPageIndex += count; |
|
|
|
currentPageIndex += count; |
|
|
@ -1251,7 +1274,7 @@ var XRef = (function XRefClosure() { |
|
|
|
var cacheEntry = this.cache[num]; |
|
|
|
var cacheEntry = this.cache[num]; |
|
|
|
// In documents with Object Streams, it's possible that cached `Dict`s
|
|
|
|
// In documents with Object Streams, it's possible that cached `Dict`s
|
|
|
|
// have not been assigned an `objId` yet (see e.g. issue3115r.pdf).
|
|
|
|
// have not been assigned an `objId` yet (see e.g. issue3115r.pdf).
|
|
|
|
if (isDict(cacheEntry) && !cacheEntry.objId) { |
|
|
|
if (cacheEntry instanceof Dict && !cacheEntry.objId) { |
|
|
|
cacheEntry.objId = ref.toString(); |
|
|
|
cacheEntry.objId = ref.toString(); |
|
|
|
} |
|
|
|
} |
|
|
|
return cacheEntry; |
|
|
|
return cacheEntry; |
|
|
|