Merge remote-tracking branch 'origin/master' into mozilla
This commit is contained in:
commit
5600cf93a0
5
Makefile
5
Makefile
@ -226,6 +226,7 @@ FIREFOX_CONTENT_DIR := $(EXTENSION_SRC)/firefox/$(CONTENT_DIR)/
|
||||
FIREFOX_EXTENSION_FILES_TO_COPY = \
|
||||
*.js \
|
||||
*.rdf \
|
||||
*.png \
|
||||
install.rdf.in \
|
||||
README.mozilla \
|
||||
components \
|
||||
@ -234,12 +235,16 @@ FIREFOX_EXTENSION_FILES_TO_COPY = \
|
||||
FIREFOX_EXTENSION_FILES = \
|
||||
bootstrap.js \
|
||||
install.rdf \
|
||||
icon.png \
|
||||
icon64.png \
|
||||
components \
|
||||
content \
|
||||
LICENSE \
|
||||
$(NULL)
|
||||
FIREFOX_MC_EXTENSION_FILES = \
|
||||
bootstrap.js \
|
||||
icon.png \
|
||||
icon64.png \
|
||||
components \
|
||||
content \
|
||||
LICENSE \
|
||||
|
22
extensions/firefox/bootstrap.js
vendored
22
extensions/firefox/bootstrap.js
vendored
@ -10,10 +10,14 @@ let Cc = Components.classes;
|
||||
let Ci = Components.interfaces;
|
||||
let Cm = Components.manager;
|
||||
let Cu = Components.utils;
|
||||
let application = Cc['@mozilla.org/fuel/application;1']
|
||||
.getService(Ci.fuelIApplication);
|
||||
|
||||
Cu.import('resource://gre/modules/Services.jsm');
|
||||
|
||||
function log(str) {
|
||||
if (!application.prefs.getValue(EXT_PREFIX + '.pdfBugEnabled', false))
|
||||
return;
|
||||
dump(str + '\n');
|
||||
}
|
||||
|
||||
@ -60,12 +64,7 @@ function startup(aData, aReason) {
|
||||
var ioService = Services.io;
|
||||
var resProt = ioService.getProtocolHandler('resource')
|
||||
.QueryInterface(Ci.nsIResProtocolHandler);
|
||||
var aliasFile = Cc['@mozilla.org/file/local;1']
|
||||
.createInstance(Ci.nsILocalFile);
|
||||
var componentPath = aData.installPath.clone();
|
||||
componentPath.append('content');
|
||||
aliasFile.initWithPath(componentPath.path);
|
||||
var aliasURI = ioService.newFileURI(aliasFile);
|
||||
var aliasURI = ioService.newURI('content/', 'UTF-8', aData.resourceURI);
|
||||
resProt.setSubstitution(RESOURCE_NAME, aliasURI);
|
||||
|
||||
// Load the component and register it.
|
||||
@ -73,12 +72,9 @@ function startup(aData, aReason) {
|
||||
'components/PdfStreamConverter.js';
|
||||
Cu.import(pdfStreamConverterUrl);
|
||||
Factory.register(PdfStreamConverter);
|
||||
Services.prefs.setBoolPref('extensions.pdf.js.active', true);
|
||||
}
|
||||
|
||||
function shutdown(aData, aReason) {
|
||||
if (Services.prefs.getBoolPref('extensions.pdf.js.active'))
|
||||
Services.prefs.setBoolPref('extensions.pdf.js.active', false);
|
||||
if (aReason == APP_SHUTDOWN)
|
||||
return;
|
||||
var ioService = Services.io;
|
||||
@ -89,18 +85,14 @@ function shutdown(aData, aReason) {
|
||||
// Remove the contract/component.
|
||||
Factory.unregister();
|
||||
// Unload the converter
|
||||
if (pdfStreamConverterUrl) {
|
||||
Cu.unload(pdfStreamConverterUrl);
|
||||
pdfStreamConverterUrl = null;
|
||||
}
|
||||
Cu.unload(pdfStreamConverterUrl);
|
||||
pdfStreamConverterUrl = null;
|
||||
}
|
||||
|
||||
function install(aData, aReason) {
|
||||
Services.prefs.setBoolPref('extensions.pdf.js.active', false);
|
||||
}
|
||||
|
||||
function uninstall(aData, aReason) {
|
||||
Services.prefs.clearUserPref('extensions.pdf.js.active');
|
||||
application.prefs.setValue(EXT_PREFIX + '.database', '{}');
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,15 @@ const MAX_DATABASE_LENGTH = 4096;
|
||||
Cu.import('resource://gre/modules/XPCOMUtils.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) {
|
||||
if (!application.prefs.getValue(EXT_PREFIX + '.pdfBugEnabled', false))
|
||||
return;
|
||||
let msg = 'PdfStreamConverter.js: ' + (aMsg.join ? aMsg.join('') : aMsg);
|
||||
Services.console.logStringMessage(msg);
|
||||
dump(msg + '\n');
|
||||
@ -40,11 +48,6 @@ function topWindow(win) {
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.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.
|
||||
function ChromeActions() {
|
||||
@ -125,9 +128,6 @@ PdfStreamConverter.prototype = {
|
||||
|
||||
// nsIStreamConverter::asyncConvertData
|
||||
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.
|
||||
var skipConversion = false;
|
||||
try {
|
||||
|
BIN
extensions/firefox/icon.png
Normal file
BIN
extensions/firefox/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.5 KiB |
BIN
extensions/firefox/icon64.png
Normal file
BIN
extensions/firefox/icon64.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.7 KiB |
@ -5,9 +5,8 @@
|
||||
|
||||
<Description about="urn:mozilla:install-manifest">
|
||||
<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:iconURL>chrome://pdf.js/skin/logo.png</em:iconURL>
|
||||
<em:targetApplication>
|
||||
<Description>
|
||||
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
|
||||
@ -16,9 +15,8 @@
|
||||
</Description>
|
||||
</em:targetApplication>
|
||||
<em:bootstrap>true</em:bootstrap>
|
||||
<em:unpack>true</em:unpack>
|
||||
<em:creator>Mozilla Labs</em:creator>
|
||||
<em:description>pdf.js uri loader</em:description>
|
||||
<em:creator>Mozilla</em:creator>
|
||||
<em:description>Uses HTML5 to display PDF files directly in Firefox.</em:description>
|
||||
<em:homepageURL>https://github.com/mozilla/pdf.js/</em:homepageURL>
|
||||
<em:type>2</em:type>
|
||||
<!-- Use the raw link for updates so we we can use SSL. -->
|
||||
|
@ -7,22 +7,20 @@
|
||||
|
||||
<Description about="urn:mozilla:install-manifest">
|
||||
<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:iconURL>chrome://pdf.js/skin/logo.png</em:iconURL>
|
||||
<em:targetApplication>
|
||||
<Description>
|
||||
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
|
||||
<em:minVersion>@FIREFOX_VERSION@</em:minVersion>
|
||||
<em:maxVersion>@FIREFOX_VERSION@</em:maxVersion>
|
||||
<em:strictCompatibility>true</em:strictCompatibility>
|
||||
</Description>
|
||||
</em:targetApplication>
|
||||
<em:strictCompatibility>true</em:strictCompatibility>
|
||||
<em:bootstrap>true</em:bootstrap>
|
||||
<em:unpack>true</em:unpack>
|
||||
<em:creator>Mozilla Labs</em:creator>
|
||||
<em:description>pdf.js uri loader</em:description>
|
||||
<em:homepageURL>https://github.com/mozilla/pdf.js/</em:homepageURL>
|
||||
<em:creator>Mozilla</em:creator>
|
||||
<em:description>Uses HTML5 to display PDF files directly in Firefox.</em:description>
|
||||
<em:homepageURL>http://support.mozilla.org/kb/using-mozilla-pdf-viewer</em:homepageURL>
|
||||
<em:type>2</em:type>
|
||||
</Description>
|
||||
</RDF>
|
||||
|
5
make.js
5
make.js
@ -220,6 +220,7 @@ target.firefox = function() {
|
||||
FIREFOX_EXTENSION_FILES_TO_COPY =
|
||||
['*.js',
|
||||
'*.rdf',
|
||||
'*.png',
|
||||
'install.rdf.in',
|
||||
'README.mozilla',
|
||||
'components',
|
||||
@ -227,11 +228,15 @@ target.firefox = function() {
|
||||
FIREFOX_EXTENSION_FILES =
|
||||
['bootstrap.js',
|
||||
'install.rdf',
|
||||
'icon.png',
|
||||
'icon64.png',
|
||||
'components',
|
||||
'content',
|
||||
'LICENSE'];
|
||||
FIREFOX_MC_EXTENSION_FILES =
|
||||
['bootstrap.js',
|
||||
'icon.png',
|
||||
'icon64.png',
|
||||
'components',
|
||||
'content',
|
||||
'LICENSE'];
|
||||
|
@ -124,7 +124,7 @@ var bidi = PDFJS.bidi = (function bidiClosure() {
|
||||
}
|
||||
}
|
||||
|
||||
return (function bidi(text, startLevel) {
|
||||
function bidi(text, startLevel) {
|
||||
var str = text.str;
|
||||
var strLength = str.length;
|
||||
if (strLength == 0)
|
||||
@ -429,5 +429,8 @@ var bidi = PDFJS.bidi = (function bidiClosure() {
|
||||
result += ch;
|
||||
}
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
return bidi;
|
||||
})();
|
||||
|
||||
|
@ -70,7 +70,7 @@ var CanvasExtraState = (function CanvasExtraStateClosure() {
|
||||
return CanvasExtraState;
|
||||
})();
|
||||
|
||||
function ScratchCanvas(width, height) {
|
||||
function createScratchCanvas(width, height) {
|
||||
var canvas = document.createElement('canvas');
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
@ -188,9 +188,9 @@ function addContextCurrentTransform(ctx) {
|
||||
}
|
||||
|
||||
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.
|
||||
var kExecutionTime = 50;
|
||||
var kExecutionTime = 15;
|
||||
|
||||
function CanvasGraphics(canvasCtx, objs, textLayer) {
|
||||
this.ctx = canvasCtx;
|
||||
@ -199,7 +199,6 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
||||
this.pendingClip = null;
|
||||
this.res = null;
|
||||
this.xobjs = null;
|
||||
this.ScratchCanvas = ScratchCanvas;
|
||||
this.objs = objs;
|
||||
this.textLayer = textLayer;
|
||||
if (canvasCtx) {
|
||||
@ -229,7 +228,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
||||
'setStrokeColor': true,
|
||||
'setStrokeColorN': true,
|
||||
'setFillColor': true,
|
||||
'setFillColorN_IR': true,
|
||||
'setFillColorN': true,
|
||||
'setStrokeGray': true,
|
||||
'setFillGray': true,
|
||||
'setStrokeRGBColor': true,
|
||||
@ -268,15 +267,16 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
||||
this.textLayer.beginLayout();
|
||||
},
|
||||
|
||||
executeIRQueue: function canvasGraphicsExecuteIRQueue(codeIR,
|
||||
executionStartIdx, continueCallback,
|
||||
stepper) {
|
||||
var argsArray = codeIR.argsArray;
|
||||
var fnArray = codeIR.fnArray;
|
||||
executeOperatorList: function canvasGraphicsExecuteOperatorList(
|
||||
operatorList,
|
||||
executionStartIdx, continueCallback,
|
||||
stepper) {
|
||||
var argsArray = operatorList.argsArray;
|
||||
var fnArray = operatorList.fnArray;
|
||||
var i = executionStartIdx || 0;
|
||||
var argsArrayLen = argsArray.length;
|
||||
|
||||
// Sometimes the IRQueue to execute is empty.
|
||||
// Sometimes the OperatorList to execute is empty.
|
||||
if (argsArrayLen == i) {
|
||||
return i;
|
||||
}
|
||||
@ -314,7 +314,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
||||
|
||||
i++;
|
||||
|
||||
// If the entire IRQueue was executed, stop as were done.
|
||||
// If the entire operatorList was executed, stop as were done.
|
||||
if (i == argsArrayLen) {
|
||||
return i;
|
||||
}
|
||||
@ -327,8 +327,8 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
||||
return i;
|
||||
}
|
||||
|
||||
// If the IRQueue isn't executed completly yet OR the execution time
|
||||
// was short enough, do another execution round.
|
||||
// If the operatorList isn't executed completely yet OR the execution
|
||||
// time was short enough, do another execution round.
|
||||
}
|
||||
},
|
||||
|
||||
@ -556,7 +556,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
||||
this.current.leading = -leading;
|
||||
},
|
||||
setFont: function canvasGraphicsSetFont(fontRefName, size) {
|
||||
var fontObj = this.objs.get(fontRefName).fontObj;
|
||||
var fontObj = this.objs.get(fontRefName);
|
||||
var current = this.current;
|
||||
|
||||
if (!fontObj)
|
||||
@ -707,7 +707,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
||||
this.save();
|
||||
ctx.scale(fontSize, fontSize);
|
||||
ctx.transform.apply(ctx, fontMatrix);
|
||||
this.executeIRQueue(glyph.codeIRQueue);
|
||||
this.executeOperatorList(glyph.operatorList);
|
||||
this.restore();
|
||||
|
||||
var transformed = Util.applyTransform([glyph.width, 0], fontMatrix);
|
||||
@ -908,7 +908,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
||||
this.ctx.strokeStyle = 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') {
|
||||
var args = IR[1];
|
||||
var base = cs.base;
|
||||
@ -930,11 +930,11 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
||||
}
|
||||
return pattern;
|
||||
},
|
||||
setStrokeColorN_IR: function canvasGraphicsSetStrokeColorN(/*...*/) {
|
||||
setStrokeColorN: function canvasGraphicsSetStrokeColorN(/*...*/) {
|
||||
var cs = this.current.strokeColorSpace;
|
||||
|
||||
if (cs.name == 'Pattern') {
|
||||
this.current.strokeColor = this.getColorN_IR_Pattern(arguments, cs);
|
||||
this.current.strokeColor = this.getColorN_Pattern(arguments, cs);
|
||||
} else {
|
||||
this.setStrokeColor.apply(this, arguments);
|
||||
}
|
||||
@ -946,11 +946,11 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
||||
this.ctx.fillStyle = color;
|
||||
this.current.fillColor = color;
|
||||
},
|
||||
setFillColorN_IR: function canvasGraphicsSetFillColorN(/*...*/) {
|
||||
setFillColorN: function canvasGraphicsSetFillColorN(/*...*/) {
|
||||
var cs = this.current.fillColorSpace;
|
||||
|
||||
if (cs.name == 'Pattern') {
|
||||
this.current.fillColor = this.getColorN_IR_Pattern(arguments, cs);
|
||||
this.current.fillColor = this.getColorN_Pattern(arguments, cs);
|
||||
} else {
|
||||
this.setFillColor.apply(this, arguments);
|
||||
}
|
||||
@ -1116,7 +1116,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
||||
// scale the image to the unit square
|
||||
ctx.scale(1 / w, -1 / h);
|
||||
|
||||
var tmpCanvas = new this.ScratchCanvas(w, h);
|
||||
var tmpCanvas = createScratchCanvas(w, h);
|
||||
var tmpCtx = tmpCanvas.getContext('2d');
|
||||
|
||||
var fillColor = this.current.fillColor;
|
||||
@ -1147,7 +1147,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
||||
// scale the image to the unit square
|
||||
ctx.scale(1 / w, -1 / h);
|
||||
|
||||
var tmpCanvas = new this.ScratchCanvas(w, h);
|
||||
var tmpCanvas = createScratchCanvas(w, h);
|
||||
var tmpCtx = tmpCanvas.getContext('2d');
|
||||
this.putBinaryImageData(tmpCtx, imgData, w, h);
|
||||
|
||||
|
@ -135,6 +135,7 @@ var ColorSpace = (function ColorSpaceClosure() {
|
||||
basePatternCS = ColorSpace.parseToIR(basePatternCS, xref, res);
|
||||
return ['PatternCS', basePatternCS];
|
||||
case 'Indexed':
|
||||
case 'I':
|
||||
var baseIndexedCS = ColorSpace.parseToIR(cs[1], xref, res);
|
||||
var hiVal = cs[2] + 1;
|
||||
var lookup = xref.fetchIfRef(cs[3]);
|
||||
|
84
src/core.js
84
src/core.js
@ -170,10 +170,10 @@ var Page = (function PageClosure() {
|
||||
return shadow(this, 'rotate', rotate);
|
||||
},
|
||||
|
||||
startRenderingFromIRQueue: function pageStartRenderingFromIRQueue(
|
||||
IRQueue, fonts) {
|
||||
startRenderingFromOperatorList: function pageStartRenderingFromOperatorList(
|
||||
operatorList, fonts) {
|
||||
var self = this;
|
||||
this.IRQueue = IRQueue;
|
||||
this.operatorList = operatorList;
|
||||
|
||||
var displayContinuation = function pageDisplayContinuation() {
|
||||
// Always defer call to display() to work around bug in
|
||||
@ -184,15 +184,16 @@ var Page = (function PageClosure() {
|
||||
};
|
||||
|
||||
this.ensureFonts(fonts,
|
||||
function pageStartRenderingFromIRQueueEnsureFonts() {
|
||||
displayContinuation();
|
||||
});
|
||||
function pageStartRenderingFromOperatorListEnsureFonts() {
|
||||
displayContinuation();
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
getIRQueue: function pageGetIRQueue(handler, dependency) {
|
||||
if (this.IRQueue) {
|
||||
getOperatorList: function pageGetOperatorList(handler, dependency) {
|
||||
if (this.operatorList) {
|
||||
// content was compiled
|
||||
return this.IRQueue;
|
||||
return this.operatorList;
|
||||
}
|
||||
|
||||
this.stats.time('Build IR Queue');
|
||||
@ -213,11 +214,10 @@ var Page = (function PageClosure() {
|
||||
|
||||
var pe = this.pe = new PartialEvaluator(
|
||||
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');
|
||||
return this.IRQueue;
|
||||
return this.operatorList;
|
||||
},
|
||||
|
||||
ensureFonts: function pageEnsureFonts(fonts, callback) {
|
||||
@ -228,14 +228,13 @@ var Page = (function PageClosure() {
|
||||
}
|
||||
|
||||
// Load all the fonts
|
||||
var fontObjs = FontLoader.bind(
|
||||
FontLoader.bind(
|
||||
fonts,
|
||||
function pageEnsureFontsFontObjs(fontObjs) {
|
||||
this.stats.timeEnd('Font Loading');
|
||||
|
||||
callback.call(this);
|
||||
}.bind(this),
|
||||
this.objs
|
||||
}.bind(this)
|
||||
);
|
||||
},
|
||||
|
||||
@ -255,18 +254,19 @@ var Page = (function PageClosure() {
|
||||
rotate: this.rotate });
|
||||
|
||||
var startIdx = 0;
|
||||
var length = this.IRQueue.fnArray.length;
|
||||
var IRQueue = this.IRQueue;
|
||||
var length = this.operatorList.fnArray.length;
|
||||
var operatorList = this.operatorList;
|
||||
var stepper = null;
|
||||
if (PDFJS.pdfBug && StepperManager.enabled) {
|
||||
stepper = StepperManager.create(this.pageNumber);
|
||||
stepper.init(IRQueue);
|
||||
stepper.init(operatorList);
|
||||
stepper.nextBreakPoint = stepper.getNextBreakPoint();
|
||||
}
|
||||
|
||||
var self = this;
|
||||
function next() {
|
||||
startIdx = gfx.executeIRQueue(IRQueue, startIdx, next, stepper);
|
||||
startIdx =
|
||||
gfx.executeOperatorList(operatorList, startIdx, next, stepper);
|
||||
if (startIdx == length) {
|
||||
gfx.endDrawing();
|
||||
stats.timeEnd('Rendering');
|
||||
@ -436,13 +436,14 @@ var Page = (function PageClosure() {
|
||||
startRendering: function pageStartRendering(ctx, callback, textLayer) {
|
||||
var stats = this.stats;
|
||||
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.
|
||||
if (!this.displayReadyPromise) {
|
||||
this.pdf.startRendering(this);
|
||||
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(
|
||||
function pageDisplayReadyPromise() {
|
||||
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
|
||||
* for each worker. If there is no worker support enabled, there are two
|
||||
* `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() {
|
||||
function PDFDocModel(arg, callback) {
|
||||
@ -645,9 +643,9 @@ var PDFDoc = (function PDFDocClosure() {
|
||||
|
||||
this.data = data;
|
||||
this.stream = stream;
|
||||
this.pdf = new PDFDocModel(stream);
|
||||
this.fingerprint = this.pdf.getFingerprint();
|
||||
this.catalog = this.pdf.catalog;
|
||||
this.pdfModel = new PDFDocModel(stream);
|
||||
this.fingerprint = this.pdfModel.getFingerprint();
|
||||
this.catalog = this.pdfModel.catalog;
|
||||
this.objs = new PDFObjects();
|
||||
|
||||
this.pageCache = [];
|
||||
@ -733,8 +731,9 @@ var PDFDoc = (function PDFDocClosure() {
|
||||
var pageNum = data.pageNum;
|
||||
var page = this.pageCache[pageNum];
|
||||
var depFonts = data.depFonts;
|
||||
|
||||
page.stats.timeEnd('Page Request');
|
||||
page.startRenderingFromIRQueue(data.IRQueue, depFonts);
|
||||
page.startRenderingFromOperatorList(data.operatorList, depFonts);
|
||||
}, this);
|
||||
|
||||
messageHandler.on('obj', function pdfDocObj(data) {
|
||||
@ -761,31 +760,16 @@ var PDFDoc = (function PDFDocClosure() {
|
||||
file = new Stream(file, 0, file.length, fontFileDict);
|
||||
}
|
||||
|
||||
// For now, resolve the font object here direclty. The real font
|
||||
// object is then created in FontLoader.bind().
|
||||
this.objs.resolve(id, {
|
||||
name: name,
|
||||
file: file,
|
||||
properties: properties
|
||||
});
|
||||
// At this point, only the font object is created but the font is
|
||||
// not yet attached to the DOM. This is done in `FontLoader.bind`.
|
||||
var font = new Font(name, file, properties);
|
||||
this.objs.resolve(id, font);
|
||||
break;
|
||||
default:
|
||||
error('Got unkown object type ' + type);
|
||||
}
|
||||
}, 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) {
|
||||
var page = this.pageCache[data.pageNum];
|
||||
if (page.displayReadyPromise)
|
||||
@ -807,7 +791,7 @@ var PDFDoc = (function PDFDocClosure() {
|
||||
var size = width * height;
|
||||
var rgbaLength = size * 4;
|
||||
var buf = new Uint8Array(size * components);
|
||||
var tmpCanvas = new ScratchCanvas(width, height);
|
||||
var tmpCanvas = createScratchCanvas(width, height);
|
||||
var tmpCtx = tmpCanvas.getContext('2d');
|
||||
tmpCtx.drawImage(img, 0, 0);
|
||||
var data = tmpCtx.getImageData(0, 0, width, height).data;
|
||||
@ -836,7 +820,7 @@ var PDFDoc = (function PDFDocClosure() {
|
||||
},
|
||||
|
||||
get numPages() {
|
||||
return this.pdf.numPages;
|
||||
return this.pdfModel.numPages;
|
||||
},
|
||||
|
||||
startRendering: function pdfDocStartRendering(page) {
|
||||
@ -851,7 +835,7 @@ var PDFDoc = (function PDFDocClosure() {
|
||||
if (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
|
||||
// to the CanvasGraphics and so on.
|
||||
page.objs = this.objs;
|
||||
|
@ -570,7 +570,6 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() {
|
||||
};
|
||||
}
|
||||
error('Unknown crypto method');
|
||||
return null;
|
||||
}
|
||||
|
||||
CipherTransformFactory.prototype = {
|
||||
|
@ -112,8 +112,8 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
||||
};
|
||||
|
||||
PartialEvaluator.prototype = {
|
||||
getIRQueue: function partialEvaluatorGetIRQueue(stream, resources,
|
||||
queue, dependency) {
|
||||
getOperatorList: function partialEvaluatorGetOperatorList(stream, resources,
|
||||
dependency, queue) {
|
||||
|
||||
var self = this;
|
||||
var xref = this.xref;
|
||||
@ -136,8 +136,6 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
||||
|
||||
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');
|
||||
|
||||
fontRes = xref.fetchIfRef(fontRes);
|
||||
@ -177,7 +175,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
||||
|
||||
// Ensure the font is ready before the font is set
|
||||
// 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.
|
||||
insertDependency([loadedName]);
|
||||
return loadedName;
|
||||
@ -239,6 +237,9 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
||||
}, handler, xref, resources, image, inline);
|
||||
}
|
||||
|
||||
if (!queue)
|
||||
queue = {};
|
||||
|
||||
if (!queue.argsArray) {
|
||||
queue.argsArray = [];
|
||||
}
|
||||
@ -280,9 +281,6 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
||||
// TODO figure out how to type-check vararg functions
|
||||
|
||||
if ((cmd == 'SCN' || cmd == 'scn') && !args[args.length - 1].code) {
|
||||
// Use the IR version for setStroke/FillColorN.
|
||||
fn += '_IR';
|
||||
|
||||
// compile tiling patterns
|
||||
var patternName = args[args.length - 1];
|
||||
// SCN/scn applies patterns along with normal colors
|
||||
@ -295,15 +293,14 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
||||
if (typeNum == TILING_PATTERN) {
|
||||
// Create an IR of the pattern code.
|
||||
var depIdx = dependencyArray.length;
|
||||
var queueObj = {};
|
||||
var codeIR = this.getIRQueue(pattern, dict.get('Resources') ||
|
||||
resources, queueObj, dependencyArray);
|
||||
var operatorList = this.getOperatorList(pattern,
|
||||
dict.get('Resources') || resources, dependencyArray);
|
||||
|
||||
// Add the dependencies that are required to execute the
|
||||
// codeIR.
|
||||
// operatorList.
|
||||
insertDependency(dependencyArray.slice(depIdx));
|
||||
|
||||
args = TilingPattern.getIR(codeIR, dict, args);
|
||||
args = TilingPattern.getIR(operatorList, dict, args);
|
||||
}
|
||||
else if (typeNum == SHADING_PATTERN) {
|
||||
var shading = xref.fetchIfRef(dict.get('Shading'));
|
||||
@ -337,14 +334,18 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
||||
fnArray.push('paintFormXObjectBegin');
|
||||
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;
|
||||
|
||||
this.getIRQueue(xobj, xobj.dict.get('Resources') || resources,
|
||||
queue, dependencyArray);
|
||||
// Pass in the current `queue` object. That means the `fnArray`
|
||||
// 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
|
||||
// codeIR.
|
||||
// operatorList.
|
||||
insertDependency(dependencyArray.slice(depIdx));
|
||||
|
||||
fn = 'paintFormXObjectEnd';
|
||||
@ -454,10 +455,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
fnArray: fnArray,
|
||||
argsArray: argsArray
|
||||
};
|
||||
return queue;
|
||||
},
|
||||
|
||||
extractDataStructures: function
|
||||
@ -855,12 +853,11 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
||||
var charProcs = xref.fetchIfRef(dict.get('CharProcs'));
|
||||
var fontResources = xref.fetchIfRef(dict.get('Resources')) || resources;
|
||||
properties.resources = fontResources;
|
||||
properties.charProcIRQueues = {};
|
||||
properties.charProcOperatorList = {};
|
||||
for (var key in charProcs.map) {
|
||||
var glyphStream = xref.fetchIfRef(charProcs.map[key]);
|
||||
var queueObj = {};
|
||||
properties.charProcIRQueues[key] =
|
||||
this.getIRQueue(glyphStream, fontResources, queueObj, dependency);
|
||||
properties.charProcOperatorList[key] =
|
||||
this.getOperatorList(glyphStream, fontResources, dependency);
|
||||
}
|
||||
}
|
||||
|
||||
|
1546
src/fonts.js
1546
src/fonts.js
File diff suppressed because it is too large
Load Diff
@ -514,7 +514,6 @@ var XRef = (function XRefClosure() {
|
||||
return dict;
|
||||
// nothing helps
|
||||
error('Invalid PDF structure');
|
||||
return null;
|
||||
},
|
||||
readXRef: function readXref(startXRef) {
|
||||
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
|
||||
// data isn't ready yet!
|
||||
if (!obj || !obj.isResolved) {
|
||||
if (!obj || !obj.isResolved)
|
||||
error('Requesting object that isn\'t resolved yet ' + objId);
|
||||
return null;
|
||||
} else {
|
||||
return obj.data;
|
||||
}
|
||||
|
||||
return obj.data;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -53,15 +53,14 @@ var Parser = (function ParserClosure() {
|
||||
this.shift();
|
||||
var dict = new Dict();
|
||||
while (!isCmd(this.buf1, '>>') && !isEOF(this.buf1)) {
|
||||
if (!isName(this.buf1)) {
|
||||
if (!isName(this.buf1))
|
||||
error('Dictionary key must be a name object');
|
||||
} else {
|
||||
var key = this.buf1.name;
|
||||
this.shift();
|
||||
if (isEOF(this.buf1))
|
||||
break;
|
||||
dict.set(key, this.getObj(cipherTransform));
|
||||
}
|
||||
|
||||
var key = this.buf1.name;
|
||||
this.shift();
|
||||
if (isEOF(this.buf1))
|
||||
break;
|
||||
dict.set(key, this.getObj(cipherTransform));
|
||||
}
|
||||
if (isEOF(this.buf1))
|
||||
error('End of file inside dictionary');
|
||||
@ -106,15 +105,14 @@ var Parser = (function ParserClosure() {
|
||||
// parse dictionary
|
||||
var dict = new Dict();
|
||||
while (!isCmd(this.buf1, 'ID') && !isEOF(this.buf1)) {
|
||||
if (!isName(this.buf1)) {
|
||||
if (!isName(this.buf1))
|
||||
error('Dictionary key must be a name object');
|
||||
} else {
|
||||
var key = this.buf1.name;
|
||||
this.shift();
|
||||
if (isEOF(this.buf1))
|
||||
break;
|
||||
dict.set(key, this.getObj(cipherTransform));
|
||||
}
|
||||
|
||||
var key = this.buf1.name;
|
||||
this.shift();
|
||||
if (isEOF(this.buf1))
|
||||
break;
|
||||
dict.set(key, this.getObj(cipherTransform));
|
||||
}
|
||||
|
||||
// parse image stream
|
||||
@ -176,10 +174,8 @@ var Parser = (function ParserClosure() {
|
||||
|
||||
// get length
|
||||
var length = this.fetchIfRef(dict.get('Length'));
|
||||
if (!isInt(length)) {
|
||||
if (!isInt(length))
|
||||
error('Bad ' + length + ' attribute in stream');
|
||||
length = 0;
|
||||
}
|
||||
|
||||
// skip over the stream data
|
||||
stream.pos = pos + length;
|
||||
@ -208,14 +204,13 @@ var Parser = (function ParserClosure() {
|
||||
filter = filterArray[i];
|
||||
if (!isName(filter))
|
||||
error('Bad filter name: ' + filter);
|
||||
else {
|
||||
params = null;
|
||||
if (isArray(paramsArray) && (i in paramsArray))
|
||||
params = paramsArray[i];
|
||||
stream = this.makeFilter(stream, filter.name, length, params);
|
||||
// after the first stream the length variable is invalid
|
||||
length = null;
|
||||
}
|
||||
|
||||
params = null;
|
||||
if (isArray(paramsArray) && (i in paramsArray))
|
||||
params = paramsArray[i];
|
||||
stream = this.makeFilter(stream, filter.name, length, params);
|
||||
// after the first stream the length variable is invalid
|
||||
length = null;
|
||||
}
|
||||
}
|
||||
return stream;
|
||||
@ -527,17 +522,15 @@ var Lexer = (function LexerClosure() {
|
||||
// fall through
|
||||
case ')':
|
||||
error('Illegal character: ' + ch);
|
||||
return Error;
|
||||
}
|
||||
|
||||
// command
|
||||
var str = ch;
|
||||
while (!!(ch = stream.lookChar()) && !specialChars[ch.charCodeAt(0)]) {
|
||||
stream.skip();
|
||||
if (str.length == 128) {
|
||||
if (str.length == 128)
|
||||
error('Command token too long: ' + str.length);
|
||||
break;
|
||||
}
|
||||
|
||||
str += ch;
|
||||
}
|
||||
if (str == 'true')
|
||||
@ -594,7 +587,6 @@ var Linearization = (function LinearizationClosure() {
|
||||
return obj;
|
||||
}
|
||||
error('"' + name + '" field in linearization table is invalid');
|
||||
return 0;
|
||||
},
|
||||
getHint: function linearizationGetHint(index) {
|
||||
var linDict = this.linDict;
|
||||
@ -607,7 +599,6 @@ var Linearization = (function LinearizationClosure() {
|
||||
return obj2;
|
||||
}
|
||||
error('Hints table in linearization table is invalid: ' + index);
|
||||
return 0;
|
||||
},
|
||||
get length() {
|
||||
if (!isDict(this.linDict))
|
||||
|
@ -82,7 +82,7 @@ Shadings.RadialAxial = (function RadialAxialClosure() {
|
||||
fnObj = xref.fetchIfRef(fnObj);
|
||||
if (isArray(fnObj))
|
||||
error('No support for array of functions');
|
||||
else if (!isPDFFunction(fnObj))
|
||||
if (!isPDFFunction(fnObj))
|
||||
error('Invalid function');
|
||||
var fn = PDFFunction.parse(xref, fnObj);
|
||||
|
||||
@ -190,7 +190,7 @@ var TilingPattern = (function TilingPatternClosure() {
|
||||
var MAX_PATTERN_SIZE = 512;
|
||||
|
||||
function TilingPattern(IR, color, ctx, objs) {
|
||||
var IRQueue = IR[2];
|
||||
var operatorList = IR[2];
|
||||
this.matrix = IR[3];
|
||||
var bbox = IR[4];
|
||||
var xstep = IR[5];
|
||||
@ -222,7 +222,7 @@ var TilingPattern = (function TilingPatternClosure() {
|
||||
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
|
||||
var tmpCtx = tmpCanvas.getContext('2d');
|
||||
@ -259,12 +259,12 @@ var TilingPattern = (function TilingPatternClosure() {
|
||||
graphics.endPath();
|
||||
}
|
||||
|
||||
graphics.executeIRQueue(IRQueue);
|
||||
graphics.executeOperatorList(operatorList);
|
||||
|
||||
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 bbox = dict.get('BBox');
|
||||
var xstep = dict.get('XStep');
|
||||
@ -272,7 +272,7 @@ var TilingPattern = (function TilingPatternClosure() {
|
||||
var paintType = dict.get('PaintType');
|
||||
|
||||
return [
|
||||
'TilingPattern', args, codeIR, matrix, bbox, xstep, ystep, paintType
|
||||
'TilingPattern', args, operatorList, matrix, bbox, xstep, ystep, paintType
|
||||
];
|
||||
};
|
||||
|
||||
|
@ -79,7 +79,7 @@ MessageHandler.prototype = {
|
||||
|
||||
var WorkerMessageHandler = {
|
||||
setup: function wphSetup(handler) {
|
||||
var pdfDoc = null;
|
||||
var pdfModel = null;
|
||||
|
||||
handler.on('test', function wphSetupTest(data) {
|
||||
handler.send('test', data instanceof Uint8Array);
|
||||
@ -88,7 +88,7 @@ var WorkerMessageHandler = {
|
||||
handler.on('doc', function wphSetupDoc(data) {
|
||||
// Create only the model of the PDFDoc, which is enough for
|
||||
// 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) {
|
||||
@ -103,14 +103,14 @@ var WorkerMessageHandler = {
|
||||
var start = Date.now();
|
||||
|
||||
var dependency = [];
|
||||
var IRQueue = null;
|
||||
var operatorList = null;
|
||||
try {
|
||||
var page = pdfDoc.getPage(pageNum);
|
||||
var page = pdfModel.getPage(pageNum);
|
||||
// Pre compile the pdf page and fetch the fonts/images.
|
||||
IRQueue = page.getIRQueue(handler, dependency);
|
||||
operatorList = page.getOperatorList(handler, dependency);
|
||||
} catch (e) {
|
||||
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
|
||||
if (typeof e === 'string') {
|
||||
@ -137,8 +137,8 @@ var WorkerMessageHandler = {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('page=%d - getIRQueue: time=%dms, len=%d', pageNum,
|
||||
Date.now() - start, IRQueue.fnArray.length);
|
||||
console.log('page=%d - getOperatorList: time=%dms, len=%d', pageNum,
|
||||
Date.now() - start, operatorList.fnArray.length);
|
||||
|
||||
// Filter the dependecies for fonts.
|
||||
var fonts = {};
|
||||
@ -151,59 +151,10 @@ var WorkerMessageHandler = {
|
||||
|
||||
handler.send('page', {
|
||||
pageNum: pageNum,
|
||||
IRQueue: IRQueue,
|
||||
operatorList: operatorList,
|
||||
depFonts: Object.keys(fonts)
|
||||
});
|
||||
}, 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]);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
2
test/pdfs/.gitignore
vendored
2
test/pdfs/.gitignore
vendored
@ -20,10 +20,12 @@
|
||||
!scan-bad.pdf
|
||||
!freeculture.pdf
|
||||
!pdfkit_compressed.pdf
|
||||
!TAMReview.pdf
|
||||
!issue918.pdf
|
||||
!issue1249.pdf
|
||||
!smaskdim.pdf
|
||||
!type4psfunc.pdf
|
||||
!S2.pdf
|
||||
!zerowidthline.pdf
|
||||
!issue1002.pdf
|
||||
!issue925.pdf
|
||||
|
BIN
test/pdfs/TAMReview.pdf
Normal file
BIN
test/pdfs/TAMReview.pdf
Normal file
Binary file not shown.
BIN
test/pdfs/issue1002.pdf
Normal file
BIN
test/pdfs/issue1002.pdf
Normal file
Binary file not shown.
@ -472,6 +472,14 @@
|
||||
"rounds": 1,
|
||||
"type": "eq"
|
||||
},
|
||||
{ "id": "tamreview",
|
||||
"file": "pdfs/TAMReview.pdf",
|
||||
"md5": "8039aba56790d3597d2bc8c794a51301",
|
||||
"rounds": 1,
|
||||
"pageLimit": 5,
|
||||
"link": true,
|
||||
"type": "eq"
|
||||
},
|
||||
{ "id": "issue925",
|
||||
"file": "pdfs/issue925.pdf",
|
||||
"md5": "f58fe943090aff89dcc8e771bc0db4c2",
|
||||
@ -500,6 +508,13 @@
|
||||
"link": true,
|
||||
"type": "eq"
|
||||
},
|
||||
{ "id": "issue1002",
|
||||
"file": "pdfs/issue1002.pdf",
|
||||
"md5": "af62d6cd95079322d4af18edd960d15c",
|
||||
"rounds": 1,
|
||||
"link": false,
|
||||
"type": "eq"
|
||||
},
|
||||
{ "id": "issue1243",
|
||||
"file": "pdfs/issue1243.pdf",
|
||||
"md5": "130c849b83513d5ac5e03c6421fc7489",
|
||||
|
223
test/unit/font_spec.js
Normal file
223
test/unit/font_spec.js
Normal 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
|
||||
});
|
||||
});
|
@ -25,6 +25,7 @@ load:
|
||||
- ../../src/bidi.js
|
||||
- ../../external/jpgjs/jpg.js
|
||||
- ../unit/obj_spec.js
|
||||
- ../unit/font_spec.js
|
||||
- ../unit/function_spec.js
|
||||
- ../unit/crypto_spec.js
|
||||
- ../unit/stream_spec.js
|
||||
|
Loading…
Reference in New Issue
Block a user