Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(29)

Unified Diff: freetype/truetype/hint.go

Issue 13965043: code review 13965043: freetype/truetype: implement IUP opcode. (Closed)
Patch Set: diff -r 2c7f9c2cb4bd https://code.google.com/p/freetype-go Created 11 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | freetype/truetype/truetype_test.go » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: freetype/truetype/hint.go
===================================================================
--- a/freetype/truetype/hint.go
+++ b/freetype/truetype/hint.go
@@ -402,16 +402,37 @@
h.gs.rp[1] = i
case opIUP0, opIUP1:
- // TODO: implement IUP.
- // Glyph 4 in luxisr.ttf (the '!' glyph) has IUP instructions but
- // they have no effect since none of the points are untouched.
- // 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")
+ iupY, mask := opcode == opIUP0, uint32(flagTouchedX)
+ if iupY {
+ mask = flagTouchedY
+ }
+ 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:
@@ -1043,6 +1064,117 @@
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
// variable length PUSHB or PUSHW instruction.
func skipInstructionPayload(program []byte, pc int) (newPC int, ok bool) {
« no previous file with comments | « no previous file | freetype/truetype/truetype_test.go » ('j') | no next file with comments »

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b