From cf7a05f80f68b5b1c8bcc0089679dd497cec2506 Mon Sep 17 00:00:00 2001 From: =Corey Hulen Date: Sun, 14 Jun 2015 23:53:32 -0800 Subject: first commit --- .../p/freetype-go/freetype/truetype/glyph.go | 530 +++++++++++++++++++++ 1 file changed, 530 insertions(+) create mode 100644 Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/truetype/glyph.go (limited to 'Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/truetype/glyph.go') diff --git a/Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/truetype/glyph.go b/Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/truetype/glyph.go new file mode 100644 index 000000000..b5f327851 --- /dev/null +++ b/Godeps/_workspace/src/code.google.com/p/freetype-go/freetype/truetype/glyph.go @@ -0,0 +1,530 @@ +// Copyright 2010 The Freetype-Go Authors. All rights reserved. +// Use of this source code is governed by your choice of either the +// FreeType License or the GNU General Public License version 2 (or +// any later version), both of which can be found in the LICENSE file. + +package truetype + +// Hinting is the policy for snapping a glyph's contours to pixel boundaries. +type Hinting int32 + +const ( + // NoHinting means to not perform any hinting. + NoHinting Hinting = iota + // FullHinting means to use the font's hinting instructions. + FullHinting + + // TODO: implement VerticalHinting. +) + +// A Point is a co-ordinate pair plus whether it is ``on'' a contour or an +// ``off'' control point. +type Point struct { + X, Y int32 + // The Flags' LSB means whether or not this Point is ``on'' the contour. + // Other bits are reserved for internal use. + Flags uint32 +} + +// A GlyphBuf holds a glyph's contours. A GlyphBuf can be re-used to load a +// series of glyphs from a Font. +type GlyphBuf struct { + // AdvanceWidth is the glyph's advance width. + AdvanceWidth int32 + // B is the glyph's bounding box. + B Bounds + // Point contains all Points from all contours of the glyph. If + // hinting was used to load a glyph then Unhinted contains those + // Points before they were hinted, and InFontUnits contains those + // Points before they were hinted and scaled. + Point, Unhinted, InFontUnits []Point + // End is the point indexes of the end point of each countour. The + // length of End is the number of contours in the glyph. The i'th + // contour consists of points Point[End[i-1]:End[i]], where End[-1] + // is interpreted to mean zero. + End []int + + font *Font + scale int32 + hinting Hinting + hinter hinter + // phantomPoints are the co-ordinates of the synthetic phantom points + // used for hinting and bounding box calculations. + phantomPoints [4]Point + // pp1x is the X co-ordinate of the first phantom point. The '1' is + // using 1-based indexing; pp1x is almost always phantomPoints[0].X. + // TODO: eliminate this and consistently use phantomPoints[0].X. + pp1x int32 + // metricsSet is whether the glyph's metrics have been set yet. For a + // compound glyph, a sub-glyph may override the outer glyph's metrics. + metricsSet bool + // tmp is a scratch buffer. + tmp []Point +} + +// Flags for decoding a glyph's contours. These flags are documented at +// http://developer.apple.com/fonts/TTRefMan/RM06/Chap6glyf.html. +const ( + flagOnCurve = 1 << iota + flagXShortVector + flagYShortVector + flagRepeat + flagPositiveXShortVector + flagPositiveYShortVector + + // The remaining flags are for internal use. + flagTouchedX + flagTouchedY +) + +// The same flag bits (0x10 and 0x20) are overloaded to have two meanings, +// dependent on the value of the flag{X,Y}ShortVector bits. +const ( + flagThisXIsSame = flagPositiveXShortVector + flagThisYIsSame = flagPositiveYShortVector +) + +// Load loads a glyph's contours from a Font, overwriting any previously +// loaded contours for this GlyphBuf. scale is the number of 26.6 fixed point +// units in 1 em, i is the glyph index, and h is the hinting policy. +func (g *GlyphBuf) Load(f *Font, scale int32, i Index, h Hinting) error { + g.Point = g.Point[:0] + g.Unhinted = g.Unhinted[:0] + g.InFontUnits = g.InFontUnits[:0] + g.End = g.End[:0] + g.font = f + g.hinting = h + g.scale = scale + g.pp1x = 0 + g.phantomPoints = [4]Point{} + g.metricsSet = false + + if h != NoHinting { + if err := g.hinter.init(f, scale); err != nil { + return err + } + } + if err := g.load(0, i, true); err != nil { + return err + } + // TODO: this selection of either g.pp1x or g.phantomPoints[0].X isn't ideal, + // and should be cleaned up once we have all the testScaling tests passing, + // plus additional tests for Freetype-Go's bounding boxes matching C Freetype's. + pp1x := g.pp1x + if h != NoHinting { + pp1x = g.phantomPoints[0].X + } + if pp1x != 0 { + for i := range g.Point { + g.Point[i].X -= pp1x + } + } + + advanceWidth := g.phantomPoints[1].X - g.phantomPoints[0].X + if h != NoHinting { + if len(f.hdmx) >= 8 { + if n := u32(f.hdmx, 4); n > 3+uint32(i) { + for hdmx := f.hdmx[8:]; uint32(len(hdmx)) >= n; hdmx = hdmx[n:] { + if int32(hdmx[0]) == scale>>6 { + advanceWidth = int32(hdmx[2+i]) << 6 + break + } + } + } + } + advanceWidth = (advanceWidth + 32) &^ 63 + } + g.AdvanceWidth = advanceWidth + + // Set g.B to the 'control box', which is the bounding box of the Bézier + // curves' control points. This is easier to calculate, no smaller than + // and often equal to the tightest possible bounding box of the curves + // themselves. This approach is what C Freetype does. We can't just scale + // the nominal bounding box in the glyf data as the hinting process and + // phantom point adjustment may move points outside of that box. + if len(g.Point) == 0 { + g.B = Bounds{} + } else { + p := g.Point[0] + g.B.XMin = p.X + g.B.XMax = p.X + g.B.YMin = p.Y + g.B.YMax = p.Y + for _, p := range g.Point[1:] { + if g.B.XMin > p.X { + g.B.XMin = p.X + } else if g.B.XMax < p.X { + g.B.XMax = p.X + } + if g.B.YMin > p.Y { + g.B.YMin = p.Y + } else if g.B.YMax < p.Y { + g.B.YMax = p.Y + } + } + // Snap the box to the grid, if hinting is on. + if h != NoHinting { + g.B.XMin &^= 63 + g.B.YMin &^= 63 + g.B.XMax += 63 + g.B.XMax &^= 63 + g.B.YMax += 63 + g.B.YMax &^= 63 + } + } + return nil +} + +func (g *GlyphBuf) load(recursion int32, i Index, useMyMetrics bool) (err error) { + // The recursion limit here is arbitrary, but defends against malformed glyphs. + if recursion >= 32 { + return UnsupportedError("excessive compound glyph recursion") + } + // Find the relevant slice of g.font.glyf. + var g0, g1 uint32 + if g.font.locaOffsetFormat == locaOffsetFormatShort { + g0 = 2 * uint32(u16(g.font.loca, 2*int(i))) + g1 = 2 * uint32(u16(g.font.loca, 2*int(i)+2)) + } else { + g0 = u32(g.font.loca, 4*int(i)) + g1 = u32(g.font.loca, 4*int(i)+4) + } + + // Decode the contour count and nominal bounding box, from the first + // 10 bytes of the glyf data. boundsYMin and boundsXMax, at offsets 4 + // and 6, are unused. + glyf, ne, boundsXMin, boundsYMax := []byte(nil), 0, int32(0), int32(0) + if g0+10 <= g1 { + glyf = g.font.glyf[g0:g1] + ne = int(int16(u16(glyf, 0))) + boundsXMin = int32(int16(u16(glyf, 2))) + boundsYMax = int32(int16(u16(glyf, 8))) + } + + // Create the phantom points. + uhm, pp1x := g.font.unscaledHMetric(i), int32(0) + uvm := g.font.unscaledVMetric(i, boundsYMax) + g.phantomPoints = [4]Point{ + {X: boundsXMin - uhm.LeftSideBearing}, + {X: boundsXMin - uhm.LeftSideBearing + uhm.AdvanceWidth}, + {X: uhm.AdvanceWidth / 2, Y: boundsYMax + uvm.TopSideBearing}, + {X: uhm.AdvanceWidth / 2, Y: boundsYMax + uvm.TopSideBearing - uvm.AdvanceHeight}, + } + if len(glyf) == 0 { + g.addPhantomsAndScale(len(g.Point), len(g.Point), true, true) + copy(g.phantomPoints[:], g.Point[len(g.Point)-4:]) + g.Point = g.Point[:len(g.Point)-4] + return nil + } + + // Load and hint the contours. + if ne < 0 { + if ne != -1 { + // http://developer.apple.com/fonts/TTRefMan/RM06/Chap6glyf.html says that + // "the values -2, -3, and so forth, are reserved for future use." + return UnsupportedError("negative number of contours") + } + pp1x = g.font.scale(g.scale * (boundsXMin - uhm.LeftSideBearing)) + if err := g.loadCompound(recursion, uhm, i, glyf, useMyMetrics); err != nil { + return err + } + } else { + np0, ne0 := len(g.Point), len(g.End) + program := g.loadSimple(glyf, ne) + g.addPhantomsAndScale(np0, np0, true, true) + pp1x = g.Point[len(g.Point)-4].X + if g.hinting != NoHinting { + if len(program) != 0 { + err := g.hinter.run( + program, + g.Point[np0:], + g.Unhinted[np0:], + g.InFontUnits[np0:], + g.End[ne0:], + ) + if err != nil { + return err + } + } + // Drop the four phantom points. + g.InFontUnits = g.InFontUnits[:len(g.InFontUnits)-4] + g.Unhinted = g.Unhinted[:len(g.Unhinted)-4] + } + if useMyMetrics { + copy(g.phantomPoints[:], g.Point[len(g.Point)-4:]) + } + g.Point = g.Point[:len(g.Point)-4] + if np0 != 0 { + // The hinting program expects the []End values to be indexed relative + // to the inner glyph, not the outer glyph, so we delay adding np0 until + // after the hinting program (if any) has run. + for i := ne0; i < len(g.End); i++ { + g.End[i] += np0 + } + } + } + if useMyMetrics && !g.metricsSet { + g.metricsSet = true + g.pp1x = pp1x + } + return nil +} + +// loadOffset is the initial offset for loadSimple and loadCompound. The first +// 10 bytes are the number of contours and the bounding box. +const loadOffset = 10 + +func (g *GlyphBuf) loadSimple(glyf []byte, ne int) (program []byte) { + offset := loadOffset + for i := 0; i < ne; i++ { + g.End = append(g.End, 1+int(u16(glyf, offset))) + offset += 2 + } + + // Note the TrueType hinting instructions. + instrLen := int(u16(glyf, offset)) + offset += 2 + program = glyf[offset : offset+instrLen] + offset += instrLen + + np0 := len(g.Point) + np1 := np0 + int(g.End[len(g.End)-1]) + + // Decode the flags. + for i := np0; i < np1; { + c := uint32(glyf[offset]) + offset++ + g.Point = append(g.Point, Point{Flags: c}) + i++ + if c&flagRepeat != 0 { + count := glyf[offset] + offset++ + for ; count > 0; count-- { + g.Point = append(g.Point, Point{Flags: c}) + i++ + } + } + } + + // Decode the co-ordinates. + var x int16 + for i := np0; i < np1; i++ { + f := g.Point[i].Flags + if f&flagXShortVector != 0 { + dx := int16(glyf[offset]) + offset++ + if f&flagPositiveXShortVector == 0 { + x -= dx + } else { + x += dx + } + } else if f&flagThisXIsSame == 0 { + x += int16(u16(glyf, offset)) + offset += 2 + } + g.Point[i].X = int32(x) + } + var y int16 + for i := np0; i < np1; i++ { + f := g.Point[i].Flags + if f&flagYShortVector != 0 { + dy := int16(glyf[offset]) + offset++ + if f&flagPositiveYShortVector == 0 { + y -= dy + } else { + y += dy + } + } else if f&flagThisYIsSame == 0 { + y += int16(u16(glyf, offset)) + offset += 2 + } + g.Point[i].Y = int32(y) + } + + return program +} + +func (g *GlyphBuf) loadCompound(recursion int32, uhm HMetric, i Index, + glyf []byte, useMyMetrics bool) error { + + // Flags for decoding a compound glyph. These flags are documented at + // http://developer.apple.com/fonts/TTRefMan/RM06/Chap6glyf.html. + const ( + flagArg1And2AreWords = 1 << iota + flagArgsAreXYValues + flagRoundXYToGrid + flagWeHaveAScale + flagUnused + flagMoreComponents + flagWeHaveAnXAndYScale + flagWeHaveATwoByTwo + flagWeHaveInstructions + flagUseMyMetrics + flagOverlapCompound + ) + np0, ne0 := len(g.Point), len(g.End) + offset := loadOffset + for { + flags := u16(glyf, offset) + component := Index(u16(glyf, offset+2)) + dx, dy, transform, hasTransform := int32(0), int32(0), [4]int32{}, false + if flags&flagArg1And2AreWords != 0 { + dx = int32(int16(u16(glyf, offset+4))) + dy = int32(int16(u16(glyf, offset+6))) + offset += 8 + } else { + dx = int32(int16(int8(glyf[offset+4]))) + dy = int32(int16(int8(glyf[offset+5]))) + offset += 6 + } + if flags&flagArgsAreXYValues == 0 { + return UnsupportedError("compound glyph transform vector") + } + if flags&(flagWeHaveAScale|flagWeHaveAnXAndYScale|flagWeHaveATwoByTwo) != 0 { + hasTransform = true + switch { + case flags&flagWeHaveAScale != 0: + transform[0] = int32(int16(u16(glyf, offset+0))) + transform[3] = transform[0] + offset += 2 + case flags&flagWeHaveAnXAndYScale != 0: + transform[0] = int32(int16(u16(glyf, offset+0))) + transform[3] = int32(int16(u16(glyf, offset+2))) + offset += 4 + case flags&flagWeHaveATwoByTwo != 0: + transform[0] = int32(int16(u16(glyf, offset+0))) + transform[1] = int32(int16(u16(glyf, offset+2))) + transform[2] = int32(int16(u16(glyf, offset+4))) + transform[3] = int32(int16(u16(glyf, offset+6))) + offset += 8 + } + } + savedPP := g.phantomPoints + np0 := len(g.Point) + componentUMM := useMyMetrics && (flags&flagUseMyMetrics != 0) + if err := g.load(recursion+1, component, componentUMM); err != nil { + return err + } + if flags&flagUseMyMetrics == 0 { + g.phantomPoints = savedPP + } + if hasTransform { + for j := np0; j < len(g.Point); j++ { + p := &g.Point[j] + newX := int32((int64(p.X)*int64(transform[0])+1<<13)>>14) + + int32((int64(p.Y)*int64(transform[2])+1<<13)>>14) + newY := int32((int64(p.X)*int64(transform[1])+1<<13)>>14) + + int32((int64(p.Y)*int64(transform[3])+1<<13)>>14) + p.X, p.Y = newX, newY + } + } + dx = g.font.scale(g.scale * dx) + dy = g.font.scale(g.scale * dy) + if flags&flagRoundXYToGrid != 0 { + dx = (dx + 32) &^ 63 + dy = (dy + 32) &^ 63 + } + for j := np0; j < len(g.Point); j++ { + p := &g.Point[j] + p.X += dx + p.Y += dy + } + // TODO: also adjust g.InFontUnits and g.Unhinted? + if flags&flagMoreComponents == 0 { + break + } + } + + instrLen := 0 + if g.hinting != NoHinting && offset+2 <= len(glyf) { + instrLen = int(u16(glyf, offset)) + offset += 2 + } + + g.addPhantomsAndScale(np0, len(g.Point), false, instrLen > 0) + points, ends := g.Point[np0:], g.End[ne0:] + g.Point = g.Point[:len(g.Point)-4] + for j := range points { + points[j].Flags &^= flagTouchedX | flagTouchedY + } + + if instrLen == 0 { + if !g.metricsSet { + copy(g.phantomPoints[:], points[len(points)-4:]) + } + return nil + } + + // Hint the compound glyph. + program := glyf[offset : offset+instrLen] + // Temporarily adjust the ends to be relative to this compound glyph. + if np0 != 0 { + for i := range ends { + ends[i] -= np0 + } + } + // Hinting instructions of a composite glyph completely refer to the + // (already) hinted subglyphs. + g.tmp = append(g.tmp[:0], points...) + if err := g.hinter.run(program, points, g.tmp, g.tmp, ends); err != nil { + return err + } + if np0 != 0 { + for i := range ends { + ends[i] += np0 + } + } + if !g.metricsSet { + copy(g.phantomPoints[:], points[len(points)-4:]) + } + return nil +} + +func (g *GlyphBuf) addPhantomsAndScale(np0, np1 int, simple, adjust bool) { + // Add the four phantom points. + g.Point = append(g.Point, g.phantomPoints[:]...) + // Scale the points. + if simple && g.hinting != NoHinting { + g.InFontUnits = append(g.InFontUnits, g.Point[np1:]...) + } + for i := np1; i < len(g.Point); i++ { + p := &g.Point[i] + p.X = g.font.scale(g.scale * p.X) + p.Y = g.font.scale(g.scale * p.Y) + } + if g.hinting == NoHinting { + return + } + // Round the 1st phantom point to the grid, shifting all other points equally. + // Note that "all other points" starts from np0, not np1. + // TODO: delete this adjustment and the np0/np1 distinction, when + // we update the compatibility tests to C Freetype 2.5.3. + // See http://git.savannah.gnu.org/cgit/freetype/freetype2.git/commit/?id=05c786d990390a7ca18e62962641dac740bacb06 + if adjust { + pp1x := g.Point[len(g.Point)-4].X + if dx := ((pp1x + 32) &^ 63) - pp1x; dx != 0 { + for i := np0; i < len(g.Point); i++ { + g.Point[i].X += dx + } + } + } + if simple { + g.Unhinted = append(g.Unhinted, g.Point[np1:]...) + } + // Round the 2nd and 4th phantom point to the grid. + p := &g.Point[len(g.Point)-3] + p.X = (p.X + 32) &^ 63 + p = &g.Point[len(g.Point)-1] + p.Y = (p.Y + 32) &^ 63 +} + +// TODO: is this necessary? The zero-valued GlyphBuf is perfectly usable. + +// NewGlyphBuf returns a newly allocated GlyphBuf. +func NewGlyphBuf() *GlyphBuf { + return &GlyphBuf{ + Point: make([]Point, 0, 256), + End: make([]int, 0, 32), + } +} -- cgit v1.2.3-1-g7c22