freetype/truetype: implement IUP opcode.
R=bsiegert CC=golang-dev https://codereview.appspot.com/13965043
This commit is contained in:
parent
75fff80b59
commit
c661e372c6
|
@ -402,16 +402,37 @@ func (h *Hinter) run(program []byte) error {
|
||||||
h.gs.rp[1] = i
|
h.gs.rp[1] = i
|
||||||
|
|
||||||
case opIUP0, opIUP1:
|
case opIUP0, opIUP1:
|
||||||
// TODO: implement IUP.
|
iupY, mask := opcode == opIUP0, uint32(flagTouchedX)
|
||||||
// Glyph 4 in luxisr.ttf (the '!' glyph) has IUP instructions but
|
if iupY {
|
||||||
// they have no effect since none of the points are untouched.
|
mask = flagTouchedY
|
||||||
// The IUP ops will be implemented when the N in truetype_test.go
|
|
||||||
// is raised above 5.
|
|
||||||
const mask = flagTouchedX | flagTouchedY
|
|
||||||
for _, p := range h.g.Point {
|
|
||||||
if p.Flags&mask != mask {
|
|
||||||
return errors.New("truetype: hinting: unimplemented IUP instruction")
|
|
||||||
}
|
}
|
||||||
|
prevEnd := 0
|
||||||
|
for _, end := range h.g.End {
|
||||||
|
for i := prevEnd; i < end; i++ {
|
||||||
|
for i < end && h.g.Point[i].Flags&mask == 0 {
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
if i == end {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
firstTouched, curTouched := i, i
|
||||||
|
i++
|
||||||
|
for ; i < end; i++ {
|
||||||
|
if h.g.Point[i].Flags&mask != 0 {
|
||||||
|
h.iupInterp(iupY, curTouched+1, i-1, curTouched, i)
|
||||||
|
curTouched = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if curTouched == firstTouched {
|
||||||
|
h.iupShift(iupY, prevEnd, end, curTouched)
|
||||||
|
} else {
|
||||||
|
h.iupInterp(iupY, curTouched+1, end-1, curTouched, firstTouched)
|
||||||
|
if firstTouched > 0 {
|
||||||
|
h.iupInterp(iupY, prevEnd, firstTouched-1, curTouched, firstTouched)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prevEnd = end
|
||||||
}
|
}
|
||||||
|
|
||||||
case opIP:
|
case opIP:
|
||||||
|
@ -1043,6 +1064,117 @@ func (h *Hinter) move(p *Point, distance f26dot6) {
|
||||||
p.Flags |= flagTouchedX | flagTouchedY
|
p.Flags |= flagTouchedX | flagTouchedY
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *Hinter) iupInterp(interpY bool, p1, p2, ref1, ref2 int) {
|
||||||
|
if p1 > p2 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if ref1 >= len(h.g.Point) || ref2 >= len(h.g.Point) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var ifu1, ifu2 int32
|
||||||
|
if interpY {
|
||||||
|
ifu1 = h.g.InFontUnits[ref1].Y
|
||||||
|
ifu2 = h.g.InFontUnits[ref2].Y
|
||||||
|
} else {
|
||||||
|
ifu1 = h.g.InFontUnits[ref1].X
|
||||||
|
ifu2 = h.g.InFontUnits[ref2].X
|
||||||
|
}
|
||||||
|
if ifu1 > ifu2 {
|
||||||
|
ifu1, ifu2 = ifu2, ifu1
|
||||||
|
ref1, ref2 = ref2, ref1
|
||||||
|
}
|
||||||
|
|
||||||
|
var unh1, unh2, delta1, delta2 int32
|
||||||
|
if interpY {
|
||||||
|
unh1 = h.g.Unhinted[ref1].Y
|
||||||
|
unh2 = h.g.Unhinted[ref2].Y
|
||||||
|
delta1 = h.g.Point[ref1].Y - unh1
|
||||||
|
delta2 = h.g.Point[ref2].Y - unh2
|
||||||
|
} else {
|
||||||
|
unh1 = h.g.Unhinted[ref1].X
|
||||||
|
unh2 = h.g.Unhinted[ref2].X
|
||||||
|
delta1 = h.g.Point[ref1].X - unh1
|
||||||
|
delta2 = h.g.Point[ref2].X - unh2
|
||||||
|
}
|
||||||
|
|
||||||
|
var xy, ifuXY int32
|
||||||
|
if ifu1 == ifu2 {
|
||||||
|
for i := p1; i <= p2; i++ {
|
||||||
|
if interpY {
|
||||||
|
xy = h.g.Unhinted[i].Y
|
||||||
|
} else {
|
||||||
|
xy = h.g.Unhinted[i].X
|
||||||
|
}
|
||||||
|
|
||||||
|
if xy <= unh1 {
|
||||||
|
xy += delta1
|
||||||
|
} else {
|
||||||
|
xy += delta2
|
||||||
|
}
|
||||||
|
|
||||||
|
if interpY {
|
||||||
|
h.g.Point[i].Y = xy
|
||||||
|
} else {
|
||||||
|
h.g.Point[i].X = xy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
scale, scaleOK := int64(0), false
|
||||||
|
for i := p1; i <= p2; i++ {
|
||||||
|
if interpY {
|
||||||
|
xy = h.g.Unhinted[i].Y
|
||||||
|
ifuXY = h.g.InFontUnits[i].Y
|
||||||
|
} else {
|
||||||
|
xy = h.g.Unhinted[i].X
|
||||||
|
ifuXY = h.g.InFontUnits[i].X
|
||||||
|
}
|
||||||
|
|
||||||
|
if xy <= unh1 {
|
||||||
|
xy += delta1
|
||||||
|
} else if xy >= unh2 {
|
||||||
|
xy += delta2
|
||||||
|
} else {
|
||||||
|
if !scaleOK {
|
||||||
|
scaleOK = true
|
||||||
|
denom := int64(ifu2 - ifu1)
|
||||||
|
scale = (int64(unh2+delta2-unh1-delta1)*0x10000 + denom/2) / denom
|
||||||
|
}
|
||||||
|
xy = unh1 + delta1 + int32((int64(ifuXY-ifu1)*scale+0x8000)/0x10000)
|
||||||
|
}
|
||||||
|
|
||||||
|
if interpY {
|
||||||
|
h.g.Point[i].Y = xy
|
||||||
|
} else {
|
||||||
|
h.g.Point[i].X = xy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Hinter) iupShift(interpY bool, p1, p2, p int) {
|
||||||
|
var delta int32
|
||||||
|
if interpY {
|
||||||
|
delta = h.g.Point[p].Y - h.g.Unhinted[p].Y
|
||||||
|
} else {
|
||||||
|
delta = h.g.Point[p].X - h.g.Unhinted[p].X
|
||||||
|
}
|
||||||
|
if delta == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for i := p1; i < p2; i++ {
|
||||||
|
if i == p {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if interpY {
|
||||||
|
h.g.Point[i].Y += delta
|
||||||
|
} else {
|
||||||
|
h.g.Point[i].X += delta
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// skipInstructionPayload increments pc by the extra data that follows a
|
// skipInstructionPayload increments pc by the extra data that follows a
|
||||||
// variable length PUSHB or PUSHW instruction.
|
// variable length PUSHB or PUSHW instruction.
|
||||||
func skipInstructionPayload(program []byte, pc int) (newPC int, ok bool) {
|
func skipInstructionPayload(program []byte, pc int) (newPC int, ok bool) {
|
||||||
|
|
|
@ -116,7 +116,7 @@ func testScaling(t *testing.T, filename string, hinter *Hinter) {
|
||||||
for i, want := range wants {
|
for i, want := range wants {
|
||||||
// TODO: completely implement hinting. For now, only the first N glyphs
|
// TODO: completely implement hinting. For now, only the first N glyphs
|
||||||
// of luxisr.ttf are correctly hinted.
|
// of luxisr.ttf are correctly hinted.
|
||||||
const N = 5
|
const N = 8
|
||||||
if hinter != nil && i == N {
|
if hinter != nil && i == N {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue