Merge remote-tracking branch 'origin/master' into mozilla

This commit is contained in:
Saebekassebil 2012-03-22 20:35:05 +01:00
commit 5600cf93a0
25 changed files with 1474 additions and 712 deletions

View File

@ -226,6 +226,7 @@ FIREFOX_CONTENT_DIR := $(EXTENSION_SRC)/firefox/$(CONTENT_DIR)/
FIREFOX_EXTENSION_FILES_TO_COPY = \ FIREFOX_EXTENSION_FILES_TO_COPY = \
*.js \ *.js \
*.rdf \ *.rdf \
*.png \
install.rdf.in \ install.rdf.in \
README.mozilla \ README.mozilla \
components \ components \
@ -234,12 +235,16 @@ FIREFOX_EXTENSION_FILES_TO_COPY = \
FIREFOX_EXTENSION_FILES = \ FIREFOX_EXTENSION_FILES = \
bootstrap.js \ bootstrap.js \
install.rdf \ install.rdf \
icon.png \
icon64.png \
components \ components \
content \ content \
LICENSE \ LICENSE \
$(NULL) $(NULL)
FIREFOX_MC_EXTENSION_FILES = \ FIREFOX_MC_EXTENSION_FILES = \
bootstrap.js \ bootstrap.js \
icon.png \
icon64.png \
components \ components \
content \ content \
LICENSE \ LICENSE \

View File

