Merge pull request #1106 from arturadib/issue-1049
fontMatrix parsing fix, setFont() supports negative sizes
This commit is contained in:
commit
b3fb41caa9
@ -23,6 +23,7 @@ var CanvasExtraState = (function CanvasExtraStateClosure() {
|
|||||||
this.alphaIsShape = false;
|
this.alphaIsShape = false;
|
||||||
this.fontSize = 0;
|
this.fontSize = 0;
|
||||||
this.textMatrix = IDENTITY_MATRIX;
|
this.textMatrix = IDENTITY_MATRIX;
|
||||||
|
this.fontMatrix = IDENTITY_MATRIX;
|
||||||
this.leading = 0;
|
this.leading = 0;
|
||||||
// Current point (in user coordinates)
|
// Current point (in user coordinates)
|
||||||
this.x = 0;
|
this.x = 0;
|
||||||
@ -546,12 +547,32 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
|||||||
},
|
},
|
||||||
setFont: function canvasGraphicsSetFont(fontRefName, size) {
|
setFont: function canvasGraphicsSetFont(fontRefName, size) {
|
||||||
var fontObj = this.objs.get(fontRefName).fontObj;
|
var fontObj = this.objs.get(fontRefName).fontObj;
|
||||||
|
var current = this.current;
|
||||||
|
|
||||||
if (!fontObj) {
|
if (!fontObj)
|
||||||
error('Can\'t find font for ' + fontRefName);
|
error('Can\'t find font for ' + fontRefName);
|
||||||
|
|
||||||
|
// Slice-clone matrix so we can manipulate it without affecting original
|
||||||
|
if (fontObj.fontMatrix)
|
||||||
|
current.fontMatrix = fontObj.fontMatrix.slice(0);
|
||||||
|
else
|
||||||
|
current.fontMatrix = IDENTITY_MATRIX.slice(0);
|
||||||
|
|
||||||
|
// A valid matrix needs all main diagonal elements to be non-zero
|
||||||
|
// This also ensures we bypass FF bugzilla bug #719844.
|
||||||
|
if (current.fontMatrix[0] === 0 ||
|
||||||
|
current.fontMatrix[3] === 0) {
|
||||||
|
warn('Invalid font matrix for font ' + fontRefName);
|
||||||
}
|
}
|
||||||
|
|
||||||
var name = fontObj.loadedName || 'sans-serif';
|
// The spec for Tf (setFont) says that 'size' specifies the font 'scale',
|
||||||
|
// and in some docs this can be negative (inverted x-y axes).
|
||||||
|
// We implement this condition with fontMatrix.
|
||||||
|
if (size < 0) {
|
||||||
|
size = -size;
|
||||||
|
current.fontMatrix[0] *= -1;
|
||||||
|
current.fontMatrix[3] *= -1;
|
||||||
|
}
|
||||||
|
|
||||||
this.current.font = fontObj;
|
this.current.font = fontObj;
|
||||||
this.current.fontSize = size;
|
this.current.fontSize = size;
|
||||||
@ -595,7 +616,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
|||||||
var ctx = this.ctx;
|
var ctx = this.ctx;
|
||||||
var current = this.current;
|
var current = this.current;
|
||||||
var textHScale = current.textHScale;
|
var textHScale = current.textHScale;
|
||||||
var fontMatrix = current.font.fontMatrix || IDENTITY_MATRIX;
|
var fontMatrix = current.fontMatrix || IDENTITY_MATRIX;
|
||||||
|
|
||||||
ctx.transform.apply(ctx, current.textMatrix);
|
ctx.transform.apply(ctx, current.textMatrix);
|
||||||
ctx.scale(1, -1);
|
ctx.scale(1, -1);
|
||||||
@ -629,7 +650,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
|||||||
var charSpacing = current.charSpacing;
|
var charSpacing = current.charSpacing;
|
||||||
var wordSpacing = current.wordSpacing;
|
var wordSpacing = current.wordSpacing;
|
||||||
var textHScale = current.textHScale;
|
var textHScale = current.textHScale;
|
||||||
var fontMatrix = font.fontMatrix || IDENTITY_MATRIX;
|
var fontMatrix = current.fontMatrix || IDENTITY_MATRIX;
|
||||||
var textHScale2 = textHScale * fontMatrix[0];
|
var textHScale2 = textHScale * fontMatrix[0];
|
||||||
var glyphsLength = glyphs.length;
|
var glyphsLength = glyphs.length;
|
||||||
var textLayer = this.textLayer;
|
var textLayer = this.textLayer;
|
||||||
@ -667,7 +688,8 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
|||||||
this.restore();
|
this.restore();
|
||||||
|
|
||||||
var transformed = Util.applyTransform([glyph.width, 0], fontMatrix);
|
var transformed = Util.applyTransform([glyph.width, 0], fontMatrix);
|
||||||
var width = transformed[0] * fontSize + charSpacing;
|
var width = transformed[0] * fontSize +
|
||||||
|
Util.sign(current.fontMatrix[0]) * charSpacing;
|
||||||
|
|
||||||
ctx.translate(width, 0);
|
ctx.translate(width, 0);
|
||||||
current.x += width * textHScale;
|
current.x += width * textHScale;
|
||||||
@ -693,44 +715,45 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
|||||||
if (textSelection)
|
if (textSelection)
|
||||||
text.geom = this.getTextGeometry();
|
text.geom = this.getTextGeometry();
|
||||||
|
|
||||||
var width = 0;
|
var x = 0;
|
||||||
for (var i = 0; i < glyphsLength; ++i) {
|
for (var i = 0; i < glyphsLength; ++i) {
|
||||||
var glyph = glyphs[i];
|
var glyph = glyphs[i];
|
||||||
if (glyph === null) {
|
if (glyph === null) {
|
||||||
// word break
|
// word break
|
||||||
width += wordSpacing;
|
x += Util.sign(current.fontMatrix[0]) * wordSpacing;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var char = glyph.fontChar;
|
var char = glyph.fontChar;
|
||||||
var charWidth = glyph.width * fontSize * 0.001 + charSpacing;
|
var charWidth = glyph.width * fontSize * 0.001 +
|
||||||
|
Util.sign(current.fontMatrix[0]) * charSpacing;
|
||||||
|
|
||||||
switch (textRenderingMode) {
|
switch (textRenderingMode) {
|
||||||
default: // other unsupported rendering modes
|
default: // other unsupported rendering modes
|
||||||
case TextRenderingMode.FILL:
|
case TextRenderingMode.FILL:
|
||||||
case TextRenderingMode.FILL_ADD_TO_PATH:
|
case TextRenderingMode.FILL_ADD_TO_PATH:
|
||||||
ctx.fillText(char, width, 0);
|
ctx.fillText(char, x, 0);
|
||||||
break;
|
break;
|
||||||
case TextRenderingMode.STROKE:
|
case TextRenderingMode.STROKE:
|
||||||
case TextRenderingMode.STROKE_ADD_TO_PATH:
|
case TextRenderingMode.STROKE_ADD_TO_PATH:
|
||||||
ctx.strokeText(char, width, 0);
|
ctx.strokeText(char, x, 0);
|
||||||
break;
|
break;
|
||||||
case TextRenderingMode.FILL_STROKE:
|
case TextRenderingMode.FILL_STROKE:
|
||||||
case TextRenderingMode.FILL_STROKE_ADD_TO_PATH:
|
case TextRenderingMode.FILL_STROKE_ADD_TO_PATH:
|
||||||
ctx.fillText(char, width, 0);
|
ctx.fillText(char, x, 0);
|
||||||
ctx.strokeText(char, width, 0);
|
ctx.strokeText(char, x, 0);
|
||||||
break;
|
break;
|
||||||
case TextRenderingMode.INVISIBLE:
|
case TextRenderingMode.INVISIBLE:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
width += charWidth;
|
x += charWidth;
|
||||||
|
|
||||||
text.str += glyph.unicode === ' ' ? '\u00A0' : glyph.unicode;
|
text.str += glyph.unicode === ' ' ? '\u00A0' : glyph.unicode;
|
||||||
text.length++;
|
text.length++;
|
||||||
text.canvasWidth += charWidth;
|
text.canvasWidth += charWidth;
|
||||||
}
|
}
|
||||||
current.x += width * textHScale2;
|
current.x += x * textHScale2;
|
||||||
ctx.restore();
|
ctx.restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -746,7 +769,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() {
|
|||||||
var fontSize = current.fontSize;
|
var fontSize = current.fontSize;
|
||||||
var textHScale = current.textHScale;
|
var textHScale = current.textHScale;
|
||||||
if (!font.coded)
|
if (!font.coded)
|
||||||
textHScale *= (font.fontMatrix || IDENTITY_MATRIX)[0];
|
textHScale *= (current.fontMatrix || IDENTITY_MATRIX)[0];
|
||||||
var arrLength = arr.length;
|
var arrLength = arr.length;
|
||||||
var textLayer = this.textLayer;
|
var textLayer = this.textLayer;
|
||||||
var text = {str: '', length: 0, canvasWidth: 0, geom: {}};
|
var text = {str: '', length: 0, canvasWidth: 0, geom: {}};
|
||||||
|
@ -159,6 +159,10 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|||||||
// a Stream in the main thread.
|
// a Stream in the main thread.
|
||||||
if (translated.file)
|
if (translated.file)
|
||||||
translated.file = translated.file.getBytes();
|
translated.file = translated.file.getBytes();
|
||||||
|
if (translated.properties.file) {
|
||||||
|
translated.properties.file =
|
||||||
|
translated.properties.file.getBytes();
|
||||||
|
}
|
||||||
|
|
||||||
handler.send('obj', [
|
handler.send('obj', [
|
||||||
loadedName,
|
loadedName,
|
||||||
@ -783,11 +787,10 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
|
|||||||
properties: properties
|
properties: properties
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// According to the spec if 'FontDescriptor' is declared, 'FirstChar',
|
// According to the spec if 'FontDescriptor' is declared, 'FirstChar',
|
||||||
// 'LastChar' and 'Widths' should exists too, but some PDF encoders seems
|
// 'LastChar' and 'Widths' should exist too, but some PDF encoders seem
|
||||||
// to ignore this rule when a variant of a standart font is used.
|
// to ignore this rule when a variant of a standart font is used.
|
||||||
// TODO Fill the width array depending on which of the base font this is
|
// TODO Fill the width array depending on which of the base font this is
|
||||||
// a variant.
|
// a variant.
|
||||||
|
10
src/fonts.js
10
src/fonts.js
@ -2619,7 +2619,13 @@ var Type1Parser = function type1Parser() {
|
|||||||
while (str[index++] != ']')
|
while (str[index++] != ']')
|
||||||
count++;
|
count++;
|
||||||
|
|
||||||
var array = str.substr(start, count).split(' ');
|
str = str.substr(start, count);
|
||||||
|
|
||||||
|
str = str.trim();
|
||||||
|
// Remove adjacent spaces
|
||||||
|
str = str.replace(/\s+/g, ' ');
|
||||||
|
|
||||||
|
var array = str.split(' ');
|
||||||
for (var i = 0, ii = array.length; i < ii; i++)
|
for (var i = 0, ii = array.length; i < ii; i++)
|
||||||
array[i] = parseFloat(array[i] || 0);
|
array[i] = parseFloat(array[i] || 0);
|
||||||
return array;
|
return array;
|
||||||
@ -3620,7 +3626,7 @@ var Type2CFF = (function Type2CFFClosure() {
|
|||||||
dict['cidOperatorPresent'] = true;
|
dict['cidOperatorPresent'] = true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
TODO('interpret top dict key');
|
TODO('interpret top dict key: ' + key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return dict;
|
return dict;
|
||||||
|
@ -93,6 +93,10 @@ var Util = (function UtilClosure() {
|
|||||||
return [xt, yt];
|
return [xt, yt];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Util.sign = function sign(num) {
|
||||||
|
return num < 0 ? -1 : 1;
|
||||||
|
};
|
||||||
|
|
||||||
return Util;
|
return Util;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
@ -109,11 +109,27 @@ var WorkerMessageHandler = {
|
|||||||
// Pre compile the pdf page and fetch the fonts/images.
|
// Pre compile the pdf page and fetch the fonts/images.
|
||||||
IRQueue = page.getIRQueue(handler, dependency);
|
IRQueue = page.getIRQueue(handler, dependency);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
var minimumStackMessage =
|
||||||
|
'worker.js: while trying to getPage() and getIRQueue()';
|
||||||
|
|
||||||
// Turn the error into an obj that can be serialized
|
// Turn the error into an obj that can be serialized
|
||||||
e = {
|
if (typeof e === 'string') {
|
||||||
message: typeof e === 'object' ? e.message : e,
|
e = {
|
||||||
stack: typeof e === 'object' ? e.stack : null
|
message: e,
|
||||||
};
|
stack: minimumStackMessage
|
||||||
|
};
|
||||||
|
} else if (typeof e === 'object') {
|
||||||
|
e = {
|
||||||
|
message: e.message || e.toString(),
|
||||||
|
stack: e.stack || minimumStackMessage
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
e = {
|
||||||
|
message: 'Unknown exception type: ' + (typeof e),
|
||||||
|
stack: minimumStackMessage
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
handler.send('page_error', {
|
handler.send('page_error', {
|
||||||
pageNum: pageNum,
|
pageNum: pageNum,
|
||||||
error: e
|
error: e
|
||||||
|
1
test/pdfs/issue1049.pdf.link
Normal file
1
test/pdfs/issue1049.pdf.link
Normal file
@ -0,0 +1 @@
|
|||||||
|
http://ernestinefont.com/wp-content/themes/iA3%201.2.1/assets/pdf/ErnestinePro-InfoGuide.pdf
|
@ -444,5 +444,12 @@
|
|||||||
"rounds": 1,
|
"rounds": 1,
|
||||||
"link": false,
|
"link": false,
|
||||||
"type": "eq"
|
"type": "eq"
|
||||||
|
},
|
||||||
|
{ "id": "issue1049",
|
||||||
|
"file": "pdfs/issue1049.pdf",
|
||||||
|
"md5": "15473fffcdde9fb8f3756a4cf1aab347",
|
||||||
|
"rounds": 1,
|
||||||
|
"link": true,
|
||||||
|
"type": "eq"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -380,8 +380,14 @@ var PDFView = {
|
|||||||
|
|
||||||
if (moreInfo) {
|
if (moreInfo) {
|
||||||
errorMoreInfo.value += 'Message: ' + moreInfo.message;
|
errorMoreInfo.value += 'Message: ' + moreInfo.message;
|
||||||
if (moreInfo.stack)
|
if (moreInfo.stack) {
|
||||||
errorMoreInfo.value += '\n' + 'Stack: ' + moreInfo.stack;
|
errorMoreInfo.value += '\n' + 'Stack: ' + moreInfo.stack;
|
||||||
|
} else {
|
||||||
|
if (moreInfo.filename)
|
||||||
|
errorMoreInfo.value += '\n' + 'File: ' + moreInfo.filename;
|
||||||
|
if (moreInfo.lineNumber)
|
||||||
|
errorMoreInfo.value += '\n' + 'Line: ' + moreInfo.lineNumber;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
errorMoreInfo.rows = errorMoreInfo.value.split('\n').length - 1;
|
errorMoreInfo.rows = errorMoreInfo.value.split('\n').length - 1;
|
||||||
},
|
},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user