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