[Pkg-javascript-commits] [pdf.js] 57/141: Build the text layer geometry on the worker.
David Prévot
taffit at moszumanska.debian.org
Sat Apr 19 22:40:30 UTC 2014
This is an automated email from the git hooks/post-receive script.
taffit pushed a commit to branch master
in repository pdf.js.
commit 5bd8a83c9bd7c23003b09e1cfd71422c6b083826
Author: Brendan Dahl <brendan.dahl at gmail.com>
Date: Wed Apr 9 16:44:07 2014 -0700
Build the text layer geometry on the worker.
---
src/core/core.js | 11 +-
src/core/evaluator.js | 473 ++++++++++++++++++++++++++++-----------------
src/core/fonts.js | 17 --
src/display/api.js | 35 +++-
src/display/canvas.js | 109 +----------
test/driver.js | 39 ++--
web/page_view.js | 27 +--
web/pdf_find_controller.js | 7 +-
web/text_layer_builder.js | 97 ++++------
web/viewer.css | 1 -
10 files changed, 402 insertions(+), 414 deletions(-)
diff --git a/src/core/core.js b/src/core/core.js
index 7138ce0..bff7ab5 100644
--- a/src/core/core.js
+++ b/src/core/core.js
@@ -233,8 +233,6 @@ var Page = (function PageClosure() {
var self = this;
- var textContentPromise = new LegacyPromise();
-
var pdfManager = this.pdfManager;
var contentStreamPromise = pdfManager.ensure(this, 'getContentStream',
[]);
@@ -247,7 +245,7 @@ var Page = (function PageClosure() {
var dataPromises = Promise.all([contentStreamPromise,
resourcesPromise]);
- dataPromises.then(function(data) {
+ return dataPromises.then(function(data) {
var contentStream = data[0];
var partialEvaluator = new PartialEvaluator(pdfManager, self.xref,
handler, self.pageIndex,
@@ -255,12 +253,9 @@ var Page = (function PageClosure() {
self.idCounters,
self.fontCache);
- var bidiTexts = partialEvaluator.getTextContent(contentStream,
- self.resources);
- textContentPromise.resolve(bidiTexts);
+ return partialEvaluator.getTextContent(contentStream,
+ self.resources);
});
-
- return textContentPromise;
},
getAnnotationsData: function Page_getAnnotationsData() {
diff --git a/src/core/evaluator.js b/src/core/evaluator.js
index 6e550fd..936cc18 100644
--- a/src/core/evaluator.js
+++ b/src/core/evaluator.js
@@ -21,16 +21,14 @@
MurmurHash3_64, Name, Parser, Pattern, PDFImage, PDFJS, serifFonts,
stdFontMap, symbolsFonts, getTilingPatternIR, warn, Util, Promise,
LegacyPromise, RefSetCache, isRef, TextRenderingMode, CMapFactory,
- OPS, UNSUPPORTED_FEATURES, UnsupportedManager */
+ OPS, UNSUPPORTED_FEATURES, UnsupportedManager, NormalizedUnicodes,
+ IDENTITY_MATRIX, reverseIfRtl */
'use strict';
var PartialEvaluator = (function PartialEvaluatorClosure() {
function PartialEvaluator(pdfManager, xref, handler, pageIndex,
uniquePrefix, idCounters, fontCache) {
- this.state = new EvalState();
- this.stateStack = [];
-
this.pdfManager = pdfManager;
this.xref = xref;
this.handler = handler;
@@ -96,7 +94,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
buildFormXObject: function PartialEvaluator_buildFormXObject(resources,
xobj, smask,
operatorList,
- state) {
+ initialState) {
var matrix = xobj.dict.get('Matrix');
var bbox = xobj.dict.get('BBox');
var group = xobj.dict.get('Group');
@@ -123,7 +121,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
operatorList.addOp(OPS.paintFormXObjectBegin, [matrix, bbox]);
this.getOperatorList(xobj, (xobj.dict.get('Resources') || resources),
- operatorList, state);
+ operatorList, initialState);
operatorList.addOp(OPS.paintFormXObjectEnd, []);
if (group) {
@@ -221,15 +219,15 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
},
handleSMask: function PartialEvaluator_handleSmask(smask, resources,
- operatorList) {
+ operatorList,
+ stateManager) {
var smaskContent = smask.get('G');
var smaskOptions = {
subtype: smask.get('S').name,
backdrop: smask.get('BC')
};
-
this.buildFormXObject(resources, smaskContent, smaskOptions,
- operatorList);
+ operatorList, stateManager.state.clone());
},
handleTilingType:
@@ -250,7 +248,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
handleSetFont:
function PartialEvaluator_handleSetFont(resources, fontArgs, fontRef,
- operatorList) {
+ operatorList, state) {
// TODO(mack): Not needed?
var fontName;
if (fontArgs) {
@@ -260,7 +258,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
var self = this;
var font = this.loadFont(fontName, fontRef, this.xref, resources,
operatorList);
- this.state.font = font;
+ state.font = font;
var loadedName = font.loadedName;
if (!font.sent) {
var fontData = font.translated.exportData();
@@ -276,10 +274,10 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
return loadedName;
},
- handleText: function PartialEvaluator_handleText(chars) {
- var font = this.state.font.translated;
+ handleText: function PartialEvaluator_handleText(chars, state) {
+ var font = state.font.translated;
var glyphs = font.charsToGlyphs(chars);
- var isAddToPathSet = !!(this.state.textRenderingMode &
+ var isAddToPathSet = !!(state.textRenderingMode &
TextRenderingMode.ADD_TO_PATH_FLAG);
if (font.data && (isAddToPathSet || PDFJS.disableFontFace)) {
for (var i = 0; i < glyphs.length; i++) {
@@ -302,7 +300,8 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
},
setGState: function PartialEvaluator_setGState(resources, gState,
- operatorList, xref) {
+ operatorList, xref,
+ stateManager) {
var self = this;
// TODO(mack): This should be rewritten so that this function returns
@@ -324,7 +323,8 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
break;
case 'Font':
var loadedName = self.handleSetFont(resources, null, value[0],
- operatorList);
+ operatorList,
+ stateManager.state);
operatorList.addDependency(loadedName);
gStateObj.push([key, [loadedName, value[1]]]);
break;
@@ -338,7 +338,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
}
var dict = xref.fetchIfRef(value);
if (isDict(dict)) {
- self.handleSMask(dict, resources, operatorList);
+ self.handleSMask(dict, resources, operatorList, stateManager);
gStateObj.push([key, true]);
} else {
warn('Unsupported SMask type');
@@ -495,7 +495,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
getOperatorList: function PartialEvaluator_getOperatorList(stream,
resources,
operatorList,
- evaluatorState) {
+ initialState) {
var self = this;
var xref = this.xref;
@@ -507,10 +507,8 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
resources = (resources || Dict.empty);
var xobjs = (resources.get('XObject') || Dict.empty);
var patterns = (resources.get('Pattern') || Dict.empty);
- var preprocessor = new EvaluatorPreprocessor(stream, xref);
- if (evaluatorState) {
- preprocessor.setState(evaluatorState);
- }
+ var stateManager = new StateManager(initialState || new EvalState());
+ var preprocessor = new EvaluatorPreprocessor(stream, xref, stateManager);
var promise = new LegacyPromise();
var operation;
@@ -570,9 +568,11 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
'XObject should have a Name subtype');
if ('Form' == type.name) {
+ stateManager.save();
self.buildFormXObject(resources, xobj, null, operatorList,
- preprocessor.getState());
+ stateManager.state.clone());
args = [];
+ stateManager.restore();
continue;
} else if ('Image' == type.name) {
self.buildPaintImageXObject(resources, xobj, false,
@@ -587,7 +587,8 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
case OPS.setFont:
// eagerly collect all fonts
var loadedName = self.handleSetFont(resources, args, null,
- operatorList);
+ operatorList,
+ stateManager.state);
operatorList.addDependency(loadedName);
args[0] = loadedName;
break;
@@ -602,37 +603,26 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
operatorList, cacheKey, imageCache);
args = [];
continue;
- case OPS.save:
- var old = this.state;
- this.stateStack.push(this.state);
- this.state = old.clone();
- break;
- case OPS.restore:
- var prev = this.stateStack.pop();
- if (prev) {
- this.state = prev;
- }
- break;
case OPS.showText:
- args[0] = this.handleText(args[0]);
+ args[0] = this.handleText(args[0], stateManager.state);
break;
case OPS.showSpacedText:
var arr = args[0];
var arrLength = arr.length;
for (var i = 0; i < arrLength; ++i) {
if (isString(arr[i])) {
- arr[i] = this.handleText(arr[i]);
+ arr[i] = this.handleText(arr[i], stateManager.state);
}
}
break;
case OPS.nextLineShowText:
- args[0] = this.handleText(args[0]);
+ args[0] = this.handleText(args[0], stateManager.state);
break;
case OPS.nextLineSetSpacingShowText:
- args[2] = this.handleText(args[2]);
+ args[2] = this.handleText(args[2], stateManager.state);
break;
case OPS.setTextRenderingMode:
- this.state.textRenderingMode = args[0];
+ stateManager.state.textRenderingMode = args[0];
break;
// Parse the ColorSpace data to a raw format.
case OPS.setFillColorSpace:
@@ -665,7 +655,8 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
}
var gState = extGState.get(dictName.name);
- self.setGState(resources, gState, operatorList, xref);
+ self.setGState(resources, gState, operatorList, xref,
+ stateManager);
args = [];
continue;
}
@@ -682,40 +673,165 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
},
getTextContent: function PartialEvaluator_getTextContent(stream, resources,
- textState) {
+ stateManager) {
- textState = (textState || new TextState());
+ stateManager = (stateManager || new StateManager(new TextState()));
- var bidiTexts = [];
+ var textContent = {
+ items: [],
+ styles: Object.create(null)
+ };
+ var bidiTexts = textContent.items;
var SPACE_FACTOR = 0.35;
var MULTI_SPACE_FACTOR = 1.5;
var self = this;
var xref = this.xref;
- function handleSetFont(fontName, fontRef) {
- return self.loadFont(fontName, fontRef, xref, resources, null);
- }
-
resources = (xref.fetchIfRef(resources) || Dict.empty);
+
// The xobj is parsed iff it's needed, e.g. if there is a `DO` cmd.
var xobjs = null;
var xobjsCache = {};
- var preprocessor = new EvaluatorPreprocessor(stream, xref);
+ var preprocessor = new EvaluatorPreprocessor(stream, xref, stateManager);
var res = resources;
- var chunkBuf = [];
- var font = null;
- var charSpace = 0, wordSpace = 0;
var operation;
+ var textState;
+
+ function newTextChunk() {
+ var font = textState.font;
+ if (!(font.loadedName in textContent.styles)) {
+ textContent.styles[font.loadedName] = {
+ fontFamily: font.fallbackName,
+ ascent: font.ascent,
+ descent: font.descent,
+ vertical: font.vertical
+ };
+ }
+ return {
+ str: '',
+ dir: null,
+ width: 0,
+ height: 0,
+ transform: null,
+ fontName: font.loadedName
+ };
+ }
+
+ function runBidi(textChunk) {
+ var bidiResult = PDFJS.bidi(textChunk.str, -1, textState.font.vertical);
+ textChunk.str = bidiResult.str;
+ textChunk.dir = bidiResult.dir;
+ return textChunk;
+ }
+
+ function handleSetFont(fontName, fontRef) {
+ var font = textState.font = self.loadFont(fontName, fontRef, xref,
+ resources, null).translated;
+ textState.fontMatrix = font.fontMatrix ? font.fontMatrix :
+ FONT_IDENTITY_MATRIX;
+ }
+
+ function buildTextGeometry(chars, textChunk) {
+ var font = textState.font;
+ textChunk = textChunk || newTextChunk();
+ if (!textChunk.transform) {
+ // 9.4.4 Text Space Details
+ var tsm = [textState.fontSize * textState.textHScale, 0,
+ 0, textState.fontSize,
+ 0, textState.textRise];
+ var trm = textChunk.transform = Util.transform(textState.ctm,
+ Util.transform(textState.textMatrix, tsm));
+ if (!font.vertical) {
+ textChunk.height = Math.sqrt(trm[2] * trm[2] + trm[3] * trm[3]);
+ } else {
+ textChunk.width = Math.sqrt(trm[0] * trm[0] + trm[1] * trm[1]);
+ }
+ }
+ var width = 0;
+ var height = 0;
+ var glyphs = font.charsToGlyphs(chars);
+ var defaultVMetrics = font.defaultVMetrics;
+ for (var i = 0; i < glyphs.length; i++) {
+ var glyph = glyphs[i];
+ if (!glyph) { // Previous glyph was a space.
+ continue;
+ }
+ var vMetricX = null;
+ var vMetricY = null;
+ var glyphWidth = null;
+ if (font.vertical) {
+ if (glyph.vmetric) {
+ glyphWidth = glyph.vmetric[0];
+ vMetricX = glyph.vmetric[1];
+ vMetricY = glyph.vmetric[2];
+ } else {
+ glyphWidth = glyph.width;
+ vMetricX = glyph.width * 0.5;
+ vMetricY = defaultVMetrics[2];
+ }
+ } else {
+ glyphWidth = glyph.width;
+ }
+
+ var glyphUnicode = glyph.unicode;
+ if (glyphUnicode in NormalizedUnicodes) {
+ glyphUnicode = NormalizedUnicodes[glyphUnicode];
+ }
+ glyphUnicode = reverseIfRtl(glyphUnicode);
+
+ // The following will calculate the x and y of the individual glyphs.
+ // if (font.vertical) {
+ // tsm[4] -= vMetricX * Math.abs(textState.fontSize) *
+ // textState.fontMatrix[0];
+ // tsm[5] -= vMetricY * textState.fontSize *
+ // textState.fontMatrix[0];
+ // }
+ // var trm = Util.transform(textState.textMatrix, tsm);
+ // var pt = Util.applyTransform([trm[4], trm[5]], textState.ctm);
+ // var x = pt[0];
+ // var y = pt[1];
+
+ var tx = 0;
+ var ty = 0;
+ if (!font.vertical) {
+ var w0 = glyphWidth * textState.fontMatrix[0];
+ tx = (w0 * textState.fontSize + textState.charSpacing) *
+ textState.textHScale;
+ width += tx;
+ } else {
+ var w1 = glyphWidth * textState.fontMatrix[0];
+ ty = w1 * textState.fontSize + textState.charSpacing;
+ height += ty;
+ }
+ textState.translateTextMatrix(tx, ty);
+
+ textChunk.str += glyphUnicode;
+ }
+
+ var a = textState.textLineMatrix[0];
+ var b = textState.textLineMatrix[1];
+ var scaleLineX = Math.sqrt(a * a + b * b);
+ a = textState.ctm[0];
+ b = textState.ctm[1];
+ var scaleCtmX = Math.sqrt(a * a + b * b);
+ if (!font.vertical) {
+ textChunk.width += width * scaleCtmX * scaleLineX;
+ } else {
+ textChunk.height += Math.abs(height * scaleCtmX * scaleLineX);
+ }
+ return textChunk;
+ }
+
while ((operation = preprocessor.read())) {
+ textState = stateManager.state;
var fn = operation.fn;
var args = operation.args;
switch (fn) {
- // TODO: Add support for SAVE/RESTORE and XFORM here.
case OPS.setFont:
- font = handleSetFont(args[0].name).translated;
+ handleSetFont(args[0].name);
textState.fontSize = args[1];
break;
case OPS.setTextRise:
@@ -728,64 +844,79 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
textState.leading = args[0];
break;
case OPS.moveText:
- textState.translateTextMatrix(args[0], args[1]);
+ textState.translateTextLineMatrix(args[0], args[1]);
+ textState.textMatrix = textState.textLineMatrix.slice();
break;
case OPS.setLeadingMoveText:
textState.leading = -args[1];
- textState.translateTextMatrix(args[0], args[1]);
+ textState.translateTextLineMatrix(args[0], args[1]);
+ textState.textMatrix = textState.textLineMatrix.slice();
break;
case OPS.nextLine:
- textState.translateTextMatrix(0, -textState.leading);
+ textState.carriageReturn();
break;
case OPS.setTextMatrix:
- textState.setTextMatrix(args[0], args[1],
- args[2], args[3], args[4], args[5]);
+ textState.setTextMatrix(args[0], args[1], args[2], args[3],
+ args[4], args[5]);
+ textState.setTextLineMatrix(args[0], args[1], args[2], args[3],
+ args[4], args[5]);
break;
case OPS.setCharSpacing:
- charSpace = args[0];
+ textState.charSpace = args[0];
break;
case OPS.setWordSpacing:
- wordSpace = args[0];
+ textState.wordSpace = args[0];
break;
case OPS.beginText:
- textState.initialiseTextObj();
+ textState.textMatrix = IDENTITY_MATRIX.slice();
+ textState.textLineMatrix = IDENTITY_MATRIX.slice();
break;
case OPS.showSpacedText:
var items = args[0];
+ var textChunk = newTextChunk();
for (var j = 0, jj = items.length; j < jj; j++) {
if (typeof items[j] === 'string') {
- chunkBuf.push(fontCharsToUnicode(items[j], font));
- } else if (items[j] < 0 && font.spaceWidth > 0) {
- var fakeSpaces = -items[j] / font.spaceWidth;
- if (fakeSpaces > MULTI_SPACE_FACTOR) {
- fakeSpaces = Math.round(fakeSpaces);
- while (fakeSpaces--) {
- chunkBuf.push(' ');
+ buildTextGeometry(items[j], textChunk);
+ } else {
+ var val = items[j] / 1000;
+ if (!textState.font.vertical) {
+ var offset = -val * textState.fontSize * textState.textHScale;
+ textState.translateTextMatrix(offset, 0);
+ textChunk.width += offset;
+ } else {
+ var offset = -val * textState.fontSize;
+ textState.translateTextMatrix(0, offset);
+ textChunk.height += offset;
+ }
+ if (items[j] < 0 && textState.font.spaceWidth > 0) {
+ var fakeSpaces = -items[j] / textState.font.spaceWidth;
+ if (fakeSpaces > MULTI_SPACE_FACTOR) {
+ fakeSpaces = Math.round(fakeSpaces);
+ while (fakeSpaces--) {
+ textChunk.str += ' ';
+ }
+ } else if (fakeSpaces > SPACE_FACTOR) {
+ textChunk.str += ' ';
}
- } else if (fakeSpaces > SPACE_FACTOR) {
- chunkBuf.push(' ');
}
}
}
+ bidiTexts.push(runBidi(textChunk));
break;
case OPS.showText:
- chunkBuf.push(fontCharsToUnicode(args[0], font));
+ bidiTexts.push(runBidi(buildTextGeometry(args[0])));
break;
case OPS.nextLineShowText:
- // For search, adding a extra white space for line breaks would be
- // better here, but that causes too much spaces in the
- // text-selection divs.
- chunkBuf.push(fontCharsToUnicode(args[0], font));
+ textState.carriageReturn();
+ bidiTexts.push(runBidi(buildTextGeometry(args[0])));
break;
case OPS.nextLineSetSpacingShowText:
- // Note comment in "'"
- chunkBuf.push(fontCharsToUnicode(args[2], font));
+ textState.wordSpacing = args[0];
+ textState.charSpacing = args[1];
+ textState.carriageReturn();
+ bidiTexts.push(runBidi(buildTextGeometry(args[2])));
break;
case OPS.paintXObject:
- // Set the chunk such that the following if won't add something
- // to the state.
- chunkBuf.length = 0;
-
if (args[0].code) {
break;
}
@@ -797,7 +928,8 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
var name = args[0].name;
if (xobjsCache.key === name) {
if (xobjsCache.texts) {
- Util.concatenateToArray(bidiTexts, xobjsCache.texts);
+ Util.concatenateToArray(bidiTexts, xobjsCache.texts.items);
+ Util.extendObj(textContent.styles, xobjsCache.texts.styles);
}
break;
}
@@ -818,11 +950,23 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
break;
}
- var formTexts = this.getTextContent(xobj,
- (xobj.dict.get('Resources') || resources), textState);
+ stateManager.save();
+ var matrix = xobj.dict.get('Matrix');
+ if (isArray(matrix) && matrix.length === 6) {
+ stateManager.transform(matrix);
+ }
+
+ var formTextContent = this.getTextContent(
+ xobj,
+ xobj.dict.get('Resources') || resources,
+ stateManager
+ );
+ Util.concatenateToArray(bidiTexts, formTextContent.items);
+ Util.extendObj(textContent.styles, formTextContent.styles);
+ stateManager.restore();
+
xobjsCache.key = name;
- xobjsCache.texts = formTexts;
- Util.concatenateToArray(bidiTexts, formTexts);
+ xobjsCache.texts = formTextContent;
break;
case OPS.setGState:
var dictName = args[0];
@@ -836,36 +980,14 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
for (var i = 0; i < gsState.length; i++) {
if (gsState[i] === 'Font') {
- font = handleSetFont(args[0].name).translated;
+ handleSetFont(args[0].name);
}
}
break;
- }
-
- if (chunkBuf.length > 0) {
- var chunk = chunkBuf.join('');
- var bidiText = PDFJS.bidi(chunk, -1, font.vertical);
- var renderParams = textState.calcRenderParams(preprocessor.ctm);
- var fontHeight = textState.fontSize * renderParams.vScale;
- var fontAscent = (font.ascent ? (font.ascent * fontHeight) :
- (font.descent ? ((1 + font.descent) * fontHeight) : fontHeight));
- bidiText.x = renderParams.renderMatrix[4] - (fontAscent *
- Math.sin(renderParams.angle));
- bidiText.y = renderParams.renderMatrix[5] + (fontAscent *
- Math.cos(renderParams.angle));
- if (bidiText.dir == 'ttb') {
- bidiText.x += renderParams.vScale / 2;
- bidiText.y -= renderParams.vScale;
- }
- bidiText.angle = renderParams.angle;
- bidiText.size = fontHeight;
- bidiTexts.push(bidiText);
-
- chunkBuf.length = 0;
- }
- }
+ } // switch
+ } // while
- return bidiTexts;
+ return textContent;
},
extractDataStructures: function
@@ -1467,64 +1589,89 @@ var OperatorList = (function OperatorListClosure() {
return OperatorList;
})();
+var StateManager = (function StateManagerClosure() {
+ function StateManager(initialState) {
+ this.state = initialState;
+ this.stateStack = [];
+ }
+ StateManager.prototype = {
+ save: function () {
+ var old = this.state;
+ this.stateStack.push(this.state);
+ this.state = old.clone();
+ },
+ restore: function () {
+ var prev = this.stateStack.pop();
+ if (prev) {
+ this.state = prev;
+ }
+ },
+ transform: function (args) {
+ this.state.ctm = Util.transform(this.state.ctm, args);
+ }
+ };
+ return StateManager;
+})();
+
var TextState = (function TextStateClosure() {
function TextState() {
+ this.ctm = new Float32Array(IDENTITY_MATRIX);
this.fontSize = 0;
- this.textMatrix = [1, 0, 0, 1, 0, 0];
- this.stateStack = [];
- //textState variables
+ this.font = null;
+ this.fontMatrix = FONT_IDENTITY_MATRIX;
+ this.textMatrix = IDENTITY_MATRIX.slice();
+ this.textLineMatrix = IDENTITY_MATRIX.slice();
+ this.charSpacing = 0;
+ this.wordSpacing = 0;
this.leading = 0;
this.textHScale = 1;
this.textRise = 0;
}
TextState.prototype = {
- initialiseTextObj: function TextState_initialiseTextObj() {
- var m = this.textMatrix;
- m[0] = 1; m[1] = 0; m[2] = 0; m[3] = 1; m[4] = 0; m[5] = 0;
- },
setTextMatrix: function TextState_setTextMatrix(a, b, c, d, e, f) {
var m = this.textMatrix;
m[0] = a; m[1] = b; m[2] = c; m[3] = d; m[4] = e; m[5] = f;
},
+ setTextLineMatrix: function TextState_setTextMatrix(a, b, c, d, e, f) {
+ var m = this.textLineMatrix;
+ m[0] = a; m[1] = b; m[2] = c; m[3] = d; m[4] = e; m[5] = f;
+ },
translateTextMatrix: function TextState_translateTextMatrix(x, y) {
var m = this.textMatrix;
m[4] = m[0] * x + m[2] * y + m[4];
m[5] = m[1] * x + m[3] * y + m[5];
},
- calcRenderParams: function TextState_calcRenderingParams(cm) {
- var tm = this.textMatrix;
- var a = this.fontSize;
- var b = a * this.textHScale;
- var c = this.textRise;
- var vScale = Math.sqrt((tm[2] * tm[2]) + (tm[3] * tm[3]));
- var angle = Math.atan2(tm[1], tm[0]);
- var m0 = tm[0] * cm[0] + tm[1] * cm[2];
- var m1 = tm[0] * cm[1] + tm[1] * cm[3];
- var m2 = tm[2] * cm[0] + tm[3] * cm[2];
- var m3 = tm[2] * cm[1] + tm[3] * cm[3];
- var m4 = tm[4] * cm[0] + tm[5] * cm[2] + cm[4];
- var m5 = tm[4] * cm[1] + tm[5] * cm[3] + cm[5];
- var renderMatrix = [
- b * m0,
- b * m1,
- a * m2,
- a * m3,
- c * m2 + m4,
- c * m3 + m5
- ];
- return {
- renderMatrix: renderMatrix,
- vScale: vScale,
- angle: angle
- };
+ translateTextLineMatrix: function TextState_translateTextMatrix(x, y) {
+ var m = this.textLineMatrix;
+ m[4] = m[0] * x + m[2] * y + m[4];
+ m[5] = m[1] * x + m[3] * y + m[5];
},
+ calcRenderMatrix: function TextState_calcRendeMatrix(ctm) {
+ // 9.4.4 Text Space Details
+ var tsm = [this.fontSize * this.textHScale, 0,
+ 0, this.fontSize,
+ 0, this.textRise];
+ return Util.transform(ctm, Util.transform(this.textMatrix, tsm));
+ },
+ carriageReturn: function TextState_carriageReturn() {
+ this.translateTextLineMatrix(0, -this.leading);
+ this.textMatrix = this.textLineMatrix.slice();
+ },
+ clone: function TextState_clone() {
+ var clone = Object.create(this);
+ clone.textMatrix = this.textMatrix.slice();
+ clone.textLineMatrix = this.textLineMatrix.slice();
+ clone.fontMatrix = this.fontMatrix.slice();
+ return clone;
+ }
};
return TextState;
})();
var EvalState = (function EvalStateClosure() {
function EvalState() {
+ this.ctm = new Float32Array(IDENTITY_MATRIX);
this.font = null;
this.textRenderingMode = TextRenderingMode.FILL;
}
@@ -1650,17 +1797,16 @@ var EvaluatorPreprocessor = (function EvaluatorPreprocessor() {
'null': null
};
- function EvaluatorPreprocessor(stream, xref) {
+ function EvaluatorPreprocessor(stream, xref, stateManager) {
// TODO(mduan): pass array of knownCommands rather than OP_MAP
// dictionary
this.parser = new Parser(new Lexer(stream, OP_MAP), false, xref);
- this.ctm = new Float32Array([1, 0, 0, 1, 0, 0]);
- this.savedStates = [];
+ this.stateManager = stateManager;
}
EvaluatorPreprocessor.prototype = {
get savedStatesDepth() {
- return this.savedStates.length;
+ return this.stateManager.stateStack.length;
},
read: function EvaluatorPreprocessor_read() {
@@ -1717,38 +1863,17 @@ var EvaluatorPreprocessor = (function EvaluatorPreprocessor() {
}
},
- getState: function EvaluatorPreprocessor_getState() {
- return {
- ctm: this.ctm
- };
- },
-
- setState: function EvaluatorPreprocessor_setState(state) {
- this.ctm = state.ctm;
- },
-
preprocessCommand:
function EvaluatorPreprocessor_preprocessCommand(fn, args) {
switch (fn | 0) {
case OPS.save:
- this.savedStates.push(this.getState());
+ this.stateManager.save();
break;
case OPS.restore:
- var previousState = this.savedStates.pop();
- if (previousState) {
- this.setState(previousState);
- }
+ this.stateManager.restore();
break;
case OPS.transform:
- var ctm = this.ctm;
- var m = new Float32Array(6);
- m[0] = ctm[0] * args[0] + ctm[2] * args[1];
- m[1] = ctm[1] * args[0] + ctm[3] * args[1];
- m[2] = ctm[0] * args[2] + ctm[2] * args[3];
- m[3] = ctm[1] * args[2] + ctm[3] * args[3];
- m[4] = ctm[0] * args[4] + ctm[2] * args[5] + ctm[4];
- m[5] = ctm[1] * args[4] + ctm[3] * args[5] + ctm[5];
- this.ctm = m;
+ this.stateManager.transform(args);
break;
}
}
diff --git a/src/core/fonts.js b/src/core/fonts.js
index ffcd030..3da4cae 100644
--- a/src/core/fonts.js
+++ b/src/core/fonts.js
@@ -2102,23 +2102,6 @@ function reverseIfRtl(chars) {
return s;
}
-function fontCharsToUnicode(charCodes, font) {
- var glyphs = font.charsToGlyphs(charCodes);
- var result = '';
- for (var i = 0, ii = glyphs.length; i < ii; i++) {
- var glyph = glyphs[i];
- if (!glyph) {
- continue;
- }
- var glyphUnicode = glyph.unicode;
- if (glyphUnicode in NormalizedUnicodes) {
- glyphUnicode = NormalizedUnicodes[glyphUnicode];
- }
- result += reverseIfRtl(glyphUnicode);
- }
- return result;
-}
-
function adjustWidths(properties) {
if (properties.fontMatrix[0] === FONT_IDENTITY_MATRIX[0]) {
return;
diff --git a/src/display/api.js b/src/display/api.js
index 320f83d..aff296f 100644
--- a/src/display/api.js
+++ b/src/display/api.js
@@ -340,15 +340,33 @@ var PDFDocumentProxy = (function PDFDocumentProxyClosure() {
})();
/**
+ * Page text content.
+ *
+ * @typedef {Object} TextContent
+ * @property {array} items - array of {@link TextItem}
+ * @property {Object} styles - {@link TextStyles} objects, indexed by font
+ * name.
+ */
+
+/**
* Page text content part.
*
- * @typedef {Object} BidiText
+ * @typedef {Object} TextItem
* @property {string} str - text content.
* @property {string} dir - text direction: 'ttb', 'ltr' or 'rtl'.
- * @property {number} x - x position of the text on the page.
- * @property {number} y - y position of the text on the page.
- * @property {number} angle - text rotation.
- * @property {number} size - font size.
+ * @property {array} transform - transformation matrix.
+ * @property {number} width - width in device space.
+ * @property {number} height - height in device space.
+ * @property {string} fontName - font name used by pdf.js for converted font.
+ */
+
+/**
+ * Text style
+ * @typedef {Object} TextStyle
+ * @property {number} ascent - font ascent.
+ * @property {number} descent - font descent.
+ * @property {boolean} vertical - text is in vertical mode.
+ * @property {string} fontFamily - possible font family
*/
/**
@@ -522,8 +540,8 @@ var PDFPageProxy = (function PDFPageProxyClosure() {
return renderTask;
},
/**
- * @return {Promise} That is resolved with the array of {@link BidiText}
- * objects that represent the page text content.
+ * @return {Promise} That is resolved a {@link TextContent}
+ * object that represent the page text content.
*/
getTextContent: function PDFPageProxy_getTextContent() {
var promise = new PDFJS.LegacyPromise();
@@ -1210,8 +1228,7 @@ var InternalRenderTask = (function InternalRenderTaskClosure() {
var params = this.params;
this.gfx = new CanvasGraphics(params.canvasContext, this.commonObjs,
- this.objs, params.textLayer,
- params.imageLayer);
+ this.objs, params.imageLayer);
this.gfx.beginDrawing(params.viewport, transparency);
this.operatorListIdx = 0;
diff --git a/src/display/canvas.js b/src/display/canvas.js
index bf247df..55d11dc 100644
--- a/src/display/canvas.js
+++ b/src/display/canvas.js
@@ -402,7 +402,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
// before it stops and shedules a continue of execution.
var EXECUTION_TIME = 15;
- function CanvasGraphics(canvasCtx, commonObjs, objs, textLayer, imageLayer) {
+ function CanvasGraphics(canvasCtx, commonObjs, objs, imageLayer) {
this.ctx = canvasCtx;
this.current = new CanvasExtraState();
this.stateStack = [];
@@ -412,7 +412,6 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
this.xobjs = null;
this.commonObjs = commonObjs;
this.objs = objs;
- this.textLayer = textLayer;
this.imageLayer = imageLayer;
this.groupStack = [];
this.processingType3 = null;
@@ -718,9 +717,6 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
this.baseTransform = this.ctx.mozCurrentTransform.slice();
- if (this.textLayer) {
- this.textLayer.beginLayout();
- }
if (this.imageLayer) {
this.imageLayer.beginLayout();
}
@@ -802,9 +798,6 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
CachedCanvases.clear();
WebGLUtils.clear();
- if (this.textLayer) {
- this.textLayer.endLayout();
- }
if (this.imageLayer) {
this.imageLayer.endLayout();
}
@@ -1234,33 +1227,6 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
ctx.scale(-current.textHScale, 1);
}
},
- createTextGeometry: function CanvasGraphics_createTextGeometry() {
- var geometry = {};
- var ctx = this.ctx;
- var font = this.current.font;
- var ctxMatrix = ctx.mozCurrentTransform;
- var a = ctxMatrix[0], b = ctxMatrix[1], c = ctxMatrix[2];
- var d = ctxMatrix[3], e = ctxMatrix[4], f = ctxMatrix[5];
- var sx = (a >= 0) ?
- Math.sqrt((a * a) + (b * b)) : -Math.sqrt((a * a) + (b * b));
- var sy = (d >= 0) ?
- Math.sqrt((c * c) + (d * d)) : -Math.sqrt((c * c) + (d * d));
- var angle = Math.atan2(b, a);
- var x = e;
- var y = f;
- geometry.x = x;
- geometry.y = y;
- geometry.hScale = sx;
- geometry.vScale = sy;
- geometry.angle = angle;
- geometry.spaceWidth = font.spaceWidth;
- geometry.fontName = font.loadedName;
- geometry.fontFamily = font.fallbackName;
- geometry.fontSize = this.current.fontSize;
- geometry.ascent = font.ascent;
- geometry.descent = font.descent;
- return geometry;
- },
paintChar: function (character, x, y) {
var ctx = this.ctx;
@@ -1332,7 +1298,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
return shadow(this, 'isFontSubpixelAAEnabled', enabled);
},
- showText: function CanvasGraphics_showText(glyphs, skipTextSelection) {
+ showText: function CanvasGraphics_showText(glyphs) {
var ctx = this.ctx;
var current = this.current;
var font = current.font;
@@ -1343,24 +1309,11 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
var textHScale = current.textHScale * current.fontDirection;
var fontMatrix = current.fontMatrix || FONT_IDENTITY_MATRIX;
var glyphsLength = glyphs.length;
- var textLayer = this.textLayer;
- var geom;
- var textSelection = textLayer && !skipTextSelection ? true : false;
- var canvasWidth = 0.0;
var vertical = font.vertical;
var defaultVMetrics = font.defaultVMetrics;
if (fontSize === 0) {
- if (textSelection) {
- geom = this.createTextGeometry();
- geom.canvasWidth = canvasWidth;
- if (vertical) {
- var VERTICAL_TEXT_ROTATION = Math.PI / 2;
- geom.angle += VERTICAL_TEXT_ROTATION;
- }
- this.textLayer.appendText(geom);
- }
- return canvasWidth;
+ return;
}
// Type3 fonts - each glyph is a "mini-PDF"
@@ -1371,12 +1324,6 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
ctx.scale(textHScale, 1);
- if (textSelection) {
- this.save();
- ctx.scale(1, -1);
- geom = this.createTextGeometry();
- this.restore();
- }
for (var i = 0; i < glyphsLength; ++i) {
var glyph = glyphs[i];
@@ -1400,8 +1347,6 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
ctx.translate(width, 0);
current.x += width * textHScale;
-
- canvasWidth += width;
}
ctx.restore();
this.processingType3 = null;
@@ -1418,10 +1363,6 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
lineWidth /= scale;
}
- if (textSelection) {
- geom = this.createTextGeometry();
- }
-
if (fontSizeScale != 1.0) {
ctx.scale(fontSizeScale, fontSizeScale);
lineWidth /= fontSizeScale;
@@ -1485,8 +1426,6 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
x += charWidth;
- canvasWidth += charWidth;
-
if (restoreNeeded) {
ctx.restore();
}
@@ -1498,17 +1437,6 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
}
ctx.restore();
}
-
- if (textSelection) {
- geom.canvasWidth = canvasWidth;
- if (vertical) {
- var VERTICAL_TEXT_ROTATION = Math.PI / 2;
- geom.angle += VERTICAL_TEXT_ROTATION;
- }
- this.textLayer.appendText(geom);
- }
-
- return canvasWidth;
},
showSpacedText: function CanvasGraphics_showSpacedText(arr) {
var ctx = this.ctx;
@@ -1518,19 +1446,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
// TJ array's number is independent from fontMatrix
var textHScale = current.textHScale * 0.001 * current.fontDirection;
var arrLength = arr.length;
- var textLayer = this.textLayer;
- var geom;
- var canvasWidth = 0.0;
- var textSelection = textLayer ? true : false;
var vertical = font.vertical;
- var spacingAccumulator = 0;
-
- if (textSelection) {
- ctx.save();
- this.applyTextTransforms();
- geom = this.createTextGeometry();
- ctx.restore();
- }
for (var i = 0; i < arrLength; ++i) {
var e = arr[i];
@@ -1542,26 +1458,9 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
current.x += spacingLength;
}
- if (textSelection) {
- spacingAccumulator += spacingLength;
- }
} else {
- var shownCanvasWidth = this.showText(e, true);
-
- if (textSelection) {
- canvasWidth += spacingAccumulator + shownCanvasWidth;
- spacingAccumulator = 0;
- }
- }
- }
-
- if (textSelection) {
- geom.canvasWidth = canvasWidth;
- if (vertical) {
- var VERTICAL_TEXT_ROTATION = Math.PI / 2;
- geom.angle += VERTICAL_TEXT_ROTATION;
+ this.showText(e);
}
- this.textLayer.appendText(geom);
}
},
nextLineShowText: function CanvasGraphics_nextLineShowText(text) {
diff --git a/test/driver.js b/test/driver.js
index f171c36..ccc38f8 100644
--- a/test/driver.js
+++ b/test/driver.js
@@ -203,38 +203,39 @@ function SimpleTextLayerBuilder(ctx, viewport) {
this.textCounter = 0;
}
SimpleTextLayerBuilder.prototype = {
- beginLayout: function SimpleTextLayerBuilder_BeginLayout() {
- this.ctx.save();
- },
- endLayout: function SimpleTextLayerBuilder_EndLayout() {
- this.ctx.restore();
- },
- appendText: function SimpleTextLayerBuilder_AppendText(geom) {
+ appendText: function SimpleTextLayerBuilder_AppendText(geom, styles) {
+ var style = styles[geom.fontName];
var ctx = this.ctx, viewport = this.viewport;
- // vScale and hScale already contain the scaling to pixel units
- var fontHeight = geom.fontSize * Math.abs(geom.vScale);
- var fontAscent = (geom.ascent ? geom.ascent * fontHeight :
- (geom.descent ? (1 + geom.descent) * fontHeight : fontHeight));
+ var tx = PDFJS.Util.transform(this.viewport.transform, geom.transform);
+ var angle = Math.atan2(tx[1], tx[0]);
+ var fontHeight = Math.sqrt((tx[2] * tx[2]) + (tx[3] * tx[3]));
+ var fontAscent = (style.ascent ? style.ascent * fontHeight :
+ (style.descent ? (1 + style.descent) * fontHeight : fontHeight));
ctx.save();
ctx.beginPath();
ctx.strokeStyle = 'red';
ctx.fillStyle = 'yellow';
- ctx.translate(geom.x + (fontAscent * Math.sin(geom.angle)),
- geom.y - (fontAscent * Math.cos(geom.angle)));
- ctx.rotate(geom.angle);
- ctx.rect(0, 0, geom.canvasWidth * Math.abs(geom.hScale), fontHeight);
+ ctx.translate(tx[4] + (fontAscent * Math.sin(angle)),
+ tx[5] - (fontAscent * Math.cos(angle)));
+ ctx.rotate(angle);
+ ctx.rect(0, 0, geom.width * viewport.scale, geom.height * viewport.scale);
ctx.stroke();
ctx.fill();
ctx.restore();
- var textContent = this.textContent[this.textCounter].str;
- ctx.font = fontHeight + 'px ' + geom.fontFamily;
+ ctx.font = fontHeight + 'px ' + style.fontFamily;
ctx.fillStyle = 'black';
- ctx.fillText(textContent, geom.x, geom.y);
+ ctx.fillText(geom.str, tx[4], tx[5]);
this.textCounter++;
},
setTextContent: function SimpleTextLayerBuilder_SetTextContent(textContent) {
- this.textContent = textContent;
+ this.ctx.save();
+ var textItems = textContent.items;
+ for (var i = 0; i < textItems.length; i++) {
+ this.appendText(textItems[i], textContent.styles);
+ }
+
+ this.ctx.restore();
}
};
diff --git a/web/page_view.js b/web/page_view.js
index ac69307..d961079 100644
--- a/web/page_view.js
+++ b/web/page_view.js
@@ -485,8 +485,8 @@ var PageView = function pageView(container, id, scale,
if (!PDFJS.disableTextLayer) {
textLayerDiv = document.createElement('div');
textLayerDiv.className = 'textLayer';
- textLayerDiv.style.width = canvas.width + 'px';
- textLayerDiv.style.height = canvas.height + 'px';
+ textLayerDiv.style.width = canvas.style.width;
+ textLayerDiv.style.height = canvas.style.height;
div.appendChild(textLayerDiv);
}
var textLayer = this.textLayer =
@@ -503,14 +503,6 @@ var PageView = function pageView(container, id, scale,
if (outputScale.scaled) {
ctx.scale(outputScale.sx, outputScale.sy);
}
- if (outputScale.scaled && textLayerDiv) {
- var cssScale = 'scale(' + (1 / outputScale.sx) + ', ' +
- (1 / outputScale.sy) + ')';
- CustomStyle.setProp('transform' , textLayerDiv, cssScale);
- CustomStyle.setProp('transformOrigin' , textLayerDiv, '0% 0%');
- textLayerDiv.dataset._scaleX = outputScale.sx;
- textLayerDiv.dataset._scaleY = outputScale.sy;
- }
// Rendering area
@@ -600,20 +592,19 @@ var PageView = function pageView(container, id, scale,
this.renderTask.promise.then(
function pdfPageRenderCallback() {
pageViewDrawCallback(null);
+ if (textLayer) {
+ self.getTextContent().then(
+ function textContentResolved(textContent) {
+ textLayer.setTextContent(textContent);
+ }
+ );
+ }
},
function pdfPageRenderError(error) {
pageViewDrawCallback(error);
}
);
- if (textLayer) {
- this.getTextContent().then(
- function textContentResolved(textContent) {
- textLayer.setTextContent(textContent);
- }
- );
- }
-
setupAnnotations(div, pdfPage, this.viewport);
div.setAttribute('data-loaded', true);
};
diff --git a/web/pdf_find_controller.js b/web/pdf_find_controller.js
index 337622c..87c8f39 100644
--- a/web/pdf_find_controller.js
+++ b/web/pdf_find_controller.js
@@ -145,11 +145,12 @@ var PDFFindController = {
var self = this;
function extractPageText(pageIndex) {
self.pdfPageSource.pages[pageIndex].getTextContent().then(
- function textContentResolved(bidiTexts) {
+ function textContentResolved(textContent) {
+ var textItems = textContent.items;
var str = '';
- for (var i = 0; i < bidiTexts.length; i++) {
- str += bidiTexts[i].str;
+ for (var i = 0; i < textItems.length; i++) {
+ str += textItems[i].str;
}
// Store the pageContent as a string.
diff --git a/web/text_layer_builder.js b/web/text_layer_builder.js
index 6829b5e..40aa857 100644
--- a/web/text_layer_builder.js
+++ b/web/text_layer_builder.js
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-/* globals CustomStyle, PDFFindController, scrollIntoView */
+/* globals CustomStyle, PDFFindController, scrollIntoView, PDFJS */
'use strict';
@@ -40,6 +40,7 @@ var TextLayerBuilder = function textLayerBuilder(options) {
this.lastScrollSource = options.lastScrollSource;
this.viewport = options.viewport;
this.isViewerInPresentationMode = options.isViewerInPresentationMode;
+ this.textDivs = [];
if (typeof PDFFindController === 'undefined') {
window.PDFFindController = null;
@@ -49,16 +50,6 @@ var TextLayerBuilder = function textLayerBuilder(options) {
this.lastScrollSource = null;
}
- this.beginLayout = function textLayerBuilderBeginLayout() {
- this.textDivs = [];
- this.renderingDone = false;
- };
-
- this.endLayout = function textLayerBuilderEndLayout() {
- this.layoutDone = true;
- this.insertDivContent();
- };
-
this.renderLayer = function textLayerBuilderRenderLayer() {
var textDivs = this.textDivs;
var canvas = document.createElement('canvas');
@@ -118,70 +109,56 @@ var TextLayerBuilder = function textLayerBuilder(options) {
}
};
- this.appendText = function textLayerBuilderAppendText(geom) {
+ this.appendText = function textLayerBuilderAppendText(geom, styles) {
+ var style = styles[geom.fontName];
var textDiv = document.createElement('div');
+ if (!/\S/.test(geom.str)) {
+ textDiv.dataset.isWhitespace = true;
+ return;
+ }
+ var tx = PDFJS.Util.transform(this.viewport.transform, geom.transform);
+ var angle = Math.atan2(tx[1], tx[0]);
+ if (style.vertical) {
+ angle += Math.PI / 2;
+ }
+ var fontHeight = Math.sqrt((tx[2] * tx[2]) + (tx[3] * tx[3]));
+ var fontAscent = (style.ascent ? style.ascent * fontHeight :
+ (style.descent ? (1 + style.descent) * fontHeight : fontHeight));
- // vScale and hScale already contain the scaling to pixel units
- var fontHeight = geom.fontSize * Math.abs(geom.vScale);
- textDiv.dataset.canvasWidth = geom.canvasWidth * Math.abs(geom.hScale);
- textDiv.dataset.fontName = geom.fontName;
- textDiv.dataset.angle = geom.angle * (180 / Math.PI);
-
+ textDiv.style.position = 'absolute';
+ textDiv.style.left = (tx[4] + (fontAscent * Math.sin(angle))) + 'px';
+ textDiv.style.top = (tx[5] - (fontAscent * Math.cos(angle))) + 'px';
textDiv.style.fontSize = fontHeight + 'px';
- textDiv.style.fontFamily = geom.fontFamily;
- var fontAscent = (geom.ascent ? geom.ascent * fontHeight :
- (geom.descent ? (1 + geom.descent) * fontHeight : fontHeight));
- textDiv.style.left = (geom.x + (fontAscent * Math.sin(geom.angle))) + 'px';
- textDiv.style.top = (geom.y - (fontAscent * Math.cos(geom.angle))) + 'px';
+ textDiv.style.fontFamily = style.fontFamily;
- // The content of the div is set in the `setTextContent` function.
+ textDiv.textContent = geom.str;
+ textDiv.dataset.fontName = geom.fontName;
+ textDiv.dataset.angle = angle * (180 / Math.PI);
+ if (style.vertical) {
+ textDiv.dataset.canvasWidth = geom.height * this.viewport.scale;
+ } else {
+ textDiv.dataset.canvasWidth = geom.width * this.viewport.scale;
+ }
this.textDivs.push(textDiv);
};
- this.insertDivContent = function textLayerUpdateTextContent() {
- // Only set the content of the divs once layout has finished, the content
- // for the divs is available and content is not yet set on the divs.
- if (!this.layoutDone || this.divContentDone || !this.textContent) {
- return;
- }
-
- this.divContentDone = true;
-
- var textDivs = this.textDivs;
- var bidiTexts = this.textContent;
-
- for (var i = 0; i < bidiTexts.length; i++) {
- var bidiText = bidiTexts[i];
- var textDiv = textDivs[i];
- if (!/\S/.test(bidiText.str)) {
- textDiv.dataset.isWhitespace = true;
- continue;
- }
+ this.setTextContent = function textLayerBuilderSetTextContent(textContent) {
+ this.textContent = textContent;
- textDiv.textContent = bidiText.str;
- // TODO refactor text layer to use text content position
- /**
- * var arr = this.viewport.convertToViewportPoint(bidiText.x, bidiText.y);
- * textDiv.style.left = arr[0] + 'px';
- * textDiv.style.top = arr[1] + 'px';
- */
- // bidiText.dir may be 'ttb' for vertical texts.
- textDiv.dir = bidiText.dir;
+ var textItems = textContent.items;
+ for (var i = 0; i < textItems.length; i++) {
+ this.appendText(textItems[i], textContent.styles);
}
+ this.divContentDone = true;
this.setupRenderLayoutTimer();
};
- this.setTextContent = function textLayerBuilderSetTextContent(textContent) {
- this.textContent = textContent;
- this.insertDivContent();
- };
-
this.convertMatches = function textLayerBuilderConvertMatches(matches) {
var i = 0;
var iIndex = 0;
- var bidiTexts = this.textContent;
+ var bidiTexts = this.textContent.items;
var end = bidiTexts.length - 1;
var queryLen = (PDFFindController === null ?
0 : PDFFindController.state.query.length);
@@ -240,7 +217,7 @@ var TextLayerBuilder = function textLayerBuilder(options) {
return;
}
- var bidiTexts = this.textContent;
+ var bidiTexts = this.textContent.items;
var textDivs = this.textDivs;
var prevEnd = null;
var isSelectedPage = (PDFFindController === null ?
@@ -356,7 +333,7 @@ var TextLayerBuilder = function textLayerBuilder(options) {
// Clear out all matches.
var matches = this.matches;
var textDivs = this.textDivs;
- var bidiTexts = this.textContent;
+ var bidiTexts = this.textContent.items;
var clearedUntilDivIdx = -1;
// Clear out all current matches.
diff --git a/web/viewer.css b/web/viewer.css
index 7f24277..84e3bc6 100644
--- a/web/viewer.css
+++ b/web/viewer.css
@@ -1286,7 +1286,6 @@ canvas {
.textLayer > div {
color: transparent;
position: absolute;
- line-height: 1;
white-space: pre;
cursor: text;
}
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/pdf.js.git
More information about the Pkg-javascript-commits
mailing list