Merge branch 'master' of github.com:andreasgal/pdf.js

This commit is contained in:
Andreas Gal 2011-06-19 13:20:00 -07:00
commit 010475176f
12 changed files with 310 additions and 39 deletions

View File

@ -6,6 +6,7 @@
Shaon Barman <shaon.barman@gmail.com>
Vivien Nicolas <21@vingtetun.org>
Justin D'Arcangelo <justindarc@gmail.com>
Yury Delendik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),

View File

@ -1,6 +1,8 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
"use strict";
/**
* Maximum file size of the font.
*/
@ -203,7 +205,7 @@ Font.prototype = {
}
}
ctx.font = "bold italic 20px " + fontName + ", Symbol, Arial";
var textWidth = ctx.mozMeasureText(testString);
var textWidth = ctx.measureText(testString).width;
if (debug)
ctx.fillText(testString, 20, 20);
@ -218,7 +220,7 @@ Font.prototype = {
window.clearInterval(interval);
Fonts[fontName].loading = false;
warn("Is " + fontName + " for charset: " + charset + " loaded?");
} else if (textWidth != ctx.mozMeasureText(testString)) {
} else if (textWidth != ctx.measureText(testString).width) {
window.clearInterval(interval);
Fonts[fontName].loading = false;
}
@ -1042,7 +1044,8 @@ var Type1Parser = function() {
this.extractFontProgram = function t1_extractFontProgram(aStream) {
var eexecString = decrypt(aStream, kEexecEncryptionKey, 4);
var subrs = [], glyphs = [];
var inSubrs = inGlyphs = false;
var inGlyphs = false;
var inSubrs = false;
var glyph = "";
var token = "";

View File

@ -1,3 +1,8 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
"use strict";
var GlyphsUnicode = {
A: 0x0041,
AE: 0x00C6,

BIN
images/combobox.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

View File

@ -113,6 +113,67 @@ span {
background: url('images/buttons.png') no-repeat -28px 0px;
}
#scaleComboBoxInput {
background: url('images/combobox.png') no-repeat 0px -23px;
display: inline-block;
float: left;
margin: 0px;
width: 35px;
height: 23px;
}
#scaleComboBoxInput input {
background: none;
border: 0px;
margin: 3px 2px 0px;
width: 31px;
}
#scaleComboBoxButton {
background: url('images/combobox.png') no-repeat -41px -23px;
cursor: pointer;
display: inline-block;
float: left;
margin: 0px;
width: 21px;
height: 23px;
}
#scaleComboBoxButton.down {
background: url('images/combobox.png') no-repeat -41px -46px;
}
#scaleComboBoxButton.disabled {
background: url('images/combobox.png') no-repeat -41px 0px;
}
#scaleComboBoxList {
background-color: #fff;
border: 1px solid #666;
clear: both;
position: relative;
display: none;
top: -20px;
width: 48px;
}
#scaleComboBoxList > ul {
list-style: none;
padding: 0px;
margin: 0px;
}
#scaleComboBoxList > ul > li {
display: inline-block;
cursor: pointer;
width: 100%;
}
#scaleComboBoxList > ul > li:hover {
background-color: #09f;
color: #fff;
}
#pageNumber, #scale {
text-align: right;
}

View File

@ -21,9 +21,18 @@
<span class="label">Page Number</span>
</span>
<span class="control">
<input type="text" id="scale" value="100" size="2"/>
<span>%</span>
<span id="scaleComboBoxInput"><input type="text" id="scale" value="100%" size="2"/></span><span id="scaleComboBoxButton"></span>
<span class="label">Zoom</span>
<div id="scaleComboBoxList">
<ul>
<li>50%</li>
<li>75%</li>
<li>100%</li>
<li>125%</li>
<li>150%</li>
<li>200%</li>
</ul>
</div>
</span>
</div>
<div id="viewer"></div>

View File

