提交 c3fc3971 编写于 作者: N Nigel Tao

freetype/truetype: refactor dispatch for high opcodes.

Also delete "q means that that opcode is not yet implemented", as all
valid opcodes are now implemented.

R=bsiegert
CC=golang-codereviews
https://codereview.appspot.com/53050044
上级 39b01678
......@@ -195,9 +195,6 @@ func (h *Hinter) run(program []byte, pCurrent, pUnhinted, pInFontUnits []Point,
return errors.New("truetype: hinting: too many steps")
}
opcode = program[pc]
if popCount[opcode] == q {
return errors.New("truetype: hinting: unimplemented instruction")
}
if top < int(popCount[opcode]) {
return errors.New("truetype: hinting: stack underflow")
}
......@@ -1115,170 +1112,159 @@ func (h *Hinter) run(program []byte, pCurrent, pUnhinted, pInFontUnits []Point,
// freetype-go does not support rotated or stretched glyphs.
top -= 2
case opPUSHB000, opPUSHB001, opPUSHB010, opPUSHB011,
opPUSHB100, opPUSHB101, opPUSHB110, opPUSHB111:
opcode -= opPUSHB000 - 1
goto push
case opPUSHW000, opPUSHW001, opPUSHW010, opPUSHW011,
opPUSHW100, opPUSHW101, opPUSHW110, opPUSHW111:
opcode -= opPUSHW000 - 1
opcode += 0x80
goto push
case opMDRP00000, opMDRP00001, opMDRP00010, opMDRP00011,
opMDRP00100, opMDRP00101, opMDRP00110, opMDRP00111,
opMDRP01000, opMDRP01001, opMDRP01010, opMDRP01011,
opMDRP01100, opMDRP01101, opMDRP01110, opMDRP01111,
opMDRP10000, opMDRP10001, opMDRP10010, opMDRP10011,
opMDRP10100, opMDRP10101, opMDRP10110, opMDRP10111,
opMDRP11000, opMDRP11001, opMDRP11010, opMDRP11011,
opMDRP11100, opMDRP11101, opMDRP11110, opMDRP11111:
top--
i := h.stack[top]
ref := h.point(0, current, h.gs.rp[0])
p := h.point(1, current, i)
if ref == nil || p == nil {
return errors.New("truetype: hinting: point out of range")
default:
if opcode < opPUSHB000 {
return errors.New("truetype: hinting: unrecognized instruction")
}
oldDist := f26dot6(0)
if h.gs.zp[0] == 0 || h.gs.zp[1] == 0 {
p0 := h.point(1, unhinted, i)
p1 := h.point(0, unhinted, h.gs.rp[0])
oldDist = dotProduct(f26dot6(p0.X-p1.X), f26dot6(p0.Y-p1.Y), h.gs.dv)
} else {
p0 := h.point(1, inFontUnits, i)
p1 := h.point(0, inFontUnits, h.gs.rp[0])
oldDist = dotProduct(f26dot6(p0.X-p1.X), f26dot6(p0.Y-p1.Y), h.gs.dv)
oldDist = f26dot6(h.font.scale(h.scale * int32(oldDist)))
}
if opcode < opMDRP00000 {
// PUSHxxxx opcode.
// Single-width cut-in test.
if x := (oldDist - h.gs.singleWidth).abs(); x < h.gs.singleWidthCutIn {
if oldDist >= 0 {
oldDist = +h.gs.singleWidth
if opcode < opPUSHW000 {
opcode -= opPUSHB000 - 1
} else {
oldDist = -h.gs.singleWidth
opcode -= opPUSHW000 - 1 - 0x80
}
goto push
}
// Rounding bit.
// TODO: metrics compensation.
distance := oldDist
if opcode&0x04 != 0 {
distance = h.round(oldDist)
}
if opcode < opMIRP00000 {
// MDRPxxxxx opcode.
// Minimum distance bit.
if opcode&0x08 != 0 {
if oldDist >= 0 {
if distance < h.gs.minDist {
distance = h.gs.minDist
}
top--
i := h.stack[top]
ref := h.point(0, current, h.gs.rp[0])
p := h.point(1, current, i)
if ref == nil || p == nil {
return errors.New("truetype: hinting: point out of range")
}
oldDist := f26dot6(0)
if h.gs.zp[0] == 0 || h.gs.zp[1] == 0 {
p0 := h.point(1, unhinted, i)
p1 := h.point(0, unhinted, h.gs.rp[0])
oldDist = dotProduct(f26dot6(p0.X-p1.X), f26dot6(p0.Y-p1.Y), h.gs.dv)
} else {
if distance > -h.gs.minDist {
distance = -h.gs.minDist
}
p0 := h.point(1, inFontUnits, i)
p1 := h.point(0, inFontUnits, h.gs.rp[0])
oldDist = dotProduct(f26dot6(p0.X-p1.X), f26dot6(p0.Y-p1.Y), h.gs.dv)
oldDist = f26dot6(h.font.scale(h.scale * int32(oldDist)))
}
}
// Set-RP0 bit.
h.gs.rp[1] = h.gs.rp[0]
h.gs.rp[2] = i
if opcode&0x10 != 0 {
h.gs.rp[0] = i
}
// Single-width cut-in test.
if x := (oldDist - h.gs.singleWidth).abs(); x < h.gs.singleWidthCutIn {
if oldDist >= 0 {
oldDist = +h.gs.singleWidth
} else {
oldDist = -h.gs.singleWidth
}
}
// Move the point.
oldDist = dotProduct(f26dot6(p.X-ref.X), f26dot6(p.Y-ref.Y), h.gs.pv)
h.move(p, distance-oldDist, true)
// Rounding bit.
// TODO: metrics compensation.
distance := oldDist
if opcode&0x04 != 0 {
distance = h.round(oldDist)
}
case opMIRP00000, opMIRP00001, opMIRP00010, opMIRP00011,
opMIRP00100, opMIRP00101, opMIRP00110, opMIRP00111,
opMIRP01000, opMIRP01001, opMIRP01010, opMIRP01011,
opMIRP01100, opMIRP01101, opMIRP01110, opMIRP01111,
opMIRP10000, opMIRP10001, opMIRP10010, opMIRP10011,
opMIRP10100, opMIRP10101, opMIRP10110, opMIRP10111,
opMIRP11000, opMIRP11001, opMIRP11010, opMIRP11011,
opMIRP11100, opMIRP11101, opMIRP11110, opMIRP11111:
// Minimum distance bit.
if opcode&0x08 != 0 {
if oldDist >= 0 {
if distance < h.gs.minDist {
distance = h.gs.minDist
}
} else {
if distance > -h.gs.minDist {
distance = -h.gs.minDist
}
}
}
top -= 2
i := h.stack[top]
cvtDist := h.getScaledCVT(h.stack[top+1])
if (cvtDist - h.gs.singleWidth).abs() < h.gs.singleWidthCutIn {
if cvtDist >= 0 {
cvtDist = +h.gs.singleWidth
} else {
cvtDist = -h.gs.singleWidth
// Set-RP0 bit.
h.gs.rp[1] = h.gs.rp[0]
h.gs.rp[2] = i
if opcode&0x10 != 0 {
h.gs.rp[0] = i
}
}
if h.gs.zp[1] == 0 {
// TODO: implement once we have a .ttf file that triggers
// this, so that we can step through C's freetype.
return errors.New("truetype: hinting: unimplemented twilight point adjustment")
}
// Move the point.
oldDist = dotProduct(f26dot6(p.X-ref.X), f26dot6(p.Y-ref.Y), h.gs.pv)
h.move(p, distance-oldDist, true)
ref := h.point(0, unhinted, h.gs.rp[0])
p := h.point(1, unhinted, i)
if ref == nil || p == nil {
return errors.New("truetype: hinting: point out of range")
}
oldDist := dotProduct(f26dot6(p.X-ref.X), f26dot6(p.Y-ref.Y), h.gs.dv)
} else {
// MIRPxxxxx opcode.
ref = h.point(0, current, h.gs.rp[0])
p = h.point(1, current, i)
if ref == nil || p == nil {
return errors.New("truetype: hinting: point out of range")
}
curDist := dotProduct(f26dot6(p.X-ref.X), f26dot6(p.Y-ref.Y), h.gs.pv)
top -= 2
i := h.stack[top]
cvtDist := h.getScaledCVT(h.stack[top+1])
if (cvtDist - h.gs.singleWidth).abs() < h.gs.singleWidthCutIn {
if cvtDist >= 0 {
cvtDist = +h.gs.singleWidth
} else {
cvtDist = -h.gs.singleWidth
}
}
if h.gs.autoFlip && oldDist^cvtDist < 0 {
cvtDist = -cvtDist
}
if h.gs.zp[1] == 0 {
// TODO: implement once we have a .ttf file that triggers
// this, so that we can step through C's freetype.
return errors.New("truetype: hinting: unimplemented twilight point adjustment")
}
// Rounding bit.
// TODO: metrics compensation.
distance := cvtDist
if opcode&0x04 != 0 {
// The CVT value is only used if close enough to oldDist.
if (h.gs.zp[0] == h.gs.zp[1]) &&
((cvtDist - oldDist).abs() > h.gs.controlValueCutIn) {
ref := h.point(0, unhinted, h.gs.rp[0])
p := h.point(1, unhinted, i)
if ref == nil || p == nil {
return errors.New("truetype: hinting: point out of range")
}
oldDist := dotProduct(f26dot6(p.X-ref.X), f26dot6(p.Y-ref.Y), h.gs.dv)
distance = oldDist
ref = h.point(0, current, h.gs.rp[0])
p = h.point(1, current, i)
if ref == nil || p == nil {
return errors.New("truetype: hinting: point out of range")
}
distance = h.round(distance)
}
curDist := dotProduct(f26dot6(p.X-ref.X), f26dot6(p.Y-ref.Y), h.gs.pv)
// Minimum distance bit.
if opcode&0x08 != 0 {
if oldDist >= 0 {
if distance < h.gs.minDist {
distance = h.gs.minDist
}
} else {
if distance > -h.gs.minDist {
distance = -h.gs.minDist
if h.gs.autoFlip && oldDist^cvtDist < 0 {
cvtDist = -cvtDist
}
// Rounding bit.
// TODO: metrics compensation.
distance := cvtDist
if opcode&0x04 != 0 {
// The CVT value is only used if close enough to oldDist.
if (h.gs.zp[0] == h.gs.zp[1]) &&
((cvtDist - oldDist).abs() > h.gs.controlValueCutIn) {
distance = oldDist
}
distance = h.round(distance)
}
}
// Set-RP0 bit.
h.gs.rp[1] = h.gs.rp[0]
h.gs.rp[2] = i
if opcode&0x10 != 0 {
h.gs.rp[0] = i
}
// Minimum distance bit.
if opcode&0x08 != 0 {
if oldDist >= 0 {
if distance < h.gs.minDist {
distance = h.gs.minDist
}
} else {
if distance > -h.gs.minDist {
distance = -h.gs.minDist
}
}
}
// Move the point.
h.move(p, distance-curDist, true)
// Set-RP0 bit.
h.gs.rp[1] = h.gs.rp[0]
h.gs.rp[2] = i
if opcode&0x10 != 0 {
h.gs.rp[0] = i
}
default:
return errors.New("truetype: hinting: unrecognized instruction")
// Move the point.
h.move(p, distance-curDist, true)
}
}
pc++
continue
......
......@@ -278,15 +278,12 @@ var popCount = [256]uint8{
2, 2, 2, 2, 2, 2, 1, 1, 1, 0, 2, 2, 1, 1, 1, 1, // 0x50 - 0x5f
2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x60 - 0x6f
2, 1, 1, 1, 1, 1, 1, 1, 2, 2, 0, 0, 0, 0, 1, 1, // 0x70 - 0x7f
0, 2, 2, 0, 0, 1, 2, 2, 1, 1, 3, 2, 2, 1, 2, q, // 0x80 - 0x8f
q, q, q, q, q, q, q, q, q, q, q, q, q, q, q, q, // 0x90 - 0x9f
q, q, q, q, q, q, q, q, q, q, q, q, q, q, q, q, // 0xa0 - 0xaf
0, 2, 2, 0, 0, 1, 2, 2, 1, 1, 3, 2, 2, 1, 2, 0, // 0x80 - 0x8f
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x90 - 0x9f
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xa0 - 0xaf
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xb0 - 0xbf
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xc0 - 0xcf
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xd0 - 0xdf
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xe0 - 0xef
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xf0 - 0xff
}
// popCount[opcode] == q means that that opcode is not yet implemented.
const q = 255
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册