mirror of
https://github.com/mozilla/pdf.js.git
synced 2025-04-22 16:18:08 +02:00
Merge branch 'master' into issue3156
This commit is contained in:
commit
34eed81b46
21 changed files with 654 additions and 365 deletions
|
@ -16,7 +16,7 @@
|
|||
*/
|
||||
/* globals ColorSpace, DeviceCmykCS, DeviceGrayCS, DeviceRgbCS, error,
|
||||
FONT_IDENTITY_MATRIX, IDENTITY_MATRIX, ImageData, isArray, isNum,
|
||||
isString, Pattern, TilingPattern, TODO, Util, warn, assert */
|
||||
isString, Pattern, TilingPattern, TODO, Util, warn, assert, info */
|
||||
|
||||
'use strict';
|
||||
|
||||
|
@ -1401,7 +1401,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
|||
// - remove background color:
|
||||
// colorNew = color - alphaNew *colorBackdrop /(1 - alphaNew)
|
||||
if (!group.isolated) {
|
||||
TODO('Support non-isolated groups.');
|
||||
info('TODO: Support non-isolated groups.');
|
||||
}
|
||||
|
||||
// TODO knockout - supposedly possible with the clever use of compositing
|
||||
|
@ -1422,9 +1422,10 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
|||
group.bbox,
|
||||
currentCtx.mozCurrentTransform);
|
||||
// Use ceil in case we're between sizes so we don't create canvas that is
|
||||
// too small.
|
||||
var drawnWidth = Math.ceil(bounds[2] - bounds[0]);
|
||||
var drawnHeight = Math.ceil(bounds[3] - bounds[1]);
|
||||
// too small and make the canvas at least 1x1 pixels.
|
||||
var drawnWidth = Math.max(Math.ceil(bounds[2] - bounds[0]), 1);
|
||||
var drawnHeight = Math.max(Math.ceil(bounds[3] - bounds[1]), 1);
|
||||
|
||||
var scratchCanvas = createScratchCanvas(drawnWidth, drawnHeight);
|
||||
var groupCtx = scratchCanvas.getContext('2d');
|
||||
addContextCurrentTransform(groupCtx);
|
||||
|
|
|
@ -1532,7 +1532,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|||
var fontNameStr = fontName && fontName.name;
|
||||
var baseFontStr = baseFont && baseFont.name;
|
||||
if (fontNameStr !== baseFontStr) {
|
||||
warn('The FontDescriptor\'s FontName is "' + fontNameStr +
|
||||
info('The FontDescriptor\'s FontName is "' + fontNameStr +
|
||||
'" but should be the same as the Font\'s BaseFont "' +
|
||||
baseFontStr + '"');
|
||||
}
|
||||
|
|
210
src/fonts.js
210
src/fonts.js
|
@ -17,7 +17,7 @@
|
|||
/* globals assert, bytesToString, CIDToUnicodeMaps, error, ExpertCharset,
|
||||
ExpertSubsetCharset, FileReaderSync, globalScope, GlyphsUnicode,
|
||||
info, isArray, isNum, ISOAdobeCharset, isWorker, PDFJS, Stream,
|
||||
stringToBytes, TextDecoder, TODO, warn, Lexer */
|
||||
stringToBytes, TextDecoder, TODO, warn, Lexer, Util */
|
||||
|
||||
'use strict';
|
||||
|
||||
|
@ -3647,80 +3647,144 @@ var Font = (function FontClosure() {
|
|||
var TTOpsStackDeltas = [
|
||||
0, 0, 0, 0, 0, 0, 0, 0, -2, -2, -2, -2, 0, 0, -2, -5,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, 0, 0, -1, 0, -1, -1, -1, -1,
|
||||
1, -1, -999, 0, 1, 0, 0, -2, 0, -1, -2, -1, -999, -999, -1, -1,
|
||||
1, -1, -999, 0, 1, 0, -1, -2, 0, -1, -2, -1, -1, 0, -1, -1,
|
||||
0, 0, -999, -999, -1, -1, -1, -1, -2, -999, -2, -2, -2, 0, -2, -2,
|
||||
0, 0, -2, 0, -2, 0, 0, 0, -2, -1, -1, 1, 1, 0, 0, -1,
|
||||
-1, -1, -1, -1, -1, -1, 0, 0, -1, 0, -1, -1, 0, -999, -1, -1,
|
||||
-1, -1, -1, -1, 0, 0, 0, 0, -1, -1, 0, 0, 0, 0, 0, 0,
|
||||
-1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
-2, -999, -999, -999, -999, -999, -1, -1, -2, -2, 0, 0, 0, 0, -1, -1,
|
||||
-999, -2, -2, 0, 0, -1, -2, -2, 0, -999, 0, 0, 0, -1, -2];
|
||||
-999, -2, -2, 0, 0, -1, -2, -2, 0, 0, 0, -1, -1, -1, -2];
|
||||
// 0xC0-DF == -1 and 0xE0-FF == -2
|
||||
|
||||
function sanitizeTTProgram(table, ttContext) {
|
||||
var data = table.data;
|
||||
var i = 0, n, lastEndf = 0, lastDeff = 0;
|
||||
var stack = [];
|
||||
var callstack = [];
|
||||
var functionsCalled = [];
|
||||
var tooComplexToFollowFunctions =
|
||||
ttContext.tooComplexToFollowFunctions;
|
||||
var inFDEF = false, ifLevel = 0, inELSE = 0;
|
||||
for (var ii = data.length; i < ii;) {
|
||||
var op = data[i++];
|
||||
// The TrueType instruction set docs can be found at
|
||||
// https://developer.apple.com/fonts/TTRefMan/RM05/Chap5.html
|
||||
if (op === 0x40) { // NPUSHB - pushes n bytes
|
||||
n = data[i++];
|
||||
for (var j = 0; j < n; j++) {
|
||||
stack.push(data[i++]);
|
||||
if (inFDEF || inELSE) {
|
||||
i += n;
|
||||
} else {
|
||||
for (var j = 0; j < n; j++) {
|
||||
stack.push(data[i++]);
|
||||
}
|
||||
}
|
||||
} else if (op === 0x41) { // NPUSHW - pushes n words
|
||||
n = data[i++];
|
||||
for (var j = 0; j < n; j++) {
|
||||
var b = data[i++];
|
||||
stack.push((b << 8) | data[i++]);
|
||||
if (inFDEF || inELSE) {
|
||||
i += n * 2;
|
||||
} else {
|
||||
for (var j = 0; j < n; j++) {
|
||||
var b = data[i++];
|
||||
stack.push((b << 8) | data[i++]);
|
||||
}
|
||||
}
|
||||
} else if ((op & 0xF8) === 0xB0) { // PUSHB - pushes bytes
|
||||
n = op - 0xB0 + 1;
|
||||
for (var j = 0; j < n; j++) {
|
||||
stack.push(data[i++]);
|
||||
if (inFDEF || inELSE) {
|
||||
i += n;
|
||||
} else {
|
||||
for (var j = 0; j < n; j++) {
|
||||
stack.push(data[i++]);
|
||||
}
|
||||
}
|
||||
} else if ((op & 0xF8) === 0xB8) { // PUSHW - pushes words
|
||||
n = op - 0xB8 + 1;
|
||||
for (var j = 0; j < n; j++) {
|
||||
var b = data[i++];
|
||||
stack.push((b << 8) | data[i++]);
|
||||
if (inFDEF || inELSE) {
|
||||
i += n * 2;
|
||||
} else {
|
||||
for (var j = 0; j < n; j++) {
|
||||
var b = data[i++];
|
||||
stack.push((b << 8) | data[i++]);
|
||||
}
|
||||
}
|
||||
} else if (op === 0x2B && !tooComplexToFollowFunctions) { // CALL
|
||||
// collecting inforamtion about which functions are used
|
||||
var funcId = stack[stack.length - 1];
|
||||
ttContext.functionsUsed[funcId] = true;
|
||||
if (i >= 2 && data[i - 2] === 0x2B) {
|
||||
// all data in stack, calls are performed in sequence
|
||||
tooComplexToFollowFunctions = true;
|
||||
if (!inFDEF && !inELSE) {
|
||||
// collecting inforamtion about which functions are used
|
||||
var funcId = stack[stack.length - 1];
|
||||
ttContext.functionsUsed[funcId] = true;
|
||||
if (funcId in ttContext.functionsStackDeltas) {
|
||||
stack.length += ttContext.functionsStackDeltas[funcId];
|
||||
} else if (funcId in ttContext.functionsDefined &&
|
||||
functionsCalled.indexOf(funcId) < 0) {
|
||||
callstack.push({data: data, i: i, stackTop: stack.length - 1});
|
||||
functionsCalled.push(funcId);
|
||||
var pc = ttContext.functionsDefined[funcId];
|
||||
data = pc.data;
|
||||
i = pc.i;
|
||||
}
|
||||
}
|
||||
} else if (op === 0x2C && !tooComplexToFollowFunctions) { // FDEF
|
||||
// collecting inforamtion about which functions are defined
|
||||
lastDeff = i;
|
||||
var funcId = stack[stack.length - 1];
|
||||
ttContext.functionsDefined[funcId] = true;
|
||||
if (i >= 2 && data[i - 2] === 0x2D) {
|
||||
// all function ids in stack, FDEF/ENDF perfomed in sequence
|
||||
if (inFDEF || inELSE) {
|
||||
warn('TT: nested FDEFs not allowed');
|
||||
tooComplexToFollowFunctions = true;
|
||||
}
|
||||
inFDEF = true;
|
||||
// collecting inforamtion about which functions are defined
|
||||
lastDeff = i;
|
||||
var funcId = stack.pop();
|
||||
ttContext.functionsDefined[funcId] = {data: data, i: i};
|
||||
} else if (op === 0x2D) { // ENDF - end of function
|
||||
lastEndf = i;
|
||||
if (inFDEF) {
|
||||
inFDEF = false;
|
||||
lastEndf = i;
|
||||
} else {
|
||||
var pc = callstack.pop();
|
||||
var funcId = functionsCalled.pop();
|
||||
data = pc.data;
|
||||
i = pc.i;
|
||||
ttContext.functionsStackDeltas[funcId] =
|
||||
stack.length - pc.stackTop;
|
||||
}
|
||||
} else if (op === 0x89) { // IDEF - instruction definition
|
||||
if (inFDEF || inELSE) {
|
||||
warn('TT: nested IDEFs not allowed');
|
||||
tooComplexToFollowFunctions = true;
|
||||
}
|
||||
inFDEF = true;
|
||||
// recording it as a function to track ENDF
|
||||
lastDeff = i;
|
||||
} else if (op === 0x58) { // IF
|
||||
++ifLevel;
|
||||
} else if (op === 0x1B) { // ELSE
|
||||
inELSE = ifLevel;
|
||||
} else if (op === 0x59) { // EIF
|
||||
if (inELSE === ifLevel) {
|
||||
inELSE = 0;
|
||||
}
|
||||
--ifLevel;
|
||||
} else if (op === 0x1C) { // JMPR
|
||||
var offset = stack[stack.length - 1];
|
||||
// only jumping forward to prevent infinite loop
|
||||
if (offset > 0) { i += offset - 1; }
|
||||
}
|
||||
// Adjusting stack not extactly, but just enough to get function id
|
||||
var stackDelta = op <= 0x8E ? TTOpsStackDeltas[op] :
|
||||
op >= 0xC0 && op <= 0xDF ? -1 : op >= 0xE0 ? -2 : 0;
|
||||
while (stackDelta < 0 && stack.length > 0) {
|
||||
stack.pop();
|
||||
stackDelta++;
|
||||
}
|
||||
while (stackDelta > 0) {
|
||||
stack.push(NaN); // pushing any number into stack
|
||||
stackDelta--;
|
||||
if (!inFDEF && !inELSE) {
|
||||
var stackDelta = op <= 0x8E ? TTOpsStackDeltas[op] :
|
||||
op >= 0xC0 && op <= 0xDF ? -1 : op >= 0xE0 ? -2 : 0;
|
||||
if (op >= 0x71 && op <= 0x75) {
|
||||
n = stack.pop();
|
||||
if (n === n) {
|
||||
stackDelta = -n * 2;
|
||||
}
|
||||
}
|
||||
while (stackDelta < 0 && stack.length > 0) {
|
||||
stack.pop();
|
||||
stackDelta++;
|
||||
}
|
||||
while (stackDelta > 0) {
|
||||
stack.push(NaN); // pushing any number into stack
|
||||
stackDelta--;
|
||||
}
|
||||
}
|
||||
}
|
||||
ttContext.tooComplexToFollowFunctions = tooComplexToFollowFunctions;
|
||||
|
@ -3729,20 +3793,44 @@ var Font = (function FontClosure() {
|
|||
content.push(new Uint8Array(i - data.length));
|
||||
}
|
||||
if (lastDeff > lastEndf) {
|
||||
warn('TT: complementing a missing function tail');
|
||||
// new function definition started, but not finished
|
||||
// complete function by [CLEAR, ENDF]
|
||||
content.push(new Uint8Array([0x22, 0x2D]));
|
||||
}
|
||||
if (ttContext.defineMissingFunctions && !tooComplexToFollowFunctions) {
|
||||
foldTTTable(table, content);
|
||||
}
|
||||
|
||||
function addTTDummyFunctions(table, ttContext, maxFunctionDefs) {
|
||||
var content = [table.data];
|
||||
if (!ttContext.tooComplexToFollowFunctions) {
|
||||
var undefinedFunctions = [];
|
||||
for (var j = 0, jj = ttContext.functionsUsed.length; j < jj; j++) {
|
||||
if (!ttContext.functionsUsed[j] || ttContext.functionsDefined[j]) {
|
||||
continue;
|
||||
}
|
||||
undefinedFunctions.push(j);
|
||||
if (j >= maxFunctionDefs) {
|
||||
continue;
|
||||
}
|
||||
// function is used, but not defined
|
||||
// creating empty one [PUSHB, function-id, FDEF, ENDF]
|
||||
content.push(new Uint8Array([0xB0, j, 0x2C, 0x2D]));
|
||||
if (j < 256) {
|
||||
// creating empty one [PUSHB, function-id, FDEF, ENDF]
|
||||
content.push(new Uint8Array([0xB0, j, 0x2C, 0x2D]));
|
||||
} else {
|
||||
// creating empty one [PUSHW, function-id, FDEF, ENDF]
|
||||
content.push(
|
||||
new Uint8Array([0xB8, j >> 8, j & 255, 0x2C, 0x2D]));
|
||||
}
|
||||
}
|
||||
if (undefinedFunctions.length > 0) {
|
||||
warn('TT: undefined functions: ' + undefinedFunctions);
|
||||
}
|
||||
}
|
||||
foldTTTable(table, content);
|
||||
}
|
||||
|
||||
function foldTTTable(table, content) {
|
||||
if (content.length > 1) {
|
||||
// concatenating the content items
|
||||
var newLength = 0;
|
||||
|
@ -3765,15 +3853,17 @@ var Font = (function FontClosure() {
|
|||
var ttContext = {
|
||||
functionsDefined: [],
|
||||
functionsUsed: [],
|
||||
functionsStackDeltas: [],
|
||||
tooComplexToFollowFunctions: false
|
||||
};
|
||||
if (fpgm) {
|
||||
sanitizeTTProgram(fpgm, ttContext);
|
||||
}
|
||||
if (prep) {
|
||||
// collecting prep functions info first
|
||||
sanitizeTTProgram(prep, ttContext);
|
||||
}
|
||||
if (fpgm) {
|
||||
ttContext.defineMissingFunctions = true;
|
||||
sanitizeTTProgram(fpgm, ttContext);
|
||||
addTTDummyFunctions(fpgm, ttContext, maxFunctionDefs);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3843,12 +3933,17 @@ var Font = (function FontClosure() {
|
|||
// Ensure the hmtx table contains the advance width and
|
||||
// sidebearings information for numGlyphs in the maxp table
|
||||
font.pos = (font.start || 0) + maxp.offset;
|
||||
var version = int16(font.getBytes(4));
|
||||
var version = int32(font.getBytes(4));
|
||||
var numGlyphs = int16(font.getBytes(2));
|
||||
var maxFunctionDefs = 0;
|
||||
if (version >= 0x00010000 && maxp.length >= 22) {
|
||||
font.pos += 14;
|
||||
var maxFunctionDefs = int16(font.getBytes(2));
|
||||
}
|
||||
|
||||
sanitizeMetrics(font, hhea, hmtx, numGlyphs);
|
||||
|
||||
sanitizeTTPrograms(fpgm, prep);
|
||||
sanitizeTTPrograms(fpgm, prep, maxFunctionDefs);
|
||||
|
||||
if (head) {
|
||||
sanitizeHead(head, numGlyphs, loca.length);
|
||||
|
@ -6696,6 +6791,33 @@ var CFFCompiler = (function CFFCompilerClosure() {
|
|||
var nameIndex = this.compileNameIndex(cff.names);
|
||||
output.add(nameIndex);
|
||||
|
||||
if (cff.isCIDFont) {
|
||||
// The spec is unclear on how font matrices should relate to each other
|
||||
// when there is one in the main top dict and the sub top dicts.
|
||||
// Windows handles this differently than linux and osx so we have to
|
||||
// normalize to work on all.
|
||||
// Rules based off of some mailing list discussions:
|
||||
// - If main font has a matrix and subfont doesn't, use the main matrix.
|
||||
// - If no main font matrix and there is a subfont matrix, use the
|
||||
// subfont matrix.
|
||||
// - If both have matrices, concat together.
|
||||
// - If neither have matrices, use default.
|
||||
// To make this work on all platforms we move the top matrix into each
|
||||
// sub top dict and concat if necessary.
|
||||
if (cff.topDict.hasName('FontMatrix')) {
|
||||
var base = cff.topDict.getByName('FontMatrix');
|
||||
cff.topDict.removeByName('FontMatrix');
|
||||
for (var i = 0, ii = cff.fdArray.length; i < ii; i++) {
|
||||
var subDict = cff.fdArray[i];
|
||||
var matrix = base.slice(0);
|
||||
if (subDict.hasName('FontMatrix')) {
|
||||
matrix = Util.transform(matrix, subDict.getByName('FontMatrix'));
|
||||
}
|
||||
subDict.setByName('FontMatrix', matrix);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var compiled = this.compileTopDicts([cff.topDict],
|
||||
output.length,
|
||||
cff.isCIDFont);
|
||||
|
|
|
@ -33,10 +33,6 @@
|
|||
// // TODO(mack): dump() doesn't seem to work here...
|
||||
// dump(msg + '\n');
|
||||
//}
|
||||
//#else
|
||||
function log(aMsg) {
|
||||
console.log(aMsg);
|
||||
}
|
||||
//#endif
|
||||
|
||||
var NetworkManager = (function NetworkManagerClosure() {
|
||||
|
|
12
src/util.js
12
src/util.js
|
@ -262,6 +262,18 @@ var Util = PDFJS.Util = (function UtilClosure() {
|
|||
return Util.makeCssCmyk(cmyk);
|
||||
};
|
||||
|
||||
// Concatenates two transformation matrices together and returns the result.
|
||||
Util.transform = function Util_transform(m1, m2) {
|
||||
return [
|
||||
m1[0] * m2[0] + m1[2] * m2[1],
|
||||
m1[1] * m2[0] + m1[3] * m2[1],
|
||||
m1[0] * m2[2] + m1[2] * m2[3],
|
||||
m1[1] * m2[2] + m1[3] * m2[3],
|
||||
m1[0] * m2[4] + m1[2] * m2[5] + m1[4],
|
||||
m1[1] * m2[4] + m1[3] * m2[5] + m1[5]
|
||||
];
|
||||
};
|
||||
|
||||
// For 2d affine transforms
|
||||
Util.applyTransform = function Util_applyTransform(p, m) {
|
||||
var xt = p[0] * m[0] + p[1] * m[2] + m[4];
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue