From 51055e5836e628e5279733d5907e3b3477b8fb3f Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 4 Aug 2014 23:38:43 -0700 Subject: [PATCH] Make IdentityCMaps more compact. IdentityCMap uses an array to represent a 16-bit unsigned identity function. This is very space-inefficient, and some files cause multiple IdentityCMaps to be instantiated (e.g. the one from #4580 has 74). This patch make the representation implicit. When loading the PDF from issue #4580, this change reduces peak RSS from ~370 to ~280 MiB. It also improves overall speed on that PDF by ~30%, going from 522 ms to 366 ms. --- src/core/cmap.js | 53 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/src/core/cmap.js b/src/core/cmap.js index 4ffeb7700..5647f09fb 100644 --- a/src/core/cmap.js +++ b/src/core/cmap.js @@ -302,20 +302,69 @@ var CMap = (function CMapClosure() { return [0, 1]; } - }; return CMap; })(); +// A special case of CMap, where the _map array implicitly has a length of +// 65535 and each element is equal to its index. var IdentityCMap = (function IdentityCMapClosure() { function IdentityCMap(vertical, n) { CMap.call(this); this.vertical = vertical; this.addCodespaceRange(n, 0, 0xffff); - this.mapCidRange(0, 0xffff, 0); } Util.inherit(IdentityCMap, CMap, {}); + IdentityCMap.prototype = { + addCodespaceRange: CMap.prototype.addCodespaceRange, + + mapCidRange: function(low, high, dstLow) { + error('should not call mapCidRange'); + }, + + mapBfRange: function(low, high, dstLow) { + error('should not call mapBfRange'); + }, + + mapBfRangeToArray: function(low, high, array) { + error('should not call mapBfRangeToArray'); + }, + + mapOne: function(src, dst) { + error('should not call mapCidOne'); + }, + + lookup: function(code) { + return (isInt(code) && code <= 0xffff) ? code : undefined; + }, + + contains: function(code) { + return isInt(code) && code <= 0xffff; + }, + + forEach: function(callback) { + for (var i = 0; i <= 0xffff; i++) { + callback(i, i); + } + }, + + charCodeOf: function(value) { + return (isInt(value) && value <= 0xffff) ? value : -1; + }, + + getMap: function() { + // Sometimes identity maps must be instantiated, but it's rare. + var map = new Array(0x10000); + for (var i = 0; i <= 0xffff; i++) { + map[i] = i; + } + return map; + }, + + readCharCode: CMap.prototype.readCharCode + }; + return IdentityCMap; })();