Browse Source

Addressing Vivian's comments.

= 14 years ago
parent
commit
300730c335
  1. 196
      pdf.js

196
pdf.js

@ -5,6 +5,7 @@
var ERRORS = 0, WARNINGS = 1, TODOS = 5; var ERRORS = 0, WARNINGS = 1, TODOS = 5;
var verbosity = WARNINGS; var verbosity = WARNINGS;
// Set this to true if you want to use workers. // Set this to true if you want to use workers.
var useWorker = false; var useWorker = false;
@ -898,10 +899,9 @@ var PredictorStream = (function predictorStream() {
})(); })();
var JpegImage = (function() { var JpegImage = (function() {
function JpegImage(objId, IR, objs) { function JpegImage(objId, imageData, objs) {
var src = 'data:image/jpeg;base64,' + window.btoa(IR); var src = 'data:image/jpeg;base64,' + window.btoa(imageData);
// create DOM image
var img = new Image(); var img = new Image();
img.onload = (function() { img.onload = (function() {
this.loaded = true; this.loaded = true;
@ -2375,6 +2375,10 @@ function isStream(v) {
return typeof v == 'object' && v != null && ('getChar' in v); return typeof v == 'object' && v != null && ('getChar' in v);
} }
function isArrayBuffer(v) {
return typeof v == 'object' && v != null && ('byteLength' in v);
}
function isRef(v) { function isRef(v) {
return v instanceof Ref; return v instanceof Ref;
} }
@ -3517,20 +3521,15 @@ var Page = (function pagePage() {
this.IRQueue = IRQueue; this.IRQueue = IRQueue;
var gfx = new CanvasGraphics(this.ctx, this.objs); var gfx = new CanvasGraphics(this.ctx, this.objs);
var startTime = Date.now(); var startTime = Date.now();
var continuation = function(err) {
this.callback(err);
}.bind(this);
var displayContinuation = function pageDisplayContinuation() { var displayContinuation = function pageDisplayContinuation() {
// Always defer call to display() to work around bug in // Always defer call to display() to work around bug in
// Firefox error reporting from XHR callbacks. // Firefox error reporting from XHR callbacks.
setTimeout(function pageSetTimeout() { setTimeout(function pageSetTimeout() {
var exc = null;
try { try {
self.display(gfx, continuation); self.display(gfx, self.callback);
} catch (e) { } catch (e) {
exc = e.toString(); if (self.callback) self.callback(e.toString());
continuation(exc);
throw e; throw e;
} }
}); });
@ -3606,7 +3605,7 @@ var Page = (function pagePage() {
startIdx = gfx.executeIRQueue(IRQueue, startIdx, next); startIdx = gfx.executeIRQueue(IRQueue, startIdx, next);
if (startIdx == length) { if (startIdx == length) {
self.stats.render = Date.now(); self.stats.render = Date.now();
callback(); if (callback) callback();
} }
} }
next(); next();
@ -3853,17 +3852,12 @@ var Catalog = (function catalogCatalog() {
*/ */
var PDFDocModel = (function pdfDoc() { var PDFDocModel = (function pdfDoc() {
function constructor(arg, callback) { function constructor(arg, callback) {
// Stream argument if (isStream(arg))
if (typeof arg.isStream !== 'undefined') {
init.call(this, arg); init.call(this, arg);
} else if (isArrayBuffer(arg))
// ArrayBuffer argument
else if (typeof arg.byteLength !== 'undefined') {
init.call(this, new Stream(arg)); init.call(this, new Stream(arg));
} else
else { error('PDFDocModel: Unknown argument type');
error('Unknown argument type');
}
} }
function init(stream) { function init(stream) {
@ -3980,18 +3974,14 @@ var PDFDoc = (function() {
var stream = null; var stream = null;
var data = null; var data = null;
// Stream argument if (isStream(arg)) {
if (typeof arg.isStream !== 'undefined') {
stream = arg; stream = arg;
data = arg.bytes; data = arg.bytes;
} } else if (isArrayBuffer(arg)) {
// ArrayBuffer argument
else if (typeof arg.byteLength !== 'undefined') {
stream = new Stream(arg); stream = new Stream(arg);
data = arg; data = arg;
} } else {
else { error('PDFDoc: Unknown argument type');
error('Unknown argument type');
} }
this.data = data; this.data = data;
@ -4004,15 +3994,17 @@ var PDFDoc = (function() {
this.pageCache = []; this.pageCache = [];
if (useWorker) { if (useWorker) {
var worker = this.worker = new Worker('../worker/pdf_worker_loader.js'); var worker = new Worker('../worker/pdf_worker_loader.js');
} else { } else {
// If we don't use a worker, just post/sendMessage to the main thread. // If we don't use a worker, just post/sendMessage to the main thread.
var worker = { var worker = {
postMessage: function(obj) { postMessage: function(obj) {
worker.onmessage({data: obj}); worker.onmessage({data: obj});
} },
terminate: function() {}
}; };
} }
this.worker = worker;
this.fontsLoading = {}; this.fontsLoading = {};
@ -4028,13 +4020,13 @@ var PDFDoc = (function() {
}, this); }, this);
processorHandler.on('obj', function(data) { processorHandler.on('obj', function(data) {
var objId = data[0]; var id = data[0];
var objType = data[1]; var type = data[1];
switch (objType) { switch (type) {
case 'JpegStream': case 'JpegStream':
var IR = data[2]; var IR = data[2];
new JpegImage(objId, IR, this.objs); new JpegImage(id, IR, this.objs);
break; break;
case 'Font': case 'Font':
var name = data[2]; var name = data[2];
@ -4060,26 +4052,26 @@ var PDFDoc = (function() {
// For now, resolve the font object here direclty. The real font // For now, resolve the font object here direclty. The real font
// object is then created in FontLoader.bind(). // object is then created in FontLoader.bind().
this.objs.resolve(objId, { this.objs.resolve(id, {
name: name, name: name,
file: file, file: file,
properties: properties properties: properties
}); });
break; break;
default: default:
throw 'Got unkown object type ' + objType; throw 'Got unkown object type ' + type;
} }
}, this); }, this);
processorHandler.on('font_ready', function(data) { processorHandler.on('font_ready', function(data) {
var objId = data[0]; var id = data[0];
var fontObj = new FontShape(data[1]); var font = new FontShape(data[1]);
// If there is no string, then there is nothing to attach to the DOM. // If there is no string, then there is nothing to attach to the DOM.
if (!fontObj.str) { if (!font.str) {
this.objs.resolve(objId, fontObj); this.objs.resolve(id, font);
} else { } else {
this.objs.setData(objId, fontObj); this.objs.setData(id, font);
} }
}.bind(this)); }.bind(this));
@ -4109,9 +4101,8 @@ var PDFDoc = (function() {
}, },
getPage: function(n) { getPage: function(n) {
if (this.pageCache[n]) { if (this.pageCache[n])
return this.pageCache[n]; return this.pageCache[n];
}
var page = this.pdf.getPage(n); var page = this.pdf.getPage(n);
// Add a reference to the objects such that Page can forward the reference // Add a reference to the objects such that Page can forward the reference
@ -4122,16 +4113,15 @@ var PDFDoc = (function() {
}, },
destroy: function() { destroy: function() {
if (this.worker) { if (this.worker)
this.worker.terminate(); this.worker.terminate();
}
if (this.fontWorker) { if (this.fontWorker)
this.fontWorker.terminate(); this.fontWorker.terminate();
}
for (var n in this.pageCache) { for (var n in this.pageCache)
delete this.pageCache[n]; delete this.pageCache[n];
}
delete this.data; delete this.data;
delete this.stream; delete this.stream;
delete this.pdf; delete this.pdf;
@ -4564,7 +4554,11 @@ var PartialEvaluator = (function partialEvaluator() {
var loadedName = null; var loadedName = null;
var fontRes = resources.get('Font'); var fontRes = resources.get('Font');
if (fontRes) {
// TODO: TOASK: Is it possible to get here? If so, what does
// args[0].name should be like???
assert(fontRes, 'fontRes not available');
fontRes = xref.fetchIfRef(fontRes); fontRes = xref.fetchIfRef(fontRes);
fontRef = fontRef || fontRes.get(fontName); fontRef = fontRef || fontRes.get(fontName);
var font = xref.fetchIfRef(fontRef); var font = xref.fetchIfRef(fontRef);
@ -4579,12 +4573,13 @@ var PartialEvaluator = (function partialEvaluator() {
font.translated.properties.loadedName = loadedName; font.translated.properties.loadedName = loadedName;
font.loadedName = loadedName; font.loadedName = loadedName;
var translated = font.translated;
handler.send('obj', [ handler.send('obj', [
loadedName, loadedName,
'Font', 'Font',
font.translated.name, translated.name,
font.translated.file, translated.file,
font.translated.properties translated.properties
]); ]);
} }
} }
@ -4596,11 +4591,6 @@ var PartialEvaluator = (function partialEvaluator() {
// page. // page.
insertDependency([loadedName]); insertDependency([loadedName]);
return loadedName; return loadedName;
} else {
// TODO: TOASK: Is it possible to get here? If so, what does
// args[0].name should be like???
return null;
}
} }
function buildPaintImageXObject(image, inline) { function buildPaintImageXObject(image, inline) {
@ -4618,7 +4608,10 @@ var PartialEvaluator = (function partialEvaluator() {
// The normal fn. // The normal fn.
fn = 'paintJpegXObject'; fn = 'paintJpegXObject';
args = [objId, w, h]; args = [objId, w, h];
} else {
return;
}
// Needs to be rendered ourself. // Needs to be rendered ourself.
// Figure out if the image has an imageMask. // Figure out if the image has an imageMask.
@ -4643,7 +4636,9 @@ var PartialEvaluator = (function partialEvaluator() {
fn = 'paintImageXObject'; fn = 'paintImageXObject';
args = [imgData]; args = [imgData];
} else /* imageMask == true */ { return;
}
// This depends on a tmpCanvas beeing filled with the // This depends on a tmpCanvas beeing filled with the
// current fillStyle, such that processing the pixel // current fillStyle, such that processing the pixel
// data can't be done here. Instead of creating a // data can't be done here. Instead of creating a
@ -4660,8 +4655,6 @@ var PartialEvaluator = (function partialEvaluator() {
args = [imgArray, inverseDecode, width, height]; args = [imgArray, inverseDecode, width, height];
} }
}
}
uniquePrefix = uniquePrefix || ''; uniquePrefix = uniquePrefix || '';
if (!queue.argsArray) { if (!queue.argsArray) {
@ -4684,6 +4677,7 @@ var PartialEvaluator = (function partialEvaluator() {
parser = this.oldParser; parser = this.oldParser;
return { name: 'BT' }; return { name: 'BT' };
}; };
var TILING_PATTERN = 1, SHADING_PATTERN = 2;
while (!isEOF(obj = parser.getObj())) { while (!isEOF(obj = parser.getObj())) {
if (isCmd(obj)) { if (isCmd(obj)) {
@ -4716,8 +4710,7 @@ var PartialEvaluator = (function partialEvaluator() {
var dict = isStream(pattern) ? pattern.dict : pattern; var dict = isStream(pattern) ? pattern.dict : pattern;
var typeNum = dict.get('PatternType'); var typeNum = dict.get('PatternType');
// Type1 is TilingPattern if (typeNum == TILING_PATTERN) {
if (typeNum == 1) {
// Create an IR of the pattern code. // Create an IR of the pattern code.
var depIdx = dependency.length; var depIdx = dependency.length;
var codeIR = this.getIRQueue(pattern, var codeIR = this.getIRQueue(pattern,
@ -4729,8 +4722,7 @@ var PartialEvaluator = (function partialEvaluator() {
args = TilingPattern.getIR(codeIR, dict, args); args = TilingPattern.getIR(codeIR, dict, args);
} }
// Type2 is ShadingPattern. else if (typeNum == SHADING_PATTERN) {
else if (typeNum == 2) {
var shading = xref.fetchIfRef(dict.get('Shading')); var shading = xref.fetchIfRef(dict.get('Shading'));
var matrix = dict.get('Matrix'); var matrix = dict.get('Matrix');
var pattern = Pattern.parseShading(shading, matrix, xref, res, var pattern = Pattern.parseShading(shading, matrix, xref, res,
@ -4786,7 +4778,6 @@ var PartialEvaluator = (function partialEvaluator() {
buildPaintImageXObject(args[0], true); buildPaintImageXObject(args[0], true);
} }
// Transform some cmds.
switch (fn) { switch (fn) {
// Parse the ColorSpace data to a raw format. // Parse the ColorSpace data to a raw format.
case 'setFillColorSpace': case 'setFillColorSpace':
@ -4803,17 +4794,18 @@ var PartialEvaluator = (function partialEvaluator() {
error('No shading object found'); error('No shading object found');
var shadingFill = Pattern.parseShading(shading, null, xref, res, var shadingFill = Pattern.parseShading(shading, null, xref, res,
/* ctx */ null); null);
var patternIR = shadingFill.getIR(); var patternIR = shadingFill.getIR();
args = [patternIR]; args = [patternIR];
fn = 'shadingFill'; fn = 'shadingFill';
break; break;
case 'setGState': case 'setGState':
var dictName = args[0]; var dictName = args[0];
var extGState = xref.fetchIfRef(resources.get('ExtGState')); var extGState = xref.fetchIfRef(resources.get('ExtGState'));
if (isDict(extGState) && extGState.has(dictName.name)) {
if (!isDict(extGState) || !extGState.has(dictName.name))
break;
var gsState = xref.fetchIfRef(extGState.get(dictName.name)); var gsState = xref.fetchIfRef(extGState.get(dictName.name));
// This array holds the converted/processed state data. // This array holds the converted/processed state data.
@ -4864,10 +4856,11 @@ var PartialEvaluator = (function partialEvaluator() {
warn('Unknown graphic state operator ' + key); warn('Unknown graphic state operator ' + key);
break; break;
} }
});
args = [gsStateObj];
}
} }
);
args = [gsStateObj];
break;
} // switch
fnArray.push(fn); fnArray.push(fn);
argsArray.push(args); argsArray.push(args);
@ -5370,9 +5363,10 @@ function ScratchCanvas(width, height) {
} }
var CanvasGraphics = (function canvasGraphics() { var CanvasGraphics = (function canvasGraphics() {
// Defines the time the executeIRQueue gonna be executing // Defines the time the executeIRQueue is going to be executing
// before it stops and shedules a continue of execution. // before it stops and shedules a continue of execution.
var kExecutionTime = 50; var kExecutionTime = 50;
// Number of IR commands to execute before checking // Number of IR commands to execute before checking
// if we execute longer then `kExecutionTime`. // if we execute longer then `kExecutionTime`.
var kExecutionTimeCheck = 500; var kExecutionTimeCheck = 500;
@ -5451,11 +5445,11 @@ var CanvasGraphics = (function canvasGraphics() {
if (i == argsArrayLen) { if (i == argsArrayLen) {
return i; return i;
} }
// If the execution took longer then a certain amount of time, shedule // If the execution took longer then a certain amount of time, shedule
// to continue exeution after a short delay. // to continue exeution after a short delay.
// However, this is only possible if a 'continueCallback' is passed in. // However, this is only possible if a 'continueCallback' is passed in.
else if (continueCallback && if (continueCallback && (Date.now() - startTime) > kExecutionTime) {
(Date.now() - startTime) > kExecutionTime) {
setTimeout(continueCallback, 0); setTimeout(continueCallback, 0);
return i; return i;
} }
@ -5686,7 +5680,6 @@ var CanvasGraphics = (function canvasGraphics() {
this.current.leading = -leading; this.current.leading = -leading;
}, },
setFont: function canvasGraphicsSetFont(fontRefName, size) { setFont: function canvasGraphicsSetFont(fontRefName, size) {
// Lookup the fontObj using fontRefName only.
var fontObj = this.objs.get(fontRefName).fontObj; var fontObj = this.objs.get(fontRefName).fontObj;
if (!fontObj) { if (!fontObj) {
@ -5731,7 +5724,6 @@ var CanvasGraphics = (function canvasGraphics() {
nextLine: function canvasGraphicsNextLine() { nextLine: function canvasGraphicsNextLine() {
this.moveText(0, this.current.leading); this.moveText(0, this.current.leading);
}, },
showText: function canvasGraphicsShowText(text) { showText: function canvasGraphicsShowText(text) {
var ctx = this.ctx; var ctx = this.ctx;
var current = this.current; var current = this.current;
@ -5855,12 +5847,10 @@ var CanvasGraphics = (function canvasGraphics() {
// Color // Color
setStrokeColorSpace: setStrokeColorSpace:
function canvasGraphicsSetStrokeColorSpacefunction(raw) { function canvasGraphicsSetStrokeColorSpacefunction(raw) {
this.current.strokeColorSpace = this.current.strokeColorSpace = ColorSpace.fromIR(raw);
ColorSpace.fromIR(raw);
}, },
setFillColorSpace: function canvasGraphicsSetFillColorSpace(raw) { setFillColorSpace: function canvasGraphicsSetFillColorSpace(raw) {
this.current.fillColorSpace = this.current.fillColorSpace = ColorSpace.fromIR(raw);
ColorSpace.fromIR(raw);
}, },
setStrokeColor: function canvasGraphicsSetStrokeColor(/*...*/) { setStrokeColor: function canvasGraphicsSetStrokeColor(/*...*/) {
var cs = this.current.strokeColorSpace; var cs = this.current.strokeColorSpace;
@ -5869,8 +5859,6 @@ var CanvasGraphics = (function canvasGraphics() {
}, },
getColorN_IR_Pattern: function(IR, cs) { getColorN_IR_Pattern: function(IR, cs) {
if (IR[0] == 'TilingPattern') { if (IR[0] == 'TilingPattern') {
// First, build the `color` var like it's done in the
// Pattern.prototype.parse function.
var args = IR[1]; var args = IR[1];
var base = cs.base; var base = cs.base;
var color; var color;
@ -5883,8 +5871,6 @@ var CanvasGraphics = (function canvasGraphics() {
color = base.getRgb(color); color = base.getRgb(color);
} }
// Build the pattern based on the IR data.
var pattern = new TilingPattern(IR, color, this.ctx, this.objs); var pattern = new TilingPattern(IR, color, this.ctx, this.objs);
} else if (IR[0] == 'RadialAxialShading' || IR[0] == 'DummyShading') { } else if (IR[0] == 'RadialAxialShading' || IR[0] == 'DummyShading') {
var pattern = Pattern.shadingFromIR(this.ctx, IR); var pattern = Pattern.shadingFromIR(this.ctx, IR);
@ -6016,6 +6002,7 @@ var CanvasGraphics = (function canvasGraphics() {
this.save(); this.save();
var ctx = this.ctx; var ctx = this.ctx;
// scale the image to the unit square
ctx.scale(1 / w, -1 / h); ctx.scale(1 / w, -1 / h);
var domImage = image.getImage(); var domImage = image.getImage();
@ -6051,7 +6038,6 @@ var CanvasGraphics = (function canvasGraphics() {
var ctx = this.ctx; var ctx = this.ctx;
var w = width, h = height; var w = width, h = height;
// 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);
@ -6205,11 +6191,10 @@ var ColorSpace = (function colorSpaceColorSpace() {
constructor.parse = function colorspace_parse(cs, xref, res) { constructor.parse = function colorspace_parse(cs, xref, res) {
var IR = constructor.parseToIR(cs, xref, res, true); var IR = constructor.parseToIR(cs, xref, res, true);
if (!(IR instanceof SeparationCS)) { if (IR instanceof SeparationCS)
return constructor.fromIR(IR);
} else {
return IR; return IR;
}
return constructor.fromIR(IR);
}; };
constructor.fromIR = function(IR) { constructor.fromIR = function(IR) {
@ -6758,7 +6743,6 @@ var TilingPattern = (function tilingPattern() {
var PAINT_TYPE_COLORED = 1, PAINT_TYPE_UNCOLORED = 2; var PAINT_TYPE_COLORED = 1, PAINT_TYPE_UNCOLORED = 2;
function TilingPattern(IR, color, ctx, objs) { function TilingPattern(IR, color, ctx, objs) {
// 'Unfolding' the IR.
var IRQueue = IR[2]; var IRQueue = IR[2];
this.matrix = IR[3]; this.matrix = IR[3];
var bbox = IR[4]; var bbox = IR[4];
@ -6766,7 +6750,6 @@ var TilingPattern = (function tilingPattern() {
var ystep = IR[6]; var ystep = IR[6];
var paintType = IR[7]; var paintType = IR[7];
//
TODO('TilingType'); TODO('TilingType');
this.curMatrix = ctx.mozCurrentTransform; this.curMatrix = ctx.mozCurrentTransform;
@ -6775,6 +6758,7 @@ var TilingPattern = (function tilingPattern() {
this.type = 'Pattern'; this.type = 'Pattern';
var x0 = bbox[0], y0 = bbox[1], x1 = bbox[2], y1 = bbox[3]; var x0 = bbox[0], y0 = bbox[1], x1 = bbox[2], y1 = bbox[3];
var topLeft = [x0, y0]; var topLeft = [x0, y0];
// 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 = [x0 + xstep, y0 + ystep]; var botRight = [x0 + xstep, y0 + ystep];
@ -7113,7 +7097,6 @@ var PDFFunction = (function() {
var strBytes = str.getBytes((length * bps + 7) / 8); var strBytes = str.getBytes((length * bps + 7) / 8);
var strIdx = 0; var strIdx = 0;
for (var i = 0; i < length; i++) { for (var i = 0; i < length; i++) {
var b;
while (codeSize < bps) { while (codeSize < bps) {
codeBuf <<= 8; codeBuf <<= 8;
codeBuf |= strBytes[strIdx++]; codeBuf |= strBytes[strIdx++];
@ -7396,7 +7379,7 @@ var PDFFunction = (function() {
})(); })();
/** /**
* A PDF document and page is build up of many objects. E.g. there are objects * A PDF document and page is built of many objects. E.g. there are objects
* for fonts, images, rendering code and such. These objects might get processed * for fonts, images, rendering code and such. These objects might get processed
* inside of a worker. The `PDFObjects` implements some basic functions to * inside of a worker. The `PDFObjects` implements some basic functions to
* manage these objects. * manage these objects.
@ -7415,11 +7398,9 @@ var PDFObjects = (function() {
* object *if* it is created. * object *if* it is created.
*/ */
ensureObj: function(objId, data) { ensureObj: function(objId, data) {
if (!this.objs[objId]) { if (this.objs[objId])
return this.objs[objId] = new Promise(objId, data);
} else {
return this.objs[objId]; return this.objs[objId];
} return this.objs[objId] = new Promise(objId, data);
}, },
/** /**
@ -7436,22 +7417,19 @@ var PDFObjects = (function() {
// not required to be resolved right now // not required to be resolved right now
if (callback) { if (callback) {
this.ensureObj(objId).then(callback); this.ensureObj(objId).then(callback);
return;
} }
// If there isn't a callback, the user expects to get the resolved data // If there isn't a callback, the user expects to get the resolved data
// directly. // directly.
else {
var obj = this.objs[objId]; var obj = this.objs[objId];
// If there isn't an object yet or the object isn't resolved, then the // If there isn't an object yet or the object isn't resolved, then the
// data isn't ready yet! // data isn't ready yet!
if (!obj || !obj.isResolved) { if (!obj || !obj.isResolved)
throw 'Requesting object that isn\'t resolved yet ' + objId; throw 'Requesting object that isn\'t resolved yet ' + objId;
} else
// Direct access.
else {
return obj.data; return obj.data;
}
}
}, },
/** /**
@ -7494,8 +7472,8 @@ var PDFObjects = (function() {
* Sets the data of an object but *doesn't* resolve it. * Sets the data of an object but *doesn't* resolve it.
*/ */
setData: function(objId, data) { setData: function(objId, data) {
// Watchout! If you call `this.ensureObj(objId, data)` you'll gonna create // Watchout! If you call `this.ensureObj(objId, data)` you're going to
// a *resolved* promise which shouldn't be the case! // create a *resolved* promise which shouldn't be the case!
this.ensureObj(objId).data = data; this.ensureObj(objId).data = data;
} }
}; };

Loading…
Cancel
Save