Merge pull request #6588 from yurydelendik/spacing
Better spacing in text layer.
This commit is contained in:
commit
7e8dacf57b
@ -350,9 +350,6 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|||||||
|
|
||||||
for (var i = 0, ii = glyphs.length; i < ii; i++) {
|
for (var i = 0, ii = glyphs.length; i < ii; i++) {
|
||||||
var glyph = glyphs[i];
|
var glyph = glyphs[i];
|
||||||
if (glyph === null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
buildPath(glyph.fontChar);
|
buildPath(glyph.fontChar);
|
||||||
|
|
||||||
// If the glyph has an accent we need to build a path for its
|
// If the glyph has an accent we need to build a path for its
|
||||||
@ -1012,10 +1009,6 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|||||||
var defaultVMetrics = font.defaultVMetrics;
|
var defaultVMetrics = font.defaultVMetrics;
|
||||||
for (var i = 0; i < glyphs.length; i++) {
|
for (var i = 0; i < glyphs.length; i++) {
|
||||||
var glyph = glyphs[i];
|
var glyph = glyphs[i];
|
||||||
if (!glyph) { // Previous glyph was a space.
|
|
||||||
width += textState.wordSpacing * textState.textHScale;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
var vMetricX = null;
|
var vMetricX = null;
|
||||||
var vMetricY = null;
|
var vMetricY = null;
|
||||||
var glyphWidth = null;
|
var glyphWidth = null;
|
||||||
@ -1051,11 +1044,14 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|||||||
// var x = pt[0];
|
// var x = pt[0];
|
||||||
// var y = pt[1];
|
// var y = pt[1];
|
||||||
|
|
||||||
var charSpacing = 0;
|
var charSpacing = textState.charSpacing;
|
||||||
if (textChunk.str.length > 0) {
|
if (glyph.isSpace) {
|
||||||
// Apply char spacing only when there are chars.
|
var wordSpacing = textState.wordSpacing;
|
||||||
// As a result there is only spacing between glyphs.
|
charSpacing += wordSpacing;
|
||||||
charSpacing = textState.charSpacing;
|
if (wordSpacing > 0) {
|
||||||
|
addFakeSpaces(wordSpacing * 1000 / textState.fontSize,
|
||||||
|
textChunk.str);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var tx = 0;
|
var tx = 0;
|
||||||
@ -1089,6 +1085,22 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|||||||
return textChunk;
|
return textChunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addFakeSpaces(width, strBuf) {
|
||||||
|
var spaceWidth = textState.font.spaceWidth;
|
||||||
|
if (spaceWidth <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var fakeSpaces = width / spaceWidth;
|
||||||
|
if (fakeSpaces > MULTI_SPACE_FACTOR) {
|
||||||
|
fakeSpaces = Math.round(fakeSpaces);
|
||||||
|
while (fakeSpaces--) {
|
||||||
|
strBuf.push(' ');
|
||||||
|
}
|
||||||
|
} else if (fakeSpaces > SPACE_FACTOR) {
|
||||||
|
strBuf.push(' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var timeSlotManager = new TimeSlotManager();
|
var timeSlotManager = new TimeSlotManager();
|
||||||
|
|
||||||
return new Promise(function next(resolve, reject) {
|
return new Promise(function next(resolve, reject) {
|
||||||
@ -1167,29 +1179,26 @@ 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.
|
||||||
var val = items[j] * textState.fontSize / 1000;
|
var advance = items[j];
|
||||||
|
var val = advance * textState.fontSize / 1000;
|
||||||
if (textState.font.vertical) {
|
if (textState.font.vertical) {
|
||||||
offset = val * textState.textMatrix[3];
|
offset = val *
|
||||||
textState.translateTextMatrix(0, offset);
|
(textState.textHScale * textState.textMatrix[2] +
|
||||||
|
textState.textMatrix[3]);
|
||||||
|
textState.translateTextMatrix(0, val);
|
||||||
// Value needs to be added to height to paint down.
|
// Value needs to be added to height to paint down.
|
||||||
textChunk.height += offset;
|
textChunk.height += offset;
|
||||||
} else {
|
} else {
|
||||||
offset = val * textState.textHScale *
|
offset = val * (
|
||||||
textState.textMatrix[0];
|
textState.textHScale * textState.textMatrix[0] +
|
||||||
textState.translateTextMatrix(offset, 0);
|
textState.textMatrix[1]);
|
||||||
|
textState.translateTextMatrix(-val, 0);
|
||||||
// Value needs to be subtracted from width to paint left.
|
// Value needs to be subtracted from width to paint left.
|
||||||
textChunk.width -= offset;
|
textChunk.width -= offset;
|
||||||
|
advance = -advance;
|
||||||
}
|
}
|
||||||
if (items[j] < 0 && textState.font.spaceWidth > 0) {
|
if (advance > 0) {
|
||||||
var fakeSpaces = -items[j] / textState.font.spaceWidth;
|
addFakeSpaces(advance, textChunk.str);
|
||||||
if (fakeSpaces > MULTI_SPACE_FACTOR) {
|
|
||||||
fakeSpaces = Math.round(fakeSpaces);
|
|
||||||
while (fakeSpaces--) {
|
|
||||||
textChunk.str.push(' ');
|
|
||||||
}
|
|
||||||
} else if (fakeSpaces > SPACE_FACTOR) {
|
|
||||||
textChunk.str.push(' ');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2170,23 +2170,26 @@ function getFontType(type, subtype) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var Glyph = (function GlyphClosure() {
|
var Glyph = (function GlyphClosure() {
|
||||||
function Glyph(fontChar, unicode, accent, width, vmetric, operatorListId) {
|
function Glyph(fontChar, unicode, accent, width, vmetric, operatorListId,
|
||||||
|
isSpace) {
|
||||||
this.fontChar = fontChar;
|
this.fontChar = fontChar;
|
||||||
this.unicode = unicode;
|
this.unicode = unicode;
|
||||||
this.accent = accent;
|
this.accent = accent;
|
||||||
this.width = width;
|
this.width = width;
|
||||||
this.vmetric = vmetric;
|
this.vmetric = vmetric;
|
||||||
this.operatorListId = operatorListId;
|
this.operatorListId = operatorListId;
|
||||||
|
this.isSpace = isSpace;
|
||||||
}
|
}
|
||||||
|
|
||||||
Glyph.prototype.matchesForCache =
|
Glyph.prototype.matchesForCache = function(fontChar, unicode, accent, width,
|
||||||
function(fontChar, unicode, accent, width, vmetric, operatorListId) {
|
vmetric, operatorListId, isSpace) {
|
||||||
return this.fontChar === fontChar &&
|
return this.fontChar === fontChar &&
|
||||||
this.unicode === unicode &&
|
this.unicode === unicode &&
|
||||||
this.accent === accent &&
|
this.accent === accent &&
|
||||||
this.width === width &&
|
this.width === width &&
|
||||||
this.vmetric === vmetric &&
|
this.vmetric === vmetric &&
|
||||||
this.operatorListId === operatorListId;
|
this.operatorListId === operatorListId &&
|
||||||
|
this.isSpace === isSpace;
|
||||||
};
|
};
|
||||||
|
|
||||||
return Glyph;
|
return Glyph;
|
||||||
@ -4701,7 +4704,7 @@ var Font = (function FontClosure() {
|
|||||||
return width;
|
return width;
|
||||||
},
|
},
|
||||||
|
|
||||||
charToGlyph: function Font_charToGlyph(charcode) {
|
charToGlyph: function Font_charToGlyph(charcode, isSpace) {
|
||||||
var fontCharCode, width, operatorListId;
|
var fontCharCode, width, operatorListId;
|
||||||
|
|
||||||
var widthCode = charcode;
|
var widthCode = charcode;
|
||||||
@ -4744,9 +4747,9 @@ var Font = (function FontClosure() {
|
|||||||
var glyph = this.glyphCache[charcode];
|
var glyph = this.glyphCache[charcode];
|
||||||
if (!glyph ||
|
if (!glyph ||
|
||||||
!glyph.matchesForCache(fontChar, unicode, accent, width, vmetric,
|
!glyph.matchesForCache(fontChar, unicode, accent, width, vmetric,
|
||||||
operatorListId)) {
|
operatorListId, isSpace)) {
|
||||||
glyph = new Glyph(fontChar, unicode, accent, width, vmetric,
|
glyph = new Glyph(fontChar, unicode, accent, width, vmetric,
|
||||||
operatorListId);
|
operatorListId, isSpace);
|
||||||
this.glyphCache[charcode] = glyph;
|
this.glyphCache[charcode] = glyph;
|
||||||
}
|
}
|
||||||
return glyph;
|
return glyph;
|
||||||
@ -4782,22 +4785,16 @@ var Font = (function FontClosure() {
|
|||||||
charcode = c.charcode;
|
charcode = c.charcode;
|
||||||
var length = c.length;
|
var length = c.length;
|
||||||
i += length;
|
i += length;
|
||||||
glyph = this.charToGlyph(charcode);
|
// Space is char with code 0x20 and length 1 in multiple-byte codes.
|
||||||
|
var isSpace = length === 1 && chars.charCodeAt(i - 1) === 0x20;
|
||||||
|
glyph = this.charToGlyph(charcode, isSpace);
|
||||||
glyphs.push(glyph);
|
glyphs.push(glyph);
|
||||||
// placing null after each word break charcode (ASCII SPACE)
|
|
||||||
// Ignore occurences of 0x20 in multiple-byte codes.
|
|
||||||
if (length === 1 && chars.charCodeAt(i - 1) === 0x20) {
|
|
||||||
glyphs.push(null);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (i = 0, ii = chars.length; i < ii; ++i) {
|
for (i = 0, ii = chars.length; i < ii; ++i) {
|
||||||
charcode = chars.charCodeAt(i);
|
charcode = chars.charCodeAt(i);
|
||||||
glyph = this.charToGlyph(charcode);
|
glyph = this.charToGlyph(charcode, charcode === 0x20);
|
||||||
glyphs.push(glyph);
|
glyphs.push(glyph);
|
||||||
if (charcode === 0x20) {
|
|
||||||
glyphs.push(null);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1397,16 +1397,13 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
|||||||
var x = 0, i;
|
var x = 0, i;
|
||||||
for (i = 0; i < glyphsLength; ++i) {
|
for (i = 0; i < glyphsLength; ++i) {
|
||||||
var glyph = glyphs[i];
|
var glyph = glyphs[i];
|
||||||
if (glyph === null) {
|
if (isNum(glyph)) {
|
||||||
// word break
|
|
||||||
x += fontDirection * wordSpacing;
|
|
||||||
continue;
|
|
||||||
} else if (isNum(glyph)) {
|
|
||||||
x += spacingDir * glyph * fontSize / 1000;
|
x += spacingDir * glyph * fontSize / 1000;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var restoreNeeded = false;
|
var restoreNeeded = false;
|
||||||
|
var spacing = (glyph.isSpace ? wordSpacing : 0) + charSpacing;
|
||||||
var character = glyph.fontChar;
|
var character = glyph.fontChar;
|
||||||
var accent = glyph.accent;
|
var accent = glyph.accent;
|
||||||
var scaledX, scaledY, scaledAccentX, scaledAccentY;
|
var scaledX, scaledY, scaledAccentX, scaledAccentY;
|
||||||
@ -1450,7 +1447,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var charWidth = width * widthAdvanceScale + charSpacing * fontDirection;
|
var charWidth = width * widthAdvanceScale + spacing * fontDirection;
|
||||||
x += charWidth;
|
x += charWidth;
|
||||||
|
|
||||||
if (restoreNeeded) {
|
if (restoreNeeded) {
|
||||||
@ -1495,18 +1492,14 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
|||||||
|
|
||||||
for (i = 0; i < glyphsLength; ++i) {
|
for (i = 0; i < glyphsLength; ++i) {
|
||||||
glyph = glyphs[i];
|
glyph = glyphs[i];
|
||||||
if (glyph === null) {
|
if (isNum(glyph)) {
|
||||||
// word break
|
|
||||||
this.ctx.translate(wordSpacing, 0);
|
|
||||||
current.x += wordSpacing * textHScale;
|
|
||||||
continue;
|
|
||||||
} else if (isNum(glyph)) {
|
|
||||||
spacingLength = spacingDir * glyph * fontSize / 1000;
|
spacingLength = spacingDir * glyph * fontSize / 1000;
|
||||||
this.ctx.translate(spacingLength, 0);
|
this.ctx.translate(spacingLength, 0);
|
||||||
current.x += spacingLength * textHScale;
|
current.x += spacingLength * textHScale;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var spacing = (glyph.isSpace ? wordSpacing : 0) + charSpacing;
|
||||||
var operatorList = font.charProcOperatorList[glyph.operatorListId];
|
var operatorList = font.charProcOperatorList[glyph.operatorListId];
|
||||||
if (!operatorList) {
|
if (!operatorList) {
|
||||||
warn('Type3 character \"' + glyph.operatorListId +
|
warn('Type3 character \"' + glyph.operatorListId +
|
||||||
@ -1521,7 +1514,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
|||||||
this.restore();
|
this.restore();
|
||||||
|
|
||||||
var transformed = Util.applyTransform([glyph.width, 0], fontMatrix);
|
var transformed = Util.applyTransform([glyph.width, 0], fontMatrix);
|
||||||
width = transformed[0] * fontSize + charSpacing;
|
width = transformed[0] * fontSize + spacing;
|
||||||
|
|
||||||
ctx.translate(width, 0);
|
ctx.translate(width, 0);
|
||||||
current.x += width * textHScale;
|
current.x += width * textHScale;
|
||||||
|
1
test/pdfs/.gitignore
vendored
1
test/pdfs/.gitignore
vendored
@ -29,6 +29,7 @@
|
|||||||
!issue3205r.pdf
|
!issue3205r.pdf
|
||||||
!issue3879r.pdf
|
!issue3879r.pdf
|
||||||
!close-path-bug.pdf
|
!close-path-bug.pdf
|
||||||
|
!issue6019.pdf
|
||||||
!issue1293r.pdf
|
!issue1293r.pdf
|
||||||
!issue6541.pdf
|
!issue6541.pdf
|
||||||
!issue2948.pdf
|
!issue2948.pdf
|
||||||
|
80
test/pdfs/issue6019.pdf
Normal file
80
test/pdfs/issue6019.pdf
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
%PDF-1.7
|
||||||
|
%âãÏÓ
|
||||||
|
1 0 obj
|
||||||
|
<<
|
||||||
|
/Type /Encoding
|
||||||
|
/BaseEncoding /WinAnsiEncoding
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
2 0 obj
|
||||||
|
<<
|
||||||
|
/Pages 3 0 R
|
||||||
|
/Type /Catalog
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
3 0 obj
|
||||||
|
<<
|
||||||
|
/Kids [4 0 R]
|
||||||
|
/Count 1
|
||||||
|
/Type /Pages
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
4 0 obj
|
||||||
|
<<
|
||||||
|
/Rotate 90
|
||||||
|
/Parent 3 0 R
|
||||||
|
/MediaBox [0 0 50 400]
|
||||||
|
/Resources
|
||||||
|
<<
|
||||||
|
/Font
|
||||||
|
<<
|
||||||
|
/F1 5 0 R
|
||||||
|
>>
|
||||||
|
>>
|
||||||
|
/Contents 6 0 R
|
||||||
|
/Type /Page
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
5 0 obj
|
||||||
|
<<
|
||||||
|
/BaseFont /Times-Italic
|
||||||
|
/Subtype /Type1
|
||||||
|
/Encoding 1 0 R
|
||||||
|
/Type /Font
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
6 0 obj
|
||||||
|
<<
|
||||||
|
/Length 108
|
||||||
|
>>
|
||||||
|
stream
|
||||||
|
BT
|
||||||
|
/F1 1 Tf
|
||||||
|
0 24 -24 0 30 30 Tm
|
||||||
|
0 Tw
|
||||||
|
(Ð)Tj
|
||||||
|
0.94 0 TD
|
||||||
|
-0.0002 Tc
|
||||||
|
0.0002 Tw
|
||||||
|
[(Medicine Bow)-3653( 936)]TJ
|
||||||
|
ET
|
||||||
|
|
||||||
|
endstream
|
||||||
|
endobj xref
|
||||||
|
0 7
|
||||||
|
0000000000 65535 f
|
||||||
|
0000000015 00000 n
|
||||||
|
0000000085 00000 n
|
||||||
|
0000000136 00000 n
|
||||||
|
0000000195 00000 n
|
||||||
|
0000000335 00000 n
|
||||||
|
0000000426 00000 n
|
||||||
|
trailer
|
||||||
|
|
||||||
|
<<
|
||||||
|
/Root 2 0 R
|
||||||
|
/Size 7
|
||||||
|
>>
|
||||||
|
startxref
|
||||||
|
587
|
||||||
|
%%EOF
|
@ -1288,6 +1288,13 @@
|
|||||||
"link": false,
|
"link": false,
|
||||||
"type": "eq"
|
"type": "eq"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "issue6019-text",
|
||||||
|
"file": "pdfs/issue6019.pdf",
|
||||||
|
"md5": "7a2e5dda3b0fc5c2e9060e378a8cdc4e",
|
||||||
|
"rounds": 1,
|
||||||
|
"type": "text"
|
||||||
|
},
|
||||||
{ "id": "bug893730",
|
{ "id": "bug893730",
|
||||||
"file": "pdfs/bug893730.pdf",
|
"file": "pdfs/bug893730.pdf",
|
||||||
"md5": "2587379fb1b3bbff89c14f0863e78383",
|
"md5": "2587379fb1b3bbff89c14f0863e78383",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user