freetype/truetype: if/else opcodes.
R=gri CC=golang-dev http://codereview.appspot.com/6354067
This commit is contained in:
parent
8ed9e9345e
commit
523d04e0a7
3 changed files with 230 additions and 9 deletions
|
@ -18,6 +18,9 @@ type hinter struct {
|
|||
}
|
||||
|
||||
func (h *hinter) run(program []byte) error {
|
||||
if len(program) > 50000 {
|
||||
return errors.New("truetype: hinting: too many instructions")
|
||||
}
|
||||
var (
|
||||
steps, pc, top int
|
||||
opcode uint8
|
||||
|
@ -25,7 +28,7 @@ func (h *hinter) run(program []byte) error {
|
|||
for int(pc) < len(program) {
|
||||
steps++
|
||||
if steps == 100000 {
|
||||
return errors.New("truetype: hinting: too many instructions")
|
||||
return errors.New("truetype: hinting: too many steps")
|
||||
}
|
||||
opcode = program[pc]
|
||||
if popCount[opcode] == q {
|
||||
|
@ -36,6 +39,10 @@ func (h *hinter) run(program []byte) error {
|
|||
}
|
||||
switch opcode {
|
||||
|
||||
case opELSE:
|
||||
opcode = 1
|
||||
goto ifelse
|
||||
|
||||
case opDUP:
|
||||
if int(top) >= len(h.stack) {
|
||||
return errors.New("truetype: hinting: stack overflow")
|
||||
|
@ -78,6 +85,9 @@ func (h *hinter) run(program []byte) error {
|
|||
opcode = 0x80
|
||||
goto push
|
||||
|
||||
case opDEBUG:
|
||||
// No-op.
|
||||
|
||||
case opLT:
|
||||
h.stack[top-2] = bool2int32(h.stack[top-2] < h.stack[top-1])
|
||||
top--
|
||||
|
@ -113,6 +123,16 @@ func (h *hinter) run(program []byte) error {
|
|||
case opNOT:
|
||||
h.stack[top-1] = bool2int32(h.stack[top-1] == 0)
|
||||
|
||||
case opIF:
|
||||
top--
|
||||
if h.stack[top] == 0 {
|
||||
opcode = 0
|
||||
goto ifelse
|
||||
}
|
||||
|
||||
case opEIF:
|
||||
// No-op.
|
||||
|
||||
case opADD:
|
||||
h.stack[top-2] += h.stack[top-1]
|
||||
top--
|
||||
|
@ -162,8 +182,55 @@ func (h *hinter) run(program []byte) error {
|
|||
pc++
|
||||
continue
|
||||
|
||||
ifelse:
|
||||
// Skip past bytecode until the next ELSE (if opcode == 0) or the
|
||||
// next EIF (for all opcodes). Opcode == 0 means that we have come
|
||||
// from an IF. Opcode == 1 means that we have come from an ELSE.
|
||||
{
|
||||
ifelseloop:
|
||||
for depth := 0; ; {
|
||||
pc++
|
||||
if pc >= len(program) {
|
||||
return errors.New("truetype: hinting: unbalanced IF or ELSE")
|
||||
}
|
||||
switch program[pc] {
|
||||
case opIF:
|
||||
depth++
|
||||
case opELSE:
|
||||
if depth == 0 && opcode == 0 {
|
||||
break ifelseloop
|
||||
}
|
||||
case opEIF:
|
||||
depth--
|
||||
if depth < 0 {
|
||||
break ifelseloop
|
||||
}
|
||||
case opNPUSHB:
|
||||
pc++
|
||||
if pc >= len(program) {
|
||||
return errors.New("truetype: hinting: unbalanced IF or ELSE")
|
||||
}
|
||||
pc += int(program[pc])
|
||||
case opNPUSHW:
|
||||
pc++
|
||||
if pc >= len(program) {
|
||||
return errors.New("truetype: hinting: unbalanced IF or ELSE")
|
||||
}
|
||||
pc += 2 * int(program[pc])
|
||||
case opPUSHB000, opPUSHB001, opPUSHB010, opPUSHB011, opPUSHB100, opPUSHB101, opPUSHB110, opPUSHB111:
|
||||
pc += int(program[pc] - (opPUSHB000 - 1))
|
||||
case opPUSHW000, opPUSHW001, opPUSHW010, opPUSHW011, opPUSHW100, opPUSHW101, opPUSHW110, opPUSHW111:
|
||||
pc += 2 * int(program[pc]-(opPUSHW000-1))
|
||||
default:
|
||||
// No-op.
|
||||
}
|
||||
}
|
||||
pc++
|
||||
continue
|
||||
}
|
||||
|
||||
push:
|
||||
// push n elements from the program to the stack, where n is the low 7 bits of
|
||||
// Push n elements from the program to the stack, where n is the low 7 bits of
|
||||
// opcode. If the low 7 bits are zero, then n is the next byte from the program.
|
||||
// The high bit being 0 means that the elements are zero-extended bytes.
|
||||
// The high bit being 1 means that the elements are sign-extended words.
|
||||
|
|
|
@ -26,6 +26,16 @@ func TestBytecode(t *testing.T) {
|
|||
nil,
|
||||
"underflow",
|
||||
},
|
||||
{
|
||||
"unbalanced if/else",
|
||||
[]byte{
|
||||
opPUSHB000, // [0]
|
||||
0,
|
||||
opIF,
|
||||
},
|
||||
nil,
|
||||
"unbalanced",
|
||||
},
|
||||
{
|
||||
"stack ops",
|
||||
[]byte{
|
||||
|
@ -102,6 +112,150 @@ func TestBytecode(t *testing.T) {
|
|||
[]int32{1, 0},
|
||||
"",
|
||||
},
|
||||
{
|
||||
"if true",
|
||||
[]byte{
|
||||
opPUSHB001, // [255, 1]
|
||||
255,
|
||||
1,
|
||||
opIF,
|
||||
opPUSHB000, // [255, 2]
|
||||
2,
|
||||
opEIF,
|
||||
opPUSHB000, // [255, 2, 254]
|
||||
254,
|
||||
},
|
||||
[]int32{255, 2, 254},
|
||||
"",
|
||||
},
|
||||
{
|
||||
"if false",
|
||||
[]byte{
|
||||
opPUSHB001, // [255, 0]
|
||||
255,
|
||||
0,
|
||||
opIF,
|
||||
opPUSHB000, // [255]
|
||||
2,
|
||||
opEIF,
|
||||
opPUSHB000, // [255, 254]
|
||||
254,
|
||||
},
|
||||
[]int32{255, 254},
|
||||
"",
|
||||
},
|
||||
{
|
||||
"if/else true",
|
||||
[]byte{
|
||||
opPUSHB000, // [1]
|
||||
1,
|
||||
opIF,
|
||||
opPUSHB000, // [2]
|
||||
2,
|
||||
opELSE,
|
||||
opPUSHB000, // not executed
|
||||
3,
|
||||
opEIF,
|
||||
},
|
||||
[]int32{2},
|
||||
"",
|
||||
},
|
||||
{
|
||||
"if/else false",
|
||||
[]byte{
|
||||
opPUSHB000, // [0]
|
||||
0,
|
||||
opIF,
|
||||
opPUSHB000, // not executed
|
||||
2,
|
||||
opELSE,
|
||||
opPUSHB000, // [3]
|
||||
3,
|
||||
opEIF,
|
||||
},
|
||||
[]int32{3},
|
||||
"",
|
||||
},
|
||||
{
|
||||
"if/else true if/else false",
|
||||
// 0x58 is the opcode for opIF. The literal 0x58s below are pushed data.
|
||||
[]byte{
|
||||
opPUSHB010, // [255, 0, 1]
|
||||
255,
|
||||
0,
|
||||
1,
|
||||
opIF,
|
||||
opIF,
|
||||
opPUSHB001, // not executed
|
||||
0x58,
|
||||
0x58,
|
||||
opELSE,
|
||||
opPUSHW000, // [255, 0x5858]
|
||||
0x58,
|
||||
0x58,
|
||||
opEIF,
|
||||
opELSE,
|
||||
opIF,
|
||||
opNPUSHB, // not executed
|
||||
3,
|
||||
0x58,
|
||||
0x58,
|
||||
0x58,
|
||||
opELSE,
|
||||
opNPUSHW, // not executed
|
||||
2,
|
||||
0x58,
|
||||
0x58,
|
||||
0x58,
|
||||
0x58,
|
||||
opEIF,
|
||||
opEIF,
|
||||
opPUSHB000, // [255, 0x5858, 254]
|
||||
254,
|
||||
},
|
||||
[]int32{255, 0x5858, 254},
|
||||
"",
|
||||
},
|
||||
{
|
||||
"if/else false if/else true",
|
||||
// 0x58 is the opcode for opIF. The literal 0x58s below are pushed data.
|
||||
[]byte{
|
||||
opPUSHB010, // [255, 1, 0]
|
||||
255,
|
||||
1,
|
||||
0,
|
||||
opIF,
|
||||
opIF,
|
||||
opPUSHB001, // not executed
|
||||
0x58,
|
||||
0x58,
|
||||
opELSE,
|
||||
opPUSHW000, // not executed
|
||||
0x58,
|
||||
0x58,
|
||||
opEIF,
|
||||
opELSE,
|
||||
opIF,
|
||||
opNPUSHB, // [255, 0x58, 0x58, 0x58]
|
||||
3,
|
||||
0x58,
|
||||
0x58,
|
||||
0x58,
|
||||
opELSE,
|
||||
opNPUSHW, // not executed
|
||||
2,
|
||||
0x58,
|
||||
0x58,
|
||||
0x58,
|
||||
0x58,
|
||||
opEIF,
|
||||
opEIF,
|
||||
opPUSHB000, // [255, 0x58, 0x58, 0x58, 254]
|
||||
254,
|
||||
},
|
||||
[]int32{255, 0x58, 0x58, 0x58, 254},
|
||||
"",
|
||||
},
|
||||
{
|
||||
"logical ops",
|
||||
[]byte{
|
||||
|
|
|
@ -37,7 +37,7 @@ const (
|
|||
opRTG = 0x18
|
||||
opRTHG = 0x19
|
||||
opSMD = 0x1a
|
||||
opELSE = 0x1b
|
||||
opELSE = 0x1b // ELSE clause
|
||||
opJMPR = 0x1c
|
||||
opSCVTCI = 0x1d
|
||||
opSSWCI = 0x1e
|
||||
|
@ -89,7 +89,7 @@ const (
|
|||
opMPS = 0x4c
|
||||
opFLIPON = 0x4d
|
||||
opFLIPOFF = 0x4e
|
||||
opDEBUG = 0x4f
|
||||
opDEBUG = 0x4f // DEBUG call
|
||||
opLT = 0x50 // Less Than
|
||||
opLTEQ = 0x51 // Less Than or EQual
|
||||
opGT = 0x52 // Greater Than
|
||||
|
@ -98,8 +98,8 @@ const (
|
|||
opNEQ = 0x55 // Not EQual
|
||||
opODD = 0x56
|
||||
opEVEN = 0x57
|
||||
opIF = 0x58
|
||||
opEIF = 0x59
|
||||
opIF = 0x58 // IF test
|
||||
opEIF = 0x59 // End IF
|
||||
opAND = 0x5a // logical AND
|
||||
opOR = 0x5b // logical OR
|
||||
opNOT = 0x5c // logical NOT
|
||||
|
@ -272,11 +272,11 @@ const (
|
|||
var popCount = [256]uint8{
|
||||
// 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f
|
||||
q, q, q, q, q, q, q, q, q, q, q, q, q, q, q, q, // 0x00 - 0x0f
|
||||
q, q, q, q, q, q, q, q, q, q, q, q, q, q, q, q, // 0x10 - 0x1f
|
||||
q, q, q, q, q, q, q, q, q, q, q, 0, q, q, q, q, // 0x10 - 0x1f
|
||||
1, 1, 0, 2, 0, 1, 1, q, q, q, q, q, q, q, q, q, // 0x20 - 0x2f
|
||||
q, q, q, q, q, q, q, q, q, q, q, q, q, q, q, q, // 0x30 - 0x3f
|
||||
0, 0, q, q, q, q, q, q, q, q, q, q, q, q, q, q, // 0x40 - 0x4f
|
||||
2, 2, 2, 2, 2, 2, q, q, q, q, 2, 2, 1, q, q, q, // 0x50 - 0x5f
|
||||
0, 0, q, q, q, q, q, q, q, q, q, q, q, q, q, 0, // 0x40 - 0x4f
|
||||
2, 2, 2, 2, 2, 2, q, q, 1, 0, 2, 2, 1, q, q, q, // 0x50 - 0x5f
|
||||
2, 2, 2, 2, 1, 1, 1, 1, q, q, q, q, q, q, q, q, // 0x60 - 0x6f
|
||||
q, q, q, q, q, q, q, q, q, q, q, q, q, q, q, q, // 0x70 - 0x7f
|
||||
q, q, q, q, q, q, q, q, q, q, q, q, q, q, q, q, // 0x80 - 0x8f
|
||||
|
|
Loading…
Reference in a new issue