Skip to content

Commit

Permalink
Refactors font matrix operations
Browse files Browse the repository at this point in the history
  • Loading branch information
yurydelendik committed Jan 4, 2013
1 parent ccfa0e1 commit 10bb6c9
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 56 deletions.
65 changes: 26 additions & 39 deletions src/canvas.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -716,11 +716,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.
Expand All @@ -731,11 +728,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;
Expand Down Expand Up @@ -788,14 +785,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 = {};
Expand Down Expand Up @@ -826,9 +822,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;
Expand Down Expand Up @@ -867,8 +862,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;
Expand All @@ -882,8 +877,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
Expand All @@ -904,13 +898,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;
Expand Down Expand Up @@ -943,7 +937,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {

canvasWidth += charWidth;
}
current.x += x * textHScale2;
current.x += x * textHScale;
ctx.restore();
}

Expand All @@ -959,9 +953,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;
Expand All @@ -970,22 +964,15 @@ 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();
}

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)
Expand Down
2 changes: 1 addition & 1 deletion src/evaluator.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'),
Expand Down
43 changes: 27 additions & 16 deletions src/fonts.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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).
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
};

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -4902,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':
Expand Down Expand Up @@ -5185,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
Expand Down Expand Up @@ -5459,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');
Expand Down

0 comments on commit 10bb6c9

Please sign in to comment.