Merge pull request #1106 from arturadib/issue-1049

fontMatrix parsing fix, setFont() supports negative sizes
This commit is contained in:
Brendan Dahl 2012-02-03 11:10:58 -08:00
commit b3fb41caa9
8 changed files with 90 additions and 24 deletions

View File

@ -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: {}};

View File

@ -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.

View File

@ -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;

View File

@ -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;
})(); })();

View File

@ -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

View File

@ -0,0 +1 @@
http://ernestinefont.com/wp-content/themes/iA3%201.2.1/assets/pdf/ErnestinePro-InfoGuide.pdf

View File

@ -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"
} }
] ]

View File

@ -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;
}, },