Created
February 7, 2015 00:01
-
-
Save tshinnic/64f70567ed8d4cdc2af8 to your computer and use it in GitHub Desktop.
opentype.js 2-byte decoding and add operator/operand decode tracing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Combine 1- and 2 byte operator decoding, add trace | |
With the implementation of the flex operator variations 2-byte operators | |
are now "mainstreamed". Realign the operator code decoding so as to | |
have just one switch+case clause for all operators. | |
Additionally, add a debug trace while decoding operators and operands. | |
This has been useful elsewhere when hints were decoded badly, and useful | |
here recently to show that the flex operators were being exercised and | |
failing in a font file not tested before. | |
Dumping of operand decoding is provided for, but disabled. The operator | |
decoding will dump the stack as seen before the operator is executed, e.g. | |
. Glyph# 66 | |
. on operator 29 callgsubr stack: (1) [-26] | |
. on operator 10 callsubr stack: (3) [17, -3, -5] | |
. on operator 11 return stack: (7) [17, -3, 14, 223, 35, 387, -20] | |
. on operator 11 return stack: (7) [17, -3, 14, 223, 35, 387, -20] | |
. on operator 1 hstem stack: (7) [17, -3, 14, 223, 35, 387, -20] | |
. on operator 3 vstem stack: (2) [-26, 689] | |
. on operator 29 callgsubr stack: (1) [-107] | |
. on operator 21 rmoveto stack: (2) [82, 91] | |
. on operator 8 rrcurveto stack: (6) [-17, -43, -17, -30, -40, -5] | |
The use of the 'dbg' variable to turn on debugging for just some glyphs is | |
clumsy and could be improved on. | |
These changes should be in two different patches. | |
diff --git a/src/tables/cff.js b/src/tables/cff.js | |
index 18d2cc9..7d1a087 100644 | |
--- a/src/tables/cff.js | |
+++ b/src/tables/cff.js | |
@@ -327,17 +327,38 @@ function parseCFFEncoding(data, start, charset) { | |
return new encoding.CffEncoding(enc, charset); | |
} | |
+ | |
+var CFFType2OperatorsByCode = { | |
+ 1: 'hstem', 3: 'vstem', 4: 'vmoveto', 5: 'rlineto', | |
+ 6: 'hlineto', 7: 'vlineto', 8: 'rrcurveto', 10: 'callsubr', | |
+ 11: 'return', 14: 'endchar', 18: 'hstemhm', 19: 'hintmask', | |
+ 20: 'cntrmask', 21: 'rmoveto', 22: 'hmoveto', 23: 'vstemhm', | |
+ 24: 'rcurveline', 25: 'rlinecurve', 26: 'vvcurveto', 27: 'hhcurveto', | |
+ 28: 'shortint', 29: 'callgsubr', 30: 'vhcurveto', 31: 'hvcurveto', | |
+ 1203: 'and', 1204: 'or', 1205: 'not', 1209: 'abs', | |
+ 1210: 'add', 1211: 'sub', 1212: 'div', 1214: 'neg', | |
+ 1215: 'eq', 1218: 'drop', 1220: 'put', 1221: 'get', | |
+ 1222: 'ifelse', 1223: 'random', 1224: 'mul', 1226: 'sqrt', | |
+ 1227: 'dup', 1228: 'exch', 1229: 'index', 1230: 'roll', | |
+ 1234: 'hflex', 1235: 'flex', 1236: 'hflex1', 1237: 'flex1', | |
+ 1299: '???' | |
+}; | |
+ | |
+ | |
// Take in charstring code and return a Glyph object. | |
// The encoding is described in the Type 2 Charstring Format | |
// https://www.microsoft.com/typography/OTSPEC/charstr2.htm | |
function parseCFFCharstring(code, font, index) { | |
var p, glyph, stack, nStems, haveWidth, width, x, y, c1x, c1y, c2x, c2y, v; | |
+ var jpx, jpy, c3x, c3y, c4x, c4y, fd; | |
p = new path.Path(); | |
stack = []; | |
nStems = 0; | |
haveWidth = false; | |
width = font.defaultWidthX; | |
x = y = 0; | |
+ var dbg = (index === 66 || index === 67); | |
+ if ( dbg ) console.log(' Glyph# %d', index); | |
function parseStems() { | |
var hasWidthArg; | |
@@ -358,6 +379,23 @@ function parseCFFCharstring(code, font, index) { | |
while (i < code.length) { | |
v = code[i]; | |
i += 1; | |
+ if (v === 12) { | |
+ if (i < code.length) { | |
+ v = 1200 + code[i]; | |
+ i += 1; | |
+ } else | |
+ v = 1299; | |
+ } | |
+ if ( dbg ) { | |
+ if ( v in CFFType2OperatorsByCode ) { | |
+ console.log(' on operator %d %s stack: (%d) ', | |
+ v, CFFType2OperatorsByCode[v], stack.length, stack); | |
+ } else { | |
+ //console.log(' on operand %d stack: (%d) ', | |
+ // v, stack.length, stack); | |
+ } | |
+ } | |
+ | |
switch (v) { | |
case 1: // hstem | |
parseStems(); | |
@@ -422,89 +460,80 @@ function parseCFFCharstring(code, font, index) { | |
break; | |
case 11: // return | |
return; | |
- case 12: // flex operators | |
- v = code[i]; | |
- i += 1; | |
- var jpx, jpy, c3x, c3y, c4x, c4y, fd; | |
- switch (v) { | |
- case 35: // flex | |
- // |- dx1 dy1 dx2 dy2 dx3 dy3 dx4 dy4 dx5 dy5 dx6 dy6 fd flex (12 35) |- | |
- c1x = x + stack.shift(); // dx1 | |
- c1y = y + stack.shift(); // dy1 | |
- c2x = c1x + stack.shift(); // dx2 | |
- c2y = c1y + stack.shift(); // dy2 | |
- jpx = c2x + stack.shift(); // dx3 | |
- jpy = c2y + stack.shift(); // dy3 | |
- c3x = jpx + stack.shift(); // dx4 | |
- c3y = jpy + stack.shift(); // dy4 | |
- c4x = c3x + stack.shift(); // dx5 | |
- c4y = c3y + stack.shift(); // dy5 | |
- x = c4x + stack.shift(); // dx6 | |
- y = c4y + stack.shift(); // dy6 | |
- fd = stack.shift(); // flex depth | |
- p.curveTo(c1x, c1y, c2x, c2y, jpx, jpy); | |
- p.curveTo(c3x, c3y, c4x, c4y, x, y); | |
- break; | |
- case 34: // hflex | |
- // |- dx1 dx2 dy2 dx3 dx4 dx5 dx6 hflex (12 34) |- | |
- c1x = x + stack.shift(); // dx1 | |
- c1y = y; // dy1 | |
- c2x = c1x + stack.shift(); // dx2 | |
- c2y = c1y + stack.shift(); // dy2 | |
- jpx = c2x + stack.shift(); // dx3 | |
- jpy = c2y; // dy3 | |
- c3x = jpx + stack.shift(); // dx4 | |
- c3y = c2y; // dy4 | |
- c4x = c3x + stack.shift(); // dx5 | |
- c4y = y; // dy5 | |
- x = c4x + stack.shift(); // dx6 | |
- // y = y; // dy6 | |
- p.curveTo(c1x, c1y, c2x, c2y, jpx, jpy); | |
- p.curveTo(c3x, c3y, c4x, c4y, x, y); | |
- break; | |
- case 36: // hflex1 | |
- // |- dx1 dy1 dx2 dy2 dx3 dx4 dx5 dy5 dx6 hflex1 (12 36) |- | |
- c1x = x + stack.shift(); // dx1 | |
- c1y = y + stack.shift(); // dy1 | |
- c2x = c1x + stack.shift(); // dx2 | |
- c2y = c1y + stack.shift(); // dy2 | |
- jpx = c2x + stack.shift(); // dx3 | |
- jpy = c2y; // dy3 | |
- c3x = jpx + stack.shift(); // dx4 | |
- c3y = c2y; // dy4 | |
- c4x = c3x + stack.shift(); // dx5 | |
- c4y = c3y + stack.shift(); // dy5 | |
- x = c4x + stack.shift(); // dx6 | |
- // y = y; // dy6 | |
- p.curveTo(c1x, c1y, c2x, c2y, jpx, jpy); | |
- p.curveTo(c3x, c3y, c4x, c4y, x, y); | |
- break; | |
- case 37: // flex1 | |
- // |- dx1 dy1 dx2 dy2 dx3 dy3 dx4 dy4 dx5 dy5 d6 flex1 (12 37) |- | |
- c1x = x + stack.shift(); // dx1 | |
- c1y = y + stack.shift(); // dy1 | |
- c2x = c1x + stack.shift(); // dx2 | |
- c2y = c1y + stack.shift(); // dy2 | |
- jpx = c2x + stack.shift(); // dx3 | |
- jpy = c2y + stack.shift(); // dy3 | |
- c3x = jpx + stack.shift(); // dx4 | |
- c3y = jpy + stack.shift(); // dy4 | |
- c4x = c3x + stack.shift(); // dx5 | |
- c4y = c3y + stack.shift(); // dy5 | |
- | |
- if (Math.abs(c4x - x) > Math.abs(c4y - y)) { | |
- x = c4x + stack.shift(); // d6 | |
- } else { | |
- y = c4y + stack.shift(); // d6 | |
- } | |
- p.curveTo(c1x, c1y, c2x, c2y, jpx, jpy); | |
- p.curveTo(c3x, c3y, c4x, c4y, x, y); | |
- break; | |
- default: | |
- console.log('Glyph ' + index + ': unknown operator ' + 1200 + v); | |
- stack.length = 0; | |
+ case 1235: // flex | |
+ // |- dx1 dy1 dx2 dy2 dx3 dy3 dx4 dy4 dx5 dy5 dx6 dy6 fd flex (12 35) |- | |
+ c1x = x + stack.shift(); // dx1 | |
+ c1y = y + stack.shift(); // dy1 | |
+ c2x = c1x + stack.shift(); // dx2 | |
+ c2y = c1y + stack.shift(); // dy2 | |
+ jpx = c2x + stack.shift(); // dx3 | |
+ jpy = c2y + stack.shift(); // dy3 | |
+ c3x = jpx + stack.shift(); // dx4 | |
+ c3y = jpy + stack.shift(); // dy4 | |
+ c4x = c3x + stack.shift(); // dx5 | |
+ c4y = c3y + stack.shift(); // dy5 | |
+ x = c4x + stack.shift(); // dx6 | |
+ y = c4y + stack.shift(); // dy6 | |
+ fd = stack.shift(); // flex depth | |
+ p.curveTo(c1x, c1y, c2x, c2y, jpx, jpy); | |
+ p.curveTo(c3x, c3y, c4x, c4y, x, y); | |
+ break; | |
+ case 1234: // hflex | |
+ // |- dx1 dx2 dy2 dx3 dx4 dx5 dx6 hflex (12 34) |- | |
+ c1x = x + stack.shift(); // dx1 | |
+ c1y = y; // dy1 | |
+ c2x = c1x + stack.shift(); // dx2 | |
+ c2y = c1y + stack.shift(); // dy2 | |
+ jpx = c2x + stack.shift(); // dx3 | |
+ jpy = c2y; // dy3 | |
+ c3x = jpx + stack.shift(); // dx4 | |
+ c3y = c2y; // dy4 | |
+ c4x = c3x + stack.shift(); // dx5 | |
+ c4y = y; // dy5 | |
+ x = c4x + stack.shift(); // dx6 | |
+ // y = y; // dy6 | |
+ p.curveTo(c1x, c1y, c2x, c2y, jpx, jpy); | |
+ p.curveTo(c3x, c3y, c4x, c4y, x, y); | |
+ break; | |
+ case 1236: // hflex1 | |
+ // |- dx1 dy1 dx2 dy2 dx3 dx4 dx5 dy5 dx6 hflex1 (12 36) |- | |
+ c1x = x + stack.shift(); // dx1 | |
+ c1y = y + stack.shift(); // dy1 | |
+ c2x = c1x + stack.shift(); // dx2 | |
+ c2y = c1y + stack.shift(); // dy2 | |
+ jpx = c2x + stack.shift(); // dx3 | |
+ jpy = c2y; // dy3 | |
+ c3x = jpx + stack.shift(); // dx4 | |
+ c3y = c2y; // dy4 | |
+ c4x = c3x + stack.shift(); // dx5 | |
+ c4y = c3y + stack.shift(); // dy5 | |
+ x = c4x + stack.shift(); // dx6 | |
+ // y = y; // dy6 | |
+ p.curveTo(c1x, c1y, c2x, c2y, jpx, jpy); | |
+ p.curveTo(c3x, c3y, c4x, c4y, x, y); | |
+ break; | |
+ case 1237: // flex1 | |
+ // |- dx1 dy1 dx2 dy2 dx3 dy3 dx4 dy4 dx5 dy5 d6 flex1 (12 37) |- | |
+ c1x = x + stack.shift(); // dx1 | |
+ c1y = y + stack.shift(); // dy1 | |
+ c2x = c1x + stack.shift(); // dx2 | |
+ c2y = c1y + stack.shift(); // dy2 | |
+ jpx = c2x + stack.shift(); // dx3 | |
+ jpy = c2y + stack.shift(); // dy3 | |
+ c3x = jpx + stack.shift(); // dx4 | |
+ c3y = jpy + stack.shift(); // dy4 | |
+ c4x = c3x + stack.shift(); // dx5 | |
+ c4y = c3y + stack.shift(); // dy5 | |
+ | |
+ if (Math.abs(c4x - x) > Math.abs(c4y - y)) { | |
+ x = c4x + stack.shift(); // d6 | |
+ } else { | |
+ y = c4y + stack.shift(); // d6 | |
} | |
+ p.curveTo(c1x, c1y, c2x, c2y, jpx, jpy); | |
+ p.curveTo(c3x, c3y, c4x, c4y, x, y); | |
break; | |
+ | |
case 14: // endchar | |
if (stack.length > 0 && !haveWidth) { | |
width = stack.shift() + font.nominalWidthX; | |
@@ -654,6 +683,7 @@ function parseCFFCharstring(code, font, index) { | |
default: | |
if (v < 32) { | |
console.log('Glyph ' + index + ': unknown operator ' + v); | |
+ stack.length = 0; | |
} else if (v < 247) { | |
stack.push(v - 139); | |
} else if (v < 251) { | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment