Merge pull request #2505 from yurydelendik/refactor-cff-float
Refactors encodeFloat, font matrix and flex args
This commit is contained in:
commit
bf0abd61d1
@ -159,7 +159,7 @@ var CanvasExtraState = (function CanvasExtraStateClosure() {
|
||||
this.fontSize = 0;
|
||||
this.fontSizeScale = 1;
|
||||
this.textMatrix = IDENTITY_MATRIX;
|
||||
this.fontMatrix = IDENTITY_MATRIX;
|
||||
this.fontMatrix = FONT_IDENTITY_MATRIX;
|
||||
this.leading = 0;
|
||||
// Current point (in user coordinates)
|
||||
this.x = 0;
|
||||
@ -768,11 +768,8 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
||||
if (!fontObj)
|
||||
error('Can\'t find font for ' + fontRefName);
|
||||
|
||||
// Slice-clone matrix so we can manipulate it without affecting original
|
||||
if (fontObj.fontMatrix)
|
||||
current.fontMatrix = fontObj.fontMatrix.slice(0);
|
||||
else
|
||||
current.fontMatrix = IDENTITY_MATRIX.slice(0);
|
||||
current.fontMatrix = fontObj.fontMatrix ? fontObj.fontMatrix :
|
||||
FONT_IDENTITY_MATRIX;
|
||||
|
||||
// A valid matrix needs all main diagonal elements to be non-zero
|
||||
// This also ensures we bypass FF bugzilla bug #719844.
|
||||
@ -783,11 +780,11 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
||||
|
||||
// The spec for Tf (setFont) says that 'size' specifies the font 'scale',
|
||||
// and in some docs this can be negative (inverted x-y axes).
|
||||
// We implement this condition with fontMatrix.
|
||||
if (size < 0) {
|
||||
size = -size;
|
||||
current.fontMatrix[0] *= -1;
|
||||
current.fontMatrix[3] *= -1;
|
||||
current.fontDirection = -1;
|
||||
} else {
|
||||
current.fontDirection = 1;
|
||||
}
|
||||
|
||||
this.current.font = fontObj;
|
||||
@ -840,14 +837,13 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
||||
applyTextTransforms: function CanvasGraphics_applyTextTransforms() {
|
||||
var ctx = this.ctx;
|
||||
var current = this.current;
|
||||
var textHScale = current.textHScale;
|
||||
var fontMatrix = current.fontMatrix || IDENTITY_MATRIX;
|
||||
|
||||
ctx.transform.apply(ctx, current.textMatrix);
|
||||
ctx.scale(1, -1);
|
||||
ctx.translate(current.x, -current.y - current.textRise);
|
||||
ctx.transform.apply(ctx, fontMatrix);
|
||||
ctx.scale(textHScale, 1);
|
||||
ctx.translate(current.x, current.y + current.textRise);
|
||||
if (current.fontDirection > 0) {
|
||||
ctx.scale(current.textHScale, -1);
|
||||
} else {
|
||||
ctx.scale(-current.textHScale, 1);
|
||||
}
|
||||
},
|
||||
createTextGeometry: function CanvasGraphics_createTextGeometry() {
|
||||
var geometry = {};
|
||||
@ -878,9 +874,8 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
||||
var fontSizeScale = current.fontSizeScale;
|
||||
var charSpacing = current.charSpacing;
|
||||
var wordSpacing = current.wordSpacing;
|
||||
var textHScale = current.textHScale;
|
||||
var fontMatrix = current.fontMatrix || IDENTITY_MATRIX;
|
||||
var textHScale2 = textHScale * fontMatrix[0];
|
||||
var textHScale = current.textHScale * current.fontDirection;
|
||||
var fontMatrix = current.fontMatrix || FONT_IDENTITY_MATRIX;
|
||||
var glyphsLength = glyphs.length;
|
||||
var textLayer = this.textLayer;
|
||||
var geom;
|
||||
@ -919,8 +914,8 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
||||
this.restore();
|
||||
|
||||
var transformed = Util.applyTransform([glyph.width, 0], fontMatrix);
|
||||
var width = transformed[0] * fontSize +
|
||||
Util.sign(current.fontMatrix[0]) * charSpacing;
|
||||
var width = (transformed[0] * fontSize + charSpacing) *
|
||||
current.fontDirection;
|
||||
|
||||
ctx.translate(width, 0);
|
||||
current.x += width * textHScale;
|
||||
@ -934,8 +929,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
||||
|
||||
var lineWidth = current.lineWidth;
|
||||
var a1 = current.textMatrix[0], b1 = current.textMatrix[1];
|
||||
var a2 = fontMatrix[0], b2 = fontMatrix[1];
|
||||
var scale = Math.sqrt((a1 * a1 + b1 * b1) * (a2 * a2 + b2 * b2));
|
||||
var scale = Math.sqrt(a1 * a1 + b1 * b1);
|
||||
if (scale == 0 || lineWidth == 0)
|
||||
lineWidth = this.getSinglePixelWidth();
|
||||
else
|
||||
@ -956,13 +950,13 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
||||
var glyph = glyphs[i];
|
||||
if (glyph === null) {
|
||||
// word break
|
||||
x += Util.sign(current.fontMatrix[0]) * wordSpacing;
|
||||
x += current.fontDirection * wordSpacing;
|
||||
continue;
|
||||
}
|
||||
|
||||
var character = glyph.fontChar;
|
||||
var charWidth = glyph.width * fontSize * 0.001 +
|
||||
Util.sign(current.fontMatrix[0]) * charSpacing;
|
||||
var charWidth = glyph.width * fontSize * current.fontMatrix[0] +
|
||||
charSpacing * current.fontDirection;
|
||||
|
||||
if (!glyph.disabled) {
|
||||
var scaledX = x / fontSizeScale;
|
||||
@ -995,7 +989,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
||||
|
||||
canvasWidth += charWidth;
|
||||
}
|
||||
current.x += x * textHScale2;
|
||||
current.x += x * textHScale;
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
@ -1011,9 +1005,9 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
||||
var current = this.current;
|
||||
var font = current.font;
|
||||
var fontSize = current.fontSize;
|
||||
var textHScale = current.textHScale;
|
||||
if (!font.coded)
|
||||
textHScale *= (current.fontMatrix || IDENTITY_MATRIX)[0];
|
||||
var textHScale = current.textHScale * (current.fontMatrix && !font.coded ?
|
||||
current.fontMatrix[0] : FONT_IDENTITY_MATRIX[0]) *
|
||||
current.fontDirection;
|
||||
var arrLength = arr.length;
|
||||
var textLayer = this.textLayer;
|
||||
var geom;
|
||||
@ -1022,14 +1016,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
||||
|
||||
if (textSelection) {
|
||||
ctx.save();
|
||||
// Type3 fonts - each glyph is a "mini-PDF" (see also showText)
|
||||
if (font.coded) {
|
||||
ctx.transform.apply(ctx, current.textMatrix);
|
||||
ctx.scale(1, -1);
|
||||
ctx.translate(current.x, -1 * current.y);
|
||||
ctx.scale(textHScale, 1);
|
||||
} else
|
||||
this.applyTextTransforms();
|
||||
this.applyTextTransforms();
|
||||
geom = this.createTextGeometry();
|
||||
ctx.restore();
|
||||
}
|
||||
@ -1037,7 +1024,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
||||
for (var i = 0; i < arrLength; ++i) {
|
||||
var e = arr[i];
|
||||
if (isNum(e)) {
|
||||
var spacingLength = -e * 0.001 * fontSize * textHScale;
|
||||
var spacingLength = -e * fontSize * textHScale;
|
||||
current.x += spacingLength;
|
||||
|
||||
if (textSelection)
|
||||
|
@ -1171,7 +1171,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
||||
composite: composite,
|
||||
wideChars: composite,
|
||||
fixedPitch: false,
|
||||
fontMatrix: dict.get('FontMatrix') || IDENTITY_MATRIX,
|
||||
fontMatrix: dict.get('FontMatrix') || FONT_IDENTITY_MATRIX,
|
||||
firstChar: firstChar || 0,
|
||||
lastChar: lastChar || maxCharIndex,
|
||||
bbox: descriptor.get('FontBBox'),
|
||||
|
142
src/fonts.js
142
src/fonts.js
@ -29,6 +29,8 @@ var PDF_GLYPH_SPACE_UNITS = 1000;
|
||||
// Until hinting is fully supported this constant can be used
|
||||
var HINTING_ENABLED = false;
|
||||
|
||||
var FONT_IDENTITY_MATRIX = [0.001, 0, 0, 0.001, 0, 0];
|
||||
|
||||
var FontFlags = {
|
||||
FixedPitch: 1,
|
||||
Serif: 2,
|
||||
@ -2214,6 +2216,19 @@ function fontCharsToUnicode(charCodes, font) {
|
||||
return result;
|
||||
}
|
||||
|
||||
function adjustWidths(properties) {
|
||||
if (properties.fontMatrix[0] === FONT_IDENTITY_MATRIX[0]) {
|
||||
return;
|
||||
}
|
||||
// adjusting width to fontMatrix scale
|
||||
var scale = 0.001 / properties.fontMatrix[0];
|
||||
var glyphsWidths = properties.widths;
|
||||
for (var glyph in glyphsWidths) {
|
||||
glyphsWidths[glyph] *= scale;
|
||||
}
|
||||
properties.defaultWidth *= scale;
|
||||
}
|
||||
|
||||
/**
|
||||
* 'Font' is the class the outside world should use, it encapsulate all the font
|
||||
* decoding logics whatever type it is (assuming the font type is supported).
|
||||
@ -2260,7 +2275,6 @@ var Font = (function FontClosure() {
|
||||
this.hasEncoding = properties.hasEncoding;
|
||||
|
||||
this.fontMatrix = properties.fontMatrix;
|
||||
this.widthMultiplier = 1.0;
|
||||
if (properties.type == 'Type3') {
|
||||
this.encoding = properties.baseEncoding;
|
||||
return;
|
||||
@ -2318,6 +2332,8 @@ var Font = (function FontClosure() {
|
||||
var cff = (subtype == 'Type1C' || subtype == 'CIDFontType0C') ?
|
||||
new CFFFont(file, properties) : new Type1Font(name, file, properties);
|
||||
|
||||
adjustWidths(properties);
|
||||
|
||||
// Wrap the CFF data inside an OTF font file
|
||||
data = this.convert(name, cff, properties);
|
||||
break;
|
||||
@ -2337,10 +2353,13 @@ var Font = (function FontClosure() {
|
||||
}
|
||||
|
||||
this.data = data;
|
||||
|
||||
// Transfer some properties again that could change during font conversion
|
||||
this.fontMatrix = properties.fontMatrix;
|
||||
this.widthMultiplier = !properties.fontMatrix ? 1.0 :
|
||||
1.0 / properties.fontMatrix[0];
|
||||
this.widths = properties.widths;
|
||||
this.defaultWidth = properties.defaultWidth;
|
||||
this.encoding = properties.baseEncoding;
|
||||
|
||||
this.loading = true;
|
||||
};
|
||||
|
||||
@ -3931,7 +3950,7 @@ var Font = (function FontClosure() {
|
||||
}
|
||||
this.toFontChar = toFontChar;
|
||||
}
|
||||
var unitsPerEm = properties.unitsPerEm || 1000; // defaulting to 1000
|
||||
var unitsPerEm = 1 / (properties.fontMatrix || FONT_IDENTITY_MATRIX)[0];
|
||||
|
||||
var fields = {
|
||||
// PostScript Font Program
|
||||
@ -4170,7 +4189,7 @@ var Font = (function FontClosure() {
|
||||
if (width)
|
||||
break; // the non-zero width found
|
||||
}
|
||||
width = (width || this.defaultWidth) * this.widthMultiplier;
|
||||
width = width || this.defaultWidth;
|
||||
// Do not shadow the property here. See discussion:
|
||||
// https://github.com/mozilla/pdf.js/pull/2127#discussion_r1662280
|
||||
this._shadowWidth = width;
|
||||
@ -4251,7 +4270,7 @@ var Font = (function FontClosure() {
|
||||
if (typeof unicodeChars === 'number')
|
||||
unicodeChars = String.fromCharCode(unicodeChars);
|
||||
|
||||
width = (isNum(width) ? width : this.defaultWidth) * this.widthMultiplier;
|
||||
width = isNum(width) ? width : this.defaultWidth;
|
||||
disabled = this.unicodeIsEnabled ?
|
||||
!this.unicodeIsEnabled[fontCharCode] : false;
|
||||
|
||||
@ -4443,6 +4462,7 @@ var Type1Parser = function type1Parser() {
|
||||
// Type1 only command with command not (yet) built-in ,throw an error
|
||||
'7': -1, // sbw
|
||||
|
||||
'10': 'add',
|
||||
'11': 'sub',
|
||||
'12': 'div',
|
||||
|
||||
@ -4507,16 +4527,6 @@ var Type1Parser = function type1Parser() {
|
||||
return args;
|
||||
}
|
||||
|
||||
// Remove the same number of args from the stack that are in the args
|
||||
// parameter. Args should be built from breakUpArgs().
|
||||
function popArgs(stack, args) {
|
||||
for (var i = 0, ii = args.length; i < ii; i++) {
|
||||
for (var j = 0, jj = args[i].arg.length; j < jj; j++) {
|
||||
stack.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function decodeCharString(array) {
|
||||
var charstring = [];
|
||||
var lsb = 0;
|
||||
@ -4617,25 +4627,32 @@ var Type1Parser = function type1Parser() {
|
||||
break;
|
||||
case 0:
|
||||
var flexArgs = breakUpArgs(charstring, 17);
|
||||
popArgs(charstring, flexArgs);
|
||||
|
||||
charstring.push(
|
||||
flexArgs[2].value + flexArgs[0].value, // bcp1x + rpx
|
||||
flexArgs[3].value + flexArgs[1].value, // bcp1y + rpy
|
||||
flexArgs[4].value, // bcp2x
|
||||
flexArgs[5].value, // bcp2y
|
||||
flexArgs[6].value, // p2x
|
||||
flexArgs[7].value, // p2y
|
||||
flexArgs[8].value, // bcp3x
|
||||
flexArgs[9].value, // bcp3y
|
||||
flexArgs[10].value, // bcp4x
|
||||
flexArgs[11].value, // bcp4y
|
||||
flexArgs[12].value, // p3x
|
||||
flexArgs[13].value, // p3y
|
||||
flexArgs[14].value, // flexDepth
|
||||
// removing all flex arguments from the stack
|
||||
charstring.splice(flexArgs[0].offset,
|
||||
charstring.length - flexArgs[0].offset);
|
||||
|
||||
charstring = charstring.concat(
|
||||
flexArgs[0].arg, // bcp1x +
|
||||
flexArgs[2].arg, // rpx
|
||||
['add'],
|
||||
flexArgs[1].arg, // bcp1y +
|
||||
flexArgs[3].arg, // rpy
|
||||
['add'],
|
||||
flexArgs[4].arg, // bcp2x
|
||||
flexArgs[5].arg, // bcp2y
|
||||
flexArgs[6].arg, // p2x
|
||||
flexArgs[7].arg, // p2y
|
||||
flexArgs[8].arg, // bcp3x
|
||||
flexArgs[9].arg, // bcp3y
|
||||
flexArgs[10].arg, // bcp4x
|
||||
flexArgs[11].arg, // bcp4y
|
||||
flexArgs[12].arg, // p3x
|
||||
flexArgs[13].arg, // p3y
|
||||
flexArgs[14].arg, // flexDepth
|
||||
// 15 = finalx unused by flex
|
||||
// 16 = finaly unused by flex
|
||||
'flex'
|
||||
['flex']
|
||||
);
|
||||
|
||||
flexing = false;
|
||||
@ -4650,14 +4667,9 @@ var Type1Parser = function type1Parser() {
|
||||
charstring.push(0);
|
||||
continue; // ignoring hmoveto
|
||||
} else if (value == 4 && flexing) { // vmoveto
|
||||
// Add the dx for flex and but also swap the values so they are the
|
||||
// right order.
|
||||
var vArgs = breakUpArgs(charstring, 1);
|
||||
popArgs(charstring, vArgs);
|
||||
charstring.push(0);
|
||||
for (var t = 0, tt = vArgs[0].arg.length; t < tt; t++) {
|
||||
charstring.push(vArgs[0].arg[t]);
|
||||
}
|
||||
// Insert the dx for flex before dy.
|
||||
var flexArgs = breakUpArgs(charstring, 1);
|
||||
charstring.splice(flexArgs[0].offset, 0, 0);
|
||||
continue; // ignoring vmoveto
|
||||
} else if (!HINTING_ENABLED && (value == 1 || value == 3)) {
|
||||
charstring.push('drop', 'drop');
|
||||
@ -4909,14 +4921,6 @@ var Type1Parser = function type1Parser() {
|
||||
switch (token) {
|
||||
case '/FontMatrix':
|
||||
var matrix = readNumberArray(headerString, i + 1);
|
||||
|
||||
// The FontMatrix is in unitPerEm, so make it pixels
|
||||
for (var j = 0, jj = matrix.length; j < jj; j++)
|
||||
matrix[j] *= 1000;
|
||||
|
||||
// Make the angle into the right direction
|
||||
matrix[2] *= -1;
|
||||
|
||||
properties.fontMatrix = matrix;
|
||||
break;
|
||||
case '/Encoding':
|
||||
@ -5124,6 +5128,7 @@ Type1Font.prototype = {
|
||||
'rrcurveto': 8,
|
||||
'callsubr': 10,
|
||||
'return': 11,
|
||||
'add': [12, 10],
|
||||
'sub': [12, 11],
|
||||
'div': [12, 12],
|
||||
'exch': [12, 28],
|
||||
@ -5191,6 +5196,7 @@ Type1Font.prototype = {
|
||||
topDict.setByName('FamilyName', 3);
|
||||
topDict.setByName('Weight', 4);
|
||||
topDict.setByName('Encoding', null); // placeholder
|
||||
topDict.setByName('FontMatrix', properties.fontMatrix);
|
||||
topDict.setByName('FontBBox', properties.bbox);
|
||||
topDict.setByName('charset', null); // placeholder
|
||||
topDict.setByName('CharStrings', null); // placeholder
|
||||
@ -5465,8 +5471,7 @@ var CFFParser = (function CFFParserClosure() {
|
||||
|
||||
var fontMatrix = topDict.getByName('FontMatrix');
|
||||
if (fontMatrix) {
|
||||
// estimating unitsPerEM for the font
|
||||
properties.unitsPerEm = 1 / fontMatrix[0];
|
||||
properties.fontMatrix = fontMatrix;
|
||||
}
|
||||
|
||||
var fontBBox = topDict.getByName('FontBBox');
|
||||
@ -6391,37 +6396,26 @@ var CFFCompiler = (function CFFCompilerClosure() {
|
||||
else
|
||||
return this.encodeFloat(value);
|
||||
},
|
||||
encodeFloat: function CFFCompiler_encodeFloat(value) {
|
||||
value = value.toString();
|
||||
// Strip off the any leading zeros.
|
||||
if (value.substr(0, 2) === '0.')
|
||||
value = value.substr(1);
|
||||
else if (value.substr(0, 3) === '-0.')
|
||||
value = '-' + value.substr(2);
|
||||
var nibbles = [];
|
||||
encodeFloat: function CFFCompiler_encodeFloat(num) {
|
||||
var value = num.toString();
|
||||
var nibbles = '';
|
||||
for (var i = 0, ii = value.length; i < ii; ++i) {
|
||||
var a = value.charAt(i), b = value.charAt(i + 1);
|
||||
var nibble;
|
||||
if (a === 'e' && b === '-') {
|
||||
nibble = 0xc;
|
||||
++i;
|
||||
var a = value[i];
|
||||
if (a === 'e') {
|
||||
nibbles += value[++i] === '-' ? 'c' : 'b';
|
||||
} else if (a === '.') {
|
||||
nibble = 0xa;
|
||||
} else if (a === 'E') {
|
||||
nibble = 0xb;
|
||||
nibbles += 'a';
|
||||
} else if (a === '-') {
|
||||
nibble = 0xe;
|
||||
nibbles += 'e';
|
||||
} else {
|
||||
nibble = a;
|
||||
nibbles += a;
|
||||
}
|
||||
nibbles.push(nibble);
|
||||
}
|
||||
nibbles.push(0xf);
|
||||
if (nibbles.length % 2)
|
||||
nibbles.push(0xf);
|
||||
nibbles += (nibbles.length & 1) ? 'f' : 'ff';
|
||||
var out = [30];
|
||||
for (var i = 0, ii = nibbles.length; i < ii; i += 2)
|
||||
out.push(nibbles[i] << 4 | nibbles[i + 1]);
|
||||
for (var i = 0, ii = nibbles.length; i < ii; i += 2) {
|
||||
out.push(parseInt(nibbles.substr(i, 2), 16));
|
||||
}
|
||||
return out;
|
||||
},
|
||||
encodeInteger: function CFFCompiler_encodeInteger(value) {
|
||||
|
Loading…
Reference in New Issue
Block a user