Merge branch 'master' of https://github.com/mozilla/pdf.js into xrefdict

This commit is contained in:
Brendan Dahl 2012-04-04 11:45:04 -07:00
commit 82a95d8bde
8 changed files with 175 additions and 61 deletions

View File

@ -752,28 +752,30 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
continue; continue;
} }
var char = glyph.fontChar; var character = glyph.fontChar;
var charWidth = glyph.width * fontSize * 0.001 + var charWidth = glyph.width * fontSize * 0.001 +
Util.sign(current.fontMatrix[0]) * charSpacing; Util.sign(current.fontMatrix[0]) * charSpacing;
var scaledX = x / fontSizeScale; if (!glyph.disabled) {
switch (textRenderingMode) { var scaledX = x / fontSizeScale;
default: // other unsupported rendering modes switch (textRenderingMode) {
case TextRenderingMode.FILL: default: // other unsupported rendering modes
case TextRenderingMode.FILL_ADD_TO_PATH: case TextRenderingMode.FILL:
ctx.fillText(char, scaledX, 0); case TextRenderingMode.FILL_ADD_TO_PATH:
break; ctx.fillText(character, scaledX, 0);
case TextRenderingMode.STROKE: break;
case TextRenderingMode.STROKE_ADD_TO_PATH: case TextRenderingMode.STROKE:
ctx.strokeText(char, scaledX, 0); case TextRenderingMode.STROKE_ADD_TO_PATH:
break; ctx.strokeText(character, scaledX, 0);
case TextRenderingMode.FILL_STROKE: break;
case TextRenderingMode.FILL_STROKE_ADD_TO_PATH: case TextRenderingMode.FILL_STROKE:
ctx.fillText(char, scaledX, 0); case TextRenderingMode.FILL_STROKE_ADD_TO_PATH:
ctx.strokeText(char, scaledX, 0); ctx.fillText(character, scaledX, 0);
break; ctx.strokeText(character, scaledX, 0);
case TextRenderingMode.INVISIBLE: break;
break; case TextRenderingMode.INVISIBLE:
break;
}
} }
x += charWidth; x += charWidth;

View File

@ -533,9 +533,9 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
var cmap = cmapObj.getBytes(cmapObj.length); var cmap = cmapObj.getBytes(cmapObj.length);
for (var i = 0, ii = cmap.length; i < ii; i++) { for (var i = 0, ii = cmap.length; i < ii; i++) {
var byte = cmap[i]; var octet = cmap[i];
if (byte == 0x20 || byte == 0x0D || byte == 0x0A || if (octet == 0x20 || octet == 0x0D || octet == 0x0A ||
byte == 0x3C || byte == 0x5B || byte == 0x5D) { octet == 0x3C || octet == 0x5B || octet == 0x5D) {
switch (token) { switch (token) {
case 'usecmap': case 'usecmap':
error('usecmap is not implemented'); error('usecmap is not implemented');
@ -592,7 +592,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
tokens.push(token); tokens.push(token);
token = ''; token = '';
} }
switch (byte) { switch (octet) {
case 0x5B: case 0x5B:
// begin list parsing // begin list parsing
tokens.push(beginArrayToken); tokens.push(beginArrayToken);
@ -606,7 +606,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
tokens.push(items); tokens.push(items);
break; break;
} }
} else if (byte == 0x3E) { } else if (octet == 0x3E) {
if (token.length) { if (token.length) {
if (token.length <= 4) { if (token.length <= 4) {
// parsing hex number // parsing hex number
@ -632,7 +632,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
} }
} }
} else { } else {
token += String.fromCharCode(byte); token += String.fromCharCode(octet);
} }
} }
} }

View File

@ -1828,8 +1828,9 @@ var Font = (function FontClosure() {
readGlyphNameMap(post, properties); readGlyphNameMap(post, properties);
} }
// Replace the old CMAP table with a shiny new one var glyphs, ids;
if (properties.type == 'CIDFontType2') { 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 // Type2 composite fonts map characters directly to glyphs so the cmap
// table must be replaced. // table must be replaced.
// canvas fillText will reencode some characters even if the font has a // 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 usedUnicodes = [];
var unassignedUnicodeItems = []; var unassignedUnicodeItems = [];
for (var i = 1; i < numGlyphs; i++) { for (var i = 1; i < numGlyphs; i++) {
@ -1892,11 +1895,12 @@ var Font = (function FontClosure() {
glyphs.push({ unicode: unicode, code: cid }); glyphs.push({ unicode: unicode, code: cid });
ids.push(i); ids.push(i);
} }
cmap.data = createCMapTable(glyphs, ids);
} else { } else {
var cmapTable = readCMapTable(cmap, font); var cmapTable = readCMapTable(cmap, font);
var glyphs = cmapTable.glyphs;
var ids = cmapTable.ids; glyphs = cmapTable.glyphs;
ids = cmapTable.ids;
var hasShortCmap = !!cmapTable.hasShortCmap; var hasShortCmap = !!cmapTable.hasShortCmap;
var toFontChar = this.toFontChar; var toFontChar = this.toFontChar;
@ -2062,10 +2066,16 @@ var Font = (function FontClosure() {
createGlyphNameMap(glyphs, ids, properties); createGlyphNameMap(glyphs, ids, properties);
this.glyphNameMap = properties.glyphNameMap; 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 // Rewrite the 'post' table if needed
if (requiredTables.indexOf('post') != -1) { if (requiredTables.indexOf('post') != -1) {
tables.push({ tables.push({
@ -2391,7 +2401,7 @@ var Font = (function FontClosure() {
}, },
charToGlyph: function fonts_charToGlyph(charcode) { charToGlyph: function fonts_charToGlyph(charcode) {
var fontCharCode, width, operatorList; var fontCharCode, width, operatorList, disabled;
var width = this.widths[charcode]; var width = this.widths[charcode];
@ -2464,11 +2474,14 @@ var Font = (function FontClosure() {
unicodeChars = String.fromCharCode(unicodeChars); unicodeChars = String.fromCharCode(unicodeChars);
width = (isNum(width) ? width : this.defaultWidth) * this.widthMultiplier; width = (isNum(width) ? width : this.defaultWidth) * this.widthMultiplier;
disabled = this.unicodeIsEnabled ?
!this.unicodeIsEnabled[fontCharCode] : false;
return { return {
fontChar: String.fromCharCode(fontCharCode), fontChar: String.fromCharCode(fontCharCode),
unicode: unicodeChars, unicode: unicodeChars,
width: width, width: width,
disabled: disabled,
operatorList: operatorList operatorList: operatorList
}; };
}, },
@ -2848,7 +2861,7 @@ var Type1Parser = function type1Parser() {
subrs: [], subrs: [],
charstrings: [], charstrings: [],
properties: { properties: {
'private': { 'privateData': {
'lenIV': 4 'lenIV': 4
} }
} }
@ -2877,7 +2890,7 @@ var Type1Parser = function type1Parser() {
(token == 'RD' || token == '-|')) { (token == 'RD' || token == '-|')) {
i++; i++;
var data = eexec.slice(i, i + length); 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 encoded = decrypt(data, kCharStringsEncryptionKey, lenIV);
var str = decodeCharString(encoded); var str = decodeCharString(encoded);
@ -2917,7 +2930,7 @@ var Type1Parser = function type1Parser() {
var length = parseInt(getToken(), 10); var length = parseInt(getToken(), 10);
getToken(); // read in 'RD' getToken(); // read in 'RD'
var data = eexec.slice(i + 1, i + 1 + length); 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 encoded = decrypt(data, kCharStringsEncryptionKey, lenIV);
var str = decodeCharString(encoded); var str = decodeCharString(encoded);
i = i + 1 + length; i = i + 1 + length;
@ -2933,12 +2946,12 @@ var Type1Parser = function type1Parser() {
case '/FamilyOtherBlues': case '/FamilyOtherBlues':
case '/StemSnapH': case '/StemSnapH':
case '/StemSnapV': case '/StemSnapV':
program.properties.private[token.substring(1)] = program.properties.privateData[token.substring(1)] =
readNumberArray(eexecStr, i + 1); readNumberArray(eexecStr, i + 1);
break; break;
case '/StdHW': case '/StdHW':
case '/StdVW': case '/StdVW':
program.properties.private[token.substring(1)] = program.properties.privateData[token.substring(1)] =
readNumberArray(eexecStr, i + 2)[0]; readNumberArray(eexecStr, i + 2)[0];
break; break;
case '/BlueShift': case '/BlueShift':
@ -2947,7 +2960,7 @@ var Type1Parser = function type1Parser() {
case '/BlueScale': case '/BlueScale':
case '/LanguageGroup': case '/LanguageGroup':
case '/ExpansionFactor': case '/ExpansionFactor':
program.properties.private[token.substring(1)] = program.properties.privateData[token.substring(1)] =
readNumber(eexecStr, i + 1); readNumber(eexecStr, i + 1);
break; break;
} }
@ -2971,14 +2984,14 @@ var Type1Parser = function type1Parser() {
var count = headerString.length; var count = headerString.length;
for (var i = 0; i < count; i++) { for (var i = 0; i < count; i++) {
var getToken = function getToken() { var getToken = function getToken() {
var char = headerString[i]; var character = headerString[i];
while (i < count && (isSeparator(char) || char == '/')) while (i < count && (isSeparator(character) || character == '/'))
char = headerString[++i]; character = headerString[++i];
var token = ''; var token = '';
while (i < count && !(isSeparator(char) || char == '/')) { while (i < count && !(isSeparator(character) || character == '/')) {
token += char; token += character;
char = headerString[++i]; character = headerString[++i];
} }
return token; return token;
@ -3344,7 +3357,7 @@ Type1Font.prototype = {
dict += self.encodeNumber(offset) + '\x11'; // Charstrings dict += self.encodeNumber(offset) + '\x11'; // Charstrings
offset = offset + fields.charstrings.length; offset = offset + fields.charstrings.length;
dict += self.encodeNumber(fields.private.length); dict += self.encodeNumber(fields.privateData.length);
dict += self.encodeNumber(offset) + '\x12'; // Private dict += self.encodeNumber(offset) + '\x12'; // Private
return header + String.fromCharCode(dict.length + 1) + dict; return header + String.fromCharCode(dict.length + 1) + dict;
@ -3385,7 +3398,7 @@ Type1Font.prototype = {
'charstrings': this.createCFFIndexHeader([[0x8B, 0x0E]].concat(glyphs), 'charstrings': this.createCFFIndexHeader([[0x8B, 0x0E]].concat(glyphs),
true), true),
'private': (function cffWrapPrivate(self) { 'privateData': (function cffWrapPrivate(self) {
var data = var data =
'\x8b\x14' + // defaultWidth '\x8b\x14' + // defaultWidth
'\x8b\x15'; // nominalWidth '\x8b\x15'; // nominalWidth
@ -3403,9 +3416,9 @@ Type1Font.prototype = {
ExpansionFactor: '\x0c\x18' ExpansionFactor: '\x0c\x18'
}; };
for (var field in fieldMap) { for (var field in fieldMap) {
if (!properties.private.hasOwnProperty(field)) if (!properties.privateData.hasOwnProperty(field))
continue; continue;
var value = properties.private[field]; var value = properties.privateData[field];
if (isArray(value)) { if (isArray(value)) {
data += self.encodeNumber(value[0]); data += self.encodeNumber(value[0]);
@ -4362,16 +4375,18 @@ var CFFCompiler = (function CFFCompilerClosure() {
output.add(charStrings); output.add(charStrings);
if (cff.isCIDFont) { 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); var compiled = this.compileTopDicts(cff.fdArray, output.length);
topDictTracker.setEntryLocation('FDArray', [output.length], output); topDictTracker.setEntryLocation('FDArray', [output.length], output);
output.add(compiled.output); output.add(compiled.output);
var fontDictTrackers = compiled.trackers; var fontDictTrackers = compiled.trackers;
this.compilePrivateDicts(cff.fdArray, fontDictTrackers, output); 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); this.compilePrivateDicts([cff.topDict], [topDictTracker], output);

View File

@ -122,9 +122,9 @@ function readFontDictData(aString, aMap) {
token = ''; token = '';
var parsed = false; var parsed = false;
while (!parsed) { 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++) { for (var j = 0; j < nibbles.length; j++) {
var nibble = nibbles[j]; var nibble = nibbles[j];
switch (nibble) { switch (nibble) {
@ -336,7 +336,7 @@ var Type2Parser = function type2Parser(aFilePath) {
var privateDict = []; var privateDict = [];
for (var i = 0; i < priv.size; i++) for (var i = 0; i < priv.size; i++)
privateDict.push(aStream.getByte()); privateDict.push(aStream.getByte());
dump('private:' + privateDict); dump('privateData:' + privateDict);
parseAsToken(privateDict, CFFDictPrivateDataMap); parseAsToken(privateDict, CFFDictPrivateDataMap);
for (var p in font.map) for (var p in font.map)

View File

@ -266,6 +266,9 @@ function sendTaskResult(snapshot, task, failure) {
r.onreadystatechange = function sendTaskResultOnreadystatechange(e) { r.onreadystatechange = function sendTaskResultOnreadystatechange(e) {
if (r.readyState == 4) { if (r.readyState == 4) {
inFlightRequests--; inFlightRequests--;
// Retry until successful
if (r.status !== 200)
sendTaskResult(snapshot, task, failure);
} }
}; };
document.getElementById('inFlightCount').innerHTML = inFlightRequests++; document.getElementById('inFlightCount').innerHTML = inFlightRequests++;

View File

@ -391,11 +391,43 @@ canvas {
} }
} }
#loading { #loadingBox {
margin: 100px 0; margin: 100px 0;
text-align: center; 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 { #PDFBug {
font-size: 10px; font-size: 10px;
position: fixed; position: fixed;

View File

@ -143,7 +143,10 @@
</div> </div>
</div> </div>
<div id="loading">Loading... 0%</div> <div id="loadingBox">
<div id="loading">Loading... 0%</div>
<div id="loadingBar"><div class="progress"></div></div>
</div>
<div id="viewer"></div> <div id="viewer"></div>
</body> </body>
</html> </html>

View File

@ -15,6 +15,15 @@ var kMaxScale = 4.0;
var kImageDirectory = './images/'; var kImageDirectory = './images/';
var kSettingsMemory = 20; var kSettingsMemory = 20;
function getFileName(url) {
var anchor = url.indexOf('#');
var query = url.indexOf('?');
var end = Math.min(
anchor > 0 ? anchor : url.length,
query > 0 ? query : url.length);
return url.substring(url.lastIndexOf('/', end) + 1, end);
}
var Cache = function cacheCache(size) { var Cache = function cacheCache(size) {
var data = []; var data = [];
this.push = function cachePush(view) { this.push = function cachePush(view) {
@ -27,6 +36,48 @@ var Cache = function cacheCache(size) {
}; };
}; };
var ProgressBar = (function ProgressBarClosure() {
function clamp(v, min, max) {
return Math.min(Math.max(v, min), max);
}
function ProgressBar(id, opts) {
// Fetch the sub-elements for later
this.div = document.querySelector(id + ' .progress');
// Get options, with sensible defaults
this.height = opts.height || 100;
this.width = opts.width || 100;
this.units = opts.units || '%';
this.percent = opts.percent || 0;
// Initialize heights
this.div.style.height = this.height + this.units;
}
ProgressBar.prototype = {
updateBar: function ProgressBar_updateBar() {
var progressSize = this.width * this._percent / 100;
this.div.style.width = progressSize + this.units;
},
get percent() {
return this._percent;
},
set percent(val) {
this._percent = clamp(val, 0, 100);
this.updateBar();
}
};
return ProgressBar;
})();
var RenderingQueue = (function RenderingQueueClosure() { var RenderingQueue = (function RenderingQueueClosure() {
function RenderingQueue() { function RenderingQueue() {
this.items = []; this.items = [];
@ -258,7 +309,13 @@ var PDFView = {
}, },
open: function pdfViewOpen(url, scale) { open: function pdfViewOpen(url, scale) {
document.title = this.url = url; this.url = url;
document.title = decodeURIComponent(getFileName(url)) || url;
if (!PDFView.loadingBar) {
PDFView.loadingBar = new ProgressBar('#loadingBar', {});
}
var self = this; var self = this;
PDFJS.getPdf( PDFJS.getPdf(
@ -400,6 +457,8 @@ var PDFView = {
var percent = Math.round(level * 100); var percent = Math.round(level * 100);
var loadingIndicator = document.getElementById('loading'); var loadingIndicator = document.getElementById('loading');
loadingIndicator.textContent = 'Loading... ' + percent + '%'; loadingIndicator.textContent = 'Loading... ' + percent + '%';
PDFView.loadingBar.percent = percent;
}, },
load: function pdfViewLoad(data, scale) { load: function pdfViewLoad(data, scale) {
@ -414,8 +473,8 @@ var PDFView = {
var errorWrapper = document.getElementById('errorWrapper'); var errorWrapper = document.getElementById('errorWrapper');
errorWrapper.setAttribute('hidden', 'true'); errorWrapper.setAttribute('hidden', 'true');
var loadingIndicator = document.getElementById('loading'); var loadingBox = document.getElementById('loadingBox');
loadingIndicator.setAttribute('hidden', 'true'); loadingBox.setAttribute('hidden', 'true');
var sidebar = document.getElementById('sidebarView'); var sidebar = document.getElementById('sidebarView');
sidebar.parentNode.scrollTop = 0; sidebar.parentNode.scrollTop = 0;