@ -10,10 +10,14 @@ let Cc = Components.classes;
let Ci = Components.interfaces; let Ci = Components.interfaces;
let Cm = Components.manager; let Cm = Components.manager;
let Cu = Components.utils; let Cu = Components.utils;
let application = Cc['@mozilla.org/fuel/application;1']
.getService(Ci.fuelIApplication);
Cu.import('resource://gre/modules/Services.jsm'); Cu.import('resource://gre/modules/Services.jsm');
function log(str) { function log(str) {
if (!application.prefs.getValue(EXT_PREFIX + '.pdfBugEnabled', false))
return;
dump(str + '\n'); dump(str + '\n');
} }
@ -60,12 +64,7 @@ function startup(aData, aReason) {
var ioService = Services.io; var ioService = Services.io;
var resProt = ioService.getProtocolHandler('resource') var resProt = ioService.getProtocolHandler('resource')
.QueryInterface(Ci.nsIResProtocolHandler); .QueryInterface(Ci.nsIResProtocolHandler);
var aliasFile = Cc['@mozilla.org/file/local;1'] var aliasURI = ioService.newURI('content/', 'UTF-8', aData.resourceURI);
.createInstance(Ci.nsILocalFile);
var componentPath = aData.installPath.clone();
componentPath.append('content');
aliasFile.initWithPath(componentPath.path);
var aliasURI = ioService.newFileURI(aliasFile);
resProt.setSubstitution(RESOURCE_NAME, aliasURI); resProt.setSubstitution(RESOURCE_NAME, aliasURI);
// Load the component and register it. // Load the component and register it.
@ -73,12 +72,9 @@ function startup(aData, aReason) {
'components/PdfStreamConverter.js'; 'components/PdfStreamConverter.js';
Cu.import(pdfStreamConverterUrl); Cu.import(pdfStreamConverterUrl);
Factory.register(PdfStreamConverter); Factory.register(PdfStreamConverter);
Services.prefs.setBoolPref('extensions.pdf.js.active', true);
} }
function shutdown(aData, aReason) { function shutdown(aData, aReason) {
if (Services.prefs.getBoolPref('extensions.pdf.js.active'))
Services.prefs.setBoolPref('extensions.pdf.js.active', false);
if (aReason == APP_SHUTDOWN) if (aReason == APP_SHUTDOWN)
return; return;
var ioService = Services.io; var ioService = Services.io;
@ -89,18 +85,14 @@ function shutdown(aData, aReason) {
// Remove the contract/component. // Remove the contract/component.
Factory.unregister(); Factory.unregister();
// Unload the converter // Unload the converter
if (pdfStreamConverterUrl) { Cu.unload(pdfStreamConverterUrl);
Cu.unload(pdfStreamConverterUrl); pdfStreamConverterUrl = null;
pdfStreamConverterUrl = null;
}
} }
function install(aData, aReason) { function install(aData, aReason) {
Services.prefs.setBoolPref('extensions.pdf.js.active', false);
} }
function uninstall(aData, aReason) { function uninstall(aData, aReason) {
Services.prefs.clearUserPref('extensions.pdf.js.active');
application.prefs.setValue(EXT_PREFIX + '.database', '{}'); application.prefs.setValue(EXT_PREFIX + '.database', '{}');
} }

View File

@ -17,7 +17,15 @@ const MAX_DATABASE_LENGTH = 4096;
Cu.import('resource://gre/modules/XPCOMUtils.jsm'); Cu.import('resource://gre/modules/XPCOMUtils.jsm');
Cu.import('resource://gre/modules/Services.jsm'); Cu.import('resource://gre/modules/Services.jsm');
let application = Cc['@mozilla.org/fuel/application;1']
.getService(Ci.fuelIApplication);
let privateBrowsing = Cc['@mozilla.org/privatebrowsing;1']
.getService(Ci.nsIPrivateBrowsingService);
let inPrivateBrowswing = privateBrowsing.privateBrowsingEnabled;
function log(aMsg) { function log(aMsg) {
if (!application.prefs.getValue(EXT_PREFIX + '.pdfBugEnabled', false))
return;
let msg = 'PdfStreamConverter.js: ' + (aMsg.join ? aMsg.join('') : aMsg); let msg = 'PdfStreamConverter.js: ' + (aMsg.join ? aMsg.join('') : aMsg);
Services.console.logStringMessage(msg); Services.console.logStringMessage(msg);
dump(msg + '\n'); dump(msg + '\n');
@ -40,11 +48,6 @@ function topWindow(win) {
.QueryInterface(Ci.nsIInterfaceRequestor) .QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindow); .getInterface(Ci.nsIDOMWindow);
} }
let application = Cc['@mozilla.org/fuel/application;1']
.getService(Ci.fuelIApplication);
let privateBrowsing = Cc['@mozilla.org/privatebrowsing;1']
.getService(Ci.nsIPrivateBrowsingService);
let inPrivateBrowswing = privateBrowsing.privateBrowsingEnabled;
// All the priviledged actions. // All the priviledged actions.
function ChromeActions() { function ChromeActions() {
@ -125,9 +128,6 @@ PdfStreamConverter.prototype = {
// nsIStreamConverter::asyncConvertData // nsIStreamConverter::asyncConvertData
asyncConvertData: function(aFromType, aToType, aListener, aCtxt) { asyncConvertData: function(aFromType, aToType, aListener, aCtxt) {
if (!Services.prefs.getBoolPref('extensions.pdf.js.active'))
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
// Ignoring HTTP POST requests -- pdf.js has to repeat the request. // Ignoring HTTP POST requests -- pdf.js has to repeat the request.
var skipConversion = false; var skipConversion = false;
try { try {

BIN
extensions/firefox/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

View File

@ -5,9 +5,8 @@
<Description about="urn:mozilla:install-manifest"> <Description about="urn:mozilla:install-manifest">
<em:id>uriloader@pdf.js</em:id> <em:id>uriloader@pdf.js</em:id>
<em:name>pdf.js</em:name> <em:name>PDF Viewer</em:name>
<em:version>PDFJSSCRIPT_VERSION</em:version> <em:version>PDFJSSCRIPT_VERSION</em:version>
<em:iconURL>chrome://pdf.js/skin/logo.png</em:iconURL>
<em:targetApplication> <em:targetApplication>
<Description> <Description>
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
@ -16,9 +15,8 @@
</Description> </Description>
</em:targetApplication> </em:targetApplication>
<em:bootstrap>true</em:bootstrap> <em:bootstrap>true</em:bootstrap>
<em:unpack>true</em:unpack> <em:creator>Mozilla</em:creator>
<em:creator>Mozilla Labs</em:creator> <em:description>Uses HTML5 to display PDF files directly in Firefox.</em:description>
<em:description>pdf.js uri loader</em:description>
<em:homepageURL>https://github.com/mozilla/pdf.js/</em:homepageURL> <em:homepageURL>https://github.com/mozilla/pdf.js/</em:homepageURL>
<em:type>2</em:type> <em:type>2</em:type>
<!-- Use the raw link for updates so we we can use SSL. --> <!-- Use the raw link for updates so we we can use SSL. -->

View File

@ -7,22 +7,20 @@
<Description about="urn:mozilla:install-manifest"> <Description about="urn:mozilla:install-manifest">
<em:id>uriloader@pdf.js</em:id> <em:id>uriloader@pdf.js</em:id>
<em:name>pdf.js</em:name> <em:name>PDF Viewer</em:name>
<em:version>PDFJSSCRIPT_VERSION</em:version> <em:version>PDFJSSCRIPT_VERSION</em:version>
<em:iconURL>chrome://pdf.js/skin/logo.png</em:iconURL>
<em:targetApplication> <em:targetApplication>
<Description> <Description>
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
<em:minVersion>@FIREFOX_VERSION@</em:minVersion> <em:minVersion>@FIREFOX_VERSION@</em:minVersion>
<em:maxVersion>@FIREFOX_VERSION@</em:maxVersion> <em:maxVersion>@FIREFOX_VERSION@</em:maxVersion>
<em:strictCompatibility>true</em:strictCompatibility>
</Description> </Description>
</em:targetApplication> </em:targetApplication>
<em:strictCompatibility>true</em:strictCompatibility>
<em:bootstrap>true</em:bootstrap> <em:bootstrap>true</em:bootstrap>
<em:unpack>true</em:unpack> <em:creator>Mozilla</em:creator>
<em:creator>Mozilla Labs</em:creator> <em:description>Uses HTML5 to display PDF files directly in Firefox.</em:description>
<em:description>pdf.js uri loader</em:description> <em:homepageURL>http://support.mozilla.org/kb/using-mozilla-pdf-viewer</em:homepageURL>
<em:homepageURL>https://github.com/mozilla/pdf.js/</em:homepageURL>
<em:type>2</em:type> <em:type>2</em:type>
</Description> </Description>
</RDF> </RDF>

View File

@ -220,6 +220,7 @@ target.firefox = function() {
FIREFOX_EXTENSION_FILES_TO_COPY = FIREFOX_EXTENSION_FILES_TO_COPY =
['*.js', ['*.js',
'*.rdf', '*.rdf',
'*.png',
'install.rdf.in', 'install.rdf.in',
'README.mozilla', 'README.mozilla',
'components', 'components',
@ -227,11 +228,15 @@ target.firefox = function() {
FIREFOX_EXTENSION_FILES = FIREFOX_EXTENSION_FILES =
['bootstrap.js', ['bootstrap.js',
'install.rdf', 'install.rdf',
'icon.png',
'icon64.png',
'components', 'components',
'content', 'content',
'LICENSE']; 'LICENSE'];
FIREFOX_MC_EXTENSION_FILES = FIREFOX_MC_EXTENSION_FILES =
['bootstrap.js', ['bootstrap.js',
'icon.png',
'icon64.png',
'components', 'components',
'content', 'content',
'LICENSE']; 'LICENSE'];

View File

@ -124,7 +124,7 @@ var bidi = PDFJS.bidi = (function bidiClosure() {
} }
} }
return (function bidi(text, startLevel) { function bidi(text, startLevel) {
var str = text.str; var str = text.str;
var strLength = str.length; var strLength = str.length;
if (strLength == 0) if (strLength == 0)
@ -429,5 +429,8 @@ var bidi = PDFJS.bidi = (function bidiClosure() {
result += ch; result += ch;
} }
return result; return result;
}); }
return bidi;
})(); })();

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,9 +188,9 @@ 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 = 50; var kExecutionTime = 15;
function CanvasGraphics(canvasCtx, objs, textLayer) { function CanvasGraphics(canvasCtx, objs, textLayer) {
this.ctx = canvasCtx; this.ctx = canvasCtx;
@ -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

@ -570,7 +570,6 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() {
}; };
} }
error('Unknown crypto method'); error('Unknown crypto method');
return null;
} }
CipherTransformFactory.prototype = { CipherTransformFactory.prototype = {

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
@ -855,12 +853,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);
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -514,7 +514,6 @@ var XRef = (function XRefClosure() {
return dict; return dict;
// nothing helps // nothing helps
error('Invalid PDF structure'); error('Invalid PDF structure');
return null;
}, },
readXRef: function readXref(startXRef) { readXRef: function readXref(startXRef) {
var stream = this.stream; var stream = this.stream;
@ -723,12 +722,10 @@ var PDFObjects = (function PDFObjectsClosure() {
// 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)
error('Requesting object that isn\'t resolved yet ' + objId); error('Requesting object that isn\'t resolved yet ' + objId);
return null;
} else { return obj.data;
return obj.data;
}
}, },
/** /**

View File

@ -53,15 +53,14 @@ var Parser = (function ParserClosure() {
this.shift(); this.shift();
var dict = new Dict(); var dict = new Dict();
while (!isCmd(this.buf1, '>>') && !isEOF(this.buf1)) { while (!isCmd(this.buf1, '>>') && !isEOF(this.buf1)) {
if (!isName(this.buf1)) { if (!isName(this.buf1))
error('Dictionary key must be a name object'); error('Dictionary key must be a name object');
} else {
var key = this.buf1.name; var key = this.buf1.name;
this.shift(); this.shift();
if (isEOF(this.buf1)) if (isEOF(this.buf1))
break; break;
dict.set(key, this.getObj(cipherTransform)); dict.set(key, this.getObj(cipherTransform));
}
} }
if (isEOF(this.buf1)) if (isEOF(this.buf1))
error('End of file inside dictionary'); error('End of file inside dictionary');
@ -106,15 +105,14 @@ var Parser = (function ParserClosure() {
// parse dictionary // parse dictionary
var dict = new Dict(); var dict = new Dict();
while (!isCmd(this.buf1, 'ID') && !isEOF(this.buf1)) { while (!isCmd(this.buf1, 'ID') && !isEOF(this.buf1)) {
if (!isName(this.buf1)) { if (!isName(this.buf1))
error('Dictionary key must be a name object'); error('Dictionary key must be a name object');
} else {
var key = this.buf1.name; var key = this.buf1.name;
this.shift(); this.shift();
if (isEOF(this.buf1)) if (isEOF(this.buf1))
break; break;
dict.set(key, this.getObj(cipherTransform)); dict.set(key, this.getObj(cipherTransform));
}
} }
// parse image stream // parse image stream
@ -176,10 +174,8 @@ var Parser = (function ParserClosure() {
// get length // get length
var length = this.fetchIfRef(dict.get('Length')); var length = this.fetchIfRef(dict.get('Length'));
if (!isInt(length)) { if (!isInt(length))
error('Bad ' + length + ' attribute in stream'); error('Bad ' + length + ' attribute in stream');
length = 0;
}
// skip over the stream data // skip over the stream data
stream.pos = pos + length; stream.pos = pos + length;
@ -208,14 +204,13 @@ var Parser = (function ParserClosure() {
filter = filterArray[i]; filter = filterArray[i];
if (!isName(filter)) if (!isName(filter))
error('Bad filter name: ' + filter); error('Bad filter name: ' + filter);
else {
params = null; params = null;
if (isArray(paramsArray) && (i in paramsArray)) if (isArray(paramsArray) && (i in paramsArray))
params = paramsArray[i]; params = paramsArray[i];
stream = this.makeFilter(stream, filter.name, length, params); stream = this.makeFilter(stream, filter.name, length, params);
// after the first stream the length variable is invalid // after the first stream the length variable is invalid
length = null; length = null;
}
} }
} }
return stream; return stream;
@ -527,17 +522,15 @@ var Lexer = (function LexerClosure() {
// fall through // fall through
case ')': case ')':
error('Illegal character: ' + ch); error('Illegal character: ' + ch);
return Error;
} }
// command // command
var str = ch; var str = ch;
while (!!(ch = stream.lookChar()) && !specialChars[ch.charCodeAt(0)]) { while (!!(ch = stream.lookChar()) && !specialChars[ch.charCodeAt(0)]) {
stream.skip(); stream.skip();
if (str.length == 128) { if (str.length == 128)
error('Command token too long: ' + str.length); error('Command token too long: ' + str.length);
break;
}
str += ch; str += ch;
} }
if (str == 'true') if (str == 'true')
@ -594,7 +587,6 @@ var Linearization = (function LinearizationClosure() {
return obj; return obj;
} }
error('"' + name + '" field in linearization table is invalid'); error('"' + name + '" field in linearization table is invalid');
return 0;
}, },
getHint: function linearizationGetHint(index) { getHint: function linearizationGetHint(index) {
var linDict = this.linDict; var linDict = this.linDict;
@ -607,7 +599,6 @@ var Linearization = (function LinearizationClosure() {
return obj2; return obj2;
} }
error('Hints table in linearization table is invalid: ' + index); error('Hints table in linearization table is invalid: ' + index);
return 0;
}, },
get length() { get length() {
if (!isDict(this.linDict)) if (!isDict(this.linDict))

View File

@ -82,7 +82,7 @@ Shadings.RadialAxial = (function RadialAxialClosure() {
fnObj = xref.fetchIfRef(fnObj); fnObj = xref.fetchIfRef(fnObj);
if (isArray(fnObj)) if (isArray(fnObj))
error('No support for array of functions'); error('No support for array of functions');
else if (!isPDFFunction(fnObj)) if (!isPDFFunction(fnObj))
error('Invalid function'); error('Invalid function');
var fn = PDFFunction.parse(xref, fnObj); var fn = PDFFunction.parse(xref, fnObj);
@ -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,10 +20,12 @@
!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
!type4psfunc.pdf !type4psfunc.pdf
!S2.pdf !S2.pdf
!zerowidthline.pdf !zerowidthline.pdf
!issue1002.pdf
!issue925.pdf !issue925.pdf

BIN
test/pdfs/TAMReview.pdf Normal file

Binary file not shown.

BIN
test/pdfs/issue1002.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": "issue925", { "id": "issue925",
"file": "pdfs/issue925.pdf", "file": "pdfs/issue925.pdf",
"md5": "f58fe943090aff89dcc8e771bc0db4c2", "md5": "f58fe943090aff89dcc8e771bc0db4c2",
@ -500,6 +508,13 @@
"link": true, "link": true,
"type": "eq" "type": "eq"
}, },
{ "id": "issue1002",
"file": "pdfs/issue1002.pdf",
"md5": "af62d6cd95079322d4af18edd960d15c",
"rounds": 1,
"link": false,
"type": "eq"
},
{ "id": "issue1243", { "id": "issue1243",
"file": "pdfs/issue1243.pdf", "file": "pdfs/issue1243.pdf",
"md5": "130c849b83513d5ac5e03c6421fc7489", "md5": "130c849b83513d5ac5e03c6421fc7489",

223
test/unit/font_spec.js Normal file
View File

@ -0,0 +1,223 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
'use strict';
describe('font', function() {
function hexDump(bytes) {
var line = '';
for (var i = 0, ii = bytes.length; i < ii; ++i) {
var b = bytes[i].toString(16);
if (b.length < 2)
b = '0' + b;
line += b.toString(16);
}
return line;
}
// This example font comes from the CFF spec:
// http://www.adobe.com/content/dam/Adobe/en/devnet/font/pdfs/5176.CFF.pdf
var exampleFont = '0100040100010101134142434445462b' +
'54696d65732d526f6d616e000101011f' +
'f81b00f81c02f81d03f819041c6f000d' +
'fb3cfb6efa7cfa1605e911b8f1120003' +
'01010813183030312e30303754696d65' +
'7320526f6d616e54696d657300000002' +
'010102030e0e7d99f92a99fb7695f773' +
'8b06f79a93fc7c8c077d99f85695f75e' +
'9908fb6e8cf87393f7108b09a70adf0b' +
'f78e14';
var fontData = [];
for (var i = 0; i < exampleFont.length; i += 2) {
var hex = exampleFont.substr(i, 2);
fontData.push(parseInt(hex, 16));
}
var bytes = new Uint8Array(fontData);
fontData = {getBytes: function() { return bytes}};
function bytesToString(bytesArray) {
var str = '';
for (var i = 0, ii = bytesArray.length; i < ii; i++)
str += String.fromCharCode(bytesArray[i]);
return str;
}
describe('CFFParser', function() {
var parser = new CFFParser(fontData);
var cff = parser.parse();
it('parses header', function() {
var header = cff.header;
expect(header.major).toEqual(1);
expect(header.minor).toEqual(0);
expect(header.hdrSize).toEqual(4);
expect(header.offSize).toEqual(1);
});
it('parses name index', function() {
var names = cff.names;
expect(names.length).toEqual(1);
expect(names[0]).toEqual('ABCDEF+Times-Roman');
});
it('sanitizes name index', function() {
var index = new CFFIndex();
index.add(['['.charCodeAt(0), 'a'.charCodeAt(0)]);
var names = parser.parseNameIndex(index);
expect(names).toEqual(['_a']);
index = new CFFIndex();
var longName = [];
for (var i = 0; i < 129; i++)
longName.push(0);
index.add(longName);
names = parser.parseNameIndex(index);
expect(names[0].length).toEqual(127);
});
it('parses string index', function() {
var strings = cff.strings;
expect(strings.count).toEqual(3);
expect(strings.get(0)).toEqual('.notdef');
expect(strings.get(391)).toEqual('001.007');
});
it('parses top dict', function() {
var topDict = cff.topDict;
// 391 version 392 FullName 393 FamilyName 389 Weight 28416 UniqueID
// -168 -218 1000 898 FontBBox 94 CharStrings 45 102 Private
expect(topDict.getByName('version')).toEqual(391);
expect(topDict.getByName('FullName')).toEqual(392);
expect(topDict.getByName('FamilyName')).toEqual(393);
expect(topDict.getByName('Weight')).toEqual(389);
expect(topDict.getByName('UniqueID')).toEqual(28416);
expect(topDict.getByName('FontBBox')).toEqual([-168, -218, 1000, 898]);
expect(topDict.getByName('CharStrings')).toEqual(94);
expect(topDict.getByName('Private')).toEqual([45, 102]);
});
it('parses predefined charsets', function() {
var charset = parser.parseCharsets(0, 0, null, true);
expect(charset.predefined).toEqual(true);
});
it('parses charset format 0', function() {
// The first three bytes make the offset large enough to skip predefined.
var bytes = new Uint8Array([0x00, 0x00, 0x00,
0x00, // format
0x00, 0x02 // sid/cid
]);
parser.bytes = bytes;
var charset = parser.parseCharsets(3, 2, new CFFStrings(), false);
expect(charset.charset[1]).toEqual('exclam');
// CID font
var charset = parser.parseCharsets(3, 2, new CFFStrings(), true);
expect(charset.charset[1]).toEqual(2);
});
it('parses charset format 1', function() {
// The first three bytes make the offset large enough to skip predefined.
var bytes = new Uint8Array([0x00, 0x00, 0x00,
0x01, // format
0x00, 0x08, // sid/cid start
0x01 // sid/cid left
]);
parser.bytes = bytes;
var charset = parser.parseCharsets(3, 2, new CFFStrings(), false);
expect(charset.charset).toEqual(['.notdef', 'quoteright', 'parenleft']);
// CID font
var charset = parser.parseCharsets(3, 2, new CFFStrings(), true);
expect(charset.charset).toEqual(['.notdef', 8, 9]);
});
it('parses charset format 2', function() {
// format 2 is the same as format 1 but the left is card16
// The first three bytes make the offset large enough to skip predefined.
var bytes = new Uint8Array([0x00, 0x00, 0x00,
0x02, // format
0x00, 0x08, // sid/cid start
0x00, 0x01 // sid/cid left
]);
parser.bytes = bytes;
var charset = parser.parseCharsets(3, 2, new CFFStrings(), false);
expect(charset.charset).toEqual(['.notdef', 'quoteright', 'parenleft']);
// CID font
var charset = parser.parseCharsets(3, 2, new CFFStrings(), true);
expect(charset.charset).toEqual(['.notdef', 8, 9]);
});
it('parses encoding format 0', function() {
// The first two bytes make the offset large enough to skip predefined.
var bytes = new Uint8Array([0x00, 0x00,
0x00, // format
0x01, // count
0x08 // start
]);
parser.bytes = bytes;
var encoding = parser.parseEncoding(2, {}, new CFFStrings(), null);
expect(encoding.encoding).toEqual({0x8: 1});
});
it('parses encoding format 1', function() {
// The first two bytes make the offset large enough to skip predefined.
var bytes = new Uint8Array([0x00, 0x00,
0x01, // format
0x01, // num ranges
0x07, // range1 start
0x01 // range2 left
]);
parser.bytes = bytes;
var encoding = parser.parseEncoding(2, {}, new CFFStrings(), null);
expect(encoding.encoding).toEqual({0x7: 0x01, 0x08: 0x02});
});
it('parses fdselect format 0', function() {
var bytes = new Uint8Array([0x00, // format
0x00, // gid: 0 fd: 0
0x01 // gid: 1 fd: 1
]);
parser.bytes = bytes;
var fdSelect = parser.parseFDSelect(0, 2);
expect(fdSelect.fdSelect).toEqual([0, 1]);
});
it('parses fdselect format 3', function() {
var bytes = new Uint8Array([0x03, // format
0x00, 0x02, // range count
0x00, 0x00, // first gid
0x09, // font dict 1 id
0x00, 0x02, // nex gid
0x0a, // font dict 2 gid
0x00, 0x04 // sentinel (last gid)
]);
parser.bytes = bytes;
var fdSelect = parser.parseFDSelect(0, 2);
expect(fdSelect.fdSelect).toEqual([9, 9, 0xa, 0xa]);
});
// TODO fdArray
});
describe('CFFCompiler', function() {
it('encodes integers', function() {
var c = new CFFCompiler();
// all the examples from the spec
expect(c.encodeInteger(0)).toEqual([0x8b]);
expect(c.encodeInteger(100)).toEqual([0xef]);
expect(c.encodeInteger(-100)).toEqual([0x27]);
expect(c.encodeInteger(1000)).toEqual([0xfa, 0x7c]);
expect(c.encodeInteger(-1000)).toEqual([0xfe, 0x7c]);
expect(c.encodeInteger(10000)).toEqual([0x1c, 0x27, 0x10]);
expect(c.encodeInteger(-10000)).toEqual([0x1c, 0xd8, 0xf0]);
expect(c.encodeInteger(100000)).toEqual([0x1d, 0x00, 0x01, 0x86, 0xa0]);
expect(c.encodeInteger(-100000)).toEqual([0x1d, 0xff, 0xfe, 0x79, 0x60]);
});
it('encodes floats', function() {
var c = new CFFCompiler();
expect(c.encodeFloat(-2.25)).toEqual([0x1e, 0xe2, 0xa2, 0x5f]);
expect(c.encodeFloat(5e-11)).toEqual([0x1e, 0x5c, 0x11, 0xff]);
});
// TODO a lot more compiler tests
});
});

View File

@ -25,6 +25,7 @@ load:
- ../../src/bidi.js - ../../src/bidi.js
- ../../external/jpgjs/jpg.js - ../../external/jpgjs/jpg.js
- ../unit/obj_spec.js - ../unit/obj_spec.js
- ../unit/font_spec.js
- ../unit/function_spec.js - ../unit/function_spec.js
- ../unit/crypto_spec.js - ../unit/crypto_spec.js
- ../unit/stream_spec.js - ../unit/stream_spec.js