nextLine: function canvasGraphicsNextLine() {
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 font = current.font;
++ 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, font.fontMatrix || IDENTITY_MATRIX);
++ ctx.transform.apply(ctx, fontMatrix);
+ ctx.scale(1 / textHScale, 1);
+ },
+ getTextGeometry: function canvasGetTextGeometry() {
+ var geom = {};
+ 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);
+ geom.x = bl[0];
+ geom.y = bl[1];
+ geom.hScale = tr[0] - bl[0];
+ geom.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}];
+ geom.spaceWidth = spaceGlyph[0].width;
+ return geom;
+ },
+ 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 current = this.current;
var font = current.font;
var charSpacing = current.charSpacing;
var wordSpacing = current.wordSpacing;
var textHScale = current.textHScale;
+ var fontMatrix = font.fontMatrix || IDENTITY_MATRIX;
+ var textHScale2 = textHScale * fontMatrix[0];
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) {
ctx.save();
ctx.transform.apply(ctx, current.textMatrix);
this.restore();
var transformed = Util.applyTransform([glyph.width, 0], fontMatrix);
- var charWidth = transformed[0] * fontSize + charSpacing;
- ctx.translate(charWidth, 0);
- current.x += charWidth;
+ var width = transformed[0] * fontSize + charSpacing;
+
+ ctx.translate(width, 0);
+ current.x += width * textHScale2;
- text.str += glyph.fontChar;
++ text.str += glyph.unicode;
+ text.length++;
- text.canvasWidth += charWidth;
++ text.canvasWidth += width;
}
ctx.restore();
} else {
}
var char = glyph.fontChar;
+ var charWidth = glyph.width * fontSize * 0.001 + charSpacing;
ctx.fillText(char, width, 0);
- width += glyph.width * fontSize * 0.001 + charSpacing;
+ width += charWidth;
- text.str += char === ' ' ? ' ' : char;
- // TODO actual characters can be extracted from the glyph.unicode
++ text.str += glyph.unicode === ' ' ? ' ' : glyph.unicode;
+ text.length++;
+ text.canvasWidth += charWidth;
}
-
- current.x += width;
+ current.x += width * textHScale2;
-
ctx.restore();
}
- },
+ if (textSelection)
+ this.pushTextDivs(text);
+
+ return text;
+ },
showSpacedText: function canvasGraphicsShowSpacedText(arr) {
var ctx = this.ctx;
var current = this.current;
var fontSize = current.fontSize;
- var textHScale = current.textHScale;
+ var textHScale2 = current.textHScale *
+ (current.font.fontMatrix || IDENTITY_MATRIX)[0];
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) {
var e = arr[i];
if (isNum(e)) {
- var spacingLength = -e * 0.001 * fontSize * textHScale;
- current.x -= e * 0.001 * fontSize * textHScale2;
++ 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)) {
- 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 {
malformed('TJ array element ' + e + ' is not string or num');
}