diff --git a/src/canvas.js b/src/canvas.js index 7bf94a642..dd363ecf3 100644 --- a/src/canvas.js +++ b/src/canvas.js @@ -752,28 +752,30 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { continue; } - var char = glyph.fontChar; + var character = glyph.fontChar; var charWidth = glyph.width * fontSize * 0.001 + Util.sign(current.fontMatrix[0]) * charSpacing; - var scaledX = x / fontSizeScale; - switch (textRenderingMode) { - default: // other unsupported rendering modes - case TextRenderingMode.FILL: - case TextRenderingMode.FILL_ADD_TO_PATH: - ctx.fillText(char, scaledX, 0); - break; - case TextRenderingMode.STROKE: - case TextRenderingMode.STROKE_ADD_TO_PATH: - ctx.strokeText(char, scaledX, 0); - break; - case TextRenderingMode.FILL_STROKE: - case TextRenderingMode.FILL_STROKE_ADD_TO_PATH: - ctx.fillText(char, scaledX, 0); - ctx.strokeText(char, scaledX, 0); - break; - case TextRenderingMode.INVISIBLE: - break; + if (!glyph.disabled) { + var scaledX = x / fontSizeScale; + switch (textRenderingMode) { + default: // other unsupported rendering modes + case TextRenderingMode.FILL: + case TextRenderingMode.FILL_ADD_TO_PATH: + ctx.fillText(character, scaledX, 0); + break; + case TextRenderingMode.STROKE: + case TextRenderingMode.STROKE_ADD_TO_PATH: + ctx.strokeText(character, scaledX, 0); + break; + case TextRenderingMode.FILL_STROKE: + case TextRenderingMode.FILL_STROKE_ADD_TO_PATH: + ctx.fillText(character, scaledX, 0); + ctx.strokeText(character, scaledX, 0); + break; + case TextRenderingMode.INVISIBLE: + break; + } } x += charWidth; diff --git a/src/evaluator.js b/src/evaluator.js index c0a96d382..8db082d59 100644 --- a/src/evaluator.js +++ b/src/evaluator.js @@ -533,9 +533,9 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { var cmap = cmapObj.getBytes(cmapObj.length); for (var i = 0, ii = cmap.length; i < ii; i++) { - var byte = cmap[i]; - if (byte == 0x20 || byte == 0x0D || byte == 0x0A || - byte == 0x3C || byte == 0x5B || byte == 0x5D) { + var octet = cmap[i]; + if (octet == 0x20 || octet == 0x0D || octet == 0x0A || + octet == 0x3C || octet == 0x5B || octet == 0x5D) { switch (token) { case 'usecmap': error('usecmap is not implemented'); @@ -592,7 +592,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { tokens.push(token); token = ''; } - switch (byte) { + switch (octet) { case 0x5B: // begin list parsing tokens.push(beginArrayToken); @@ -606,7 +606,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { tokens.push(items); break; } - } else if (byte == 0x3E) { + } else if (octet == 0x3E) { if (token.length) { if (token.length <= 4) { // parsing hex number @@ -632,7 +632,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { } } } else { - token += String.fromCharCode(byte); + token += String.fromCharCode(octet); } } } diff --git a/src/fonts.js b/src/fonts.js index b756ff2ee..74bff269c 100644 --- a/src/fonts.js +++ b/src/fonts.js @@ -1828,8 +1828,9 @@ var Font = (function FontClosure() { readGlyphNameMap(post, properties); } - // Replace the old CMAP table with a shiny new one + var glyphs, ids; if (properties.type == 'CIDFontType2') { + // Replace the old CMAP table with a shiny new one // Type2 composite fonts map characters directly to glyphs so the cmap // table must be replaced. // canvas fillText will reencode some characters even if the font has a @@ -1861,7 +1862,9 @@ var Font = (function FontClosure() { } } - var glyphs = [], ids = []; + glyphs = []; + ids = []; + var usedUnicodes = []; var unassignedUnicodeItems = []; for (var i = 1; i < numGlyphs; i++) { @@ -1892,11 +1895,12 @@ var Font = (function FontClosure() { glyphs.push({ unicode: unicode, code: cid }); ids.push(i); } - cmap.data = createCMapTable(glyphs, ids); } else { var cmapTable = readCMapTable(cmap, font); - var glyphs = cmapTable.glyphs; - var ids = cmapTable.ids; + + glyphs = cmapTable.glyphs; + ids = cmapTable.ids; + var hasShortCmap = !!cmapTable.hasShortCmap; var toFontChar = this.toFontChar; @@ -2062,10 +2066,16 @@ var Font = (function FontClosure() { createGlyphNameMap(glyphs, ids, properties); this.glyphNameMap = properties.glyphNameMap; - - cmap.data = createCMapTable(glyphs, ids); } + // Converting glyphs and ids into font's cmap table + cmap.data = createCMapTable(glyphs, ids); + var unicodeIsEnabled = []; + for (var i = 0, ii = glyphs.length; i < ii; i++) { + unicodeIsEnabled[glyphs[i].unicode] = true; + } + this.unicodeIsEnabled = unicodeIsEnabled; + // Rewrite the 'post' table if needed if (requiredTables.indexOf('post') != -1) { tables.push({ @@ -2391,7 +2401,7 @@ var Font = (function FontClosure() { }, charToGlyph: function fonts_charToGlyph(charcode) { - var fontCharCode, width, operatorList; + var fontCharCode, width, operatorList, disabled; var width = this.widths[charcode]; @@ -2464,11 +2474,14 @@ var Font = (function FontClosure() { unicodeChars = String.fromCharCode(unicodeChars); width = (isNum(width) ? width : this.defaultWidth) * this.widthMultiplier; + disabled = this.unicodeIsEnabled ? + !this.unicodeIsEnabled[fontCharCode] : false; return { fontChar: String.fromCharCode(fontCharCode), unicode: unicodeChars, width: width, + disabled: disabled, operatorList: operatorList }; }, @@ -2848,7 +2861,7 @@ var Type1Parser = function type1Parser() { subrs: [], charstrings: [], properties: { - 'private': { + 'privateData': { 'lenIV': 4 } } @@ -2877,7 +2890,7 @@ var Type1Parser = function type1Parser() { (token == 'RD' || token == '-|')) { i++; var data = eexec.slice(i, i + length); - var lenIV = program.properties.private['lenIV']; + var lenIV = program.properties.privateData['lenIV']; var encoded = decrypt(data, kCharStringsEncryptionKey, lenIV); var str = decodeCharString(encoded); @@ -2917,7 +2930,7 @@ var Type1Parser = function type1Parser() { var length = parseInt(getToken(), 10); getToken(); // read in 'RD' var data = eexec.slice(i + 1, i + 1 + length); - var lenIV = program.properties.private['lenIV']; + var lenIV = program.properties.privateData['lenIV']; var encoded = decrypt(data, kCharStringsEncryptionKey, lenIV); var str = decodeCharString(encoded); i = i + 1 + length; @@ -2933,12 +2946,12 @@ var Type1Parser = function type1Parser() { case '/FamilyOtherBlues': case '/StemSnapH': case '/StemSnapV': - program.properties.private[token.substring(1)] = + program.properties.privateData[token.substring(1)] = readNumberArray(eexecStr, i + 1); break; case '/StdHW': case '/StdVW': - program.properties.private[token.substring(1)] = + program.properties.privateData[token.substring(1)] = readNumberArray(eexecStr, i + 2)[0]; break; case '/BlueShift': @@ -2947,7 +2960,7 @@ var Type1Parser = function type1Parser() { case '/BlueScale': case '/LanguageGroup': case '/ExpansionFactor': - program.properties.private[token.substring(1)] = + program.properties.privateData[token.substring(1)] = readNumber(eexecStr, i + 1); break; } @@ -2971,14 +2984,14 @@ var Type1Parser = function type1Parser() { var count = headerString.length; for (var i = 0; i < count; i++) { var getToken = function getToken() { - var char = headerString[i]; - while (i < count && (isSeparator(char) || char == '/')) - char = headerString[++i]; + var character = headerString[i]; + while (i < count && (isSeparator(character) || character == '/')) + character = headerString[++i]; var token = ''; - while (i < count && !(isSeparator(char) || char == '/')) { - token += char; - char = headerString[++i]; + while (i < count && !(isSeparator(character) || character == '/')) { + token += character; + character = headerString[++i]; } return token; @@ -3344,7 +3357,7 @@ Type1Font.prototype = { dict += self.encodeNumber(offset) + '\x11'; // Charstrings offset = offset + fields.charstrings.length; - dict += self.encodeNumber(fields.private.length); + dict += self.encodeNumber(fields.privateData.length); dict += self.encodeNumber(offset) + '\x12'; // Private return header + String.fromCharCode(dict.length + 1) + dict; @@ -3385,7 +3398,7 @@ Type1Font.prototype = { 'charstrings': this.createCFFIndexHeader([[0x8B, 0x0E]].concat(glyphs), true), - 'private': (function cffWrapPrivate(self) { + 'privateData': (function cffWrapPrivate(self) { var data = '\x8b\x14' + // defaultWidth '\x8b\x15'; // nominalWidth @@ -3403,9 +3416,9 @@ Type1Font.prototype = { ExpansionFactor: '\x0c\x18' }; for (var field in fieldMap) { - if (!properties.private.hasOwnProperty(field)) + if (!properties.privateData.hasOwnProperty(field)) continue; - var value = properties.private[field]; + var value = properties.privateData[field]; if (isArray(value)) { data += self.encodeNumber(value[0]); @@ -4362,16 +4375,18 @@ var CFFCompiler = (function CFFCompilerClosure() { output.add(charStrings); if (cff.isCIDFont) { + // For some reason FDSelect must be in front of FDArray on windows. OSX + // and linux don't seem to care. + topDictTracker.setEntryLocation('FDSelect', [output.length], output); + var fdSelect = this.compileFDSelect(cff.fdSelect.raw); + output.add(fdSelect); + var compiled = this.compileTopDicts(cff.fdArray, output.length); topDictTracker.setEntryLocation('FDArray', [output.length], output); output.add(compiled.output); var fontDictTrackers = compiled.trackers; this.compilePrivateDicts(cff.fdArray, fontDictTrackers, output); - - topDictTracker.setEntryLocation('FDSelect', [output.length], output); - var fdSelect = this.compileFDSelect(cff.fdSelect.raw); - output.add(fdSelect); } this.compilePrivateDicts([cff.topDict], [topDictTracker], output); diff --git a/src/utils/fonts_utils.js b/src/utils/fonts_utils.js index 2a1f0ea72..65c02fce2 100644 --- a/src/utils/fonts_utils.js +++ b/src/utils/fonts_utils.js @@ -122,9 +122,9 @@ function readFontDictData(aString, aMap) { token = ''; var parsed = false; while (!parsed) { - var byte = aString[i++]; + var octet = aString[i++]; - var nibbles = [parseInt(byte / 16, 10), parseInt(byte % 16, 10)]; + var nibbles = [parseInt(octet / 16, 10), parseInt(octet % 16, 10)]; for (var j = 0; j < nibbles.length; j++) { var nibble = nibbles[j]; switch (nibble) { @@ -336,7 +336,7 @@ var Type2Parser = function type2Parser(aFilePath) { var privateDict = []; for (var i = 0; i < priv.size; i++) privateDict.push(aStream.getByte()); - dump('private:' + privateDict); + dump('privateData:' + privateDict); parseAsToken(privateDict, CFFDictPrivateDataMap); for (var p in font.map) diff --git a/test/driver.js b/test/driver.js index 5a3263bda..8814da00e 100644 --- a/test/driver.js +++ b/test/driver.js @@ -266,6 +266,9 @@ function sendTaskResult(snapshot, task, failure) { r.onreadystatechange = function sendTaskResultOnreadystatechange(e) { if (r.readyState == 4) { inFlightRequests--; + // Retry until successful + if (r.status !== 200) + sendTaskResult(snapshot, task, failure); } }; document.getElementById('inFlightCount').innerHTML = inFlightRequests++; diff --git a/web/viewer.css b/web/viewer.css index fdce0288a..9a0cf388c 100644 --- a/web/viewer.css +++ b/web/viewer.css @@ -391,11 +391,43 @@ canvas { } } -#loading { +#loadingBox { margin: 100px 0; text-align: center; } +#loadingBar { + background-color: #333; + display: inline-block; + border: 1px solid black; + clear: both; + margin:0px; + line-height: 0; + border-radius: 4px; + width: 15em; + height: 1.5em; +} + +#loadingBar .progress { + background-color: green; + display: inline-block; + float: left; + + background: #b4e391; + background: -moz-linear-gradient(top, #b4e391 0%, #61c419 50%, #b4e391 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#b4e391), color-stop(50%,#61c419), color-stop(100%,#b4e391)); + background: -webkit-linear-gradient(top, #b4e391 0%,#61c419 50%,#b4e391 100%); + background: -o-linear-gradient(top, #b4e391 0%,#61c419 50%,#b4e391 100%); + background: -ms-linear-gradient(top, #b4e391 0%,#61c419 50%,#b4e391 100%); + background: linear-gradient(top, #b4e391 0%,#61c419 50%,#b4e391 100%); + + border-top-left-radius: 3px; + border-bottom-left-radius: 3px; + + width: 0%; + height: 100%; +} + #PDFBug { font-size: 10px; position: fixed; diff --git a/web/viewer.html b/web/viewer.html index 2806d3a7e..d275f77c1 100644 --- a/web/viewer.html +++ b/web/viewer.html @@ -143,7 +143,10 @@ -