Merge upstream and change to error parameter for callback.
This commit is contained in:
commit
e0c231eec7
@ -6,13 +6,13 @@
|
|||||||
<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.js</em:name>
|
||||||
<em:version>0.1</em:version>
|
<em:version>0.1.0</em:version>
|
||||||
<em:iconURL>chrome://pdf.js/skin/logo.png</em:iconURL>
|
<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>6.0</em:minVersion>
|
<em:minVersion>6.0</em:minVersion>
|
||||||
<em:maxVersion>11.0.*</em:maxVersion>
|
<em:maxVersion>11.0a1</em:maxVersion>
|
||||||
</Description>
|
</Description>
|
||||||
</em:targetApplication>
|
</em:targetApplication>
|
||||||
<em:bootstrap>true</em:bootstrap>
|
<em:bootstrap>true</em:bootstrap>
|
||||||
@ -20,5 +20,6 @@
|
|||||||
<em:creator>Vivien Nicolas</em:creator>
|
<em:creator>Vivien Nicolas</em:creator>
|
||||||
<em:description>pdf.js uri loader</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>
|
||||||
</Description>
|
</Description>
|
||||||
</RDF>
|
</RDF>
|
||||||
|
197
src/canvas.js
197
src/canvas.js
@ -174,7 +174,7 @@ var CanvasGraphics = (function canvasGraphics() {
|
|||||||
// before it stops and shedules a continue of execution.
|
// before it stops and shedules a continue of execution.
|
||||||
var kExecutionTime = 50;
|
var kExecutionTime = 50;
|
||||||
|
|
||||||
function constructor(canvasCtx, objs) {
|
function constructor(canvasCtx, objs, textLayer) {
|
||||||
this.ctx = canvasCtx;
|
this.ctx = canvasCtx;
|
||||||
this.current = new CanvasExtraState();
|
this.current = new CanvasExtraState();
|
||||||
this.stateStack = [];
|
this.stateStack = [];
|
||||||
@ -183,7 +183,7 @@ var CanvasGraphics = (function canvasGraphics() {
|
|||||||
this.xobjs = null;
|
this.xobjs = null;
|
||||||
this.ScratchCanvas = ScratchCanvas;
|
this.ScratchCanvas = ScratchCanvas;
|
||||||
this.objs = objs;
|
this.objs = objs;
|
||||||
|
this.textLayer = textLayer;
|
||||||
if (canvasCtx) {
|
if (canvasCtx) {
|
||||||
addContextCurrentTransform(canvasCtx);
|
addContextCurrentTransform(canvasCtx);
|
||||||
}
|
}
|
||||||
@ -212,7 +212,13 @@ var CanvasGraphics = (function canvasGraphics() {
|
|||||||
this.ctx.transform(0, -1, -1, 0, cw, ch);
|
this.ctx.transform(0, -1, -1, 0, cw, ch);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
// Scale so that canvas units are the same as PDF user space units
|
||||||
this.ctx.scale(cw / mediaBox.width, ch / mediaBox.height);
|
this.ctx.scale(cw / mediaBox.width, ch / mediaBox.height);
|
||||||
|
this.textDivs = [];
|
||||||
|
this.textLayerQueue = [];
|
||||||
|
// Prevent textLayerQueue from being rendered while rendering a new page
|
||||||
|
if (this.textLayerTimer)
|
||||||
|
clearTimeout(this.textLayerTimer);
|
||||||
},
|
},
|
||||||
|
|
||||||
executeIRQueue: function canvasGraphicsExecuteIRQueue(codeIR,
|
executeIRQueue: function canvasGraphicsExecuteIRQueue(codeIR,
|
||||||
@ -270,6 +276,37 @@ var CanvasGraphics = (function canvasGraphics() {
|
|||||||
|
|
||||||
endDrawing: function canvasGraphicsEndDrawing() {
|
endDrawing: function canvasGraphicsEndDrawing() {
|
||||||
this.ctx.restore();
|
this.ctx.restore();
|
||||||
|
|
||||||
|
var textLayer = this.textLayer;
|
||||||
|
if (!textLayer)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
var renderTextLayer = function canvasRenderTextLayer() {
|
||||||
|
var textDivs = self.textDivs;
|
||||||
|
for (var i = 0, length = textDivs.length; i < length; ++i) {
|
||||||
|
if (textDivs[i].dataset.textLength > 1) { // avoid div by zero
|
||||||
|
textLayer.appendChild(textDivs[i]);
|
||||||
|
// Adjust div width (via letterSpacing) to match canvas text
|
||||||
|
// Due to the .offsetWidth calls, this is slow
|
||||||
|
textDivs[i].style.letterSpacing =
|
||||||
|
((textDivs[i].dataset.canvasWidth - textDivs[i].offsetWidth) /
|
||||||
|
(textDivs[i].dataset.textLength - 1)) + 'px';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var textLayerQueue = this.textLayerQueue;
|
||||||
|
textLayerQueue.push(renderTextLayer);
|
||||||
|
|
||||||
|
// Lazy textLayer rendering (to prevent UI hangs)
|
||||||
|
// Only render queue if activity has stopped, where "no activity" ==
|
||||||
|
// "no beginDrawing() calls in the last N ms"
|
||||||
|
this.textLayerTimer = setTimeout(function renderTextLayerQueue() {
|
||||||
|
// Render most recent (==most relevant) layers first
|
||||||
|
for (var i = textLayerQueue.length - 1; i >= 0; i--) {
|
||||||
|
textLayerQueue.pop().call();
|
||||||
|
}
|
||||||
|
}, 500);
|
||||||
},
|
},
|
||||||
|
|
||||||
// Graphics state
|
// Graphics state
|
||||||
@ -528,23 +565,93 @@ var CanvasGraphics = (function canvasGraphics() {
|
|||||||
nextLine: function canvasGraphicsNextLine() {
|
nextLine: function canvasGraphicsNextLine() {
|
||||||
this.moveText(0, this.current.leading);
|
this.moveText(0, this.current.leading);
|
||||||
},
|
},
|
||||||
showText: function canvasGraphicsShowText(text) {
|
applyTextTransforms: function canvasApplyTransforms() {
|
||||||
|
var ctx = this.ctx;
|
||||||
|
var current = this.current;
|
||||||
|
var textHScale = current.textHScale;
|
||||||
|
var fontMatrix = current.font.fontMatrix || IDENTITY_MATRIX;
|
||||||
|
|
||||||
|
ctx.transform.apply(ctx, current.textMatrix);
|
||||||
|
ctx.scale(1, -1);
|
||||||
|
ctx.translate(current.x, -1 * current.y);
|
||||||
|
ctx.transform.apply(ctx, fontMatrix);
|
||||||
|
ctx.scale(textHScale, 1);
|
||||||
|
},
|
||||||
|
getTextGeometry: function canvasGetTextGeometry() {
|
||||||
|
var geometry = {};
|
||||||
|
var ctx = this.ctx;
|
||||||
|
var font = this.current.font;
|
||||||
|
var ctxMatrix = ctx.mozCurrentTransform;
|
||||||
|
if (ctxMatrix) {
|
||||||
|
var bl = Util.applyTransform([0, 0], ctxMatrix);
|
||||||
|
var tr = Util.applyTransform([1, 1], ctxMatrix);
|
||||||
|
geometry.x = bl[0];
|
||||||
|
geometry.y = bl[1];
|
||||||
|
geometry.hScale = tr[0] - bl[0];
|
||||||
|
geometry.vScale = tr[1] - bl[1];
|
||||||
|
}
|
||||||
|
var spaceGlyph = font.charsToGlyphs(' ');
|
||||||
|
|
||||||
|
// Hack (sometimes space is not encoded)
|
||||||
|
if (spaceGlyph.length === 0 || spaceGlyph[0].width === 0)
|
||||||
|
spaceGlyph = font.charsToGlyphs('i');
|
||||||
|
|
||||||
|
// Fallback
|
||||||
|
if (spaceGlyph.length === 0 || spaceGlyph[0].width === 0)
|
||||||
|
spaceGlyph = [{width: 0}];
|
||||||
|
|
||||||
|
geometry.spaceWidth = spaceGlyph[0].width;
|
||||||
|
return geometry;
|
||||||
|
},
|
||||||
|
|
||||||
|
pushTextDivs: function canvasGraphicsPushTextDivs(text) {
|
||||||
|
var div = document.createElement('div');
|
||||||
|
var fontSize = this.current.fontSize;
|
||||||
|
|
||||||
|
// vScale and hScale already contain the scaling to pixel units
|
||||||
|
// as mozCurrentTransform reflects ctx.scale() changes
|
||||||
|
// (see beginDrawing())
|
||||||
|
var fontHeight = fontSize * text.geom.vScale;
|
||||||
|
div.dataset.canvasWidth = text.canvasWidth * text.geom.hScale;
|
||||||
|
|
||||||
|
div.style.fontSize = fontHeight + 'px';
|
||||||
|
div.style.fontFamily = this.current.font.loadedName || 'sans-serif';
|
||||||
|
div.style.left = text.geom.x + 'px';
|
||||||
|
div.style.top = (text.geom.y - fontHeight) + 'px';
|
||||||
|
div.innerHTML = text.str;
|
||||||
|
div.dataset.textLength = text.length;
|
||||||
|
this.textDivs.push(div);
|
||||||
|
},
|
||||||
|
showText: function canvasGraphicsShowText(str, skipTextSelection) {
|
||||||
var ctx = this.ctx;
|
var ctx = this.ctx;
|
||||||
var current = this.current;
|
var current = this.current;
|
||||||
var font = current.font;
|
var font = current.font;
|
||||||
var glyphs = font.charsToGlyphs(text);
|
var glyphs = font.charsToGlyphs(str);
|
||||||
var fontSize = current.fontSize;
|
var fontSize = current.fontSize;
|
||||||
var charSpacing = current.charSpacing;
|
var charSpacing = current.charSpacing;
|
||||||
var wordSpacing = current.wordSpacing;
|
var wordSpacing = current.wordSpacing;
|
||||||
var textHScale = current.textHScale;
|
var textHScale = current.textHScale;
|
||||||
|
var fontMatrix = font.fontMatrix || IDENTITY_MATRIX;
|
||||||
|
var textHScale2 = textHScale * fontMatrix[0];
|
||||||
var glyphsLength = glyphs.length;
|
var glyphsLength = glyphs.length;
|
||||||
|
var textLayer = this.textLayer;
|
||||||
|
var text = {str: '', length: 0, canvasWidth: 0, geom: {}};
|
||||||
|
var textSelection = textLayer && !skipTextSelection ? true : false;
|
||||||
|
|
||||||
|
if (textSelection) {
|
||||||
|
ctx.save();
|
||||||
|
this.applyTextTransforms();
|
||||||
|
text.geom = this.getTextGeometry();
|
||||||
|
ctx.restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type3 fonts - each glyph is a "mini-PDF"
|
||||||
if (font.coded) {
|
if (font.coded) {
|
||||||
ctx.save();
|
ctx.save();
|
||||||
ctx.transform.apply(ctx, current.textMatrix);
|
ctx.transform.apply(ctx, current.textMatrix);
|
||||||
ctx.translate(current.x, current.y);
|
ctx.translate(current.x, current.y);
|
||||||
|
|
||||||
var fontMatrix = font.fontMatrix || IDENTITY_MATRIX;
|
ctx.scale(textHScale, 1);
|
||||||
ctx.scale(1 / textHScale, 1);
|
|
||||||
for (var i = 0; i < glyphsLength; ++i) {
|
for (var i = 0; i < glyphsLength; ++i) {
|
||||||
|
|
||||||
var glyph = glyphs[i];
|
var glyph = glyphs[i];
|
||||||
@ -564,18 +671,16 @@ var CanvasGraphics = (function canvasGraphics() {
|
|||||||
var width = transformed[0] * fontSize + charSpacing;
|
var width = transformed[0] * fontSize + charSpacing;
|
||||||
|
|
||||||
ctx.translate(width, 0);
|
ctx.translate(width, 0);
|
||||||
current.x += width;
|
current.x += width * textHScale2;
|
||||||
|
|
||||||
|
text.str += glyph.unicode;
|
||||||
|
text.length++;
|
||||||
|
text.canvasWidth += width;
|
||||||
}
|
}
|
||||||
ctx.restore();
|
ctx.restore();
|
||||||
} else {
|
} else {
|
||||||
ctx.save();
|
ctx.save();
|
||||||
ctx.transform.apply(ctx, current.textMatrix);
|
this.applyTextTransforms();
|
||||||
ctx.scale(1, -1);
|
|
||||||
ctx.translate(current.x, -1 * current.y);
|
|
||||||
ctx.transform.apply(ctx, font.fontMatrix || IDENTITY_MATRIX);
|
|
||||||
|
|
||||||
ctx.scale(1 / textHScale, 1);
|
|
||||||
|
|
||||||
var width = 0;
|
var width = 0;
|
||||||
for (var i = 0; i < glyphsLength; ++i) {
|
for (var i = 0; i < glyphsLength; ++i) {
|
||||||
@ -586,36 +691,78 @@ var CanvasGraphics = (function canvasGraphics() {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var unicode = glyph.unicode;
|
var char = glyph.fontChar;
|
||||||
var char = (unicode >= 0x10000) ?
|
var charWidth = glyph.width * fontSize * 0.001 + charSpacing;
|
||||||
String.fromCharCode(0xD800 | ((unicode - 0x10000) >> 10),
|
|
||||||
0xDC00 | (unicode & 0x3FF)) : String.fromCharCode(unicode);
|
|
||||||
|
|
||||||
ctx.fillText(char, width, 0);
|
ctx.fillText(char, width, 0);
|
||||||
width += glyph.width * fontSize * 0.001 + charSpacing;
|
width += charWidth;
|
||||||
}
|
|
||||||
current.x += width;
|
|
||||||
|
|
||||||
|
text.str += glyph.unicode === ' ' ? ' ' : glyph.unicode;
|
||||||
|
text.length++;
|
||||||
|
text.canvasWidth += charWidth;
|
||||||
|
}
|
||||||
|
current.x += width * textHScale2;
|
||||||
ctx.restore();
|
ctx.restore();
|
||||||
}
|
}
|
||||||
},
|
|
||||||
|
|
||||||
|
if (textSelection)
|
||||||
|
this.pushTextDivs(text);
|
||||||
|
|
||||||
|
return text;
|
||||||
|
},
|
||||||
showSpacedText: function canvasGraphicsShowSpacedText(arr) {
|
showSpacedText: function canvasGraphicsShowSpacedText(arr) {
|
||||||
var ctx = this.ctx;
|
var ctx = this.ctx;
|
||||||
var current = this.current;
|
var current = this.current;
|
||||||
var fontSize = current.fontSize;
|
var fontSize = current.fontSize;
|
||||||
var textHScale = current.textHScale;
|
var textHScale2 = current.textHScale *
|
||||||
|
(current.font.fontMatrix || IDENTITY_MATRIX)[0];
|
||||||
var arrLength = arr.length;
|
var arrLength = arr.length;
|
||||||
|
var textLayer = this.textLayer;
|
||||||
|
var font = current.font;
|
||||||
|
var text = {str: '', length: 0, canvasWidth: 0, geom: {}};
|
||||||
|
var textSelection = textLayer ? true : false;
|
||||||
|
|
||||||
|
if (textSelection) {
|
||||||
|
ctx.save();
|
||||||
|
this.applyTextTransforms();
|
||||||
|
text.geom = this.getTextGeometry();
|
||||||
|
ctx.restore();
|
||||||
|
}
|
||||||
|
|
||||||
for (var i = 0; i < arrLength; ++i) {
|
for (var i = 0; i < arrLength; ++i) {
|
||||||
var e = arr[i];
|
var e = arr[i];
|
||||||
if (isNum(e)) {
|
if (isNum(e)) {
|
||||||
current.x -= e * 0.001 * fontSize * textHScale;
|
var spacingLength = -e * 0.001 * fontSize * textHScale2;
|
||||||
|
current.x += spacingLength;
|
||||||
|
|
||||||
|
if (textSelection) {
|
||||||
|
// Emulate precise spacing via HTML spaces
|
||||||
|
text.canvasWidth += spacingLength;
|
||||||
|
if (e < 0 && text.geom.spaceWidth > 0) { // avoid div by zero
|
||||||
|
var numFakeSpaces = Math.round(-e / text.geom.spaceWidth);
|
||||||
|
for (var j = 0; j < numFakeSpaces; ++j)
|
||||||
|
text.str += ' ';
|
||||||
|
text.length += numFakeSpaces > 0 ? 1 : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if (isString(e)) {
|
} else if (isString(e)) {
|
||||||
this.showText(e);
|
var shownText = this.showText(e, true);
|
||||||
|
|
||||||
|
if (textSelection) {
|
||||||
|
if (shownText.str === ' ') {
|
||||||
|
text.str += ' ';
|
||||||
|
} else {
|
||||||
|
text.str += shownText.str;
|
||||||
|
}
|
||||||
|
text.canvasWidth += shownText.canvasWidth;
|
||||||
|
text.length += e.length;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
malformed('TJ array element ' + e + ' is not string or num');
|
malformed('TJ array element ' + e + ' is not string or num');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (textSelection)
|
||||||
|
this.pushTextDivs(text);
|
||||||
},
|
},
|
||||||
nextLineShowText: function canvasGraphicsNextLineShowText(text) {
|
nextLineShowText: function canvasGraphicsNextLineShowText(text) {
|
||||||
this.nextLine();
|
this.nextLine();
|
||||||
|
31
src/core.js
31
src/core.js
@ -70,7 +70,6 @@ var Page = (function pagePage() {
|
|||||||
|
|
||||||
this.ctx = null;
|
this.ctx = null;
|
||||||
this.callback = null;
|
this.callback = null;
|
||||||
this.errorback = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor.prototype = {
|
constructor.prototype = {
|
||||||
@ -164,7 +163,7 @@ var Page = (function pagePage() {
|
|||||||
IRQueue, fonts) {
|
IRQueue, fonts) {
|
||||||
var self = this;
|
var self = this;
|
||||||
this.IRQueue = IRQueue;
|
this.IRQueue = IRQueue;
|
||||||
var gfx = new CanvasGraphics(this.ctx, this.objs);
|
var gfx = new CanvasGraphics(this.ctx, this.objs, this.textLayer);
|
||||||
|
|
||||||
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
|
||||||
@ -173,8 +172,8 @@ var Page = (function pagePage() {
|
|||||||
try {
|
try {
|
||||||
self.display(gfx, self.callback);
|
self.display(gfx, self.callback);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (self.errorback)
|
if (self.callback)
|
||||||
self.errorback(e);
|
self.callback(e);
|
||||||
else
|
else
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
@ -251,6 +250,7 @@ var Page = (function pagePage() {
|
|||||||
startIdx = gfx.executeIRQueue(IRQueue, startIdx, next);
|
startIdx = gfx.executeIRQueue(IRQueue, startIdx, next);
|
||||||
if (startIdx == length) {
|
if (startIdx == length) {
|
||||||
self.stats.render = Date.now();
|
self.stats.render = Date.now();
|
||||||
|
gfx.endDrawing();
|
||||||
if (callback) callback();
|
if (callback) callback();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -313,10 +313,10 @@ var Page = (function pagePage() {
|
|||||||
}
|
}
|
||||||
return links;
|
return links;
|
||||||
},
|
},
|
||||||
startRendering: function pageStartRendering(ctx, callback, errorback) {
|
startRendering: function pageStartRendering(ctx, callback, textLayer) {
|
||||||
this.ctx = ctx;
|
this.ctx = ctx;
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
this.errorback = errorback;
|
this.textLayer = textLayer;
|
||||||
|
|
||||||
this.startRenderingTime = Date.now();
|
this.startRenderingTime = Date.now();
|
||||||
this.pdf.startRendering(this);
|
this.pdf.startRendering(this);
|
||||||
@ -569,20 +569,9 @@ var PDFDoc = (function pdfDoc() {
|
|||||||
var properties = data[4];
|
var properties = data[4];
|
||||||
|
|
||||||
if (file) {
|
if (file) {
|
||||||
|
// Rewrap the ArrayBuffer in a stream.
|
||||||
var fontFileDict = new Dict();
|
var fontFileDict = new Dict();
|
||||||
fontFileDict.map = file.dict.map;
|
file = new Stream(file, 0, file.length, fontFileDict);
|
||||||
|
|
||||||
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) {
|
|
||||||
file = new FlateStream(fontFile);
|
|
||||||
} else {
|
|
||||||
file = fontFile;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// For now, resolve the font object here direclty. The real font
|
// For now, resolve the font object here direclty. The real font
|
||||||
@ -612,8 +601,8 @@ var PDFDoc = (function pdfDoc() {
|
|||||||
|
|
||||||
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.errorback)
|
if (page.callback)
|
||||||
page.errorback(data.error);
|
page.callback(data.error);
|
||||||
else
|
else
|
||||||
throw data.error;
|
throw data.error;
|
||||||
}, this);
|
}, this);
|
||||||
|
@ -155,6 +155,11 @@ var PartialEvaluator = (function partialEvaluator() {
|
|||||||
font.loadedName = loadedName;
|
font.loadedName = loadedName;
|
||||||
|
|
||||||
var translated = font.translated;
|
var translated = font.translated;
|
||||||
|
// Convert the file to an ArrayBuffer which will be turned back into
|
||||||
|
// a Stream in the main thread.
|
||||||
|
if (translated.file)
|
||||||
|
translated.file = translated.file.getBytes();
|
||||||
|
|
||||||
handler.send('obj', [
|
handler.send('obj', [
|
||||||
loadedName,
|
loadedName,
|
||||||
'Font',
|
'Font',
|
||||||
@ -493,6 +498,8 @@ var PartialEvaluator = (function partialEvaluator() {
|
|||||||
var baseName = encoding.get('BaseEncoding');
|
var baseName = encoding.get('BaseEncoding');
|
||||||
if (baseName)
|
if (baseName)
|
||||||
baseEncoding = Encodings[baseName.name];
|
baseEncoding = Encodings[baseName.name];
|
||||||
|
else
|
||||||
|
hasEncoding = false; // base encoding was not provided
|
||||||
|
|
||||||
// Load the differences between the base and original
|
// Load the differences between the base and original
|
||||||
if (encoding.has('Differences')) {
|
if (encoding.has('Differences')) {
|
||||||
@ -512,6 +519,7 @@ var PartialEvaluator = (function partialEvaluator() {
|
|||||||
error('Encoding is not a Name nor a Dict');
|
error('Encoding is not a Name nor a Dict');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
properties.differences = differences;
|
properties.differences = differences;
|
||||||
properties.baseEncoding = baseEncoding;
|
properties.baseEncoding = baseEncoding;
|
||||||
properties.hasEncoding = hasEncoding;
|
properties.hasEncoding = hasEncoding;
|
||||||
@ -554,9 +562,21 @@ var PartialEvaluator = (function partialEvaluator() {
|
|||||||
var startRange = tokens[j];
|
var startRange = tokens[j];
|
||||||
var endRange = tokens[j + 1];
|
var endRange = tokens[j + 1];
|
||||||
var code = tokens[j + 2];
|
var code = tokens[j + 2];
|
||||||
while (startRange <= endRange) {
|
if (code == 0xFFFF) {
|
||||||
charToUnicode[startRange] = code++;
|
// CMap is broken, assuming code == startRange
|
||||||
++startRange;
|
code = startRange;
|
||||||
|
}
|
||||||
|
if (isArray(code)) {
|
||||||
|
var codeindex = 0;
|
||||||
|
while (startRange <= endRange) {
|
||||||
|
charToUnicode[startRange] = code[codeindex++];
|
||||||
|
++startRange;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
while (startRange <= endRange) {
|
||||||
|
charToUnicode[startRange] = code++;
|
||||||
|
++startRange;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -595,9 +615,18 @@ var PartialEvaluator = (function partialEvaluator() {
|
|||||||
}
|
}
|
||||||
} else if (byte == 0x3E) {
|
} else if (byte == 0x3E) {
|
||||||
if (token.length) {
|
if (token.length) {
|
||||||
// parsing hex number
|
if (token.length <= 4) {
|
||||||
tokens.push(parseInt(token, 16));
|
// parsing hex number
|
||||||
token = '';
|
tokens.push(parseInt(token, 16));
|
||||||
|
token = '';
|
||||||
|
} else {
|
||||||
|
// parsing hex UTF-16BE numbers
|
||||||
|
var str = [];
|
||||||
|
for (var i = 0, ii = token.length; i < ii; i += 4)
|
||||||
|
str.push(parseInt(token.substr(i, 4), 16));
|
||||||
|
tokens.push(String.fromCharCode.apply(String, str));
|
||||||
|
token = '';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
token += String.fromCharCode(byte);
|
token += String.fromCharCode(byte);
|
||||||
|
327
src/fonts.js
327
src/fonts.js
@ -719,20 +719,10 @@ function getUnicodeRangeFor(value) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
function adaptUnicode(unicode) {
|
|
||||||
return (unicode <= 0x1F || (unicode >= 127 && unicode < kSizeOfGlyphArea)) ?
|
|
||||||
unicode + kCmapGlyphOffset : unicode;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isAdaptedUnicode(unicode) {
|
|
||||||
return unicode >= kCmapGlyphOffset &&
|
|
||||||
unicode < kCmapGlyphOffset + kSizeOfGlyphArea;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isSpecialUnicode(unicode) {
|
function isSpecialUnicode(unicode) {
|
||||||
return (unicode <= 0x1F || (unicode >= 127 && unicode < kSizeOfGlyphArea)) ||
|
return (unicode <= 0x1F || (unicode >= 127 && unicode < kSizeOfGlyphArea)) ||
|
||||||
unicode >= kCmapGlyphOffset &&
|
(unicode >= kCmapGlyphOffset &&
|
||||||
unicode < kCmapGlyphOffset + kSizeOfGlyphArea;
|
unicode < kCmapGlyphOffset + kSizeOfGlyphArea);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -771,16 +761,21 @@ var Font = (function Font() {
|
|||||||
this.widths = properties.widths;
|
this.widths = properties.widths;
|
||||||
this.defaultWidth = properties.defaultWidth;
|
this.defaultWidth = properties.defaultWidth;
|
||||||
this.composite = properties.composite;
|
this.composite = properties.composite;
|
||||||
this.toUnicode = properties.toUnicode;
|
|
||||||
this.hasEncoding = properties.hasEncoding;
|
this.hasEncoding = properties.hasEncoding;
|
||||||
|
|
||||||
this.fontMatrix = properties.fontMatrix;
|
this.fontMatrix = properties.fontMatrix;
|
||||||
|
this.widthMultiplier = 1.0;
|
||||||
if (properties.type == 'Type3')
|
if (properties.type == 'Type3')
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Trying to fix encoding using glyph CIDSystemInfo.
|
// Trying to fix encoding using glyph CIDSystemInfo.
|
||||||
this.loadCidToUnicode(properties);
|
this.loadCidToUnicode(properties);
|
||||||
|
|
||||||
|
if (properties.toUnicode)
|
||||||
|
this.toUnicode = properties.toUnicode;
|
||||||
|
else
|
||||||
|
this.rebuildToUnicode(properties);
|
||||||
|
|
||||||
if (!file) {
|
if (!file) {
|
||||||
// The file data is not specified. Trying to fix the font name
|
// The file data is not specified. Trying to fix the font name
|
||||||
// to be used with the canvas.font.
|
// to be used with the canvas.font.
|
||||||
@ -832,6 +827,8 @@ var Font = (function Font() {
|
|||||||
|
|
||||||
this.data = data;
|
this.data = data;
|
||||||
this.fontMatrix = properties.fontMatrix;
|
this.fontMatrix = properties.fontMatrix;
|
||||||
|
this.widthMultiplier = !properties.fontMatrix ? 1.0 :
|
||||||
|
1.0 / properties.fontMatrix[0];
|
||||||
this.encoding = properties.baseEncoding;
|
this.encoding = properties.baseEncoding;
|
||||||
this.hasShortCmap = properties.hasShortCmap;
|
this.hasShortCmap = properties.hasShortCmap;
|
||||||
this.loadedName = getUniqueName();
|
this.loadedName = getUniqueName();
|
||||||
@ -961,15 +958,15 @@ var Font = (function Font() {
|
|||||||
var ranges = [];
|
var ranges = [];
|
||||||
for (var n = 0; n < length; ) {
|
for (var n = 0; n < length; ) {
|
||||||
var start = codes[n].unicode;
|
var start = codes[n].unicode;
|
||||||
var startCode = codes[n].code;
|
var codeIndices = [codes[n].code];
|
||||||
++n;
|
++n;
|
||||||
var end = start;
|
var end = start;
|
||||||
while (n < length && end + 1 == codes[n].unicode) {
|
while (n < length && end + 1 == codes[n].unicode) {
|
||||||
|
codeIndices.push(codes[n].code);
|
||||||
++end;
|
++end;
|
||||||
++n;
|
++n;
|
||||||
}
|
}
|
||||||
var endCode = codes[n - 1].code;
|
ranges.push([start, end, codeIndices]);
|
||||||
ranges.push([start, end, startCode, endCode]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ranges;
|
return ranges;
|
||||||
@ -1012,17 +1009,16 @@ var Font = (function Font() {
|
|||||||
idDeltas += string16(0);
|
idDeltas += string16(0);
|
||||||
idRangeOffsets += string16(offset);
|
idRangeOffsets += string16(offset);
|
||||||
|
|
||||||
var startCode = range[2];
|
var codes = range[2];
|
||||||
var endCode = range[3];
|
for (var j = 0, jj = codes.length; j < jj; ++j)
|
||||||
for (var j = startCode; j <= endCode; ++j)
|
glyphsIds += string16(deltas[codes[j]]);
|
||||||
glyphsIds += string16(deltas[j]);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (var i = 0; i < segCount - 1; i++) {
|
for (var i = 0; i < segCount - 1; i++) {
|
||||||
var range = ranges[i];
|
var range = ranges[i];
|
||||||
var start = range[0];
|
var start = range[0];
|
||||||
var end = range[1];
|
var end = range[1];
|
||||||
var startCode = range[2];
|
var startCode = range[2][0];
|
||||||
|
|
||||||
startCount += string16(start);
|
startCount += string16(start);
|
||||||
endCount += string16(end);
|
endCount += string16(end);
|
||||||
@ -1299,7 +1295,7 @@ var Font = (function Font() {
|
|||||||
properties.baseEncoding = encoding;
|
properties.baseEncoding = encoding;
|
||||||
}
|
}
|
||||||
|
|
||||||
function replaceCMapTable(cmap, font, properties) {
|
function readCMapTable(cmap, font) {
|
||||||
var start = (font.start ? font.start : 0) + cmap.offset;
|
var start = (font.start ? font.start : 0) + cmap.offset;
|
||||||
font.pos = start;
|
font.pos = start;
|
||||||
|
|
||||||
@ -1316,7 +1312,7 @@ var Font = (function Font() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check that table are sorted by platformID then encodingID,
|
// Check that table are sorted by platformID then encodingID,
|
||||||
records.sort(function fontReplaceCMapTableSort(a, b) {
|
records.sort(function fontReadCMapTableSort(a, b) {
|
||||||
return ((a.platformID << 16) + a.encodingID) -
|
return ((a.platformID << 16) + a.encodingID) -
|
||||||
((b.platformID << 16) + b.encodingID);
|
((b.platformID << 16) + b.encodingID);
|
||||||
});
|
});
|
||||||
@ -1371,16 +1367,15 @@ var Font = (function Font() {
|
|||||||
for (var j = 0; j < 256; j++) {
|
for (var j = 0; j < 256; j++) {
|
||||||
var index = font.getByte();
|
var index = font.getByte();
|
||||||
if (index) {
|
if (index) {
|
||||||
var unicode = adaptUnicode(j);
|
glyphs.push({ unicode: j, code: j });
|
||||||
glyphs.push({ unicode: unicode, code: j });
|
|
||||||
ids.push(index);
|
ids.push(index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return {
|
||||||
properties.hasShortCmap = true;
|
glyphs: glyphs,
|
||||||
|
ids: ids,
|
||||||
createGlyphNameMap(glyphs, ids, properties);
|
hasShortCmap: true
|
||||||
return cmap.data = createCMapTable(glyphs, ids);
|
};
|
||||||
} else if (format == 4) {
|
} else if (format == 4) {
|
||||||
// re-creating the table in format 4 since the encoding
|
// re-creating the table in format 4 since the encoding
|
||||||
// might be changed
|
// might be changed
|
||||||
@ -1432,17 +1427,18 @@ var Font = (function Font() {
|
|||||||
var glyphCode = offsetIndex < 0 ? j :
|
var glyphCode = offsetIndex < 0 ? j :
|
||||||
offsets[offsetIndex + j - start];
|
offsets[offsetIndex + j - start];
|
||||||
glyphCode = (glyphCode + delta) & 0xFFFF;
|
glyphCode = (glyphCode + delta) & 0xFFFF;
|
||||||
if (glyphCode == 0 || isAdaptedUnicode(j))
|
if (glyphCode == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var unicode = adaptUnicode(j);
|
glyphs.push({ unicode: j, code: j });
|
||||||
glyphs.push({ unicode: unicode, code: j });
|
|
||||||
ids.push(glyphCode);
|
ids.push(glyphCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
createGlyphNameMap(glyphs, ids, properties);
|
return {
|
||||||
return cmap.data = createCMapTable(glyphs, ids);
|
glyphs: glyphs,
|
||||||
|
ids: ids
|
||||||
|
};
|
||||||
} else if (format == 6) {
|
} else if (format == 6) {
|
||||||
// Format 6 is a 2-bytes dense mapping, which means the font data
|
// Format 6 is a 2-bytes dense mapping, which means the font data
|
||||||
// lives glue together even if they are pretty far in the unicode
|
// lives glue together even if they are pretty far in the unicode
|
||||||
@ -1457,19 +1453,18 @@ var Font = (function Font() {
|
|||||||
for (var j = 0; j < entryCount; j++) {
|
for (var j = 0; j < entryCount; j++) {
|
||||||
var glyphCode = int16(font.getBytes(2));
|
var glyphCode = int16(font.getBytes(2));
|
||||||
var code = firstCode + j;
|
var code = firstCode + j;
|
||||||
if (isAdaptedUnicode(glyphCode))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var unicode = adaptUnicode(code);
|
glyphs.push({ unicode: code, code: code });
|
||||||
glyphs.push({ unicode: unicode, code: code });
|
|
||||||
ids.push(glyphCode);
|
ids.push(glyphCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
createGlyphNameMap(glyphs, ids, properties);
|
return {
|
||||||
return cmap.data = createCMapTable(glyphs, ids);
|
glyphs: glyphs,
|
||||||
|
ids: ids
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return cmap.data;
|
error('Unsupported cmap table format');
|
||||||
};
|
};
|
||||||
|
|
||||||
function sanitizeMetrics(font, header, metrics, numGlyphs) {
|
function sanitizeMetrics(font, header, metrics, numGlyphs) {
|
||||||
@ -1708,17 +1703,85 @@ var Font = (function Font() {
|
|||||||
tables.push(cmap);
|
tables.push(cmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
var glyphs = [];
|
var cidToGidMap = properties.cidToGidMap || [];
|
||||||
for (i = 1; i < numGlyphs; i++) {
|
var gidToCidMap = [0];
|
||||||
if (isAdaptedUnicode(i))
|
if (cidToGidMap.length > 0) {
|
||||||
continue;
|
for (var j = cidToGidMap.length - 1; j >= 0; j--) {
|
||||||
|
var gid = cidToGidMap[j];
|
||||||
glyphs.push({ unicode: adaptUnicode(i) });
|
if (gid)
|
||||||
|
gidToCidMap[gid] = j;
|
||||||
|
}
|
||||||
|
// filling the gaps using CID above the CIDs currently used in font
|
||||||
|
var nextCid = cidToGidMap.length;
|
||||||
|
for (var i = 1; i < numGlyphs; i++) {
|
||||||
|
if (!gidToCidMap[i])
|
||||||
|
gidToCidMap[i] = nextCid++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
cmap.data = createCMapTable(glyphs);
|
|
||||||
|
var glyphs = [], ids = [];
|
||||||
|
var usedUnicodes = [];
|
||||||
|
var unassignedUnicodeItems = [];
|
||||||
|
for (var i = 1; i < numGlyphs; i++) {
|
||||||
|
var cid = gidToCidMap[i] || i;
|
||||||
|
var unicode = this.toUnicode[cid];
|
||||||
|
if (!unicode || isSpecialUnicode(unicode) ||
|
||||||
|
unicode in usedUnicodes) {
|
||||||
|
unassignedUnicodeItems.push(i);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
usedUnicodes[unicode] = true;
|
||||||
|
glyphs.push({ unicode: unicode, code: cid });
|
||||||
|
ids.push(i);
|
||||||
|
}
|
||||||
|
// trying to fit as many unassigned symbols as we can
|
||||||
|
// in the range allocated for the user defined symbols
|
||||||
|
var unusedUnicode = kCmapGlyphOffset;
|
||||||
|
for (var j = 0, jj = unassignedUnicodeItems.length; j < jj; j++) {
|
||||||
|
var i = unassignedUnicodeItems[j];
|
||||||
|
var cid = gidToCidMap[i] || i;
|
||||||
|
while (unusedUnicode in usedUnicodes)
|
||||||
|
unusedUnicode++;
|
||||||
|
if (unusedUnicode >= kCmapGlyphOffset + kSizeOfGlyphArea)
|
||||||
|
break;
|
||||||
|
var unicode = unusedUnicode++;
|
||||||
|
this.toUnicode[cid] = unicode;
|
||||||
|
usedUnicodes[unicode] = true;
|
||||||
|
glyphs.push({ unicode: unicode, code: cid });
|
||||||
|
ids.push(i);
|
||||||
|
}
|
||||||
|
cmap.data = createCMapTable(glyphs, ids);
|
||||||
} else {
|
} else {
|
||||||
replaceCMapTable(cmap, font, properties);
|
var cmapTable = readCMapTable(cmap, font);
|
||||||
|
var glyphs = cmapTable.glyphs;
|
||||||
|
var ids = cmapTable.ids;
|
||||||
|
var hasShortCmap = !!cmapTable.hasShortCmap;
|
||||||
|
var toUnicode = this.toUnicode;
|
||||||
|
|
||||||
|
if (hasShortCmap && toUnicode) {
|
||||||
|
// checking if cmap is just identity map
|
||||||
|
var isIdentity = true;
|
||||||
|
for (var i = 0, ii = glyphs.length; i < ii; i++) {
|
||||||
|
if (glyphs[i].unicode != i + 1) {
|
||||||
|
isIdentity = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// if it is, replacing with meaningful toUnicode values
|
||||||
|
if (isIdentity) {
|
||||||
|
for (var i = 0, ii = glyphs.length; i < ii; i++) {
|
||||||
|
var unicode = toUnicode[i + 1] || i + 1;
|
||||||
|
glyphs[i].unicode = unicode;
|
||||||
|
}
|
||||||
|
this.useToUnicode = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
properties.hasShortCmap = hasShortCmap;
|
||||||
|
|
||||||
|
createGlyphNameMap(glyphs, ids, properties);
|
||||||
this.glyphNameMap = properties.glyphNameMap;
|
this.glyphNameMap = properties.glyphNameMap;
|
||||||
|
|
||||||
|
cmap.data = createCMapTable(glyphs, ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rewrite the 'post' table if needed
|
// Rewrite the 'post' table if needed
|
||||||
@ -1808,6 +1871,14 @@ var Font = (function Font() {
|
|||||||
}
|
}
|
||||||
properties.baseEncoding = encoding;
|
properties.baseEncoding = encoding;
|
||||||
}
|
}
|
||||||
|
if (properties.subtype == 'CIDFontType0C') {
|
||||||
|
var toUnicode = [];
|
||||||
|
for (var i = 0; i < charstrings.length; ++i) {
|
||||||
|
var charstring = charstrings[i];
|
||||||
|
toUnicode[charstring.code] = charstring.unicode;
|
||||||
|
}
|
||||||
|
this.toUnicode = toUnicode;
|
||||||
|
}
|
||||||
|
|
||||||
var fields = {
|
var fields = {
|
||||||
// PostScript Font Program
|
// PostScript Font Program
|
||||||
@ -1868,8 +1939,11 @@ var Font = (function Font() {
|
|||||||
// Horizontal metrics
|
// Horizontal metrics
|
||||||
'hmtx': (function fontFieldsHmtx() {
|
'hmtx': (function fontFieldsHmtx() {
|
||||||
var hmtx = '\x00\x00\x00\x00'; // Fake .notdef
|
var hmtx = '\x00\x00\x00\x00'; // Fake .notdef
|
||||||
for (var i = 0, ii = charstrings.length; i < ii; i++)
|
for (var i = 0, ii = charstrings.length; i < ii; i++) {
|
||||||
hmtx += string16(charstrings[i].width) + string16(0);
|
var charstring = charstrings[i];
|
||||||
|
var width = 'width' in charstring ? charstring.width : 0;
|
||||||
|
hmtx += string16(width) + string16(0);
|
||||||
|
}
|
||||||
return stringToArray(hmtx);
|
return stringToArray(hmtx);
|
||||||
})(),
|
})(),
|
||||||
|
|
||||||
@ -1898,17 +1972,35 @@ var Font = (function Font() {
|
|||||||
return stringToArray(otf.file);
|
return stringToArray(otf.file);
|
||||||
},
|
},
|
||||||
|
|
||||||
loadCidToUnicode: function font_loadCidToUnicode(properties) {
|
rebuildToUnicode: function font_rebuildToUnicode(properties) {
|
||||||
if (properties.cidToGidMap) {
|
var firstChar = properties.firstChar, lastChar = properties.lastChar;
|
||||||
this.cidToUnicode = properties.cidToGidMap;
|
var map = [];
|
||||||
return;
|
if (properties.composite) {
|
||||||
|
var isIdentityMap = this.cidToUnicode.length == 0;
|
||||||
|
for (var i = firstChar, ii = lastChar; i <= ii; i++) {
|
||||||
|
// TODO missing map the character according font's CMap
|
||||||
|
var cid = i;
|
||||||
|
map[i] = isIdentityMap ? cid : this.cidToUnicode[cid];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (var i = firstChar, ii = lastChar; i <= ii; i++) {
|
||||||
|
var glyph = properties.differences[i];
|
||||||
|
if (!glyph)
|
||||||
|
glyph = properties.baseEncoding[i];
|
||||||
|
if (!!glyph && (glyph in GlyphsUnicode))
|
||||||
|
map[i] = GlyphsUnicode[glyph];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
this.toUnicode = map;
|
||||||
|
},
|
||||||
|
|
||||||
|
loadCidToUnicode: function font_loadCidToUnicode(properties) {
|
||||||
if (!properties.cidSystemInfo)
|
if (!properties.cidSystemInfo)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var cidToUnicodeMap = [];
|
var cidToUnicodeMap = [], unicodeToCIDMap = [];
|
||||||
this.cidToUnicode = cidToUnicodeMap;
|
this.cidToUnicode = cidToUnicodeMap;
|
||||||
|
this.unicodeToCID = unicodeToCIDMap;
|
||||||
|
|
||||||
var cidSystemInfo = properties.cidSystemInfo;
|
var cidSystemInfo = properties.cidSystemInfo;
|
||||||
var cidToUnicode;
|
var cidToUnicode;
|
||||||
@ -1920,28 +2012,34 @@ var Font = (function Font() {
|
|||||||
if (!cidToUnicode)
|
if (!cidToUnicode)
|
||||||
return; // identity encoding
|
return; // identity encoding
|
||||||
|
|
||||||
var glyph = 1, i, j, k, ii;
|
var cid = 1, i, j, k, ii;
|
||||||
for (i = 0, ii = cidToUnicode.length; i < ii; ++i) {
|
for (i = 0, ii = cidToUnicode.length; i < ii; ++i) {
|
||||||
var unicode = cidToUnicode[i];
|
var unicode = cidToUnicode[i];
|
||||||
if (isArray(unicode)) {
|
if (isArray(unicode)) {
|
||||||
var length = unicode.length;
|
var length = unicode.length;
|
||||||
for (j = 0; j < length; j++)
|
for (j = 0; j < length; j++) {
|
||||||
cidToUnicodeMap[unicode[j]] = glyph;
|
cidToUnicodeMap[cid] = unicode[j];
|
||||||
glyph++;
|
unicodeToCIDMap[unicode[j]] = cid;
|
||||||
|
}
|
||||||
|
cid++;
|
||||||
} else if (typeof unicode === 'object') {
|
} else if (typeof unicode === 'object') {
|
||||||
var fillLength = unicode.f;
|
var fillLength = unicode.f;
|
||||||
if (fillLength) {
|
if (fillLength) {
|
||||||
k = unicode.c;
|
k = unicode.c;
|
||||||
for (j = 0; j < fillLength; ++j) {
|
for (j = 0; j < fillLength; ++j) {
|
||||||
cidToUnicodeMap[k] = glyph++;
|
cidToUnicodeMap[cid] = k;
|
||||||
|
unicodeToCIDMap[k] = cid;
|
||||||
|
cid++;
|
||||||
k++;
|
k++;
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
glyph += unicode.s;
|
cid += unicode.s;
|
||||||
} else if (unicode) {
|
} else if (unicode) {
|
||||||
cidToUnicodeMap[unicode] = glyph++;
|
cidToUnicodeMap[cid] = unicode;
|
||||||
|
unicodeToCIDMap[unicode] = cid;
|
||||||
|
cid++;
|
||||||
} else
|
} else
|
||||||
glyph++;
|
cid++;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -1981,19 +2079,19 @@ var Font = (function Font() {
|
|||||||
switch (this.type) {
|
switch (this.type) {
|
||||||
case 'CIDFontType0':
|
case 'CIDFontType0':
|
||||||
if (this.noUnicodeAdaptation) {
|
if (this.noUnicodeAdaptation) {
|
||||||
width = this.widths[this.cidToUnicode[charcode]];
|
width = this.widths[this.unicodeToCID[charcode] || charcode];
|
||||||
unicode = charcode;
|
unicode = charcode;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
unicode = adaptUnicode(this.cidToUnicode[charcode] || charcode);
|
unicode = this.toUnicode[charcode] || charcode;
|
||||||
break;
|
break;
|
||||||
case 'CIDFontType2':
|
case 'CIDFontType2':
|
||||||
if (this.noUnicodeAdaptation) {
|
if (this.noUnicodeAdaptation) {
|
||||||
width = this.widths[this.cidToUnicode[charcode]];
|
width = this.widths[this.unicodeToCID[charcode] || charcode];
|
||||||
unicode = charcode;
|
unicode = charcode;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
unicode = adaptUnicode(this.cidToUnicode[charcode] || charcode);
|
unicode = this.toUnicode[charcode] || charcode;
|
||||||
break;
|
break;
|
||||||
case 'Type1':
|
case 'Type1':
|
||||||
var glyphName = this.differences[charcode] || this.encoding[charcode];
|
var glyphName = this.differences[charcode] || this.encoding[charcode];
|
||||||
@ -2004,7 +2102,7 @@ var Font = (function Font() {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
unicode = this.glyphNameMap[glyphName] ||
|
unicode = this.glyphNameMap[glyphName] ||
|
||||||
adaptUnicode(GlyphsUnicode[glyphName] || charcode);
|
GlyphsUnicode[glyphName] || charcode;
|
||||||
break;
|
break;
|
||||||
case 'Type3':
|
case 'Type3':
|
||||||
var glyphName = this.differences[charcode] || this.encoding[charcode];
|
var glyphName = this.differences[charcode] || this.encoding[charcode];
|
||||||
@ -2022,16 +2120,16 @@ var Font = (function Font() {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!this.hasEncoding) {
|
if (!this.hasEncoding) {
|
||||||
unicode = adaptUnicode(charcode);
|
unicode = this.useToUnicode ? this.toUnicode[charcode] : charcode;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (this.hasShortCmap) {
|
if (this.hasShortCmap && false) {
|
||||||
var j = Encodings.MacRomanEncoding.indexOf(glyphName);
|
var j = Encodings.MacRomanEncoding.indexOf(glyphName);
|
||||||
unicode = j >= 0 && !isSpecialUnicode(j) ? j :
|
unicode = j >= 0 ? j :
|
||||||
this.glyphNameMap[glyphName];
|
this.glyphNameMap[glyphName];
|
||||||
} else {
|
} else {
|
||||||
unicode = glyphName in GlyphsUnicode ?
|
unicode = glyphName in GlyphsUnicode ?
|
||||||
adaptUnicode(GlyphsUnicode[glyphName]) :
|
GlyphsUnicode[glyphName] :
|
||||||
this.glyphNameMap[glyphName];
|
this.glyphNameMap[glyphName];
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -2039,9 +2137,17 @@ var Font = (function Font() {
|
|||||||
warn('Unsupported font type: ' + this.type);
|
warn('Unsupported font type: ' + this.type);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var unicodeChars = this.toUnicode ? this.toUnicode[charcode] : charcode;
|
||||||
|
if (typeof unicodeChars === 'number')
|
||||||
|
unicodeChars = String.fromCharCode(unicodeChars);
|
||||||
|
|
||||||
|
width = (isNum(width) ? width : this.defaultWidth) * this.widthMultiplier;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
unicode: unicode,
|
fontChar: String.fromCharCode(unicode),
|
||||||
width: isNum(width) ? width : this.defaultWidth,
|
unicode: unicodeChars,
|
||||||
|
width: width,
|
||||||
codeIRQueue: codeIRQueue
|
codeIRQueue: codeIRQueue
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@ -2753,22 +2859,13 @@ CFF.prototype = {
|
|||||||
getOrderedCharStrings: function cff_getOrderedCharStrings(glyphs,
|
getOrderedCharStrings: function cff_getOrderedCharStrings(glyphs,
|
||||||
properties) {
|
properties) {
|
||||||
var charstrings = [];
|
var charstrings = [];
|
||||||
var reverseMapping = {};
|
|
||||||
var encoding = properties.baseEncoding;
|
|
||||||
var i, length, glyphName;
|
var i, length, glyphName;
|
||||||
for (i = 0, length = encoding.length; i < length; ++i) {
|
|
||||||
glyphName = encoding[i];
|
|
||||||
if (!glyphName || isSpecialUnicode(i))
|
|
||||||
continue;
|
|
||||||
reverseMapping[glyphName] = i;
|
|
||||||
}
|
|
||||||
reverseMapping['.notdef'] = 0;
|
|
||||||
var unusedUnicode = kCmapGlyphOffset;
|
var unusedUnicode = kCmapGlyphOffset;
|
||||||
for (i = 0, length = glyphs.length; i < length; i++) {
|
for (i = 0, length = glyphs.length; i < length; i++) {
|
||||||
var item = glyphs[i];
|
var item = glyphs[i];
|
||||||
var glyphName = item.glyph;
|
var glyphName = item.glyph;
|
||||||
var unicode = glyphName in reverseMapping ?
|
var unicode = glyphName in GlyphsUnicode ?
|
||||||
reverseMapping[glyphName] : unusedUnicode++;
|
GlyphsUnicode[glyphName] : unusedUnicode++;
|
||||||
charstrings.push({
|
charstrings.push({
|
||||||
glyph: glyphName,
|
glyph: glyphName,
|
||||||
unicode: unicode,
|
unicode: unicode,
|
||||||
@ -3055,16 +3152,14 @@ var Type2CFF = (function type2CFF() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var charStrings = this.parseIndex(topDict.CharStrings);
|
var charStrings = this.parseIndex(topDict.CharStrings);
|
||||||
var charset = this.parseCharsets(topDict.charset,
|
|
||||||
charStrings.length, strings);
|
|
||||||
var encoding = this.parseEncoding(topDict.Encoding, properties,
|
|
||||||
strings, charset);
|
|
||||||
|
|
||||||
var charset, encoding;
|
var charset, encoding;
|
||||||
var isCIDFont = properties.subtype == 'CIDFontType0C';
|
var isCIDFont = properties.subtype == 'CIDFontType0C';
|
||||||
if (isCIDFont) {
|
if (isCIDFont) {
|
||||||
charset = [];
|
charset = ['.notdef'];
|
||||||
charset.length = charStrings.length;
|
for (var i = 1, ii = charStrings.length; i < ii; ++i)
|
||||||
|
charset.push('glyph' + i);
|
||||||
|
|
||||||
encoding = this.parseCidMap(topDict.charset,
|
encoding = this.parseCidMap(topDict.charset,
|
||||||
charStrings.length);
|
charStrings.length);
|
||||||
} else {
|
} else {
|
||||||
@ -3133,38 +3228,44 @@ var Type2CFF = (function type2CFF() {
|
|||||||
var charstrings = [];
|
var charstrings = [];
|
||||||
var unicodeUsed = [];
|
var unicodeUsed = [];
|
||||||
var unassignedUnicodeItems = [];
|
var unassignedUnicodeItems = [];
|
||||||
|
var inverseEncoding = [];
|
||||||
|
for (var charcode in encoding)
|
||||||
|
inverseEncoding[encoding[charcode]] = charcode | 0;
|
||||||
for (var i = 0, ii = charsets.length; i < ii; i++) {
|
for (var i = 0, ii = charsets.length; i < ii; i++) {
|
||||||
var glyph = charsets[i];
|
var glyph = charsets[i];
|
||||||
var encodingFound = false;
|
if (glyph == '.notdef') {
|
||||||
for (var charcode in encoding) {
|
charstrings.push({
|
||||||
if (encoding[charcode] == i) {
|
unicode: 0,
|
||||||
var code = charcode | 0;
|
code: 0,
|
||||||
charstrings.push({
|
gid: i,
|
||||||
unicode: adaptUnicode(code),
|
glyph: glyph
|
||||||
code: code,
|
});
|
||||||
gid: i,
|
continue;
|
||||||
glyph: glyph
|
|
||||||
});
|
|
||||||
unicodeUsed[code] = true;
|
|
||||||
encodingFound = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (!encodingFound) {
|
var code = inverseEncoding[i];
|
||||||
|
if (!code || isSpecialUnicode(code)) {
|
||||||
unassignedUnicodeItems.push(i);
|
unassignedUnicodeItems.push(i);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
charstrings.push({
|
||||||
|
unicode: code,
|
||||||
|
code: code,
|
||||||
|
gid: i,
|
||||||
|
glyph: glyph
|
||||||
|
});
|
||||||
|
unicodeUsed[code] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
var nextUnusedUnicode = 0x21;
|
var nextUnusedUnicode = kCmapGlyphOffset;
|
||||||
for (var j = 0, jj = unassignedUnicodeItems.length; j < jj; ++j) {
|
for (var j = 0, jj = unassignedUnicodeItems.length; j < jj; ++j) {
|
||||||
var i = unassignedUnicodeItems[j];
|
var i = unassignedUnicodeItems[j];
|
||||||
// giving unicode value anyway
|
// giving unicode value anyway
|
||||||
while (unicodeUsed[nextUnusedUnicode])
|
while (nextUnusedUnicode in unicodeUsed)
|
||||||
nextUnusedUnicode++;
|
nextUnusedUnicode++;
|
||||||
var code = nextUnusedUnicode++;
|
var unicode = nextUnusedUnicode++;
|
||||||
charstrings.push({
|
charstrings.push({
|
||||||
unicode: adaptUnicode(code),
|
unicode: unicode,
|
||||||
code: code,
|
code: inverseEncoding[i] || 0,
|
||||||
gid: i,
|
gid: i,
|
||||||
glyph: charsets[i]
|
glyph: charsets[i]
|
||||||
});
|
});
|
||||||
|
@ -4287,6 +4287,7 @@ var GlyphsUnicode = {
|
|||||||
zretroflexhook: 0x0290,
|
zretroflexhook: 0x0290,
|
||||||
zstroke: 0x01B6,
|
zstroke: 0x01B6,
|
||||||
zuhiragana: 0x305A,
|
zuhiragana: 0x305A,
|
||||||
zukatakana: 0x30BA
|
zukatakana: 0x30BA,
|
||||||
|
'.notdef': 0x0000
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -3,6 +3,9 @@
|
|||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
// The Metrics object contains glyph widths (in glyph space units).
|
||||||
|
// As per PDF spec, for most fonts (Type 3 being an exception) a glyph
|
||||||
|
// space unit corresponds to 1/1000th of text space unit.
|
||||||
var Metrics = {
|
var Metrics = {
|
||||||
'Courier': 600,
|
'Courier': 600,
|
||||||
'Courier-Bold': 600,
|
'Courier-Bold': 600,
|
||||||
|
@ -162,11 +162,11 @@ function nextPage(task, loadError) {
|
|||||||
|
|
||||||
page.startRendering(
|
page.startRendering(
|
||||||
ctx,
|
ctx,
|
||||||
function nextPageStartRendering() {
|
function nextPageStartRendering(error) {
|
||||||
snapshotCurrentPage(task, false);
|
var failureMessage = false;
|
||||||
},
|
if (error)
|
||||||
function errorNextPageStartRendering(e) {
|
failureMessage = 'render : ' + error.message;
|
||||||
snapshotCurrentPage(task, 'render : ' + e.message);
|
snapshotCurrentPage(task, failureMessage);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
1
test/pdfs/.gitignore
vendored
1
test/pdfs/.gitignore
vendored
@ -16,3 +16,4 @@
|
|||||||
!alphatrans.pdf
|
!alphatrans.pdf
|
||||||
!devicen.pdf
|
!devicen.pdf
|
||||||
!cmykjpeg.pdf
|
!cmykjpeg.pdf
|
||||||
|
!issue840.pdf
|
||||||
|
BIN
test/pdfs/issue840.pdf
Normal file
BIN
test/pdfs/issue840.pdf
Normal file
Binary file not shown.
1
test/pdfs/piperine.pdf.link
Normal file
1
test/pdfs/piperine.pdf.link
Normal file
@ -0,0 +1 @@
|
|||||||
|
http://www.erowid.org/archive/rhodium/chemistry/3base/piperonal.pepper/piperine.pepper/465e03piperine.pdf
|
1
test/pdfs/protectip.pdf.link
Normal file
1
test/pdfs/protectip.pdf.link
Normal file
@ -0,0 +1 @@
|
|||||||
|
http://leahy.senate.gov/imo/media/doc/BillText-PROTECTIPAct.pdf
|
@ -276,5 +276,25 @@
|
|||||||
"link": false,
|
"link": false,
|
||||||
"rounds": 1,
|
"rounds": 1,
|
||||||
"type": "eq"
|
"type": "eq"
|
||||||
|
},
|
||||||
|
{ "id": "protectip",
|
||||||
|
"file": "pdfs/protectip.pdf",
|
||||||
|
"md5": "676e7a7b8f96d04825361832b1838a93",
|
||||||
|
"link": true,
|
||||||
|
"rounds": 1,
|
||||||
|
"type": "eq"
|
||||||
|
},
|
||||||
|
{ "id": "piperine",
|
||||||
|
"file": "pdfs/piperine.pdf",
|
||||||
|
"md5": "603ca43dc5732dbba1579f122958c0c2",
|
||||||
|
"link": true,
|
||||||
|
"rounds": 1,
|
||||||
|
"type": "eq"
|
||||||
|
},
|
||||||
|
{ "id": "issue840",
|
||||||
|
"file": "pdfs/issue840.pdf",
|
||||||
|
"md5": "20d88011dd7e3c4fb5274979094dab93",
|
||||||
|
"rounds": 1,
|
||||||
|
"type": "eq"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -232,6 +232,27 @@ canvas {
|
|||||||
-webkit-box-shadow: 0px 2px 10px #ff0;
|
-webkit-box-shadow: 0px 2px 10px #ff0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.textLayer {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.textLayer > div {
|
||||||
|
color: transparent;
|
||||||
|
position: absolute;
|
||||||
|
line-height:1.3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: file FF bug to support ::-moz-selection:window-inactive
|
||||||
|
so we can override the opaque grey background when the window is inactive;
|
||||||
|
see https://bugzilla.mozilla.org/show_bug.cgi?id=706209 */
|
||||||
|
::selection { background:rgba(0,0,255,0.3); }
|
||||||
|
::-moz-selection { background:rgba(0,0,255,0.3); }
|
||||||
|
|
||||||
#viewer {
|
#viewer {
|
||||||
margin: 44px 0px 0px;
|
margin: 44px 0px 0px;
|
||||||
padding: 8px 0px;
|
padding: 8px 0px;
|
||||||
|
@ -263,7 +263,7 @@ var PDFView = {
|
|||||||
var container = document.getElementById('viewer');
|
var container = document.getElementById('viewer');
|
||||||
while (container.hasChildNodes())
|
while (container.hasChildNodes())
|
||||||
container.removeChild(container.lastChild);
|
container.removeChild(container.lastChild);
|
||||||
|
|
||||||
var pdf;
|
var pdf;
|
||||||
try {
|
try {
|
||||||
pdf = new PDFJS.PDFDoc(data);
|
pdf = new PDFJS.PDFDoc(data);
|
||||||
@ -291,10 +291,10 @@ var PDFView = {
|
|||||||
pagesRefMap[pageRef.num + ' ' + pageRef.gen + ' R'] = i;
|
pagesRefMap[pageRef.num + ' ' + pageRef.gen + ' R'] = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setScale(scale || kDefaultScale, true);
|
|
||||||
|
|
||||||
this.pagesRefMap = pagesRefMap;
|
this.pagesRefMap = pagesRefMap;
|
||||||
this.destinations = pdf.catalog.destinations;
|
this.destinations = pdf.catalog.destinations;
|
||||||
|
this.setScale(scale || kDefaultScale, true);
|
||||||
|
|
||||||
if (pdf.catalog.documentOutline) {
|
if (pdf.catalog.documentOutline) {
|
||||||
this.outline = new DocumentOutlineView(pdf.catalog.documentOutline);
|
this.outline = new DocumentOutlineView(pdf.catalog.documentOutline);
|
||||||
var outlineSwitchButton = document.getElementById('outlineSwitch');
|
var outlineSwitchButton = document.getElementById('outlineSwitch');
|
||||||
@ -542,6 +542,10 @@ var PageView = function pageView(container, content, id, pageWidth, pageHeight,
|
|||||||
div.appendChild(canvas);
|
div.appendChild(canvas);
|
||||||
this.canvas = canvas;
|
this.canvas = canvas;
|
||||||
|
|
||||||
|
var textLayer = document.createElement('div');
|
||||||
|
textLayer.className = 'textLayer';
|
||||||
|
div.appendChild(textLayer);
|
||||||
|
|
||||||
var scale = this.scale;
|
var scale = this.scale;
|
||||||
canvas.width = pageWidth * scale;
|
canvas.width = pageWidth * scale;
|
||||||
canvas.height = pageHeight * scale;
|
canvas.height = pageHeight * scale;
|
||||||
@ -555,14 +559,13 @@ var PageView = function pageView(container, content, id, pageWidth, pageHeight,
|
|||||||
|
|
||||||
stats.begin = Date.now();
|
stats.begin = Date.now();
|
||||||
this.content.startRendering(ctx,
|
this.content.startRendering(ctx,
|
||||||
(function pageViewDrawCallback() {
|
(function pageViewDrawCallback(error) {
|
||||||
|
if (error)
|
||||||
|
PDFView.error('An error occurred while rendering the page.', error);
|
||||||
this.updateStats();
|
this.updateStats();
|
||||||
if (this.onAfterDraw)
|
if (this.onAfterDraw)
|
||||||
this.onAfterDraw();
|
this.onAfterDraw();
|
||||||
}).bind(this),
|
}).bind(this), textLayer
|
||||||
function pageViewErrorback(e) {
|
|
||||||
PDFView.error('An error occurred while rendering the page.', e);
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
setupLinks(this.content, this.scale);
|
setupLinks(this.content, this.scale);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user