Skip to content

Commit 10bb6c9

Browse files
committed
Refactors font matrix operations
1 parent ccfa0e1 commit 10bb6c9

File tree

3 files changed

+54
-56
lines changed

3 files changed

+54
-56
lines changed

src/canvas.js

Lines changed: 26 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ var CanvasExtraState = (function CanvasExtraStateClosure() {
159159
this.fontSize = 0;
160160
this.fontSizeScale = 1;
161161
this.textMatrix = IDENTITY_MATRIX;
162-
this.fontMatrix = IDENTITY_MATRIX;
162+
this.fontMatrix = FONT_IDENTITY_MATRIX;
163163
this.leading = 0;
164164
// Current point (in user coordinates)
165165
this.x = 0;
@@ -716,11 +716,8 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
716716
if (!fontObj)
717717
error('Can\'t find font for ' + fontRefName);
718718

719-
// Slice-clone matrix so we can manipulate it without affecting original
720-
if (fontObj.fontMatrix)
721-
current.fontMatrix = fontObj.fontMatrix.slice(0);
722-
else
723-
current.fontMatrix = IDENTITY_MATRIX.slice(0);
719+
current.fontMatrix = fontObj.fontMatrix ? fontObj.fontMatrix :
720+
FONT_IDENTITY_MATRIX;
724721

725722
// A valid matrix needs all main diagonal elements to be non-zero
726723
// This also ensures we bypass FF bugzilla bug #719844.
@@ -731,11 +728,11 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
731728

732729
// The spec for Tf (setFont) says that 'size' specifies the font 'scale',
733730
// and in some docs this can be negative (inverted x-y axes).
734-
// We implement this condition with fontMatrix.
735731
if (size < 0) {
736732
size = -size;
737-
current.fontMatrix[0] *= -1;
738-
current.fontMatrix[3] *= -1;
733+
current.fontDirection = -1;
734+
} else {
735+
current.fontDirection = 1;
739736
}
740737

741738
this.current.font = fontObj;
@@ -788,14 +785,13 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
788785
applyTextTransforms: function CanvasGraphics_applyTextTransforms() {
789786
var ctx = this.ctx;
790787
var current = this.current;
791-
var textHScale = current.textHScale;
792-
var fontMatrix = current.fontMatrix || IDENTITY_MATRIX;
793-
794788
ctx.transform.apply(ctx, current.textMatrix);
795-
ctx.scale(1, -1);
796-
ctx.translate(current.x, -current.y - current.textRise);
797-
ctx.transform.apply(ctx, fontMatrix);
798-
ctx.scale(textHScale, 1);
789+
ctx.translate(current.x, current.y + current.textRise);
790+
if (current.fontDirection > 0) {
791+
ctx.scale(current.textHScale, -1);
792+
} else {
793+
ctx.scale(-current.textHScale, 1);
794+
}
799795
},
800796
createTextGeometry: function CanvasGraphics_createTextGeometry() {
801797
var geometry = {};
@@ -826,9 +822,8 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
826822
var fontSizeScale = current.fontSizeScale;
827823
var charSpacing = current.charSpacing;
828824
var wordSpacing = current.wordSpacing;
829-
var textHScale = current.textHScale;
830-
var fontMatrix = current.fontMatrix || IDENTITY_MATRIX;
831-
var textHScale2 = textHScale * fontMatrix[0];
825+
var textHScale = current.textHScale * current.fontDirection;
826+
var fontMatrix = current.fontMatrix || FONT_IDENTITY_MATRIX;
832827
var glyphsLength = glyphs.length;
833828
var textLayer = this.textLayer;
834829
var geom;
@@ -867,8 +862,8 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
867862
this.restore();
868863

869864
var transformed = Util.applyTransform([glyph.width, 0], fontMatrix);
870-
var width = transformed[0] * fontSize +
871-
Util.sign(current.fontMatrix[0]) * charSpacing;
865+
var width = (transformed[0] * fontSize + charSpacing) *
866+
current.fontDirection;
872867

873868
ctx.translate(width, 0);
874869
current.x += width * textHScale;
@@ -882,8 +877,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
882877

883878
var lineWidth = current.lineWidth;
884879
var a1 = current.textMatrix[0], b1 = current.textMatrix[1];
885-
var a2 = fontMatrix[0], b2 = fontMatrix[1];
886-
var scale = Math.sqrt((a1 * a1 + b1 * b1) * (a2 * a2 + b2 * b2));
880+
var scale = Math.sqrt(a1 * a1 + b1 * b1);
887881
if (scale == 0 || lineWidth == 0)
888882
lineWidth = this.getSinglePixelWidth();
889883
else
@@ -904,13 +898,13 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
904898
var glyph = glyphs[i];
905899
if (glyph === null) {
906900
// word break
907-
x += Util.sign(current.fontMatrix[0]) * wordSpacing;
901+
x += current.fontDirection * wordSpacing;
908902
continue;
909903
}
910904

911905
var character = glyph.fontChar;
912-
var charWidth = glyph.width * fontSize * 0.001 +
913-
Util.sign(current.fontMatrix[0]) * charSpacing;
906+
var charWidth = glyph.width * fontSize * current.fontMatrix[0] +
907+
charSpacing * current.fontDirection;
914908

915909
if (!glyph.disabled) {
916910
var scaledX = x / fontSizeScale;
@@ -943,7 +937,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
943937

944938
canvasWidth += charWidth;
945939
}
946-
current.x += x * textHScale2;
940+
current.x += x * textHScale;
947941
ctx.restore();
948942
}
949943

@@ -959,9 +953,9 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
959953
var current = this.current;
960954
var font = current.font;
961955
var fontSize = current.fontSize;
962-
var textHScale = current.textHScale;
963-
if (!font.coded)
964-
textHScale *= (current.fontMatrix || IDENTITY_MATRIX)[0];
956+
var textHScale = current.textHScale * (current.fontMatrix && !font.coded ?
957+
current.fontMatrix[0] : FONT_IDENTITY_MATRIX[0]) *
958+
current.fontDirection;
965959
var arrLength = arr.length;
966960
var textLayer = this.textLayer;
967961
var geom;
@@ -970,22 +964,15 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
970964

971965
if (textSelection) {
972966
ctx.save();
973-
// Type3 fonts - each glyph is a "mini-PDF" (see also showText)
974-
if (font.coded) {
975-
ctx.transform.apply(ctx, current.textMatrix);
976-
ctx.scale(1, -1);
977-
ctx.translate(current.x, -1 * current.y);
978-
ctx.scale(textHScale, 1);
979-
} else
980-
this.applyTextTransforms();
967+
this.applyTextTransforms();
981968
geom = this.createTextGeometry();
982969
ctx.restore();
983970
}
984971

985972
for (var i = 0; i < arrLength; ++i) {
986973
var e = arr[i];
987974
if (isNum(e)) {
988-
var spacingLength = -e * 0.001 * fontSize * textHScale;
975+
var spacingLength = -e * fontSize * textHScale;
989976
current.x += spacingLength;
990977

991978
if (textSelection)

src/evaluator.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1171,7 +1171,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
11711171
composite: composite,
11721172
wideChars: composite,
11731173
fixedPitch: false,
1174-
fontMatrix: dict.get('FontMatrix') || IDENTITY_MATRIX,
1174+
fontMatrix: dict.get('FontMatrix') || FONT_IDENTITY_MATRIX,
11751175
firstChar: firstChar || 0,
11761176
lastChar: lastChar || maxCharIndex,
11771177
bbox: descriptor.get('FontBBox'),

src/fonts.js

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ var PDF_GLYPH_SPACE_UNITS = 1000;
2929
// Until hinting is fully supported this constant can be used
3030
var HINTING_ENABLED = false;
3131

32+
var FONT_IDENTITY_MATRIX = [0.001, 0, 0, 0.001, 0, 0];
33+
3234
var FontFlags = {
3335
FixedPitch: 1,
3436
Serif: 2,
@@ -2214,6 +2216,19 @@ function fontCharsToUnicode(charCodes, font) {
22142216
return result;
22152217
}
22162218

2219+
function adjustWidths(properties) {
2220+
if (properties.fontMatrix[0] === FONT_IDENTITY_MATRIX[0]) {
2221+
return;
2222+
}
2223+
// adjusting width to fontMatrix scale
2224+
var scale = 0.001 / properties.fontMatrix[0];
2225+
var glyphsWidths = properties.widths;
2226+
for (var glyph in glyphsWidths) {
2227+
glyphsWidths[glyph] *= scale;
2228+
}
2229+
properties.defaultWidth *= scale;
2230+
}
2231+
22172232
/**
22182233
* 'Font' is the class the outside world should use, it encapsulate all the font
22192234
* decoding logics whatever type it is (assuming the font type is supported).
@@ -2260,7 +2275,6 @@ var Font = (function FontClosure() {
22602275
this.hasEncoding = properties.hasEncoding;
22612276

22622277
this.fontMatrix = properties.fontMatrix;
2263-
this.widthMultiplier = 1.0;
22642278
if (properties.type == 'Type3') {
22652279
this.encoding = properties.baseEncoding;
22662280
return;
@@ -2318,6 +2332,8 @@ var Font = (function FontClosure() {
23182332
var cff = (subtype == 'Type1C' || subtype == 'CIDFontType0C') ?
23192333
new CFFFont(file, properties) : new Type1Font(name, file, properties);
23202334

2335+
adjustWidths(properties);
2336+
23212337
// Wrap the CFF data inside an OTF font file
23222338
data = this.convert(name, cff, properties);
23232339
break;
@@ -2337,10 +2353,13 @@ var Font = (function FontClosure() {
23372353
}
23382354

23392355
this.data = data;
2356+
2357+
// Transfer some properties again that could change during font conversion
23402358
this.fontMatrix = properties.fontMatrix;
2341-
this.widthMultiplier = !properties.fontMatrix ? 1.0 :
2342-
1.0 / properties.fontMatrix[0];
2359+
this.widths = properties.widths;
2360+
this.defaultWidth = properties.defaultWidth;
23432361
this.encoding = properties.baseEncoding;
2362+
23442363
this.loading = true;
23452364
};
23462365

@@ -3931,7 +3950,7 @@ var Font = (function FontClosure() {
39313950
}
39323951
this.toFontChar = toFontChar;
39333952
}
3934-
var unitsPerEm = properties.unitsPerEm || 1000; // defaulting to 1000
3953+
var unitsPerEm = 1 / (properties.fontMatrix || FONT_IDENTITY_MATRIX)[0];
39353954

39363955
var fields = {
39373956
// PostScript Font Program
@@ -4170,7 +4189,7 @@ var Font = (function FontClosure() {
41704189
if (width)
41714190
break; // the non-zero width found
41724191
}
4173-
width = (width || this.defaultWidth) * this.widthMultiplier;
4192+
width = width || this.defaultWidth;
41744193
// Do not shadow the property here. See discussion:
41754194
// https://github.com/mozilla/pdf.js/pull/2127#discussion_r1662280
41764195
this._shadowWidth = width;
@@ -4251,7 +4270,7 @@ var Font = (function FontClosure() {
42514270
if (typeof unicodeChars === 'number')
42524271
unicodeChars = String.fromCharCode(unicodeChars);
42534272

4254-
width = (isNum(width) ? width : this.defaultWidth) * this.widthMultiplier;
4273+
width = isNum(width) ? width : this.defaultWidth;
42554274
disabled = this.unicodeIsEnabled ?
42564275
!this.unicodeIsEnabled[fontCharCode] : false;
42574276

@@ -4902,14 +4921,6 @@ var Type1Parser = function type1Parser() {
49024921
switch (token) {
49034922
case '/FontMatrix':
49044923
var matrix = readNumberArray(headerString, i + 1);
4905-
4906-
// The FontMatrix is in unitPerEm, so make it pixels
4907-
for (var j = 0, jj = matrix.length; j < jj; j++)
4908-
matrix[j] *= 1000;
4909-
4910-
// Make the angle into the right direction
4911-
matrix[2] *= -1;
4912-
49134924
properties.fontMatrix = matrix;
49144925
break;
49154926
case '/Encoding':
@@ -5185,6 +5196,7 @@ Type1Font.prototype = {
51855196
topDict.setByName('FamilyName', 3);
51865197
topDict.setByName('Weight', 4);
51875198
topDict.setByName('Encoding', null); // placeholder
5199+
topDict.setByName('FontMatrix', properties.fontMatrix);
51885200
topDict.setByName('FontBBox', properties.bbox);
51895201
topDict.setByName('charset', null); // placeholder
51905202
topDict.setByName('CharStrings', null); // placeholder
@@ -5459,8 +5471,7 @@ var CFFParser = (function CFFParserClosure() {
54595471

54605472
var fontMatrix = topDict.getByName('FontMatrix');
54615473
if (fontMatrix) {
5462-
// estimating unitsPerEM for the font
5463-
properties.unitsPerEm = 1 / fontMatrix[0];
5474+
properties.fontMatrix = fontMatrix;
54645475
}
54655476

54665477
var fontBBox = topDict.getByName('FontBBox');

0 commit comments

Comments
 (0)