Refactors showText: split type3, remove showSpacedText

This commit is contained in:
Yury Delendik 2014-05-23 13:36:54 -05:00
parent d2da73b8c4
commit d53dc2e7d6
3 changed files with 181 additions and 192 deletions

View File

@ -676,18 +676,31 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
break; break;
case OPS.showSpacedText: case OPS.showSpacedText:
var arr = args[0]; var arr = args[0];
var combinedGlyphs = [];
var arrLength = arr.length; var arrLength = arr.length;
for (i = 0; i < arrLength; ++i) { for (i = 0; i < arrLength; ++i) {
if (isString(arr[i])) { var arrItem = arr[i];
arr[i] = self.handleText(arr[i], stateManager.state); if (isString(arrItem)) {
Array.prototype.push.apply(combinedGlyphs,
self.handleText(arrItem, stateManager.state));
} else if (isNum(arrItem)) {
combinedGlyphs.push(arrItem);
} }
} }
args[0] = combinedGlyphs;
fn = OPS.showText;
break; break;
case OPS.nextLineShowText: case OPS.nextLineShowText:
operatorList.addOp(OPS.nextLine);
args[0] = self.handleText(args[0], stateManager.state); args[0] = self.handleText(args[0], stateManager.state);
fn = OPS.showText;
break; break;
case OPS.nextLineSetSpacingShowText: case OPS.nextLineSetSpacingShowText:
args[2] = self.handleText(args[2], stateManager.state); operatorList.addOp(OPS.nextLine);
operatorList.addOp(OPS.setWordSpacing, [args.shift()]);
operatorList.addOp(OPS.setCharSpacing, [args.shift()]);
args[0] = self.handleText(args[0], stateManager.state);
fn = OPS.showText;
break; break;
case OPS.setTextRenderingMode: case OPS.setTextRenderingMode:
stateManager.state.textRenderingMode = args[0]; stateManager.state.textRenderingMode = args[0];

View File

