Merge upstream.

This commit is contained in:
Brendan Dahl 2012-03-19 10:45:53 -07:00
commit 52a4bcbd4f
10 changed files with 123 additions and 199 deletions

View File

@ -70,7 +70,7 @@ var CanvasExtraState = (function CanvasExtraStateClosure() {
return CanvasExtraState; return CanvasExtraState;
})(); })();
function ScratchCanvas(width, height) { function createScratchCanvas(width, height) {
var canvas = document.createElement('canvas'); var canvas = document.createElement('canvas');
canvas.width = width; canvas.width = width;
canvas.height = height; canvas.height = height;
@ -188,7 +188,7 @@ function addContextCurrentTransform(ctx) {
} }
var CanvasGraphics = (function CanvasGraphicsClosure() { var CanvasGraphics = (function CanvasGraphicsClosure() {
// Defines the time the executeIRQueue is going to be executing // Defines the time the executeOperatorList 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 = 15; var kExecutionTime = 15;
@ -199,7 +199,6 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
this.pendingClip = null; this.pendingClip = null;
this.res = null; this.res = null;
this.xobjs = null; this.xobjs = null;
this.ScratchCanvas = ScratchCanvas;
this.objs = objs; this.objs = objs;
this.textLayer = textLayer; this.textLayer = textLayer;
if (canvasCtx) { if (canvasCtx) {
@ -229,7 +228,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
'setStrokeColor': true, 'setStrokeColor': true,
'setStrokeColorN': true, 'setStrokeColorN': true,
'setFillColor': true, 'setFillColor': true,
'setFillColorN_IR': true, 'setFillColorN': true,
'setStrokeGray': true, 'setStrokeGray': true,
'setFillGray': true, 'setFillGray': true,
'setStrokeRGBColor': true, 'setStrokeRGBColor': true,
@ -268,15 +267,16 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
this.textLayer.beginLayout(); this.textLayer.beginLayout();
}, },
executeIRQueue: function canvasGraphicsExecuteIRQueue(codeIR, executeOperatorList: function canvasGraphicsExecuteOperatorList(
executionStartIdx, continueCallback, operatorList,
stepper) { executionStartIdx, continueCallback,
var argsArray = codeIR.argsArray; stepper) {
var fnArray = codeIR.fnArray; var argsArray = operatorList.argsArray;
var fnArray = operatorList.fnArray;
var i = executionStartIdx || 0; var i = executionStartIdx || 0;
var argsArrayLen = argsArray.length; var argsArrayLen = argsArray.length;
// Sometimes the IRQueue to execute is empty. // Sometimes the OperatorList to execute is empty.
if (argsArrayLen == i) { if (argsArrayLen == i) {
return i; return i;
} }
@ -314,7 +314,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
i++; i++;
// If the entire IRQueue was executed, stop as were done. // If the entire operatorList was executed, stop as were done.
if (i == argsArrayLen) { if (i == argsArrayLen) {
return i; return i;
} }
@ -327,8 +327,8 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
return i; return i;
} }
// If the IRQueue isn't executed completly yet OR the execution time // If the operatorList isn't executed completely yet OR the execution
// was short enough, do another execution round. // time was short enough, do another execution round.
} }
}, },
@ -556,7 +556,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
this.current.leading = -leading; this.current.leading = -leading;
}, },
setFont: function canvasGraphicsSetFont(fontRefName, size) { setFont: function canvasGraphicsSetFont(fontRefName, size) {
var fontObj = this.objs.get(fontRefName).fontObj; var fontObj = this.objs.get(fontRefName);
var current = this.current; var current = this.current;
if (!fontObj) if (!fontObj)
@ -707,7 +707,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
this.save(); this.save();
ctx.scale(fontSize, fontSize); ctx.scale(fontSize, fontSize);
ctx.transform.apply(ctx, fontMatrix); ctx.transform.apply(ctx, fontMatrix);
this.executeIRQueue(glyph.codeIRQueue); this.executeOperatorList(glyph.operatorList);
this.restore(); this.restore();
var transformed = Util.applyTransform([glyph.width, 0], fontMatrix); var transformed = Util.applyTransform([glyph.width, 0], fontMatrix);
@ -908,7 +908,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
this.ctx.strokeStyle = color; this.ctx.strokeStyle = color;
this.current.strokeColor = color; this.current.strokeColor = color;
}, },
getColorN_IR_Pattern: function canvasGraphicsGetColorN_IR_Pattern(IR, cs) { getColorN_Pattern: function canvasGraphicsGetColorN_Pattern(IR, cs) {
if (IR[0] == 'TilingPattern') { if (IR[0] == 'TilingPattern') {
var args = IR[1]; var args = IR[1];
var base = cs.base; var base = cs.base;
@ -930,11 +930,11 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
} }
return pattern; return pattern;
}, },
setStrokeColorN_IR: function canvasGraphicsSetStrokeColorN(/*...*/) { setStrokeColorN: function canvasGraphicsSetStrokeColorN(/*...*/) {
var cs = this.current.strokeColorSpace; var cs = this.current.strokeColorSpace;
if (cs.name == 'Pattern') { if (cs.name == 'Pattern') {
this.current.strokeColor = this.getColorN_IR_Pattern(arguments, cs); this.current.strokeColor = this.getColorN_Pattern(arguments, cs);
} else { } else {
this.setStrokeColor.apply(this, arguments); this.setStrokeColor.apply(this, arguments);
} }
@ -946,11 +946,11 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
this.ctx.fillStyle = color; this.ctx.fillStyle = color;
this.current.fillColor = color; this.current.fillColor = color;
}, },
setFillColorN_IR: function canvasGraphicsSetFillColorN(/*...*/) { setFillColorN: function canvasGraphicsSetFillColorN(/*...*/) {
var cs = this.current.fillColorSpace; var cs = this.current.fillColorSpace;
if (cs.name == 'Pattern') { if (cs.name == 'Pattern') {
this.current.fillColor = this.getColorN_IR_Pattern(arguments, cs); this.current.fillColor = this.getColorN_Pattern(arguments, cs);
} else { } else {
this.setFillColor.apply(this, arguments); this.setFillColor.apply(this, arguments);
} }
@ -1116,7 +1116,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
// 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);
var tmpCanvas = new this.ScratchCanvas(w, h); var tmpCanvas = createScratchCanvas(w, h);
var tmpCtx = tmpCanvas.getContext('2d'); var tmpCtx = tmpCanvas.getContext('2d');
var fillColor = this.current.fillColor; var fillColor = this.current.fillColor;
@ -1147,7 +1147,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
// 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);
var tmpCanvas = new this.ScratchCanvas(w, h); var tmpCanvas = createScratchCanvas(w, h);
var tmpCtx = tmpCanvas.getContext('2d'); var tmpCtx = tmpCanvas.getContext('2d');
this.putBinaryImageData(tmpCtx, imgData, w, h); this.putBinaryImageData(tmpCtx, imgData, w, h);

View File

@ -135,6 +135,7 @@ var ColorSpace = (function ColorSpaceClosure() {
basePatternCS = ColorSpace.parseToIR(basePatternCS, xref, res); basePatternCS = ColorSpace.parseToIR(basePatternCS, xref, res);
return ['PatternCS', basePatternCS]; return ['PatternCS', basePatternCS];
case 'Indexed': case 'Indexed':
case 'I':
var baseIndexedCS = ColorSpace.parseToIR(cs[1], xref, res); var baseIndexedCS = ColorSpace.parseToIR(cs[1], xref, res);
var hiVal = cs[2] + 1; var hiVal = cs[2] + 1;
var lookup = xref.fetchIfRef(cs[3]); var lookup = xref.fetchIfRef(cs[3]);

View File

@ -170,10 +170,10 @@ var Page = (function PageClosure() {
return shadow(this, 'rotate', rotate); return shadow(this, 'rotate', rotate);
}, },
startRenderingFromIRQueue: function pageStartRenderingFromIRQueue( startRenderingFromOperatorList: function pageStartRenderingFromOperatorList(
IRQueue, fonts) { operatorList, fonts) {
var self = this; var self = this;
this.IRQueue = IRQueue; this.operatorList = operatorList;
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
@ -184,15 +184,16 @@ var Page = (function PageClosure() {
}; };
this.ensureFonts(fonts, this.ensureFonts(fonts,
function pageStartRenderingFromIRQueueEnsureFonts() { function pageStartRenderingFromOperatorListEnsureFonts() {
displayContinuation(); displayContinuation();
}); }
);
}, },
getIRQueue: function pageGetIRQueue(handler, dependency) { getOperatorList: function pageGetOperatorList(handler, dependency) {
if (this.IRQueue) { if (this.operatorList) {
// content was compiled // content was compiled
return this.IRQueue; return this.operatorList;
} }
this.stats.time('Build IR Queue'); this.stats.time('Build IR Queue');
@ -213,11 +214,10 @@ var Page = (function PageClosure() {
var pe = this.pe = new PartialEvaluator( var pe = this.pe = new PartialEvaluator(
xref, handler, 'p' + this.pageNumber + '_'); xref, handler, 'p' + this.pageNumber + '_');
var IRQueue = {};
this.IRQueue = pe.getIRQueue(content, resources, IRQueue, dependency);
this.operatorList = pe.getOperatorList(content, resources, dependency);
this.stats.timeEnd('Build IR Queue'); this.stats.timeEnd('Build IR Queue');
return this.IRQueue; return this.operatorList;
}, },
ensureFonts: function pageEnsureFonts(fonts, callback) { ensureFonts: function pageEnsureFonts(fonts, callback) {
@ -228,14 +228,13 @@ var Page = (function PageClosure() {
} }
// Load all the fonts // Load all the fonts
var fontObjs = FontLoader.bind( FontLoader.bind(
fonts, fonts,
function pageEnsureFontsFontObjs(fontObjs) { function pageEnsureFontsFontObjs(fontObjs) {
this.stats.timeEnd('Font Loading'); this.stats.timeEnd('Font Loading');
callback.call(this); callback.call(this);
}.bind(this), }.bind(this)
this.objs
); );
}, },
@ -255,18 +254,19 @@ var Page = (function PageClosure() {
rotate: this.rotate }); rotate: this.rotate });
var startIdx = 0; var startIdx = 0;
var length = this.IRQueue.fnArray.length; var length = this.operatorList.fnArray.length;
var IRQueue = this.IRQueue; var operatorList = this.operatorList;
var stepper = null; var stepper = null;
if (PDFJS.pdfBug && StepperManager.enabled) { if (PDFJS.pdfBug && StepperManager.enabled) {
stepper = StepperManager.create(this.pageNumber); stepper = StepperManager.create(this.pageNumber);
stepper.init(IRQueue); stepper.init(operatorList);
stepper.nextBreakPoint = stepper.getNextBreakPoint(); stepper.nextBreakPoint = stepper.getNextBreakPoint();
} }
var self = this; var self = this;
function next() { function next() {
startIdx = gfx.executeIRQueue(IRQueue, startIdx, next, stepper); startIdx =
gfx.executeOperatorList(operatorList, startIdx, next, stepper);
if (startIdx == length) { if (startIdx == length) {
gfx.endDrawing(); gfx.endDrawing();
stats.timeEnd('Rendering'); stats.timeEnd('Rendering');
@ -436,13 +436,14 @@ var Page = (function PageClosure() {
startRendering: function pageStartRendering(ctx, callback, textLayer) { startRendering: function pageStartRendering(ctx, callback, textLayer) {
var stats = this.stats; var stats = this.stats;
stats.time('Overall'); stats.time('Overall');
// If there is no displayReadyPromise yet, then the IRQueue was never // If there is no displayReadyPromise yet, then the operatorList was never
// requested before. Make the request and create the promise. // requested before. Make the request and create the promise.
if (!this.displayReadyPromise) { if (!this.displayReadyPromise) {
this.pdf.startRendering(this); this.pdf.startRendering(this);
this.displayReadyPromise = new Promise(); this.displayReadyPromise = new Promise();
} }
// Once the IRQueue and fonts are loaded, perform the actual rendering.
// Once the operatorList and fonts are loaded, do the actual rendering.
this.displayReadyPromise.then( this.displayReadyPromise.then(
function pageDisplayReadyPromise() { function pageDisplayReadyPromise() {
var gfx = new CanvasGraphics(ctx, this.objs, textLayer); var gfx = new CanvasGraphics(ctx, this.objs, textLayer);
@ -474,9 +475,6 @@ var Page = (function PageClosure() {
* Right now there exists one PDFDocModel on the main thread + one object * Right now there exists one PDFDocModel on the main thread + one object
* for each worker. If there is no worker support enabled, there are two * for each worker. If there is no worker support enabled, there are two
* `PDFDocModel` objects on the main thread created. * `PDFDocModel` objects on the main thread created.
* TODO: Refactor the internal object structure, such that there is no
* need for the `PDFDocModel` anymore and there is only one object on the
* main thread and not one entire copy on each worker instance.
*/ */
var PDFDocModel = (function PDFDocModelClosure() { var PDFDocModel = (function PDFDocModelClosure() {
function PDFDocModel(arg, callback) { function PDFDocModel(arg, callback) {
@ -645,9 +643,9 @@ var PDFDoc = (function PDFDocClosure() {
this.data = data; this.data = data;
this.stream = stream; this.stream = stream;
this.pdf = new PDFDocModel(stream); this.pdfModel = new PDFDocModel(stream);
this.fingerprint = this.pdf.getFingerprint(); this.fingerprint = this.pdfModel.getFingerprint();
this.catalog = this.pdf.catalog; this.catalog = this.pdfModel.catalog;
this.objs = new PDFObjects(); this.objs = new PDFObjects();
this.pageCache = []; this.pageCache = [];
@ -733,8 +731,9 @@ var PDFDoc = (function PDFDocClosure() {
var pageNum = data.pageNum; var pageNum = data.pageNum;
var page = this.pageCache[pageNum]; var page = this.pageCache[pageNum];
var depFonts = data.depFonts; var depFonts = data.depFonts;
page.stats.timeEnd('Page Request'); page.stats.timeEnd('Page Request');
page.startRenderingFromIRQueue(data.IRQueue, depFonts); page.startRenderingFromOperatorList(data.operatorList, depFonts);
}, this); }, this);
messageHandler.on('obj', function pdfDocObj(data) { messageHandler.on('obj', function pdfDocObj(data) {
@ -761,31 +760,16 @@ var PDFDoc = (function PDFDocClosure() {
file = new Stream(file, 0, file.length, fontFileDict); file = new Stream(file, 0, file.length, fontFileDict);
} }
// For now, resolve the font object here direclty. The real font // At this point, only the font object is created but the font is
// object is then created in FontLoader.bind(). // not yet attached to the DOM. This is done in `FontLoader.bind`.
this.objs.resolve(id, { var font = new Font(name, file, properties);
name: name, this.objs.resolve(id, font);
file: file,
properties: properties
});
break; break;
default: default:
error('Got unkown object type ' + type); error('Got unkown object type ' + type);
} }
}, this); }, this);
messageHandler.on('font_ready', function pdfDocFontReady(data) {
var id = data[0];
var font = new FontShape(data[1]);
// If there is no string, then there is nothing to attach to the DOM.
if (!font.str) {
this.objs.resolve(id, font);
} else {
this.objs.setData(id, font);
}
}.bind(this));
messageHandler.on('page_error', function pdfDocError(data) { messageHandler.on('page_error', function pdfDocError(data) {
var page = this.pageCache[data.pageNum]; var page = this.pageCache[data.pageNum];
if (page.displayReadyPromise) if (page.displayReadyPromise)
@ -807,7 +791,7 @@ var PDFDoc = (function PDFDocClosure() {
var size = width * height; var size = width * height;
var rgbaLength = size * 4; var rgbaLength = size * 4;
var buf = new Uint8Array(size * components); var buf = new Uint8Array(size * components);
var tmpCanvas = new ScratchCanvas(width, height); var tmpCanvas = createScratchCanvas(width, height);
var tmpCtx = tmpCanvas.getContext('2d'); var tmpCtx = tmpCanvas.getContext('2d');
tmpCtx.drawImage(img, 0, 0); tmpCtx.drawImage(img, 0, 0);
var data = tmpCtx.getImageData(0, 0, width, height).data; var data = tmpCtx.getImageData(0, 0, width, height).data;
@ -836,7 +820,7 @@ var PDFDoc = (function PDFDocClosure() {
}, },
get numPages() { get numPages() {
return this.pdf.numPages; return this.pdfModel.numPages;
}, },
startRendering: function pdfDocStartRendering(page) { startRendering: function pdfDocStartRendering(page) {
@ -851,7 +835,7 @@ var PDFDoc = (function PDFDocClosure() {
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.pdfModel.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
// to the CanvasGraphics and so on. // to the CanvasGraphics and so on.
page.objs = this.objs; page.objs = this.objs;

View File

@ -112,8 +112,8 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
}; };
PartialEvaluator.prototype = { PartialEvaluator.prototype = {
getIRQueue: function partialEvaluatorGetIRQueue(stream, resources, getOperatorList: function partialEvaluatorGetOperatorList(stream, resources,
queue, dependency) { dependency, queue) {
var self = this; var self = this;
var xref = this.xref; var xref = this.xref;
@ -136,8 +136,6 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
var fontRes = resources.get('Font'); var fontRes = resources.get('Font');
// TODO: TOASK: Is it possible to get here? If so, what does
// args[0].name should be like???
assert(fontRes, 'fontRes not available'); assert(fontRes, 'fontRes not available');
fontRes = xref.fetchIfRef(fontRes); fontRes = xref.fetchIfRef(fontRes);
@ -177,7 +175,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
// Ensure the font is ready before the font is set // Ensure the font is ready before the font is set
// and later on used for drawing. // and later on used for drawing.
// TODO: This should get insert to the IRQueue only once per // OPTIMIZE: This should get insert to the operatorList only once per
// page. // page.
insertDependency([loadedName]); insertDependency([loadedName]);
return loadedName; return loadedName;
@ -239,6 +237,9 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
}, handler, xref, resources, image, inline); }, handler, xref, resources, image, inline);
} }
if (!queue)
queue = {};
if (!queue.argsArray) { if (!queue.argsArray) {
queue.argsArray = []; queue.argsArray = [];
} }
@ -280,9 +281,6 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
// TODO figure out how to type-check vararg functions // TODO figure out how to type-check vararg functions
if ((cmd == 'SCN' || cmd == 'scn') && !args[args.length - 1].code) { if ((cmd == 'SCN' || cmd == 'scn') && !args[args.length - 1].code) {
// Use the IR version for setStroke/FillColorN.
fn += '_IR';
// compile tiling patterns // compile tiling patterns
var patternName = args[args.length - 1]; var patternName = args[args.length - 1];
// SCN/scn applies patterns along with normal colors // SCN/scn applies patterns along with normal colors
@ -295,15 +293,14 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
if (typeNum == TILING_PATTERN) { if (typeNum == TILING_PATTERN) {
// Create an IR of the pattern code. // Create an IR of the pattern code.
var depIdx = dependencyArray.length; var depIdx = dependencyArray.length;
var queueObj = {}; var operatorList = this.getOperatorList(pattern,
var codeIR = this.getIRQueue(pattern, dict.get('Resources') || dict.get('Resources') || resources, dependencyArray);
resources, queueObj, dependencyArray);
// Add the dependencies that are required to execute the // Add the dependencies that are required to execute the
// codeIR. // operatorList.
insertDependency(dependencyArray.slice(depIdx)); insertDependency(dependencyArray.slice(depIdx));
args = TilingPattern.getIR(codeIR, dict, args); args = TilingPattern.getIR(operatorList, dict, args);
} }
else if (typeNum == SHADING_PATTERN) { else if (typeNum == SHADING_PATTERN) {
var shading = xref.fetchIfRef(dict.get('Shading')); var shading = xref.fetchIfRef(dict.get('Shading'));
@ -337,14 +334,18 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
fnArray.push('paintFormXObjectBegin'); fnArray.push('paintFormXObjectBegin');
argsArray.push([matrix, bbox]); argsArray.push([matrix, bbox]);
// This adds the IRQueue of the xObj to the current queue. // This adds the operatorList of the xObj to the current queue.
var depIdx = dependencyArray.length; var depIdx = dependencyArray.length;
this.getIRQueue(xobj, xobj.dict.get('Resources') || resources, // Pass in the current `queue` object. That means the `fnArray`
queue, dependencyArray); // and the `argsArray` in this scope is reused and new commands
// are added to them.
this.getOperatorList(xobj,
xobj.dict.get('Resources') || resources,
dependencyArray, queue);
// Add the dependencies that are required to execute the // Add the dependencies that are required to execute the
// codeIR. // operatorList.
insertDependency(dependencyArray.slice(depIdx)); insertDependency(dependencyArray.slice(depIdx));
fn = 'paintFormXObjectEnd'; fn = 'paintFormXObjectEnd';
@ -454,10 +455,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
} }
} }
return { return queue;
fnArray: fnArray,
argsArray: argsArray
};
}, },
extractDataStructures: function extractDataStructures: function
@ -858,12 +856,11 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
var charProcs = xref.fetchIfRef(dict.get('CharProcs')); var charProcs = xref.fetchIfRef(dict.get('CharProcs'));
var fontResources = xref.fetchIfRef(dict.get('Resources')) || resources; var fontResources = xref.fetchIfRef(dict.get('Resources')) || resources;
properties.resources = fontResources; properties.resources = fontResources;
properties.charProcIRQueues = {}; properties.charProcOperatorList = {};
for (var key in charProcs.map) { for (var key in charProcs.map) {
var glyphStream = xref.fetchIfRef(charProcs.map[key]); var glyphStream = xref.fetchIfRef(charProcs.map[key]);
var queueObj = {}; properties.charProcOperatorList[key] =
properties.charProcIRQueues[key] = this.getOperatorList(glyphStream, fontResources, dependency);
this.getIRQueue(glyphStream, fontResources, queueObj, dependency);
} }
} }

View File

@ -409,8 +409,8 @@ var FontLoader = {
bind: function fontLoaderBind(fonts, callback) { bind: function fontLoaderBind(fonts, callback) {
function checkFontsLoaded() { function checkFontsLoaded() {
for (var i = 0, ii = objs.length; i < ii; i++) { for (var i = 0, ii = fonts.length; i < ii; i++) {
var fontObj = objs[i]; var fontObj = fonts[i];
if (fontObj.loading) { if (fontObj.loading) {
return false; return false;
} }
@ -423,52 +423,45 @@ var FontLoader = {
return true; return true;
} }
var rules = [], names = [], objs = []; var rules = [], names = [], fontsToLoad = [];
var fontCreateTimer = 0;
for (var i = 0, ii = fonts.length; i < ii; i++) { for (var i = 0, ii = fonts.length; i < ii; i++) {
var font = fonts[i]; var font = fonts[i];
// If there is already a fontObj on the font, then it was loaded/attached // Add the font to the DOM only once or skip if the font
// to the page already and we don't have to do anything for this font // is already loaded.
// here future. if (font.attached || font.loading == false) {
if (font.fontObj) {
continue; continue;
} }
font.attached = true;
var obj = new Font(font.name, font.file, font.properties); fontsToLoad.push(font);
// Store the fontObj on the font such that `setFont` in CanvasGraphics
// can reuse it later again.
font.fontObj = obj;
objs.push(obj);
var str = ''; var str = '';
var data = obj.data; var data = font.data;
if (data) { if (data) {
var length = data.length; var length = data.length;
for (var j = 0; j < length; j++) for (var j = 0; j < length; j++)
str += String.fromCharCode(data[j]); str += String.fromCharCode(data[j]);
var rule = isWorker ? obj.bindWorker(str) : obj.bindDOM(str); var rule = font.bindDOM(str);
if (rule) { if (rule) {
rules.push(rule); rules.push(rule);
names.push(obj.loadedName); names.push(font.loadedName);
} }
} }
} }
this.listeningForFontLoad = false; this.listeningForFontLoad = false;
if (!isWorker && rules.length) { if (!isWorker && rules.length) {
FontLoader.prepareFontLoadEvent(rules, names, objs); FontLoader.prepareFontLoadEvent(rules, names, fontsToLoad);
} }
if (!checkFontsLoaded()) { if (!checkFontsLoaded()) {
document.documentElement.addEventListener( document.documentElement.addEventListener(
'pdfjsFontLoad', checkFontsLoaded, false); 'pdfjsFontLoad', checkFontsLoaded, false);
} }
return objs;
}, },
// Set things up so that at least one pdfjsFontLoad event is // Set things up so that at least one pdfjsFontLoad event is
// dispatched when all the @font-face |rules| for |names| have been // dispatched when all the @font-face |rules| for |names| have been
@ -476,7 +469,7 @@ var FontLoader = {
// has already started in this (outer) document, so that they should // has already started in this (outer) document, so that they should
// be ordered before the load in the subdocument. // be ordered before the load in the subdocument.
prepareFontLoadEvent: function fontLoaderPrepareFontLoadEvent(rules, names, prepareFontLoadEvent: function fontLoaderPrepareFontLoadEvent(rules, names,
objs) { fonts) {
/** Hack begin */ /** Hack begin */
// There's no event when a font has finished downloading so the // There's no event when a font has finished downloading so the
// following code is a dirty hack to 'guess' when a font is // following code is a dirty hack to 'guess' when a font is
@ -523,8 +516,8 @@ var FontLoader = {
'message', 'message',
function fontLoaderMessage(e) { function fontLoaderMessage(e) {
var fontNames = JSON.parse(e.data); var fontNames = JSON.parse(e.data);
for (var i = 0, ii = objs.length; i < ii; ++i) { for (var i = 0, ii = fonts.length; i < ii; ++i) {
var font = objs[i]; var font = fonts[i];
font.loading = false; font.loading = false;
} }
var evt = document.createEvent('Events'); var evt = document.createEvent('Events');
@ -770,7 +763,7 @@ var Font = (function FontClosure() {
function Font(name, file, properties) { function Font(name, file, properties) {
this.name = name; this.name = name;
this.coded = properties.coded; this.coded = properties.coded;
this.charProcIRQueues = properties.charProcIRQueues; this.charProcOperatorList = properties.charProcOperatorList;
this.resources = properties.resources; this.resources = properties.resources;
this.sizes = []; this.sizes = [];
@ -868,7 +861,7 @@ var Font = (function FontClosure() {
this.widthMultiplier = !properties.fontMatrix ? 1.0 : this.widthMultiplier = !properties.fontMatrix ? 1.0 :
1.0 / properties.fontMatrix[0]; 1.0 / properties.fontMatrix[0];
this.encoding = properties.baseEncoding; this.encoding = properties.baseEncoding;
this.loadedName = getUniqueName(); this.loadedName = properties.loadedName;
this.loading = true; this.loading = true;
}; };
@ -2278,17 +2271,6 @@ var Font = (function FontClosure() {
} }
}, },
bindWorker: function font_bindWorker(data) {
postMessage({
action: 'font',
data: {
raw: data,
fontName: this.loadedName,
mimetype: this.mimetype
}
});
},
bindDOM: function font_bindDom(data) { bindDOM: function font_bindDom(data) {
var fontName = this.loadedName; var fontName = this.loadedName;
@ -2342,7 +2324,7 @@ var Font = (function FontClosure() {
}, },
charToGlyph: function fonts_charToGlyph(charcode) { charToGlyph: function fonts_charToGlyph(charcode) {
var fontCharCode, width, codeIRQueue; var fontCharCode, width, operatorList;
var width = this.widths[charcode]; var width = this.widths[charcode];
@ -2377,7 +2359,7 @@ var Font = (function FontClosure() {
break; break;
case 'Type3': case 'Type3':
var glyphName = this.differences[charcode] || this.encoding[charcode]; var glyphName = this.differences[charcode] || this.encoding[charcode];
codeIRQueue = this.charProcIRQueues[glyphName]; operatorList = this.charProcOperatorList[glyphName];
fontCharCode = charcode; fontCharCode = charcode;
break; break;
case 'TrueType': case 'TrueType':
@ -2420,7 +2402,7 @@ var Font = (function FontClosure() {
fontChar: String.fromCharCode(fontCharCode), fontChar: String.fromCharCode(fontCharCode),
unicode: unicodeChars, unicode: unicodeChars,
width: width, width: width,
codeIRQueue: codeIRQueue operatorList: operatorList
}; };
}, },

View File

@ -190,7 +190,7 @@ var TilingPattern = (function TilingPatternClosure() {
var MAX_PATTERN_SIZE = 512; var MAX_PATTERN_SIZE = 512;
function TilingPattern(IR, color, ctx, objs) { function TilingPattern(IR, color, ctx, objs) {
var IRQueue = IR[2]; var operatorList = IR[2];
this.matrix = IR[3]; this.matrix = IR[3];
var bbox = IR[4]; var bbox = IR[4];
var xstep = IR[5]; var xstep = IR[5];
@ -222,7 +222,7 @@ var TilingPattern = (function TilingPatternClosure() {
width = height = MAX_PATTERN_SIZE; width = height = MAX_PATTERN_SIZE;
} }
var tmpCanvas = new ScratchCanvas(width, height); var tmpCanvas = createScratchCanvas(width, height);
// 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');
@ -259,12 +259,12 @@ var TilingPattern = (function TilingPatternClosure() {
graphics.endPath(); graphics.endPath();
} }
graphics.executeIRQueue(IRQueue); graphics.executeOperatorList(operatorList);
this.canvas = tmpCanvas; this.canvas = tmpCanvas;
} }
TilingPattern.getIR = function tiling_getIR(codeIR, dict, args) { TilingPattern.getIR = function tiling_getIR(operatorList, dict, args) {
var matrix = dict.get('Matrix'); var matrix = dict.get('Matrix');
var bbox = dict.get('BBox'); var bbox = dict.get('BBox');
var xstep = dict.get('XStep'); var xstep = dict.get('XStep');
@ -272,7 +272,7 @@ var TilingPattern = (function TilingPatternClosure() {
var paintType = dict.get('PaintType'); var paintType = dict.get('PaintType');
return [ return [
'TilingPattern', args, codeIR, matrix, bbox, xstep, ystep, paintType 'TilingPattern', args, operatorList, matrix, bbox, xstep, ystep, paintType
]; ];
}; };

View File

@ -79,7 +79,7 @@ MessageHandler.prototype = {
var WorkerMessageHandler = { var WorkerMessageHandler = {
setup: function wphSetup(handler) { setup: function wphSetup(handler) {
var pdfDoc = null; var pdfModel = null;
handler.on('test', function wphSetupTest(data) { handler.on('test', function wphSetupTest(data) {
handler.send('test', data instanceof Uint8Array); handler.send('test', data instanceof Uint8Array);
@ -88,7 +88,7 @@ var WorkerMessageHandler = {
handler.on('doc', function wphSetupDoc(data) { handler.on('doc', function wphSetupDoc(data) {
// Create only the model of the PDFDoc, which is enough for // Create only the model of the PDFDoc, which is enough for
// processing the content of the pdf. // processing the content of the pdf.
pdfDoc = new PDFDocModel(new Stream(data)); pdfModel = new PDFDocModel(new Stream(data));
}); });
handler.on('page_request', function wphSetupPageRequest(pageNum) { handler.on('page_request', function wphSetupPageRequest(pageNum) {
@ -103,14 +103,14 @@ var WorkerMessageHandler = {
var start = Date.now(); var start = Date.now();
var dependency = []; var dependency = [];
var IRQueue = null; var operatorList = null;
try { try {
var page = pdfDoc.getPage(pageNum); var page = pdfModel.getPage(pageNum);
// Pre compile the pdf page and fetch the fonts/images. // Pre compile the pdf page and fetch the fonts/images.
IRQueue = page.getIRQueue(handler, dependency); operatorList = page.getOperatorList(handler, dependency);
} catch (e) { } catch (e) {
var minimumStackMessage = var minimumStackMessage =
'worker.js: while trying to getPage() and getIRQueue()'; 'worker.js: while trying to getPage() and getOperatorList()';
// Turn the error into an obj that can be serialized // Turn the error into an obj that can be serialized
if (typeof e === 'string') { if (typeof e === 'string') {
@ -137,8 +137,8 @@ var WorkerMessageHandler = {
return; return;
} }
console.log('page=%d - getIRQueue: time=%dms, len=%d', pageNum, console.log('page=%d - getOperatorList: time=%dms, len=%d', pageNum,
Date.now() - start, IRQueue.fnArray.length); Date.now() - start, operatorList.fnArray.length);
// Filter the dependecies for fonts. // Filter the dependecies for fonts.
var fonts = {}; var fonts = {};
@ -151,59 +151,10 @@ var WorkerMessageHandler = {
handler.send('page', { handler.send('page', {
pageNum: pageNum, pageNum: pageNum,
IRQueue: IRQueue, operatorList: operatorList,
depFonts: Object.keys(fonts) depFonts: Object.keys(fonts)
}); });
}, this); }, this);
handler.on('font', function wphSetupFont(data) {
var objId = data[0];
var name = data[1];
var file = data[2];
var properties = data[3];
var font = {
name: name,
file: file,
properties: properties
};
// Some fonts don't have a file, e.g. the build in ones like Arial.
if (file) {
var fontFileDict = new Dict();
fontFileDict.map = file.dict.map;
var fontFile = new Stream(file.bytes, file.start,
file.end - file.start, fontFileDict);
// Check if this is a FlateStream. Otherwise just use the created
// Stream one. This makes complex_ttf_font.pdf work.
var cmf = file.bytes[0];
if ((cmf & 0x0f) == 0x08) {
font.file = new FlateStream(fontFile);
} else {
font.file = fontFile;
}
}
var obj = new Font(font.name, font.file, font.properties);
var str = '';
var objData = obj.data;
if (objData) {
var length = objData.length;
for (var j = 0; j < length; ++j)
str += String.fromCharCode(objData[j]);
}
obj.str = str;
// Remove the data array form the font object, as it's not needed
// anymore as we sent over the ready str.
delete obj.data;
handler.send('font_ready', [objId, obj]);
});
} }
}; };

View File

@ -20,6 +20,7 @@
!scan-bad.pdf !scan-bad.pdf
!freeculture.pdf !freeculture.pdf
!pdfkit_compressed.pdf !pdfkit_compressed.pdf
!TAMReview.pdf
!issue918.pdf !issue918.pdf
!issue1249.pdf !issue1249.pdf
!smaskdim.pdf !smaskdim.pdf

BIN
test/pdfs/TAMReview.pdf Normal file

Binary file not shown.

View File

@ -472,6 +472,14 @@
"rounds": 1, "rounds": 1,
"type": "eq" "type": "eq"
}, },
{ "id": "tamreview",
"file": "pdfs/TAMReview.pdf",
"md5": "8039aba56790d3597d2bc8c794a51301",
"rounds": 1,
"pageLimit": 5,
"link": true,
"type": "eq"
},
{ "id": "issue1350", { "id": "issue1350",
"file": "pdfs/issue1350.pdf", "file": "pdfs/issue1350.pdf",
"md5": "92f72a04a4d9d05b2dd433b51f32ab1f", "md5": "92f72a04a4d9d05b2dd433b51f32ab1f",