diff options
Diffstat (limited to 'addons/web/static/lib/pdfjs/external/cmapscompress/optimize.js')
| -rw-r--r-- | addons/web/static/lib/pdfjs/external/cmapscompress/optimize.js | 211 |
1 files changed, 211 insertions, 0 deletions
diff --git a/addons/web/static/lib/pdfjs/external/cmapscompress/optimize.js b/addons/web/static/lib/pdfjs/external/cmapscompress/optimize.js new file mode 100644 index 00000000000..1252b9a2719 --- /dev/null +++ b/addons/web/static/lib/pdfjs/external/cmapscompress/optimize.js @@ -0,0 +1,211 @@ +/* Copyright 2014 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +exports.optimizeCMap = function (data) { + var i = 1; + while (i < data.body.length) { + if (data.body[i - 1].type === data.body[i].type) { + data.body[i - 1].items = data.body[i - 1].items.concat(data.body[i].items); + data.body.splice(i, 1); + } else { + i++; + } + } + // split into groups with different lengths + var i = 0; + while (i < data.body.length) { + var item = data.body[i]; + var keys = Object.keys(item.items[0]).filter(function (i) { + return typeof item.items[0][i] === 'string'; + }); + var j = 1; + while (j < item.items.length) { + var different = false; + for (var q = 0; q < keys.length && !different; q++) { + different = item.items[j - 1][keys[q]].length !== item.items[j][keys[q]].length; + } + if (different) { + break; + } + j++; + } + if (j < item.items.length) { + data.body.splice(i + 1, 0, { + type: item.type, + items: item.items.splice(j, item.items.length - j) + }); + } + i++; + } + // find sequences of single char ranges + var i = 0; + while (i < data.body.length) { + var item = data.body[i]; + if (item.type === 3 || item.type === 5) { + var j = 0; + while (j < item.items.length) { + var q = j; + while (j < item.items.length && item.items[j].start === item.items[j].end) { + j++; + } + if ((j - q) >= 9) { + if (j < item.items.length) { + data.body.splice(i + 1, 0, { + type: item.type, + items: item.items.splice(j, item.items.length - j) + }); + } + if (q > 0) { + data.body.splice(i + 1, 0, { + type: item.type - 1, + items: item.items.splice(q, j - q).map(function (i) { + return {char: i.start, code: i.code }; + }) + }); + i++; + } else { + item.type -= 1; + item.items = item.items.map(function (i) { + return {char: i.start, code: i.code }; + }); + } + continue; + } + j++; + } + } + i++; + } + + // find sequences of increasing code/ranges order + var i = 0; + while (i < data.body.length) { + var item = data.body[i]; + if (item.type >= 2 && item.type <= 5) { + var j = 1; + var startProp = item.type === 2 || item.type === 4 ? 'char' : 'start'; + var endProp = item.type === 2 || item.type === 4 ? 'char' : 'end'; + while (j < item.items.length) { + var q = j - 1; + while (j < item.items.length && incHex(item.items[j - 1][endProp]) === item.items[j][startProp]) { + j++; + } + if ((j - q) >= 9) { + if (j < item.items.length) { + data.body.splice(i + 1, 0, { + type: item.type, + items: item.items.splice(j, item.items.length - j) + }); + } + if (q > 0) { + data.body.splice(i + 1, 0, { + type: item.type, + items: item.items.splice(q, j - q), + sequence: true + }); + i++; + } else { + item.sequence = true; + } + continue; + } + j++; + } + } + i++; + } + + // split non-sequences two groups where codes are close + var i = 0; + while (i < data.body.length) { + var item = data.body[i]; + if (!item.sequence && (item.type === 2 || item.type === 3)) { + var subitems = item.items; + var codes = subitems.map(function (i) { + return i.code; + }); + codes.sort(function (a, b) { + return a - b; + }); + var maxDistance = 100, minItems = 10, itemsPerBucket = 50; + if (subitems.length > minItems && codes[codes.length - 1] - codes[0] > maxDistance) { + var gapsCount = Math.max(2, (subitems.length / itemsPerBucket) | 0); + var gaps = []; + for (var q = 0; q < gapsCount; q++) { + gaps.push({length: 0}); + } + for (var j = 1; j < codes.length; j++) { + var gapLength = codes[j] - codes[j - 1]; + var q = 0; + while (q < gaps.length && gaps[q].length > gapLength) { + q++; + } + if (q >= gaps.length) { + continue; + } + var q0 = q; + while (q < gaps.length) { + if (gaps[q].length < gaps[q0].length) { + q0 = q; + } + q++; + } + gaps[q0] = {length: gapLength, boundary: codes[j]}; + } + var groups = gaps.filter(function (g) { + return g.length >= maxDistance; + }).map(function (g) { + return g.boundary; + }); + groups.sort(function (a, b) { + return a - b; + }); + if (groups.length > 1) { + var buckets = [item.items = []]; + for (var j = 0; j < groups.length; j++) { + var newItem = {type: item.type, items: []} + buckets.push(newItem.items); + i++; + data.body.splice(i, 0, newItem); + } + for (var j = 0; j < subitems.length; j++) { + var code = subitems[j].code; + var q = 0; + while (q < groups.length && groups[q] <= code) { + q++; + } + buckets[q].push(subitems[j]); + } + } + } + } + i++; + } +}; + +function incHex(a) { + var c = 1, s = ''; + for (var i = a.length - 1; i >= 0; i--) { + c += parseInt(a[i], 16); + if (c >= 16) { + s = '0' + s; + c = 1; + } else { + s = c.toString(16) + s; + c = 0; + } + } + return s; +} |
