Browse Source

Refactors fake space heuristics for speed.

Yury Delendik 10 years ago
parent
commit
fa423cfab0
  1. 83
      src/core/evaluator.js

83
src/core/evaluator.js

@ -929,11 +929,17 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
lastAdvanceWidth: 0, lastAdvanceWidth: 0,
lastAdvanceHeight: 0, lastAdvanceHeight: 0,
textAdvanceScale: 0, textAdvanceScale: 0,
spaceWidth: 0,
fakeSpaceMin: Infinity,
fakeMultiSpaceMin: Infinity,
fakeMultiSpaceMax: -0,
textRunBreakAllowed: false,
transform: null, transform: null,
fontName: null fontName: null
}; };
var SPACE_FACTOR = 0.3; var SPACE_FACTOR = 0.3;
var MULTI_SPACE_FACTOR = 1.5; var MULTI_SPACE_FACTOR = 1.5;
var MULTI_SPACE_FACTOR_MAX = 4;
var self = this; var self = this;
var xref = this.xref; var xref = this.xref;
@ -1001,6 +1007,24 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
textContentItem.lastAdvanceWidth = 0; textContentItem.lastAdvanceWidth = 0;
textContentItem.lastAdvanceHeight = 0; textContentItem.lastAdvanceHeight = 0;
var spaceWidth = font.spaceWidth / 1000 * textState.fontSize;
if (spaceWidth) {
textContentItem.spaceWidth = spaceWidth;
textContentItem.fakeSpaceMin = spaceWidth * SPACE_FACTOR;
textContentItem.fakeMultiSpaceMin = spaceWidth * MULTI_SPACE_FACTOR;
textContentItem.fakeMultiSpaceMax =
spaceWidth * MULTI_SPACE_FACTOR_MAX;
// It's okay for monospace fonts to fake as much space as needed.
textContentItem.textRunBreakAllowed = !font.isMonospace;
} else {
textContentItem.spaceWidth = 0;
textContentItem.fakeSpaceMin = Infinity;
textContentItem.fakeMultiSpaceMin = Infinity;
textContentItem.fakeMultiSpaceMax = 0;
textContentItem.textRunBreakAllowed = false;
}
textContentItem.initialized = true; textContentItem.initialized = true;
return textContentItem; return textContentItem;
} }
@ -1076,8 +1100,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
var wordSpacing = textState.wordSpacing; var wordSpacing = textState.wordSpacing;
charSpacing += wordSpacing; charSpacing += wordSpacing;
if (wordSpacing > 0) { if (wordSpacing > 0) {
addFakeSpaces(wordSpacing * 1000 / textState.fontSize, addFakeSpaces(wordSpacing, textChunk.str);
textChunk.str);
} }
} }
@ -1105,21 +1128,20 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
textChunk.lastAdvanceHeight = height; textChunk.lastAdvanceHeight = height;
textChunk.height += Math.abs(height * textChunk.textAdvanceScale); textChunk.height += Math.abs(height * textChunk.textAdvanceScale);
} }
return textChunk; return textChunk;
} }
function addFakeSpaces(width, strBuf) { function addFakeSpaces(width, strBuf) {
var spaceWidth = textState.font.spaceWidth; if (width < textContentItem.fakeSpaceMin) {
if (spaceWidth <= 0) {
return; return;
} }
var fakeSpaces = width / spaceWidth; if (width < textContentItem.fakeMultiSpaceMin) {
if (fakeSpaces > MULTI_SPACE_FACTOR) {
fakeSpaces = Math.round(fakeSpaces);
while (fakeSpaces--) {
strBuf.push(' '); strBuf.push(' ');
return;
} }
} else if (fakeSpaces > SPACE_FACTOR) { var fakeSpaces = Math.round(width / textContentItem.spaceWidth);
while (fakeSpaces-- > 0) {
strBuf.push(' '); strBuf.push(' ');
} }
} }
@ -1177,16 +1199,18 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
// Optimization to treat same line movement as advance // Optimization to treat same line movement as advance
var isSameTextLine = !textState.font ? false : var isSameTextLine = !textState.font ? false :
((textState.font.vertical ? args[0] : args[1]) === 0); ((textState.font.vertical ? args[0] : args[1]) === 0);
if (isSameTextLine && textContentItem.initialized) { advance = args[0] - args[1];
if (isSameTextLine && textContentItem.initialized &&
advance > 0 &&
advance <= textContentItem.fakeMultiSpaceMax) {
textState.translateTextLineMatrix(args[0], args[1]); textState.translateTextLineMatrix(args[0], args[1]);
textContentItem.width += textContentItem.width +=
(args[0] - textContentItem.lastAdvanceWidth); (args[0] - textContentItem.lastAdvanceWidth);
textContentItem.height += textContentItem.height +=
(args[1] - textContentItem.lastAdvanceHeight); (args[1] - textContentItem.lastAdvanceHeight);
advance = (args[0] - args[1]) * 1000 / textState.fontSize; var diff = (args[0] - textContentItem.lastAdvanceWidth) -
if (advance > 0) { (args[1] - textContentItem.lastAdvanceHeight);
addFakeSpaces(advance, textContentItem.str); addFakeSpaces(diff, textContentItem.str);
}
break; break;
} }
@ -1229,9 +1253,8 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
if (typeof items[j] === 'string') { if (typeof items[j] === 'string') {
buildTextContentItem(items[j]); buildTextContentItem(items[j]);
} else { } else {
if (j === 0) {
ensureTextContentItem(); ensureTextContentItem();
}
// PDF Specification 5.3.2 states: // PDF Specification 5.3.2 states:
// The number is expressed in thousandths of a unit of text // The number is expressed in thousandths of a unit of text
// space. // space.
@ -1240,25 +1263,35 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
// In the default coordinate system, a positive adjustment // In the default coordinate system, a positive adjustment
// has the effect of moving the next glyph painted either to // has the effect of moving the next glyph painted either to
// the left or down by the given amount. // the left or down by the given amount.
advance = items[j]; advance = items[j] * textState.fontSize / 1000;
var val = advance * textState.fontSize / 1000; var breakTextRun = false;
if (textState.font.vertical) { if (textState.font.vertical) {
offset = val * offset = advance *
(textState.textHScale * textState.textMatrix[2] + (textState.textHScale * textState.textMatrix[2] +
textState.textMatrix[3]); textState.textMatrix[3]);
textState.translateTextMatrix(0, val); textState.translateTextMatrix(0, advance);
breakTextRun = textContentItem.textRunBreakAllowed &&
advance > textContentItem.fakeMultiSpaceMax;
if (!breakTextRun) {
// Value needs to be added to height to paint down. // Value needs to be added to height to paint down.
textContentItem.height += offset; textContentItem.height += offset;
}
} else { } else {
offset = val * ( advance = -advance;
offset = advance * (
textState.textHScale * textState.textMatrix[0] + textState.textHScale * textState.textMatrix[0] +
textState.textMatrix[1]); textState.textMatrix[1]);
textState.translateTextMatrix(-val, 0); textState.translateTextMatrix(advance, 0);
breakTextRun = textContentItem.textRunBreakAllowed &&
advance > textContentItem.fakeMultiSpaceMax;
if (!breakTextRun) {
// Value needs to be subtracted from width to paint left. // Value needs to be subtracted from width to paint left.
textContentItem.width -= offset; textContentItem.width += offset;
advance = -advance;
} }
if (advance > 0) { }
if (breakTextRun) {
flushTextContentItem();
} else if (advance > 0) {
addFakeSpaces(advance, textContentItem.str); addFakeSpaces(advance, textContentItem.str);
} }
} }

Loading…
Cancel
Save