@ -352,6 +352,7 @@ var CanvasExtraState = (function CanvasExtraStateClosure() {
this.fontSize = 0; this.fontSize = 0;
this.fontSizeScale = 1; this.fontSizeScale = 1;
this.textMatrix = IDENTITY_MATRIX; this.textMatrix = IDENTITY_MATRIX;
this.textMatrixScale = 1;
this.fontMatrix = FONT_IDENTITY_MATRIX; this.fontMatrix = FONT_IDENTITY_MATRIX;
this.leading = 0; this.leading = 0;
// Current point (in user coordinates) // Current point (in user coordinates)
@ -1129,6 +1130,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
// Text // Text
beginText: function CanvasGraphics_beginText() { beginText: function CanvasGraphics_beginText() {
this.current.textMatrix = IDENTITY_MATRIX; this.current.textMatrix = IDENTITY_MATRIX;
this.current.textMatrixScale = 1;
this.current.x = this.current.lineX = 0; this.current.x = this.current.lineX = 0;
this.current.y = this.current.lineY = 0; this.current.y = this.current.lineY = 0;
}, },
@ -1233,6 +1235,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
}, },
setTextMatrix: function CanvasGraphics_setTextMatrix(a, b, c, d, e, f) { setTextMatrix: function CanvasGraphics_setTextMatrix(a, b, c, d, e, f) {
this.current.textMatrix = [a, b, c, d, e, f]; this.current.textMatrix = [a, b, c, d, e, f];
this.current.textMatrixScale = Math.sqrt(a * a + b * b);
this.current.x = this.current.lineX = 0; this.current.x = this.current.lineX = 0;
this.current.y = this.current.lineY = 0; this.current.y = this.current.lineY = 0;
@ -1240,24 +1243,13 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
nextLine: function CanvasGraphics_nextLine() { nextLine: function CanvasGraphics_nextLine() {
this.moveText(0, this.current.leading); this.moveText(0, this.current.leading);
}, },
applyTextTransforms: function CanvasGraphics_applyTextTransforms() {
var ctx = this.ctx;
var current = this.current;
ctx.transform.apply(ctx, current.textMatrix);
ctx.translate(current.x, current.y + current.textRise);
if (current.fontDirection > 0) {
ctx.scale(current.textHScale, -1);
} else {
ctx.scale(-current.textHScale, 1);
}
},
paintChar: function CanvasGraphics_paintChar(character, x, y) { paintChar: function CanvasGraphics_paintChar(character, x, y) {
var ctx = this.ctx; var ctx = this.ctx;
var current = this.current; var current = this.current;
var font = current.font; var font = current.font;
var fontSize = current.fontSize / current.fontSizeScale;
var textRenderingMode = current.textRenderingMode; var textRenderingMode = current.textRenderingMode;
var fontSize = current.fontSize / current.fontSizeScale;
var fillStrokeMode = textRenderingMode & var fillStrokeMode = textRenderingMode &
TextRenderingMode.FILL_STROKE_MASK; TextRenderingMode.FILL_STROKE_MASK;
var isAddToPathSet = !!(textRenderingMode & var isAddToPathSet = !!(textRenderingMode &
@ -1323,181 +1315,182 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
}, },
showText: function CanvasGraphics_showText(glyphs) { showText: function CanvasGraphics_showText(glyphs) {
var ctx = this.ctx;
var current = this.current; var current = this.current;
var font = current.font; var font = current.font;
var fontSize = current.fontSize; if (font.isType3Font) {
var fontSizeScale = current.fontSizeScale; return this.showType3Text(glyphs);
var charSpacing = current.charSpacing; }
var wordSpacing = current.wordSpacing;
var textHScale = current.textHScale * current.fontDirection;
var fontMatrix = current.fontMatrix || FONT_IDENTITY_MATRIX;
var glyphsLength = glyphs.length;
var vertical = font.vertical;
var defaultVMetrics = font.defaultVMetrics;
var i, glyph, width;
var fontSize = current.fontSize;
if (fontSize === 0) { if (fontSize === 0) {
return; return;
} }
// Type3 fonts - each glyph is a "mini-PDF" var ctx = this.ctx;
if (font.isType3Font) { var fontSizeScale = current.fontSizeScale;
ctx.save(); var charSpacing = current.charSpacing;
ctx.transform.apply(ctx, current.textMatrix); var wordSpacing = current.wordSpacing;
ctx.translate(current.x, current.y); var fontDirection = current.fontDirection;
var textHScale = current.textHScale * fontDirection;
var glyphsLength = glyphs.length;
var vertical = font.vertical;
var defaultVMetrics = font.defaultVMetrics;
var widthAdvanceScale = fontSize * current.fontMatrix[0];
ctx.scale(textHScale, 1); var simpleFillText =
current.textRenderingMode === TextRenderingMode.FILL &&
!font.disableFontFace;
for (i = 0; i < glyphsLength; ++i) { ctx.save();
glyph = glyphs[i]; ctx.transform.apply(ctx, current.textMatrix);
if (glyph === null) { ctx.translate(current.x, current.y + current.textRise);
// word break
this.ctx.translate(wordSpacing, 0);
current.x += wordSpacing * textHScale;
continue;
}
this.processingType3 = glyph; if (fontDirection > 0) {
this.save(); ctx.scale(textHScale, -1);
ctx.scale(fontSize, fontSize);
ctx.transform.apply(ctx, fontMatrix);
var operatorList = font.charProcOperatorList[glyph.operatorListId];
this.executeOperatorList(operatorList);
this.restore();
var transformed = Util.applyTransform([glyph.width, 0], fontMatrix);
width = ((transformed[0] * fontSize + charSpacing) *
current.fontDirection);
ctx.translate(width, 0);
current.x += width * textHScale;
}
ctx.restore();
this.processingType3 = null;
} else { } else {
ctx.save(); ctx.scale(textHScale, 1);
this.applyTextTransforms(); }
var lineWidth = current.lineWidth; var lineWidth = current.lineWidth;
var a1 = current.textMatrix[0], b1 = current.textMatrix[1]; var scale = current.textMatrixScale;
var scale = Math.sqrt(a1 * a1 + b1 * b1); if (scale === 0 || lineWidth === 0) {
if (scale === 0 || lineWidth === 0) { lineWidth = this.getSinglePixelWidth();
lineWidth = this.getSinglePixelWidth(); } else {
lineWidth /= scale;
}
if (fontSizeScale != 1.0) {
ctx.scale(fontSizeScale, fontSizeScale);
lineWidth /= fontSizeScale;
}
ctx.lineWidth = lineWidth;
var x = 0, i;
for (i = 0; i < glyphsLength; ++i) {
var glyph = glyphs[i];
if (glyph === null) {
// word break
x += fontDirection * wordSpacing;
continue;
} else if (isNum(glyph)) {
x += -glyph * fontSize * 0.001;
continue;
}
var restoreNeeded = false;
var character = glyph.fontChar;
var accent = glyph.accent;
var scaledX, scaledY, scaledAccentX, scaledAccentY;
var width = glyph.width;
if (vertical) {
var vmetric, vx, vy;
vmetric = glyph.vmetric || defaultVMetrics;
vx = glyph.vmetric ? vmetric[1] : width * 0.5;
vx = -vx * widthAdvanceScale;
vy = vmetric[2] * widthAdvanceScale;
width = vmetric ? -vmetric[0] : width;
scaledX = vx / fontSizeScale;
scaledY = (x + vy) / fontSizeScale;
} else { } else {
lineWidth /= scale; scaledX = x / fontSizeScale;
scaledY = 0;
} }
if (fontSizeScale != 1.0) { if (font.remeasure && width > 0 && this.isFontSubpixelAAEnabled) {
ctx.scale(fontSizeScale, fontSizeScale); // some standard fonts may not have the exact width, trying to
lineWidth /= fontSizeScale; // rescale per character
var measuredWidth = ctx.measureText(character).width * 1000 /
fontSize * fontSizeScale;
var characterScaleX = width / measuredWidth;
restoreNeeded = true;
ctx.save();
ctx.scale(characterScaleX, 1);
scaledX /= characterScaleX;
} }
ctx.lineWidth = lineWidth; if (simpleFillText && !accent) {
// common case
var x = 0; ctx.fillText(character, scaledX, scaledY);
for (i = 0; i < glyphsLength; ++i) { } else {
glyph = glyphs[i];
if (glyph === null) {
// word break
x += current.fontDirection * wordSpacing;
continue;
}
var restoreNeeded = false;
var character = glyph.fontChar;
var vmetric = glyph.vmetric || defaultVMetrics;
if (vertical) {
var vx = glyph.vmetric ? vmetric[1] : glyph.width * 0.5;
vx = -vx * fontSize * current.fontMatrix[0];
var vy = vmetric[2] * fontSize * current.fontMatrix[0];
}
width = vmetric ? -vmetric[0] : glyph.width;
var charWidth = width * fontSize * current.fontMatrix[0] +
charSpacing * current.fontDirection;
var accent = glyph.accent;
var scaledX, scaledY, scaledAccentX, scaledAccentY;
if (vertical) {
scaledX = vx / fontSizeScale;
scaledY = (x + vy) / fontSizeScale;
} else {
scaledX = x / fontSizeScale;
scaledY = 0;
}
if (font.remeasure && width > 0 && this.isFontSubpixelAAEnabled) {
// some standard fonts may not have the exact width, trying to
// rescale per character
var measuredWidth = ctx.measureText(character).width * 1000 /
current.fontSize * current.fontSizeScale;
var characterScaleX = width / measuredWidth;
restoreNeeded = true;
ctx.save();
ctx.scale(characterScaleX, 1);
scaledX /= characterScaleX;
if (accent) {
scaledAccentX /= characterScaleX;
}
}
this.paintChar(character, scaledX, scaledY); this.paintChar(character, scaledX, scaledY);
if (accent) { if (accent) {
scaledAccentX = scaledX + accent.offset.x / fontSizeScale; scaledAccentX = scaledX + accent.offset.x / fontSizeScale;
scaledAccentY = scaledY - accent.offset.y / fontSizeScale; scaledAccentY = scaledY - accent.offset.y / fontSizeScale;
this.paintChar(accent.fontChar, scaledAccentX, scaledAccentY); this.paintChar(accent.fontChar, scaledAccentX, scaledAccentY);
} }
x += charWidth;
if (restoreNeeded) {
ctx.restore();
}
} }
if (vertical) {
current.y -= x * textHScale; var charWidth = width * widthAdvanceScale + charSpacing * fontDirection;
} else { x += charWidth;
current.x += x * textHScale;
if (restoreNeeded) {
ctx.restore();
} }
ctx.restore();
} }
if (vertical) {
current.y -= x * textHScale;
} else {
current.x += x * textHScale;
}
ctx.restore();
}, },
showSpacedText: function CanvasGraphics_showSpacedText(arr) {
showType3Text: function CanvasGraphics_showType3Text(glyphs) {
// Type3 fonts - each glyph is a "mini-PDF"
var ctx = this.ctx;
var current = this.current; var current = this.current;
var font = current.font; var font = current.font;
var fontSize = current.fontSize; var fontSize = current.fontSize;
// TJ array's number is independent from fontMatrix var fontDirection = current.fontDirection;
var textHScale = current.textHScale * 0.001 * current.fontDirection; var charSpacing = current.charSpacing;
var arrLength = arr.length; var wordSpacing = current.wordSpacing;
var vertical = font.vertical; var textHScale = current.textHScale * fontDirection;
var fontMatrix = current.fontMatrix || FONT_IDENTITY_MATRIX;
var glyphsLength = glyphs.length;
var i, glyph, width;
for (var i = 0; i < arrLength; ++i) { if (fontSize === 0) {
var e = arr[i]; return;
if (isNum(e)) {
var spacingLength = -e * fontSize * textHScale;
if (vertical) {
current.y += spacingLength;
} else {
current.x += spacingLength;
}
} else {
this.showText(e);
}
} }
},
nextLineShowText: function CanvasGraphics_nextLineShowText(text) { ctx.save();
this.nextLine(); ctx.transform.apply(ctx, current.textMatrix);
this.showText(text); ctx.translate(current.x, current.y);
},
nextLineSetSpacingShowText: ctx.scale(textHScale, 1);
function CanvasGraphics_nextLineSetSpacingShowText(wordSpacing,
charSpacing, for (i = 0; i < glyphsLength; ++i) {
text) { glyph = glyphs[i];
this.setWordSpacing(wordSpacing); if (glyph === null) {
this.setCharSpacing(charSpacing); // word break
this.nextLineShowText(text); this.ctx.translate(wordSpacing, 0);
current.x += wordSpacing * textHScale;
continue;
} else if (isNum(glyph)) {
var spacingLength = -glyph * 0.001 * fontSize;
this.ctx.translate(spacingLength, 0);
current.x += spacingLength * textHScale;
continue;
}
this.processingType3 = glyph;
this.save();
ctx.scale(fontSize, fontSize);
ctx.transform.apply(ctx, fontMatrix);
var operatorList = font.charProcOperatorList[glyph.operatorListId];
this.executeOperatorList(operatorList);
this.restore();
var transformed = Util.applyTransform([glyph.width, 0], fontMatrix);
width = ((transformed[0] * fontSize + charSpacing) * fontDirection);
ctx.translate(width, 0);
current.x += width * textHScale;
}
ctx.restore();
this.processingType3 = null;
}, },
// Type3 fonts // Type3 fonts

View File

@ -246,27 +246,8 @@ var Stepper = (function StepperClosure() {
return d; return d;
} }
function glyphsToString(glyphs) {
var out = '';
for (var i = 0; i < glyphs.length; i++) {
if (glyphs[i] === null) {
out += ' ';
} else {
out += glyphs[i].fontChar;
}
}
return out;
}
var opMap = null; var opMap = null;
var glyphCommands = {
'showText': 0,
'showSpacedText': 0,
'nextLineShowText': 0,
'nextLineSetSpacingShowText': 2
};
function simplifyArgs(args) { function simplifyArgs(args) {
if (typeof args === 'string') { if (typeof args === 'string') {
var MAX_STRING_LENGTH = 75; var MAX_STRING_LENGTH = 75;
@ -367,24 +348,26 @@ var Stepper = (function StepperClosure() {
line.appendChild(c('td', i.toString())); line.appendChild(c('td', i.toString()));
var fn = opMap[operatorList.fnArray[i]]; var fn = opMap[operatorList.fnArray[i]];
var decArgs = args; var decArgs = args;
if (fn in glyphCommands) { if (fn === 'showText') {
var glyphIndex = glyphCommands[fn]; var glyphs = args[0];
var glyphs = args[glyphIndex]; var newArgs = [];
decArgs = args.slice(); var str = [];
var newArg; for (var j = 0; j < glyphs.length; j++) {
if (fn === 'showSpacedText') { var glyph = glyphs[j];
newArg = []; if (typeof glyph === 'object' && glyph !== null) {
for (var j = 0; j < glyphs.length; j++) { str.push(glyph.fontChar);
if (typeof glyphs[j] === 'number') { } else {
newArg.push(glyphs[j]); if (str.length > 0) {
} else { newArgs.push(str.join(''));
newArg.push(glyphsToString(glyphs[j])); str = [];
} }
newArgs.push(glyph); // null or number
} }
} else {
newArg = glyphsToString(glyphs);
} }
decArgs[glyphIndex] = newArg; if (str.length > 0) {
newArgs.push(str.join(''));
}
decArgs = [newArgs];
} }
line.appendChild(c('td', fn)); line.appendChild(c('td', fn));
line.appendChild(c('td', JSON.stringify(simplifyArgs(decArgs)))); line.appendChild(c('td', JSON.stringify(simplifyArgs(decArgs))));