@ -1,14 +1,17 @@
/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- /
/* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */
"use strict";
var PDFViewer = {
queryParams: {},
element: null,
pageNumberInput: null,
previousPageButton: null,
nextPageButton: null,
pageNumberInput: null,
scaleInput: null,
willJumpToPage: false,
@ -156,6 +159,8 @@ var PDFViewer = {
PDFViewer.drawPage(1);
}
}
PDFViewer.scaleInput.value = Math.floor(PDFViewer.scale * 100) + '%';
},
goToPage: function(num) {
@ -315,13 +320,40 @@ window.onload = function() {
this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : '';
};
var scaleInput = document.getElementById('scale');
scaleInput.onchange = function(evt) {
PDFViewer.changeScale(this.value);
PDFViewer.scaleInput = document.getElementById('scale');
PDFViewer.scaleInput.buttonElement = document.getElementById('scaleComboBoxButton');
PDFViewer.scaleInput.buttonElement.listElement = document.getElementById('scaleComboBoxList');
PDFViewer.scaleInput.onchange = function(evt) {
PDFViewer.changeScale(parseInt(this.value));
};
PDFViewer.scaleInput.buttonElement.onclick = function(evt) {
this.listElement.style.display = (this.listElement.style.display === 'block') ? 'none' : 'block';
};
PDFViewer.scaleInput.buttonElement.onmousedown = function(evt) {
if (this.className.indexOf('disabled') === -1) {
this.className = 'down';
}
};
PDFViewer.scaleInput.buttonElement.onmouseup = function(evt) {
this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : '';
};
PDFViewer.scaleInput.buttonElement.onmouseout = function(evt) {
this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : '';
};
var listItems = PDFViewer.scaleInput.buttonElement.listElement.getElementsByTagName('LI');
for (var i = 0; i < listItems.length; i++) {
var listItem = listItems[i];
listItem.onclick = function(evt) {
PDFViewer.changeScale(parseInt(this.innerHTML));
PDFViewer.scaleInput.buttonElement.listElement.style.display = 'none';
};
}
PDFViewer.pageNumber = parseInt(PDFViewer.queryParams.page) || PDFViewer.pageNumber;
PDFViewer.scale = parseInt(scaleInput.value) / 100 || 1.0;
PDFViewer.scale = parseInt(PDFViewer.scaleInput.value) / 100 || 1.0;
PDFViewer.open(PDFViewer.queryParams.file || PDFViewer.url);
window.onscroll = function(evt) {

194
pdf.js
View File

@ -1,6 +1,8 @@
/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- /
/* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */
"use strict";
var ERRORS = 0, WARNINGS = 1, TODOS = 5;
var verbosity = WARNINGS;
@ -389,6 +391,12 @@ var FlateStream = (function() {
return [codes, maxLen];
},
readBlock: function() {
function repeat(stream, array, len, offset, what) {
var repeat = stream.getBits(len) + offset;
while (repeat-- > 0)
array[i++] = what;
}
var stream = this.stream;
// read block header
@ -449,11 +457,6 @@ var FlateStream = (function() {
var codes = numLitCodes + numDistCodes;
var codeLengths = new Array(codes);
while (i < codes) {
function repeat(stream, array, len, offset, what) {
var repeat = stream.getBits(len) + offset;
while (repeat-- > 0)
array[i++] = what;
}
var code = this.getCode(codeLenCodeTab);
if (code == 16) {
repeat(this, codeLengths, 2, 3, len);
@ -506,6 +509,94 @@ var FlateStream = (function() {
return constructor;
})();
var PredictorStream = (function() {
function constructor(stream, params) {
this.stream = stream;
this.predictor = params.get("Predictor") || 1;
if (this.predictor <= 1) {
return stream; // no prediction
}
if (params.has("EarlyChange")) {
error("EarlyChange predictor parameter is not supported");
}
this.colors = params.get("Colors") || 1;
this.bitsPerComponent = params.get("BitsPerComponent") || 8;
this.columns = params.get("Columns") || 1;
if (this.colors !== 1 || this.bitsPerComponent !== 8) {
error("Multi-color and multi-byte predictors are not supported");
}
if (this.predictor < 10 || this.predictor > 15) {
error("Unsupported predictor");
}
this.currentRow = new Uint8Array(this.columns);
this.pos = 0;
this.bufferLength = 0;
}
constructor.prototype = {
readRow : function() {
var lastRow = this.currentRow;
var predictor = this.stream.getByte();
var currentRow = this.stream.getBytes(this.columns), i;
switch (predictor) {
default:
error("Unsupported predictor");
break;
case 0:
break;
case 2:
for (i = 0; i < currentRow.length; ++i) {
currentRow[i] = (lastRow[i] + currentRow[i]) & 0xFF;
}
break;
}
this.pos = 0;
this.bufferLength = currentRow.length;
this.currentRow = currentRow;
},
getByte : function() {
if (this.pos >= this.bufferLength) {
this.readRow();
}
return this.currentRow[this.pos++];
},
getBytes : function(n) {
var i, bytes;
bytes = new Uint8Array(n);
for (i = 0; i < n; ++i) {
if (this.pos >= this.bufferLength) {
this.readRow();
}
bytes[i] = this.currentRow[this.pos++];
}
return bytes;
},
getChar : function() {
return String.formCharCode(this.getByte());
},
lookChar : function() {
if (this.pos >= this.bufferLength) {
this.readRow();
}
return String.formCharCode(this.currentRow[this.pos]);
},
skip : function(n) {
var i;
if (!n) {
n = 1;
}
while (n > this.bufferLength - this.pos) {
n -= this.bufferLength - this.pos;
this.readRow();
if (this.bufferLength === 0) break;
}
this.pos += n;
}
};
return constructor;
})();
var DecryptStream = (function() {
function constructor(str, fileKey, encAlgorithm, keyLength) {
// TODO
@ -725,6 +816,7 @@ var Lexer = (function() {
var done = false;
var str = "";
var stream = this.stream;
var ch;
do {
switch (ch = stream.getChar()) {
case undefined:
@ -1085,7 +1177,9 @@ var Parser = (function() {
this.encAlgorithm,
this.keyLength);
}
return this.filter(stream, dict);
stream = this.filter(stream, dict);
stream.parameters = dict;
return stream;
},
filter: function(stream, dict) {
var filter = dict.get2("Filter", "F");
@ -1110,8 +1204,9 @@ var Parser = (function() {
},
makeFilter: function(stream, name, params) {
if (name == "FlateDecode" || name == "Fl") {
if (params)
error("params not supported yet for FlateDecode");
if (params) {
return new PredictorStream(new FlateStream(stream), params);
}
return new FlateStream(stream);
} else {
error("filter '" + name + "' not supported yet");
@ -1204,10 +1299,10 @@ var XRef = (function() {
this.stream = stream;
this.entries = [];
this.xrefstms = {};
this.readXRef(startXRef);
var trailerDict = this.readXRef(startXRef);
// get the root dictionary (catalog) object
if (!IsRef(this.root = this.trailerDict.get("Root")))
if (!IsRef(this.root = trailerDict.get("Root")))
error("Invalid root reference");
// prepare the XRef cache
@ -1262,18 +1357,18 @@ var XRef = (function() {
error("Invalid XRef table");
// get the 'Prev' pointer
var more = false;
var prev;
obj = dict.get("Prev");
if (IsInt(obj)) {
this.prev = obj;
more = true;
prev = obj;
} else if (IsRef(obj)) {
// certain buggy PDF generators generate "/Prev NNN 0 R" instead
// of "/Prev NNN"
this.prev = obj.num;
more = true;
prev = obj.num;
}
if (prev) {
this.readXRef(prev);
}
this.trailerDict = dict;
// check for 'XRefStm' key
if (IsInt(obj = dict.get("XRefStm"))) {
@ -1283,11 +1378,64 @@ var XRef = (function() {
this.xrefstms[pos] = 1; // avoid infinite recursion
this.readXRef(pos);
}
return more;
return dict;
},
readXRefStream: function(parser) {
error("Invalid XRef stream");
readXRefStream: function(stream) {
var streamParameters = stream.parameters;
var length = streamParameters.get("Length");
var byteWidths = streamParameters.get("W");
var range = streamParameters.get("Index");
if (!range) {
range = [0, streamParameters.get("Size")];
}
var i, j;
while (range.length > 0) {
var first = range[0], n = range[1];
if (!IsInt(first) || !IsInt(n)) {
error("Invalid XRef range fields");
}
var typeFieldWidth = byteWidths[0], offsetFieldWidth = byteWidths[1], generationFieldWidth = byteWidths[2];
if (!IsInt(typeFieldWidth) || !IsInt(offsetFieldWidth) || !IsInt(generationFieldWidth)) {
error("Invalid XRef entry fields length");
}
for (i = 0; i < n; ++i) {
var type = 0, offset = 0, generation = 0;
for (j = 0; j < typeFieldWidth; ++j) {
type = (type << 8) | stream.getByte();
}
for (j = 0; j < offsetFieldWidth; ++j) {
offset = (offset << 8) | stream.getByte();
}
for (j = 0; j < generationFieldWidth; ++j) {
generation = (generation << 8) | stream.getByte();
}
var entry = { offset: offset, gen: generation };
if (typeFieldWidth > 0) {
switch (type) {
case 0:
entry.free = true;
break;
case 1:
entry.uncompressed = true;
break;
case 2:
break;
default:
error("Invalid XRef entry type");
break;
}
}
if (!this.entries[first + i]) {
this.entries[first + i] = entry;
}
}
range.splice(0, 2);
}
var prev = streamParameters.get("Prev");
if (IsInt(prev)) {
this.readXRef(prev);
}
return streamParameters;
},
readXRef: function(startXRef) {
var stream = this.stream;
@ -1429,7 +1577,7 @@ var Catalog = (function() {
return shadow(this, "toplevelPagesDict", obj);
},
get numPages() {
obj = this.toplevelPagesDict.get("Count");
var obj = this.toplevelPagesDict.get("Count");
assertWellFormed(IsInt(obj),
"page count in top level pages object is not an integer");
// shadow the prototype getter
@ -1571,7 +1719,7 @@ var PDFDoc = (function() {
},
getPage: function(n) {
var linearization = this.linearization;
assert(!linearization, "linearized page access not implemented");
// assert(!linearization, "linearized page access not implemented");
return this.catalog.getPage(n);
}
};
@ -2383,7 +2531,7 @@ var CanvasGraphics = (function() {
error("No support for array of functions");
else if (!IsPDFFunction(fnObj))
error("Invalid function");
fn = new PDFFunction(this.xref, fnObj);
var fn = new PDFFunction(this.xref, fnObj);
var gradient = this.ctx.createLinearGradient(x0, y0, x1, y1);
var step = (t1 - t0) / 10;

View File

@ -1,3 +1,8 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
"use strict";
var CFFStrings = [
".notdef",
"space",

View File

@ -1,3 +1,8 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
"use strict";
/**
* The Type2 reader code below is only used for debugging purpose since Type2
* is only a CharString format and is never used directly as a Font file.

View File

@ -1,12 +1,14 @@
/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- /
/* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */
var pdfDocument, canvas, pageDisplay, pageNum, pageInterval;
"use strict";
var pdfDocument, canvas, numPages, pageDisplay, pageNum, pageInterval;
function load(userInput) {
canvas = document.getElementById("canvas");
canvas.mozOpaque = true;
pageNum = parseInt(queryParams().page) || 1;
fileName = userInput;
var fileName = userInput;
if (!userInput) {
fileName = queryParams().file || "compressed.tracemonkey-pldi-09.pdf";
}
@ -26,7 +28,7 @@ function queryParams() {
function open(url) {
document.title = url;
req = new XMLHttpRequest();
var req = new XMLHttpRequest();
req.open("GET", url);
req.mozResponseType = req.responseType = "arraybuffer";
req.expected = (document.URL.indexOf("file:") == 0) ? 0 : 200;