freetype/truetype: load vertical metrics from the OS/2 table.
R=bsiegert CC=golang-dev, remyoudompheng https://codereview.appspot.com/34700043
This commit is contained in:
parent
1c0c5a1f9a
commit
114d43ecfe
|
@ -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) {
|
func (g *GlyphBuf) addPhantomsAndScale(b Bounds, uhm HMetric, i Index, np0 int, simple bool) {
|
||||||
// Add the four phantom points.
|
// Add the four phantom points.
|
||||||
uvm := g.font.unscaledVMetric(i)
|
uvm := g.font.unscaledVMetric(i, b.YMax)
|
||||||
g.Point = append(g.Point,
|
g.Point = append(g.Point,
|
||||||
Point{X: b.XMin - uhm.LeftSideBearing},
|
Point{X: b.XMin - uhm.LeftSideBearing},
|
||||||
Point{X: b.XMin - uhm.LeftSideBearing + uhm.AdvanceWidth},
|
Point{X: b.XMin - uhm.LeftSideBearing + uhm.AdvanceWidth},
|
||||||
Point{Y: b.YMax + uvm.TopSideBearing},
|
Point{X: uhm.AdvanceWidth / 2, Y: b.YMax + uvm.TopSideBearing},
|
||||||
Point{Y: b.YMax + uvm.TopSideBearing - uvm.AdvanceHeight},
|
Point{X: uhm.AdvanceWidth / 2, Y: b.YMax + uvm.TopSideBearing - uvm.AdvanceHeight},
|
||||||
)
|
)
|
||||||
// Scale the points.
|
// Scale the points.
|
||||||
if simple && g.hinter != nil {
|
if simple && g.hinter != nil {
|
||||||
|
|
|
@ -98,7 +98,7 @@ type cm struct {
|
||||||
type Font struct {
|
type Font struct {
|
||||||
// Tables sliced from the TTF data. The different tables are documented
|
// Tables sliced from the TTF data. The different tables are documented
|
||||||
// at http://developer.apple.com/fonts/TTRefMan/RM06/Chap6.html
|
// 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
|
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
|
// unscaledVMetric returns the unscaled vertical metrics for the glyph with
|
||||||
// the given index.
|
// the given index. yMax is the top of the glyph's bounding box.
|
||||||
func (f *Font) unscaledVMetric(i Index) (v VMetric) {
|
func (f *Font) unscaledVMetric(i Index, yMax int32) (v VMetric) {
|
||||||
j := int(i)
|
j := int(i)
|
||||||
if j < 0 || f.nGlyph <= j {
|
if j < 0 || f.nGlyph <= j {
|
||||||
return VMetric{}
|
return VMetric{}
|
||||||
|
@ -385,6 +385,19 @@ func (f *Font) unscaledVMetric(i Index) (v VMetric) {
|
||||||
TopSideBearing: int32(int16(u16(f.vmtx, 4*j+2))),
|
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{
|
return VMetric{
|
||||||
AdvanceHeight: f.fUnitsPerEm,
|
AdvanceHeight: f.fUnitsPerEm,
|
||||||
TopSideBearing: 0,
|
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.
|
// VMetric returns the vertical metrics for the glyph with the given index.
|
||||||
func (f *Font) VMetric(scale int32, i Index) VMetric {
|
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.AdvanceHeight = f.scale(scale * v.AdvanceHeight)
|
||||||
v.TopSideBearing = f.scale(scale * v.TopSideBearing)
|
v.TopSideBearing = f.scale(scale * v.TopSideBearing)
|
||||||
return v
|
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])
|
f.loca, err = readTable(ttf, ttf[x+8:x+16])
|
||||||
case "maxp":
|
case "maxp":
|
||||||
f.maxp, err = readTable(ttf, ttf[x+8:x+16])
|
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":
|
case "prep":
|
||||||
f.prep, err = readTable(ttf, ttf[x+8:x+16])
|
f.prep, err = readTable(ttf, ttf[x+8:x+16])
|
||||||
case "vmtx":
|
case "vmtx":
|
||||||
|
|
|
@ -261,22 +261,6 @@ var scalingTestCases = []struct {
|
||||||
{"x-times-new-roman", 13, 0},
|
{"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.
|
// TODO: also test bounding boxes, not just points.
|
||||||
|
|
||||||
func testScaling(t *testing.T, hinter *Hinter) {
|
func testScaling(t *testing.T, hinter *Hinter) {
|
||||||
|
@ -329,7 +313,6 @@ func testScaling(t *testing.T, hinter *Hinter) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
exceptions := scalingExceptions[tc.name]
|
|
||||||
glyphBuf := NewGlyphBuf()
|
glyphBuf := NewGlyphBuf()
|
||||||
for i, want := range wants {
|
for i, want := range wants {
|
||||||
// TODO: completely implement hinting. For now, only the first
|
// TODO: completely implement hinting. For now, only the first
|
||||||
|
@ -338,10 +321,6 @@ func testScaling(t *testing.T, hinter *Hinter) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if exceptions != nil && exceptions[i] {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = glyphBuf.Load(font, tc.size*64, Index(i), hinter); err != nil {
|
if err = glyphBuf.Load(font, tc.size*64, Index(i), hinter); err != nil {
|
||||||
t.Errorf("%s: glyph #%d: Load: %v", tc.name, i, err)
|
t.Errorf("%s: glyph #%d: Load: %v", tc.name, i, err)
|
||||||
continue
|
continue
|
||||||
|
|
Loading…
Reference in New Issue