// 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 // A Point is a co-ordinate pair plus whether it is ``on'' a contour or an // ``off'' control point. type Point struct { X, Y int16 // The Flags' LSB means whether or not this Point is ``on'' the contour. // Other bits are reserved for internal use. Flags uint8 } // 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 { // The glyph's bounding box. B Bounds // Point contains all Points from all contours of the glyph. Point []Point // 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 } // 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 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 ) // decodeFlags decodes a glyph's run-length encoded flags, // and returns the remaining data. func (g *GlyphBuf) decodeFlags(d data, np0 int) data { for i := np0; i < len(g.Point); { c := d.u8() g.Point[i].Flags = c i++ if c&flagRepeat != 0 { count := d.u8() for ; count > 0; count-- { g.Point[i].Flags = c i++ } } } return d } // decodeCoords decodes a glyph's delta encoded co-ordinates. func (g *GlyphBuf) decodeCoords(d data, np0 int) { var x int16 for i := np0; i < len(g.Point); i++ { f := g.Point[i].Flags if f&flagXShortVector != 0 { dx := int16(d.u8()) if f&flagPositiveXShortVector == 0 { x -= dx } else { x += dx } } else if f&flagThisXIsSame == 0 { x += int16(d.u16()) } g.Point[i].X = x } var y int16 for i := np0; i < len(g.Point); i++ { f := g.Point[i].Flags if f&flagYShortVector != 0 { dy := int16(d.u8()) if f&flagPositiveYShortVector == 0 { y -= dy } else { y += dy } } else if f&flagThisYIsSame == 0 { y += int16(d.u16()) } g.Point[i].Y = y } } // Load loads a glyph's contours from a Font, overwriting any previously // loaded contours for this GlyphBuf. func (g *GlyphBuf) Load(f *Font, i Index) error { // Reset the GlyphBuf. g.B = Bounds{} g.Point = g.Point[0:0] g.End = g.End[0:0] return g.load(f, i, 0) } // loadCompound loads a glyph that is composed of other glyphs. func (g *GlyphBuf) loadCompound(f *Font, d data, recursion int) 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 ) for { flags := d.u16() component := d.u16() var dx, dy int16 if flags&flagArg1And2AreWords != 0 { dx = int16(d.u16()) dy = int16(d.u16()) } else { dx = int16(int8(d.u8())) dy = int16(int8(d.u8())) } if flags&flagArgsAreXYValues == 0 { return UnsupportedError("compound glyph transform vector") } if flags&(flagWeHaveAScale|flagWeHaveAnXAndYScale|flagWeHaveATwoByTwo) != 0 { return UnsupportedError("compound glyph scale/transform") } b0, i0 := g.B, len(g.Point) g.load(f, Index(component), recursion+1) for i := i0; i < len(g.Point); i++ { g.Point[i].X += dx g.Point[i].Y += dy } if flags&flagUseMyMetrics == 0 { g.B = b0 } if flags&flagMoreComponents == 0 { break } } return nil } // load appends a glyph's contours to this GlyphBuf. func (g *GlyphBuf) load(f *Font, i Index, recursion int) error { if recursion >= 4 { return UnsupportedError("excessive compound glyph recursion") } // Find the relevant slice of f.glyf. var g0, g1 uint32 if f.locaOffsetFormat == locaOffsetFormatShort { d := data(f.loca[2*int(i):]) g0 = 2 * uint32(d.u16()) g1 = 2 * uint32(d.u16()) } else { d := data(f.loca[4*int(i):]) g0 = d.u32() g1 = d.u32() } if g0 == g1 { return nil } d := data(f.glyf[g0:g1]) // Decode the contour end indices. ne := int(int16(d.u16())) g.B.XMin = int16(d.u16()) g.B.YMin = int16(d.u16()) g.B.XMax = int16(d.u16()) g.B.YMax = int16(d.u16()) if ne == -1 { return g.loadCompound(f, d, recursion) } else if ne < 0 { // 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") } ne0, np0 := len(g.End), len(g.Point) ne += ne0 if ne <= cap(g.End) { g.End = g.End[0:ne] } else { g.End = make([]int, ne, ne*2) } for i := ne0; i < ne; i++ { g.End[i] = 1 + np0 + int(d.u16()) } // Skip the TrueType hinting instructions. instrLen := int(d.u16()) d.skip(instrLen) // Decode the points. np := int(g.End[ne-1]) if np <= cap(g.Point) { g.Point = g.Point[0:np] } else { g.Point = make([]Point, np, np*2) } d = g.decodeFlags(d, np0) g.decodeCoords(d, np0) return nil } // NewGlyphBuf returns a newly allocated GlyphBuf. func NewGlyphBuf() *GlyphBuf { g := new(GlyphBuf) g.Point = make([]Point, 0, 256) g.End = make([]int, 0, 32) return g }