From 114d43ecfe793eb95392531aa8b16faedbdcfd26 Mon Sep 17 00:00:00 2001 From: Nigel Tao Date: Fri, 29 Nov 2013 10:33:11 +1100 Subject: [PATCH] freetype/truetype: load vertical metrics from the OS/2 table. R=bsiegert CC=golang-dev, remyoudompheng https://codereview.appspot.com/34700043 --- freetype/truetype/glyph.go | 6 +++--- freetype/truetype/truetype.go | 24 ++++++++++++++++++++---- freetype/truetype/truetype_test.go | 21 --------------------- 3 files changed, 23 insertions(+), 28 deletions(-) diff --git a/freetype/truetype/glyph.go b/freetype/truetype/glyph.go index 6f59af2..2929e49 100644 --- a/freetype/truetype/glyph.go +++ b/freetype/truetype/glyph.go @@ -377,12 +377,12 @@ func (g *GlyphBuf) loadCompound(recursion int32, b Bounds, uhm HMetric, i Index, func (g *GlyphBuf) addPhantomsAndScale(b Bounds, uhm HMetric, i Index, np0 int, simple bool) { // Add the four phantom points. - uvm := g.font.unscaledVMetric(i) + uvm := g.font.unscaledVMetric(i, b.YMax) g.Point = append(g.Point, Point{X: b.XMin - uhm.LeftSideBearing}, Point{X: b.XMin - uhm.LeftSideBearing + uhm.AdvanceWidth}, - Point{Y: b.YMax + uvm.TopSideBearing}, - Point{Y: b.YMax + uvm.TopSideBearing - uvm.AdvanceHeight}, + Point{X: uhm.AdvanceWidth / 2, Y: b.YMax + uvm.TopSideBearing}, + Point{X: uhm.AdvanceWidth / 2, Y: b.YMax + uvm.TopSideBearing - uvm.AdvanceHeight}, ) // Scale the points. if simple && g.hinter != nil { diff --git a/freetype/truetype/truetype.go b/freetype/truetype/truetype.go index 5b9e654..37fc189 100644 --- a/freetype/truetype/truetype.go +++ b/freetype/truetype/truetype.go @@ -98,7 +98,7 @@ type cm struct { type Font struct { // Tables sliced from the TTF data. The different tables are documented // at http://developer.apple.com/fonts/TTRefMan/RM06/Chap6.html - cmap, cvt, fpgm, glyf, head, hhea, hmtx, kern, loca, maxp, prep, vmtx []byte + cmap, cvt, fpgm, glyf, head, hhea, hmtx, kern, loca, maxp, os2, prep, vmtx []byte cmapIndexes []byte @@ -373,8 +373,8 @@ func (f *Font) HMetric(scale int32, i Index) HMetric { } // unscaledVMetric returns the unscaled vertical metrics for the glyph with -// the given index. -func (f *Font) unscaledVMetric(i Index) (v VMetric) { +// the given index. yMax is the top of the glyph's bounding box. +func (f *Font) unscaledVMetric(i Index, yMax int32) (v VMetric) { j := int(i) if j < 0 || f.nGlyph <= j { return VMetric{} @@ -385,6 +385,19 @@ func (f *Font) unscaledVMetric(i Index) (v VMetric) { TopSideBearing: int32(int16(u16(f.vmtx, 4*j+2))), } } + // The OS/2 table has grown over time. + // https://developer.apple.com/fonts/TTRefMan/RM06/Chap6OS2.html + // says that it was originally 68 bytes. Optional fields, including + // the ascender and descender, are described at + // http://www.microsoft.com/typography/otspec/os2.htm + if len(f.os2) >= 72 { + sTypoAscender := int32(int16(u16(f.os2, 68))) + sTypoDescender := int32(int16(u16(f.os2, 70))) + return VMetric{ + AdvanceHeight: sTypoAscender - sTypoDescender, + TopSideBearing: sTypoAscender - yMax, + } + } return VMetric{ AdvanceHeight: f.fUnitsPerEm, TopSideBearing: 0, @@ -393,7 +406,8 @@ func (f *Font) unscaledVMetric(i Index) (v VMetric) { // VMetric returns the vertical metrics for the glyph with the given index. func (f *Font) VMetric(scale int32, i Index) VMetric { - v := f.unscaledVMetric(i) + // TODO: should 0 be bounds.YMax? + v := f.unscaledVMetric(i, 0) v.AdvanceHeight = f.scale(scale * v.AdvanceHeight) v.TopSideBearing = f.scale(scale * v.TopSideBearing) return v @@ -500,6 +514,8 @@ func parse(ttf []byte, offset int) (font *Font, err error) { f.loca, err = readTable(ttf, ttf[x+8:x+16]) case "maxp": f.maxp, err = readTable(ttf, ttf[x+8:x+16]) + case "OS/2": + f.os2, err = readTable(ttf, ttf[x+8:x+16]) case "prep": f.prep, err = readTable(ttf, ttf[x+8:x+16]) case "vmtx": diff --git a/freetype/truetype/truetype_test.go b/freetype/truetype/truetype_test.go index e6465d4..84084db 100644 --- a/freetype/truetype/truetype_test.go +++ b/freetype/truetype/truetype_test.go @@ -261,22 +261,6 @@ var scalingTestCases = []struct { {"x-times-new-roman", 13, 0}, } -var scalingExceptions = map[string]map[int]bool{ - // TODO: fix these exceptions now that C Freetype version 2.5.1 is released: - // see http://lists.nongnu.org/archive/html/freetype/2013-11/msg00004.html - "x-deja-vu-sans-oblique": map[int]bool{ - 269: true, - 733: true, - 734: true, - 2071: true, - 2072: true, - 2077: true, - 2078: true, - 2171: true, - 2172: true, - }, -} - // TODO: also test bounding boxes, not just points. func testScaling(t *testing.T, hinter *Hinter) { @@ -329,7 +313,6 @@ func testScaling(t *testing.T, hinter *Hinter) { continue } - exceptions := scalingExceptions[tc.name] glyphBuf := NewGlyphBuf() for i, want := range wants { // TODO: completely implement hinting. For now, only the first @@ -338,10 +321,6 @@ func testScaling(t *testing.T, hinter *Hinter) { break } - if exceptions != nil && exceptions[i] { - continue - } - if err = glyphBuf.Load(font, tc.size*64, Index(i), hinter); err != nil { t.Errorf("%s: glyph #%d: Load: %v", tc.name, i, err) continue