From ab80f5823df1d3bb062320cc89eccd8af642cf5f Mon Sep 17 00:00:00 2001 From: Nigel Tao Date: Fri, 25 Oct 2013 20:07:33 +1100 Subject: [PATCH] freetype/truetype: implement SHP and DELTAP opcodes. R=bsiegert CC=golang-dev, remyoudompheng https://codereview.appspot.com/16500043 --- freetype/truetype/hint.go | 58 ++++++++++++++++++++++++++++++ freetype/truetype/opcodes.go | 16 ++++----- freetype/truetype/truetype_test.go | 2 +- 3 files changed, 67 insertions(+), 9 deletions(-) diff --git a/freetype/truetype/hint.go b/freetype/truetype/hint.go index 1312f54..1817958 100644 --- a/freetype/truetype/hint.go +++ b/freetype/truetype/hint.go @@ -480,6 +480,24 @@ func (h *Hinter) run(program []byte, pCurrent, pUnhinted, pInFontUnits []Point, prevEnd = end } + case opSHP0, opSHP1: + if top < int(h.gs.loop) { + return errors.New("truetype: hinting: stack underflow") + } + _, _, d, ok := h.displacement(opcode&1 == 0) + if !ok { + return errors.New("truetype: hinting: point out of range") + } + for ; h.gs.loop != 0; h.gs.loop-- { + top-- + p := h.point(2, current, h.stack[top]) + if p == nil { + return errors.New("truetype: hinting: point out of range") + } + h.move(p, d, true) + } + h.gs.loop = 1 + case opSHZ0, opSHZ1: top-- zonePointer, i, d, ok := h.displacement(opcode&1 == 0) @@ -740,6 +758,9 @@ func (h *Hinter) run(program []byte, pCurrent, pUnhinted, pInFontUnits []Point, case opNOT: h.stack[top-1] = bool2int32(h.stack[top-1] == 0) + case opDELTAP1: + goto deltap + case opSDB: top-- h.gs.deltaBase = h.stack[top] @@ -794,6 +815,9 @@ func (h *Hinter) run(program []byte, pCurrent, pUnhinted, pInFontUnits []Point, // This code does not implement engine compensation, as we don't expect to // be used to output on dot-matrix printers. + case opDELTAP2, opDELTAP3: + goto deltap + case opSROUND, opS45ROUND: top-- switch (h.stack[top] >> 6) & 0x03 { @@ -1130,6 +1154,40 @@ func (h *Hinter) run(program []byte, pCurrent, pUnhinted, pInFontUnits []Point, } continue } + + deltap: + top-- + n := f26dot6(h.stack[top]) + if top < 2*int(h.gs.loop) { + return errors.New("truetype: hinting: stack underflow") + } + for ; n > 0; n-- { + top -= 2 + p := h.point(0, current, h.stack[top+1]) + if p == nil { + return errors.New("truetype: hinting: point out of range") + } + b := h.stack[top] + c := (b & 0xf0) >> 4 + switch opcode { + case opDELTAP2: + c += 16 + case opDELTAP3: + c += 32 + } + c += h.gs.deltaBase + if ppem := (h.scale + 1<<5) >> 6; ppem != c { + continue + } + b = (b & 0x0f) - 8 + if b >= 0 { + b++ + } + b = b * 64 / (1 << uint32(h.gs.deltaShift)) + h.move(p, f26dot6(b), true) + } + pc++ + continue } return nil } diff --git a/freetype/truetype/opcodes.go b/freetype/truetype/opcodes.go index 0d467e7..bb07b7e 100644 --- a/freetype/truetype/opcodes.go +++ b/freetype/truetype/opcodes.go @@ -60,8 +60,8 @@ const ( opMDAP1 = 0x2f // . opIUP0 = 0x30 // Interpolate Untouched Points through the outline opIUP1 = 0x31 // . - opSHP0 = 0x32 - opSHP1 = 0x33 + opSHP0 = 0x32 // SHift Point using reference point + opSHP1 = 0x33 // . opSHC0 = 0x34 opSHC1 = 0x35 opSHZ0 = 0x36 // SHift Zone using reference point @@ -103,7 +103,7 @@ const ( opAND = 0x5a // logical AND opOR = 0x5b // logical OR opNOT = 0x5c // logical NOT - opDELTAP1 = 0x5d + opDELTAP1 = 0x5d // DELTA exception P1 opSDB = 0x5e // Set Delta Base in the graphics state opSDS = 0x5f // Set Delta Shift in the graphics state opADD = 0x60 // ADD @@ -123,8 +123,8 @@ const ( opNROUND10 = 0x6e // . opNROUND11 = 0x6f // . opWCVTF = 0x70 - opDELTAP2 = 0x71 - opDELTAP3 = 0x72 + opDELTAP2 = 0x71 // DELTA exception P2 + opDELTAP3 = 0x72 // DELTA exception P3 opDELTAC1 = 0x73 opDELTAC2 = 0x74 opDELTAC3 = 0x75 @@ -274,11 +274,11 @@ var popCount = [256]uint8{ 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 0, 0, 0, q, // 0x00 - 0x0f 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, // 0x10 - 0x1f 1, 1, 0, 2, 0, 1, 1, q, q, q, 2, 1, 1, 0, 1, 1, // 0x20 - 0x2f - 0, 0, q, q, q, q, 1, 1, 1, 0, 2, 2, 0, 0, 2, 2, // 0x30 - 0x3f + 0, 0, 0, 0, q, q, 1, 1, 1, 0, 2, 2, 0, 0, 2, 2, // 0x30 - 0x3f 0, 0, 2, 1, 2, 1, 1, 1, q, 2, 2, 0, 0, 0, 0, 0, // 0x40 - 0x4f - 2, 2, 2, 2, 2, 2, 1, 1, 1, 0, 2, 2, 1, q, 1, 1, // 0x50 - 0x5f + 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 - q, q, q, q, q, q, 1, 1, 2, 2, 0, q, 0, 0, 1, 1, // 0x70 - 0x7f + q, 1, 1, q, q, q, 1, 1, 2, 2, 0, q, 0, 0, 1, 1, // 0x70 - 0x7f q, q, q, q, q, 1, q, q, 1, 1, 3, 2, 2, 1, q, 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 diff --git a/freetype/truetype/truetype_test.go b/freetype/truetype/truetype_test.go index b391db3..80b0b00 100644 --- a/freetype/truetype/truetype_test.go +++ b/freetype/truetype/truetype_test.go @@ -253,7 +253,7 @@ var scalingTestCases = []struct { }{ {"luxisr", 12, -1}, {"x-arial-bold", 11, 0}, - {"x-deja-vu-sans-oblique", 17, 5}, + {"x-deja-vu-sans-oblique", 17, 14}, {"x-droid-sans-japanese", 9, 0}, {"x-times-new-roman", 13, 0}, }