Merge branch 'master' into predictor

This commit is contained in:
sbarman 2011-06-20 22:42:26 -07:00
commit 650df34289
9 changed files with 937 additions and 902 deletions

1329
fonts.js

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

View File

@ -27,7 +27,30 @@ span {
.control > input { .control > input {
float: left; float: left;
border: 1px solid #4d4d4d;
height: 20px;
padding: 0px;
margin: 0px 2px 0px 0px; margin: 0px 2px 0px 0px;
border-radius: 4px;
-moz-border-radius: 4px;
-webkit-border-radius: 4px;
box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25);
-moz-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25);
-webkit-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25);
}
.control > select {
float: left;
border: 1px solid #4d4d4d;
height: 22px;
padding: 2px 0px 0px;
margin: 0px 0px 1px;
border-radius: 4px;
-moz-border-radius: 4px;
-webkit-border-radius: 4px;
box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25);
-moz-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25);
-webkit-box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.25);
} }
.control > span { .control > span {
@ -79,7 +102,7 @@ span {
#previousPageButton { #previousPageButton {
background: url('images/buttons.png') no-repeat 0px -23px; background: url('images/buttons.png') no-repeat 0px -23px;
cursor: pointer; cursor: default;
display: inline-block; display: inline-block;
float: left; float: left;
margin: 0px; margin: 0px;
@ -97,7 +120,7 @@ span {
#nextPageButton { #nextPageButton {
background: url('images/buttons.png') no-repeat -28px -23px; background: url('images/buttons.png') no-repeat -28px -23px;
cursor: pointer; cursor: default;
display: inline-block; display: inline-block;
float: left; float: left;
margin: 0px; margin: 0px;
@ -113,68 +136,7 @@ span {
background: url('images/buttons.png') no-repeat -28px 0px; background: url('images/buttons.png') no-repeat -28px 0px;
} }
#scaleComboBoxInput { #pageNumber {
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; text-align: right;
} }

View File

@ -2,7 +2,8 @@
<html> <html>
<head> <head>
<title>pdf.js Multi-Page Viewer</title> <title>pdf.js Multi-Page Viewer</title>
<link rel="stylesheet" href="multi-page-viewer.css" type="text/css" media="screen" charset="utf-8"/> <meta http-equiv="Content-type" content="text/html;charset=UTF-8"/>
<link rel="stylesheet" href="multi-page-viewer.css" type="text/css" media="screen"/>
<script type="text/javascript" src="pdf.js"></script> <script type="text/javascript" src="pdf.js"></script>
<script type="text/javascript" src="fonts.js"></script> <script type="text/javascript" src="fonts.js"></script>
<script type="text/javascript" src="glyphlist.js"></script> <script type="text/javascript" src="glyphlist.js"></script>
@ -11,7 +12,8 @@
<body> <body>
<div id="controls"> <div id="controls">
<span class="control"> <span class="control">
<span id="previousPageButton"></span><span id="nextPageButton"></span> <span id="previousPageButton" class="disabled"></span>
<span id="nextPageButton" class="disabled"></span>
<span class="label">Previous/Next</span> <span class="label">Previous/Next</span>
</span> </span>
<span class="control"> <span class="control">
@ -21,18 +23,15 @@
<span class="label">Page Number</span> <span class="label">Page Number</span>
</span> </span>
<span class="control"> <span class="control">
<span id="scaleComboBoxInput"><input type="text" id="scale" value="100%" size="2"/></span><span id="scaleComboBoxButton"></span> <select id="scaleSelect">
<option value="50">50%</option>
<option value="75">75%</option>
<option value="100" selected="selected">100%</option>
<option value="125">125%</option>
<option value="150">150%</option>
<option value="200">200%</option>
</select>
<span class="label">Zoom</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> </span>
</div> </div>
<div id="viewer"></div> <div id="viewer"></div>

View File

@ -11,7 +11,7 @@ var PDFViewer = {
previousPageButton: null, previousPageButton: null,
nextPageButton: null, nextPageButton: null,
pageNumberInput: null, pageNumberInput: null,
scaleInput: null, scaleSelect: null,
willJumpToPage: false, willJumpToPage: false,
@ -66,92 +66,103 @@ var PDFViewer = {
removePage: function(num) { removePage: function(num) {
var div = document.getElementById('pageContainer' + num); var div = document.getElementById('pageContainer' + num);
if (div && div.hasChildNodes()) { if (div) {
while (div.childNodes.length > 0) { while (div.hasChildNodes()) {
div.removeChild(div.firstChild); div.removeChild(div.firstChild);
} }
} }
}, },
drawPage: function(num) { drawPage: function(num) {
if (PDFViewer.pdf) { if (!PDFViewer.pdf) {
var page = PDFViewer.pdf.getPage(num); return;
var div = document.getElementById('pageContainer' + num); }
if (div && !div.hasChildNodes()) {
var canvas = document.createElement('canvas');
canvas.id = 'page' + num;
canvas.mozOpaque = true;
// Canvas dimensions must be specified in CSS pixels. CSS pixels
// are always 96 dpi. These dimensions are 8.5in x 11in at 96dpi.
canvas.width = PDFViewer.pageWidth();
canvas.height = PDFViewer.pageHeight();
var ctx = canvas.getContext('2d');
ctx.save();
ctx.fillStyle = 'rgb(255, 255, 255)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.restore();
var gfx = new CanvasGraphics(ctx);
var fonts = [];
// page.compile will collect all fonts for us, once we have loaded them var div = document.getElementById('pageContainer' + num);
// we can trigger the actual page rendering with page.display var canvas = document.createElement('canvas');
page.compile(gfx, fonts);
if (div && !div.hasChildNodes()) {
var fontsReady = true; div.appendChild(canvas);
// Inspect fonts and translate the missing one var page = PDFViewer.pdf.getPage(num);
var fontCount = fonts.length;
for (var i = 0; i < fontCount; i++) {
var font = fonts[i];
if (Fonts[font.name]) {
fontsReady = fontsReady && !Fonts[font.name].loading;
continue;
}
new Font(font.name, font.file, font.properties); canvas.id = 'page' + num;
canvas.mozOpaque = true;
fontsReady = false;
// Canvas dimensions must be specified in CSS pixels. CSS pixels
// are always 96 dpi. These dimensions are 8.5in x 11in at 96dpi.
canvas.width = PDFViewer.pageWidth();
canvas.height = PDFViewer.pageHeight();
var ctx = canvas.getContext('2d');
ctx.save();
ctx.fillStyle = 'rgb(255, 255, 255)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.restore();
var gfx = new CanvasGraphics(ctx);
var fonts = [];
// page.compile will collect all fonts for us, once we have loaded them
// we can trigger the actual page rendering with page.display
page.compile(gfx, fonts);
var areFontsReady = true;
// Inspect fonts and translate the missing one
var fontCount = fonts.length;
for (var i = 0; i < fontCount; i++) {
var font = fonts[i];
if (Fonts[font.name]) {
areFontsReady = areFontsReady && !Fonts[font.name].loading;
continue;
} }
var pageInterval; new Font(font.name, font.file, font.properties);
var delayLoadFont = function() {
for (var i = 0; i < fontCount; i++) { areFontsReady = false;
if (Fonts[font.name].loading) {
return;
}
}
clearInterval(pageInterval);
PDFViewer.drawPage(num);
}
if (!fontsReady) {
pageInterval = setInterval(delayLoadFont, 10);
return;
}
page.display(gfx);
div.appendChild(canvas);
} }
var pageInterval;
var delayLoadFont = function() {
for (var i = 0; i < fontCount; i++) {
if (Fonts[font.name].loading) {
return;
}
}
clearInterval(pageInterval);
while (div.hasChildNodes()) {
div.removeChild(div.firstChild);
}
PDFViewer.drawPage(num);
}
if (!areFontsReady) {
pageInterval = setInterval(delayLoadFont, 10);
return;
}
page.display(gfx);
} }
}, },
changeScale: function(num) { changeScale: function(num) {
while (PDFViewer.element.childNodes.length > 0) { while (PDFViewer.element.hasChildNodes()) {
PDFViewer.element.removeChild(PDFViewer.element.firstChild); PDFViewer.element.removeChild(PDFViewer.element.firstChild);
} }
PDFViewer.scale = num / 100; PDFViewer.scale = num / 100;
var i;
if (PDFViewer.pdf) { if (PDFViewer.pdf) {
for (var i = 1; i <= PDFViewer.numberOfPages; i++) { for (i = 1; i <= PDFViewer.numberOfPages; i++) {
PDFViewer.createPage(i); PDFViewer.createPage(i);
} }
@ -160,7 +171,21 @@ var PDFViewer = {
} }
} }
PDFViewer.scaleInput.value = Math.floor(PDFViewer.scale * 100) + '%'; for (i = 0; i < PDFViewer.scaleSelect.childNodes; i++) {
var option = PDFViewer.scaleSelect.childNodes[i];
if (option.value == num) {
if (!option.selected) {
option.selected = 'selected';
}
} else {
if (option.selected) {
option.removeAttribute('selected');
}
}
}
PDFViewer.scaleSelect.value = Math.floor(PDFViewer.scale * 100) + '%';
}, },
goToPage: function(num) { goToPage: function(num) {
@ -217,6 +242,11 @@ var PDFViewer = {
if (PDFViewer.numberOfPages > 0) { if (PDFViewer.numberOfPages > 0) {
PDFViewer.drawPage(1); PDFViewer.drawPage(1);
} }
PDFViewer.previousPageButton.className = (PDFViewer.pageNumber === 1) ?
'disabled' : '';
PDFViewer.nextPageButton.className = (PDFViewer.pageNumber === PDFViewer.numberOfPages) ?
'disabled' : '';
} }
}; };
@ -320,40 +350,14 @@ window.onload = function() {
this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : ''; this.className = (this.className.indexOf('disabled') !== -1) ? 'disabled' : '';
}; };
PDFViewer.scaleInput = document.getElementById('scale'); PDFViewer.scaleSelect = document.getElementById('scaleSelect');
PDFViewer.scaleInput.buttonElement = document.getElementById('scaleComboBoxButton'); PDFViewer.scaleSelect.onchange = function(evt) {
PDFViewer.scaleInput.buttonElement.listElement = document.getElementById('scaleComboBoxList');
PDFViewer.scaleInput.onchange = function(evt) {
PDFViewer.changeScale(parseInt(this.value)); 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.pageNumber = parseInt(PDFViewer.queryParams.page) || PDFViewer.pageNumber;
PDFViewer.scale = parseInt(PDFViewer.scaleInput.value) / 100 || 1.0; PDFViewer.scale = parseInt(PDFViewer.scaleSelect.value) / 100 || 1.0;
PDFViewer.open(PDFViewer.queryParams.file || PDFViewer.url); PDFViewer.open(PDFViewer.queryParams.file || PDFViewer.url);
window.onscroll = function(evt) { window.onscroll = function(evt) {

189
pdf.js
View File

@ -80,11 +80,12 @@ var Stream = (function() {
getBytes: function(length) { getBytes: function(length) {
var bytes = this.bytes; var bytes = this.bytes;
var pos = this.pos; var pos = this.pos;
var end = pos + length; var end = pos + length;
var strEnd = this.end; var strEnd = this.end;
if (!end || end > strEnd) if (!end || end > strEnd)
end = strEnd; end = strEnd;
this.pos = end; this.pos = end;
return bytes.subarray(pos, end); return bytes.subarray(pos, end);
}, },
@ -261,7 +262,7 @@ var FlateStream = (function() {
this.eof = false; this.eof = false;
this.codeSize = 0; this.codeSize = 0;
this.codeBuf = 0; this.codeBuf = 0;
this.pos = 0; this.pos = 0;
this.bufferLength = 0; this.bufferLength = 0;
} }
@ -367,7 +368,7 @@ var FlateStream = (function() {
skip: function(n) { skip: function(n) {
if (!n) if (!n)
n = 1; n = 1;
this.pos += n; this.pos += n;
}, },
generateHuffmanTable: function(lengths) { generateHuffmanTable: function(lengths) {
var n = lengths.length; var n = lengths.length;
@ -545,6 +546,9 @@ var JpegStream = (function() {
getImage: function() { getImage: function() {
return this.domImage; return this.domImage;
},
getChar: function() {
error("internal error: getChar is not valid on JpegStream");
} }
}; };
@ -1329,7 +1333,7 @@ var Parser = (function() {
this.keyLength); this.keyLength);
} }
stream = this.filter(stream, dict, length); stream = this.filter(stream, dict, length);
stream.parameters = dict; stream.parameters = dict;
return stream; return stream;
}, },
filter: function(stream, dict, length) { filter: function(stream, dict, length) {
@ -1340,7 +1344,8 @@ var Parser = (function() {
if (IsArray(filter)) { if (IsArray(filter)) {
var filterArray = filter; var filterArray = filter;
var paramsArray = params; var paramsArray = params;
for (filter in filterArray) { for (var i = 0, ii = filter.length; i < ii; ++i) {
filter = filter[i];
if (!IsName(filter)) if (!IsName(filter))
error("Bad filter name"); error("Bad filter name");
else { else {
@ -1521,7 +1526,7 @@ var XRef = (function() {
prev = obj.num; prev = obj.num;
} }
if (prev) { if (prev) {
this.readXRef(prev); this.readXRef(prev);
} }
// check for 'XRefStm' key // check for 'XRefStm' key
@ -1532,6 +1537,7 @@ var XRef = (function() {
this.xrefstms[pos] = 1; // avoid infinite recursion this.xrefstms[pos] = 1; // avoid infinite recursion
this.readXRef(pos); this.readXRef(pos);
} }
return dict; return dict;
}, },
readXRefStream: function(stream) { readXRefStream: function(stream) {
@ -1552,26 +1558,29 @@ var XRef = (function() {
for (i = 0; i < n; ++i) { for (i = 0; i < n; ++i) {
var type = 0, offset = 0, generation = 0; var type = 0, offset = 0, generation = 0;
for (j = 0; j < typeFieldWidth; ++j) for (j = 0; j < typeFieldWidth; ++j)
type = (type << 8) | stream.getByte(); type = (type << 8) | stream.getByte();
// if type field is absent, its default value = 1
if (typeFieldWidth == 0)
type = 1;
for (j = 0; j < offsetFieldWidth; ++j) for (j = 0; j < offsetFieldWidth; ++j)
offset = (offset << 8) | stream.getByte(); offset = (offset << 8) | stream.getByte();
for (j = 0; j < generationFieldWidth; ++j) for (j = 0; j < generationFieldWidth; ++j)
generation = (generation << 8) | stream.getByte(); generation = (generation << 8) | stream.getByte();
var entry = new Ref(offset, generation); var entry = {}
if (typeFieldWidth > 0) { entry.offset = offset;
switch (type) { entry.gen = generation;
case 0: switch (type) {
entry.free = true; case 0:
break; entry.free = true;
case 1: break;
entry.uncompressed = true; case 1:
break; entry.uncompressed = true;
case 2: break;
break; case 2:
default: break;
error("Invalid XRef entry type"); default:
break; error("Invalid XRef entry type");
} break;
} }
if (!this.entries[first + i]) if (!this.entries[first + i])
this.entries[first + i] = entry; this.entries[first + i] = entry;
@ -1650,6 +1659,7 @@ var XRef = (function() {
this.cache[num] = e; this.cache[num] = e;
return e; return e;
} }
// compressed entry // compressed entry
stream = this.fetch(new Ref(e.offset, 0)); stream = this.fetch(new Ref(e.offset, 0));
if (!IsStream(stream)) if (!IsStream(stream))
@ -1717,6 +1727,7 @@ var Page = (function() {
// content was compiled // content was compiled
return; return;
} }
var xref = this.xref; var xref = this.xref;
var content; var content;
var resources = xref.fetchIfRef(this.resources); var resources = xref.fetchIfRef(this.resources);
@ -1951,7 +1962,7 @@ var CanvasExtraState = (function() {
const Encodings = { const Encodings = {
get ExpertEncoding() { get ExpertEncoding() {
return shadow(this, "ExpertEncoding", [ return shadow(this, "ExpertEncoding", [ ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
"space","exclamsmall","Hungarumlautsmall",,"dollaroldstyle","dollarsuperior", "space","exclamsmall","Hungarumlautsmall",,"dollaroldstyle","dollarsuperior",
"ampersandsmall","Acutesmall","parenleftsuperior","parenrightsuperior", "ampersandsmall","Acutesmall","parenleftsuperior","parenrightsuperior",
"twodotenleader","onedotenleader","comma","hyphen","period","fraction", "twodotenleader","onedotenleader","comma","hyphen","period","fraction",
@ -1986,7 +1997,7 @@ const Encodings = {
]); ]);
}, },
get MacExpertEncoding() { get MacExpertEncoding() {
return shadow(this, "MacExpertEncoding", [ return shadow(this, "MacExpertEncoding", [ ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
"space","exclamsmall","Hungarumlautsmall","centoldstyle","dollaroldstyle", "space","exclamsmall","Hungarumlautsmall","centoldstyle","dollaroldstyle",
"dollarsuperior","ampersandsmall","Acutesmall","parenleftsuperior", "dollarsuperior","ampersandsmall","Acutesmall","parenleftsuperior",
"parenrightsuperior","twodotenleader","onedotenleader","comma","hyphen","period", "parenrightsuperior","twodotenleader","onedotenleader","comma","hyphen","period",
@ -2020,7 +2031,7 @@ const Encodings = {
]); ]);
}, },
get MacRomanEncoding() { get MacRomanEncoding() {
return shadow(this, "MacRomanEncoding", [ return shadow(this, "MacRomanEncoding", [ ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
"space","exclam","quotedbl","numbersign","dollar","percent","ampersand", "space","exclam","quotedbl","numbersign","dollar","percent","ampersand",
"quotesingle","parenleft","parenright","asterisk","plus","comma","hyphen", "quotesingle","parenleft","parenright","asterisk","plus","comma","hyphen",
"period","slash","zero","one","two","three","four","five","six","seven","eight", "period","slash","zero","one","two","three","four","five","six","seven","eight",
@ -2050,7 +2061,7 @@ const Encodings = {
]); ]);
}, },
get StandardEncoding() { get StandardEncoding() {
return shadow(this, "StandardEncoding", [ return shadow(this, "StandardEncoding", [ ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
"space","exclam","quotedbl","numbersign","dollar","percent","ampersand", "space","exclam","quotedbl","numbersign","dollar","percent","ampersand",
"quoteright","parenleft","parenright","asterisk","plus","comma","hyphen","period", "quoteright","parenleft","parenright","asterisk","plus","comma","hyphen","period",
"slash","zero","one","two","three","four","five","six","seven","eight","nine", "slash","zero","one","two","three","four","five","six","seven","eight","nine",
@ -2070,7 +2081,7 @@ const Encodings = {
]); ]);
}, },
get WinAnsiEncoding() { get WinAnsiEncoding() {
return shadow(this, "WinAnsiEncoding", [ return shadow(this, "WinAnsiEncoding", [ ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
"space","exclam","quotedbl","numbersign","dollar","percent","ampersand", "space","exclam","quotedbl","numbersign","dollar","percent","ampersand",
"quotesingle","parenleft","parenright","asterisk","plus","comma","hyphen", "quotesingle","parenleft","parenright","asterisk","plus","comma","hyphen",
"period","slash","zero","one","two","three","four","five","six","seven","eight", "period","slash","zero","one","two","three","four","five","six","seven","eight",
@ -2101,7 +2112,7 @@ const Encodings = {
]); ]);
}, },
get zapfDingbatsEncoding() { get zapfDingbatsEncoding() {
return shadow(this, "zapfDingbatsEncoding", [ return shadow(this, "zapfDingbatsEncoding", [ ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
"space","a1","a2","a202","a3","a4","a5","a119","a118","a117","a11","a12","a13", "space","a1","a2","a202","a3","a4","a5","a119","a118","a117","a11","a12","a13",
"a14","a15","a16","a105","a17","a18","a19","a20","a21","a22","a23","a24","a25", "a14","a15","a16","a105","a17","a18","a19","a20","a21","a22","a23","a24","a25",
"a26","a27","a28","a6","a7","a8","a9","a10","a29","a30","a31","a32","a33","a34", "a26","a27","a28","a6","a7","a8","a9","a10","a29","a30","a31","a32","a33","a34",
@ -2247,12 +2258,19 @@ var CanvasGraphics = (function() {
error("FontFile not found for font: " + fontName); error("FontFile not found for font: " + fontName);
fontFile = xref.fetchIfRef(fontFile); fontFile = xref.fetchIfRef(fontFile);
// Generate the custom cmap of the font if needed // Fonts with an embedded cmap but without any assignment in
// it are not yet supported, so ask the fonts loader to ignore
// them to not pay a stupid one sec latence.
var ignoreFont = true;
var encodingMap = {}; var encodingMap = {};
var charset = [];
if (fontDict.has("Encoding")) { if (fontDict.has("Encoding")) {
ignoreFont = false;
var encoding = xref.fetchIfRef(fontDict.get("Encoding")); var encoding = xref.fetchIfRef(fontDict.get("Encoding"));
if (IsDict(encoding)) { if (IsDict(encoding)) {
// Build an map between codes and glyphs // Build a map between codes and glyphs
var differences = encoding.get("Differences"); var differences = encoding.get("Differences");
var index = 0; var index = 0;
for (var j = 0; j < differences.length; j++) { for (var j = 0; j < differences.length; j++) {
@ -2262,26 +2280,96 @@ var CanvasGraphics = (function() {
// Get the font charset if any // Get the font charset if any
var charset = descriptor.get("CharSet"); var charset = descriptor.get("CharSet");
if (charset) { if (charset)
assertWellFormed(IsString(charset), "invalid charset"); assertWellFormed(IsString(charset), "invalid charset");
charset = charset.split("/"); charset = charset.split("/");
}
} else if (IsName(encoding)) { } else if (IsName(encoding)) {
var encoding = Encodings[encoding.name]; var encoding = Encodings[encoding.name];
if (!encoding) if (!encoding)
error("Unknown font encoding"); error("Unknown font encoding");
var widths = xref.fetchIfRef(fontDict.get("Widths")); var index = 0;
for (var j = 0; j < encoding.length; j++) {
encodingMap[index++] = GlyphsUnicode[encoding[j]];
}
var firstChar = xref.fetchIfRef(fontDict.get("FirstChar")); var firstChar = xref.fetchIfRef(fontDict.get("FirstChar"));
var widths = xref.fetchIfRef(fontDict.get("Widths"));
assertWellFormed(IsArray(widths) && IsInt(firstChar), assertWellFormed(IsArray(widths) && IsInt(firstChar),
"invalid font Widths or FirstChar"); "invalid font Widths or FirstChar");
var charset = [];
for (var j = 0; j < widths.length; j++) { for (var j = 0; j < widths.length; j++) {
if (widths[j]) if (widths[j])
charset.push(encoding[j + firstChar]); charset.push(encoding[j + firstChar]);
} }
} }
} else if (fontDict.has("ToUnicode")) {
var cmapObj = xref.fetchIfRef(fontDict.get("ToUnicode"));
if (IsName(cmapObj)) {
error("ToUnicode file cmap translation not implemented");
} else if (IsStream(cmapObj)) {
var encoding = Encodings["WinAnsiEncoding"];
var firstChar = xref.fetchIfRef(fontDict.get("FirstChar"));
for (var i = firstChar; i < encoding.length; i++)
encodingMap[i] = new Name(encoding[i]);
var tokens = [];
var token = "";
var buffer = cmapObj.ensureBuffer ? cmapObj.ensureBuffer() : cmapObj;
var cmap = cmapObj.getBytes(buffer.byteLength);
for (var i =0; i < cmap.length; i++) {
var byte = cmap[i];
if (byte == 0x20 || byte == 0x0A || byte == 0x3C || byte == 0x3E) {
switch (token) {
case "useCMap":
error("useCMap is not implemented");
break;
case "beginbfrange":
ignoreFont = false;
case "begincodespacerange":
token = "";
tokens = [];
break;
case "endcodespacerange":
TODO("Support CMap ranges");
break;
case "endbfrange":
for (var j = 0; j < tokens.length; j+=3) {
var startRange = parseInt("0x" + tokens[j]);
var endRange = parseInt("0x" + tokens[j+1]);
var code = parseInt("0x" + tokens[j+2]);
for (var k = startRange; k <= endRange; k++) {
encodingMap[k] = GlyphsUnicode[encoding[code]];
charset.push(encoding[code++]);
}
}
break;
case "beginfbchar":
case "endfbchar":
error("fbchar parsing is not implemented");
break;
default:
if (token.length) {
tokens.push(token);
token = "";
}
break;
}
} else if (byte == 0x5B || byte == 0x5D) {
error("CMAP list parsing is not implemented");
} else {
token += String.fromCharCode(byte);
}
}
}
} }
var subType = fontDict.get("Subtype"); var subType = fontDict.get("Subtype");
@ -2293,7 +2381,8 @@ var CanvasGraphics = (function() {
type: subType.name, type: subType.name,
encoding: encodingMap, encoding: encodingMap,
charset: charset, charset: charset,
bbox: bbox bbox: bbox,
ignore: ignoreFont
}; };
return { return {
@ -2553,6 +2642,7 @@ var CanvasGraphics = (function() {
fontName = fontDescriptor.get("FontName").name.replace("+", "_"); fontName = fontDescriptor.get("FontName").name.replace("+", "_");
Fonts.active = fontName; Fonts.active = fontName;
} }
if (!fontName) { if (!fontName) {
// TODO: fontDescriptor is not available, fallback to default font // TODO: fontDescriptor is not available, fallback to default font
this.current.fontSize = size; this.current.fontSize = size;
@ -2590,7 +2680,7 @@ var CanvasGraphics = (function() {
this.ctx.transform.apply(this.ctx, this.current.textMatrix); this.ctx.transform.apply(this.ctx, this.current.textMatrix);
this.ctx.scale(1, -1); this.ctx.scale(1, -1);
this.ctx.translate(0, -2 * this.current.y); this.ctx.translate(0, -2 * this.current.y);
this.ctx.fillText(Fonts.chars2Unicode(text), this.current.x, this.current.y); this.ctx.fillText(Fonts.charsToUnicode(text), this.current.x, this.current.y);
this.current.x += this.ctx.measureText(text).width; this.current.x += this.ctx.measureText(text).width;
this.ctx.restore(); this.ctx.restore();
@ -2676,7 +2766,7 @@ var CanvasGraphics = (function() {
error("Unable to find pattern resource"); error("Unable to find pattern resource");
var pattern = xref.fetchIfRef(patternRes.get(patternName.name)); var pattern = xref.fetchIfRef(patternRes.get(patternName.name));
const types = [null, this.tilingFill]; const types = [null, this.tilingFill];
var typeNum = pattern.dict.get("PatternType"); var typeNum = pattern.dict.get("PatternType");
var patternFn = types[typeNum]; var patternFn = types[typeNum];
@ -2736,11 +2826,11 @@ var CanvasGraphics = (function() {
var topLeft = applyMatrix([x0,y0], matrix); var topLeft = applyMatrix([x0,y0], matrix);
// we want the canvas to be as large as the step size // we want the canvas to be as large as the step size
var botRight = applyMatrix([x0 + xstep, y0 + ystep], matrix); var botRight = applyMatrix([x0 + xstep, y0 + ystep], matrix);
var tmpCanvas = document.createElement("canvas"); var tmpCanvas = document.createElement("canvas");
tmpCanvas.width = Math.ceil(botRight[0] - topLeft[0]); tmpCanvas.width = Math.ceil(botRight[0] - topLeft[0]);
tmpCanvas.height = Math.ceil(botRight[1] - topLeft[1]); tmpCanvas.height = Math.ceil(botRight[1] - topLeft[1]);
// set the new canvas element context as the graphics context // set the new canvas element context as the graphics context
var tmpCtx = tmpCanvas.getContext("2d"); var tmpCtx = tmpCanvas.getContext("2d");
var savedCtx = ctx; var savedCtx = ctx;
@ -2756,9 +2846,9 @@ var CanvasGraphics = (function() {
// move the top left corner of bounding box to [0,0] // move the top left corner of bounding box to [0,0]
matrix = multiply(matrix, [1, 0, 0, 1, -topLeft[0], -topLeft[1]]); matrix = multiply(matrix, [1, 0, 0, 1, -topLeft[0], -topLeft[1]]);
this.transform.apply(this, matrix); this.transform.apply(this, matrix);
if (bbox && IsArray(bbox) && 4 == bbox.length) { if (bbox && IsArray(bbox) && 4 == bbox.length) {
this.rectangle.apply(this, bbox); this.rectangle.apply(this, bbox);
this.clip(); this.clip();
@ -2770,7 +2860,7 @@ var CanvasGraphics = (function() {
if (!pattern.code) if (!pattern.code)
pattern.code = this.compile(pattern, xref, res, []); pattern.code = this.compile(pattern, xref, res, []);
this.execute(pattern.code, xref, res); this.execute(pattern.code, xref, res);
this.ctx = savedCtx; this.ctx = savedCtx;
this.restore(); this.restore();
@ -2864,19 +2954,19 @@ var CanvasGraphics = (function() {
var fn = new PDFFunction(this.xref, fnObj); var fn = new PDFFunction(this.xref, fnObj);
var gradient = this.ctx.createLinearGradient(x0, y0, x1, y1); var gradient = this.ctx.createLinearGradient(x0, y0, x1, y1);
// 10 samples seems good enough for now, but probably won't work // 10 samples seems good enough for now, but probably won't work
// if there are sharp color changes. Ideally, we would implement // if there are sharp color changes. Ideally, we would implement
// the spec faithfully and add lossless optimizations. // the spec faithfully and add lossless optimizations.
var step = (t1 - t0) / 10; var step = (t1 - t0) / 10;
for (var i = t0; i <= t1; i += step) { for (var i = t0; i <= t1; i += step) {
var c = fn.func([i]); var c = fn.func([i]);
gradient.addColorStop(i, this.makeCssRgb.apply(this, c)); gradient.addColorStop(i, this.makeCssRgb.apply(this, c));
} }
this.ctx.fillStyle = gradient; this.ctx.fillStyle = gradient;
// HACK to draw the gradient onto an infinite rectangle. // HACK to draw the gradient onto an infinite rectangle.
// PDF gradients are drawn across the entire image while // PDF gradients are drawn across the entire image while
// Canvas only allows gradients to be drawn in a rectangle // Canvas only allows gradients to be drawn in a rectangle
@ -2961,9 +3051,8 @@ var CanvasGraphics = (function() {
if (w < 1 || h < 1) if (w < 1 || h < 1)
error("Invalid image width or height"); error("Invalid image width or height");
var ctx = this.ctx;
var ctx = this.ctx;
// scale the image to the unit square // scale the image to the unit square
ctx.scale(1/w, -1/h); ctx.scale(1/w, -1/h);

View File

@ -12,6 +12,7 @@
* CharString or to understand the structure of the CFF format. * CharString or to understand the structure of the CFF format.
*/ */
"use strict";
/** /**
* Build a charset by assigning the glyph name and the human readable form * Build a charset by assigning the glyph name and the human readable form

View File

@ -3,7 +3,7 @@
"use strict"; "use strict";
var pdfDocument, canvas, numPages, pageDisplay, pageNum, pageInterval; var pdfDocument, canvas, pageDisplay, pageNum, numPages, pageInterval;
function load(userInput) { function load(userInput) {
canvas = document.getElementById("canvas"); canvas = document.getElementById("canvas");
canvas.mozOpaque = true; canvas.mozOpaque = true;
@ -52,8 +52,7 @@ function gotoPage(num) {
} }
function displayPage(num) { function displayPage(num) {
if (pageNum != num) window.clearInterval(pageInterval);
window.clearTimeout(pageInterval);
document.getElementById("pageNumber").value = num; document.getElementById("pageNumber").value = num;
@ -96,7 +95,7 @@ function displayPage(num) {
if (Fonts[font.name].loading) if (Fonts[font.name].loading)
return; return;
} }
clearInterval(pageInterval); window.clearInterval(pageInterval);
var t3 = Date.now(); var t3 = Date.now();