From 3490800cecef01e1eecc91073c7a3f26072bc086 Mon Sep 17 00:00:00 2001 From: Nigel Tao Date: Sun, 29 Sep 2013 18:30:55 +1000 Subject: [PATCH] freetype/truetype: fix rounding for negative numbers to match the C Freetype implementation. The spec is the "Order of rounding operations" part of https://developer.apple.com/fonts/TTRefMan/RM02/Chap2.html#rounding but it wasn't exactly clear to me what "the negative round value closest to zero" was: if the phase is 1/4, was that value -1/4 or -3/4? Anyway, the Go code now follows the C code, and code trumps documentation. R=bsiegert CC=golang-dev https://codereview.appspot.com/14092044 --- freetype/truetype/hint.go | 26 ++++++++++-------------- freetype/truetype/hint_test.go | 32 +++++++++++++++--------------- freetype/truetype/truetype_test.go | 2 +- 3 files changed, 27 insertions(+), 33 deletions(-) diff --git a/freetype/truetype/hint.go b/freetype/truetype/hint.go index eafd6cd..35c60e3 100644 --- a/freetype/truetype/hint.go +++ b/freetype/truetype/hint.go @@ -1237,27 +1237,21 @@ func dotProduct(x, y f26dot6, q [2]f2dot14) f26dot6 { // https://developer.apple.com/fonts/TTRefMan/RM02/Chap2.html#rounding func (h *Hinter) round(x f26dot6) f26dot6 { if h.gs.roundPeriod == 0 { + // Rounding is off. return x } - neg := x < 0 - x -= h.gs.roundPhase - x += h.gs.roundThreshold if x >= 0 { - x = (x / h.gs.roundPeriod) * h.gs.roundPeriod - } else { - x -= h.gs.roundPeriod - x += 1 - x = (x / h.gs.roundPeriod) * h.gs.roundPeriod - } - x += h.gs.roundPhase - if neg { - if x >= 0 { - x = h.gs.roundPhase - h.gs.roundPeriod + ret := (x - h.gs.roundPhase + h.gs.roundThreshold) & -h.gs.roundPeriod + if x != 0 && ret < 0 { + ret = 0 } - } else if x < 0 { - x = h.gs.roundPhase + return ret + h.gs.roundPhase } - return x + ret := -((-x - h.gs.roundPhase + h.gs.roundThreshold) & -h.gs.roundPeriod) + if ret > 0 { + ret = 0 + } + return ret - h.gs.roundPhase } func bool2int32(b bool) int32 { diff --git a/freetype/truetype/hint_test.go b/freetype/truetype/hint_test.go index 657bc26..c4c1886 100644 --- a/freetype/truetype/hint_test.go +++ b/freetype/truetype/hint_test.go @@ -445,33 +445,33 @@ func TestBytecode(t *testing.T) { opPUSHW000, // [-81] 0xff, 0xaf, - opROUND00, // [-112] - opPUSHW000, // [-112, -80] + opROUND00, // [-80] + opPUSHW000, // [-80, -80] 0xff, 0xb0, - opROUND00, // [-112, -48] - opPUSHW000, // [-112, -48, -17] + opROUND00, // [-80, -80] + opPUSHW000, // [-80, -80, -17] 0xff, 0xef, - opROUND00, // [-112, -48, -48] - opPUSHW000, // [-112, -48, -48, -16] + opROUND00, // [-80, -80, -16] + opPUSHW000, // [-80, -80, -16, -16] 0xff, 0xf0, - opROUND00, // [-112, -48, -48, -48] - opPUSHB000, // [-112, -48, -48, -48, 0] + opROUND00, // [-80, -80, -16, -16] + opPUSHB000, // [-80, -80, -16, -16, 0] 0, - opROUND00, // [-112, -48, -48, -48, 16] - opPUSHB000, // [-112, -48, -48, -48, 16, 16] + opROUND00, // [-80, -80, -16, -16, 16] + opPUSHB000, // [-80, -80, -16, -16, 16, 16] 16, - opROUND00, // [-112, -48, -48, -48, 16, 16] - opPUSHB000, // [-112, -48, -48, -48, 16, 16, 47] + opROUND00, // [-80, -80, -16, -16, 16, 16] + opPUSHB000, // [-80, -80, -16, -16, 16, 16, 47] 47, - opROUND00, // [-112, -48, -48, -48, 16, 16, 16] - opPUSHB000, // [-112, -48, -48, -48, 16, 16, 16, 48] + opROUND00, // [-80, -80, -16, -16, 16, 16, 16] + opPUSHB000, // [-80, -80, -16, -16, 16, 16, 16, 48] 48, - opROUND00, // [-112, -48, -48, -48, 16, 16, 16, 80] + opROUND00, // [-80, -80, -16, -16, 16, 16, 16, 80] }, - []int32{-112, -48, -48, -48, 16, 16, 16, 80}, + []int32{-80, -80, -16, -16, 16, 16, 16, 80}, "", }, { diff --git a/freetype/truetype/truetype_test.go b/freetype/truetype/truetype_test.go index a356bc0..37dbfea 100644 --- a/freetype/truetype/truetype_test.go +++ b/freetype/truetype/truetype_test.go @@ -116,7 +116,7 @@ func testScaling(t *testing.T, filename string, hinter *Hinter) { for i, want := range wants { // TODO: completely implement hinting. For now, only the first N glyphs // of luxisr.ttf are correctly hinted. - const N = 8 + const N = 9 if hinter != nil && i == N { break }