diff options
Diffstat (limited to 'Godeps/_workspace/src/github.com/golang/freetype/truetype')
5 files changed, 0 insertions, 3703 deletions
diff --git a/Godeps/_workspace/src/github.com/golang/freetype/truetype/face.go b/Godeps/_workspace/src/github.com/golang/freetype/truetype/face.go deleted file mode 100644 index d64a014c3..000000000 --- a/Godeps/_workspace/src/github.com/golang/freetype/truetype/face.go +++ /dev/null @@ -1,495 +0,0 @@ -// Copyright 2015 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 - -import ( - "image" - - "github.com/golang/freetype/raster" - "golang.org/x/image/font" - "golang.org/x/image/math/fixed" -) - -func powerOf2(i int) bool { - return i != 0 && (i&(i-1)) == 0 -} - -// Options are optional arguments to NewFace. -type Options struct { - // Size is the font size in points, as in "a 10 point font size". - // - // A zero value means to use a 12 point font size. - Size float64 - - // DPI is the dots-per-inch resolution. - // - // A zero value means to use 72 DPI. - DPI float64 - - // Hinting is how to quantize the glyph nodes. - // - // A zero value means to use no hinting. - Hinting font.Hinting - - // GlyphCacheEntries is the number of entries in the glyph mask image - // cache. - // - // If non-zero, it must be a power of 2. - // - // A zero value means to use 512 entries. - GlyphCacheEntries int - - // SubPixelsX is the number of sub-pixel locations a glyph's dot is - // quantized to, in the horizontal direction. For example, a value of 8 - // means that the dot is quantized to 1/8th of a pixel. This quantization - // only affects the glyph mask image, not its bounding box or advance - // width. A higher value gives a more faithful glyph image, but reduces the - // effectiveness of the glyph cache. - // - // If non-zero, it must be a power of 2, and be between 1 and 64 inclusive. - // - // A zero value means to use 4 sub-pixel locations. - SubPixelsX int - - // SubPixelsY is the number of sub-pixel locations a glyph's dot is - // quantized to, in the vertical direction. For example, a value of 8 - // means that the dot is quantized to 1/8th of a pixel. This quantization - // only affects the glyph mask image, not its bounding box or advance - // width. A higher value gives a more faithful glyph image, but reduces the - // effectiveness of the glyph cache. - // - // If non-zero, it must be a power of 2, and be between 1 and 64 inclusive. - // - // A zero value means to use 1 sub-pixel location. - SubPixelsY int -} - -func (o *Options) size() float64 { - if o != nil && o.Size > 0 { - return o.Size - } - return 12 -} - -func (o *Options) dpi() float64 { - if o != nil && o.DPI > 0 { - return o.DPI - } - return 72 -} - -func (o *Options) hinting() font.Hinting { - if o != nil { - switch o.Hinting { - case font.HintingVertical, font.HintingFull: - // TODO: support vertical hinting. - return font.HintingFull - } - } - return font.HintingNone -} - -func (o *Options) glyphCacheEntries() int { - if o != nil && powerOf2(o.GlyphCacheEntries) { - return o.GlyphCacheEntries - } - // 512 is 128 * 4 * 1, which lets us cache 128 glyphs at 4 * 1 subpixel - // locations in the X and Y direction. - return 512 -} - -func (o *Options) subPixelsX() (value uint32, halfQuantum, mask fixed.Int26_6) { - if o != nil { - switch o.SubPixelsX { - case 1, 2, 4, 8, 16, 32, 64: - return subPixels(o.SubPixelsX) - } - } - // This default value of 4 isn't based on anything scientific, merely as - // small a number as possible that looks almost as good as no quantization, - // or returning subPixels(64). - return subPixels(4) -} - -func (o *Options) subPixelsY() (value uint32, halfQuantum, mask fixed.Int26_6) { - if o != nil { - switch o.SubPixelsX { - case 1, 2, 4, 8, 16, 32, 64: - return subPixels(o.SubPixelsX) - } - } - // This default value of 1 isn't based on anything scientific, merely that - // vertical sub-pixel glyph rendering is pretty rare. Baseline locations - // can usually afford to snap to the pixel grid, so the vertical direction - // doesn't have the deal with the horizontal's fractional advance widths. - return subPixels(1) -} - -// subPixels returns q and the bias and mask that leads to q quantized -// sub-pixel locations per full pixel. -// -// For example, q == 4 leads to a bias of 8 and a mask of 0xfffffff0, or -16, -// because we want to round fractions of fixed.Int26_6 as: -// - 0 to 7 rounds to 0. -// - 8 to 23 rounds to 16. -// - 24 to 39 rounds to 32. -// - 40 to 55 rounds to 48. -// - 56 to 63 rounds to 64. -// which means to add 8 and then bitwise-and with -16, in two's complement -// representation. -// -// When q == 1, we want bias == 32 and mask == -64. -// When q == 2, we want bias == 16 and mask == -32. -// When q == 4, we want bias == 8 and mask == -16. -// ... -// When q == 64, we want bias == 0 and mask == -1. (The no-op case). -// The pattern is clear. -func subPixels(q int) (value uint32, bias, mask fixed.Int26_6) { - return uint32(q), 32 / fixed.Int26_6(q), -64 / fixed.Int26_6(q) -} - -// glyphCacheEntry caches the arguments and return values of rasterize. -type glyphCacheEntry struct { - key glyphCacheKey - val glyphCacheVal -} - -type glyphCacheKey struct { - index Index - fx, fy uint8 -} - -type glyphCacheVal struct { - advanceWidth fixed.Int26_6 - offset image.Point - gw int - gh int -} - -type indexCacheEntry struct { - rune rune - index Index -} - -// NewFace returns a new font.Face for the given Font. -func NewFace(f *Font, opts *Options) font.Face { - a := &face{ - f: f, - hinting: opts.hinting(), - scale: fixed.Int26_6(0.5 + (opts.size() * opts.dpi() * 64 / 72)), - glyphCache: make([]glyphCacheEntry, opts.glyphCacheEntries()), - } - a.subPixelX, a.subPixelBiasX, a.subPixelMaskX = opts.subPixelsX() - a.subPixelY, a.subPixelBiasY, a.subPixelMaskY = opts.subPixelsY() - - // Fill the cache with invalid entries. Valid glyph cache entries have fx - // and fy in the range [0, 64). Valid index cache entries have rune >= 0. - for i := range a.glyphCache { - a.glyphCache[i].key.fy = 0xff - } - for i := range a.indexCache { - a.indexCache[i].rune = -1 - } - - // Set the rasterizer's bounds to be big enough to handle the largest glyph. - b := f.Bounds(a.scale) - xmin := +int(b.Min.X) >> 6 - ymin := -int(b.Max.Y) >> 6 - xmax := +int(b.Max.X+63) >> 6 - ymax := -int(b.Min.Y-63) >> 6 - a.maxw = xmax - xmin - a.maxh = ymax - ymin - a.masks = image.NewAlpha(image.Rect(0, 0, a.maxw, a.maxh*len(a.glyphCache))) - a.r.SetBounds(a.maxw, a.maxh) - a.p = facePainter{a} - - return a -} - -type face struct { - f *Font - hinting font.Hinting - scale fixed.Int26_6 - subPixelX uint32 - subPixelBiasX fixed.Int26_6 - subPixelMaskX fixed.Int26_6 - subPixelY uint32 - subPixelBiasY fixed.Int26_6 - subPixelMaskY fixed.Int26_6 - masks *image.Alpha - glyphCache []glyphCacheEntry - r raster.Rasterizer - p raster.Painter - paintOffset int - maxw int - maxh int - glyphBuf GlyphBuf - indexCache [indexCacheLen]indexCacheEntry - - // TODO: clip rectangle? -} - -const indexCacheLen = 256 - -func (a *face) index(r rune) Index { - const mask = indexCacheLen - 1 - c := &a.indexCache[r&mask] - if c.rune == r { - return c.index - } - i := a.f.Index(r) - c.rune = r - c.index = i - return i -} - -// Close satisfies the font.Face interface. -func (a *face) Close() error { return nil } - -// Kern satisfies the font.Face interface. -func (a *face) Kern(r0, r1 rune) fixed.Int26_6 { - i0 := a.index(r0) - i1 := a.index(r1) - kern := a.f.Kern(a.scale, i0, i1) - if a.hinting != font.HintingNone { - kern = (kern + 32) &^ 63 - } - return kern -} - -// Glyph satisfies the font.Face interface. -func (a *face) Glyph(dot fixed.Point26_6, r rune) ( - dr image.Rectangle, mask image.Image, maskp image.Point, advance fixed.Int26_6, ok bool) { - - // Quantize to the sub-pixel granularity. - dotX := (dot.X + a.subPixelBiasX) & a.subPixelMaskX - dotY := (dot.Y + a.subPixelBiasY) & a.subPixelMaskY - - // Split the coordinates into their integer and fractional parts. - ix, fx := int(dotX>>6), dotX&0x3f - iy, fy := int(dotY>>6), dotY&0x3f - - index := a.index(r) - cIndex := uint32(index) - cIndex = cIndex*a.subPixelX - uint32(fx/a.subPixelMaskX) - cIndex = cIndex*a.subPixelY - uint32(fy/a.subPixelMaskY) - cIndex &= uint32(len(a.glyphCache) - 1) - a.paintOffset = a.maxh * int(cIndex) - k := glyphCacheKey{ - index: index, - fx: uint8(fx), - fy: uint8(fy), - } - var v glyphCacheVal - if a.glyphCache[cIndex].key != k { - var ok bool - v, ok = a.rasterize(index, fx, fy) - if !ok { - return image.Rectangle{}, nil, image.Point{}, 0, false - } - a.glyphCache[cIndex] = glyphCacheEntry{k, v} - } else { - v = a.glyphCache[cIndex].val - } - - dr.Min = image.Point{ - X: ix + v.offset.X, - Y: iy + v.offset.Y, - } - dr.Max = image.Point{ - X: dr.Min.X + v.gw, - Y: dr.Min.Y + v.gh, - } - return dr, a.masks, image.Point{Y: a.paintOffset}, v.advanceWidth, true -} - -func (a *face) GlyphBounds(r rune) (bounds fixed.Rectangle26_6, advance fixed.Int26_6, ok bool) { - if err := a.glyphBuf.Load(a.f, a.scale, a.index(r), a.hinting); err != nil { - return fixed.Rectangle26_6{}, 0, false - } - xmin := +a.glyphBuf.Bounds.Min.X - ymin := -a.glyphBuf.Bounds.Max.Y - xmax := +a.glyphBuf.Bounds.Max.X - ymax := -a.glyphBuf.Bounds.Min.Y - if xmin > xmax || ymin > ymax { - return fixed.Rectangle26_6{}, 0, false - } - return fixed.Rectangle26_6{ - Min: fixed.Point26_6{ - X: xmin, - Y: ymin, - }, - Max: fixed.Point26_6{ - X: xmax, - Y: ymax, - }, - }, a.glyphBuf.AdvanceWidth, true -} - -func (a *face) GlyphAdvance(r rune) (advance fixed.Int26_6, ok bool) { - if err := a.glyphBuf.Load(a.f, a.scale, a.index(r), a.hinting); err != nil { - return 0, false - } - return a.glyphBuf.AdvanceWidth, true -} - -// rasterize returns the advance width, integer-pixel offset to render at, and -// the width and height of the given glyph at the given sub-pixel offsets. -// -// The 26.6 fixed point arguments fx and fy must be in the range [0, 1). -func (a *face) rasterize(index Index, fx, fy fixed.Int26_6) (v glyphCacheVal, ok bool) { - if err := a.glyphBuf.Load(a.f, a.scale, index, a.hinting); err != nil { - return glyphCacheVal{}, false - } - // Calculate the integer-pixel bounds for the glyph. - xmin := int(fx+a.glyphBuf.Bounds.Min.X) >> 6 - ymin := int(fy-a.glyphBuf.Bounds.Max.Y) >> 6 - xmax := int(fx+a.glyphBuf.Bounds.Max.X+0x3f) >> 6 - ymax := int(fy-a.glyphBuf.Bounds.Min.Y+0x3f) >> 6 - if xmin > xmax || ymin > ymax { - return glyphCacheVal{}, false - } - // A TrueType's glyph's nodes can have negative co-ordinates, but the - // rasterizer clips anything left of x=0 or above y=0. xmin and ymin are - // the pixel offsets, based on the font's FUnit metrics, that let a - // negative co-ordinate in TrueType space be non-negative in rasterizer - // space. xmin and ymin are typically <= 0. - fx -= fixed.Int26_6(xmin << 6) - fy -= fixed.Int26_6(ymin << 6) - // Rasterize the glyph's vectors. - a.r.Clear() - pixOffset := a.paintOffset * a.maxw - clear(a.masks.Pix[pixOffset : pixOffset+a.maxw*a.maxh]) - e0 := 0 - for _, e1 := range a.glyphBuf.Ends { - a.drawContour(a.glyphBuf.Points[e0:e1], fx, fy) - e0 = e1 - } - a.r.Rasterize(a.p) - return glyphCacheVal{ - a.glyphBuf.AdvanceWidth, - image.Point{xmin, ymin}, - xmax - xmin, - ymax - ymin, - }, true -} - -func clear(pix []byte) { - for i := range pix { - pix[i] = 0 - } -} - -// drawContour draws the given closed contour with the given offset. -func (a *face) drawContour(ps []Point, dx, dy fixed.Int26_6) { - if len(ps) == 0 { - return - } - - // The low bit of each point's Flags value is whether the point is on the - // curve. Truetype fonts only have quadratic Bézier curves, not cubics. - // Thus, two consecutive off-curve points imply an on-curve point in the - // middle of those two. - // - // See http://chanae.walon.org/pub/ttf/ttf_glyphs.htm for more details. - - // ps[0] is a truetype.Point measured in FUnits and positive Y going - // upwards. start is the same thing measured in fixed point units and - // positive Y going downwards, and offset by (dx, dy). - start := fixed.Point26_6{ - X: dx + ps[0].X, - Y: dy - ps[0].Y, - } - var others []Point - if ps[0].Flags&0x01 != 0 { - others = ps[1:] - } else { - last := fixed.Point26_6{ - X: dx + ps[len(ps)-1].X, - Y: dy - ps[len(ps)-1].Y, - } - if ps[len(ps)-1].Flags&0x01 != 0 { - start = last - others = ps[:len(ps)-1] - } else { - start = fixed.Point26_6{ - X: (start.X + last.X) / 2, - Y: (start.Y + last.Y) / 2, - } - others = ps - } - } - a.r.Start(start) - q0, on0 := start, true - for _, p := range others { - q := fixed.Point26_6{ - X: dx + p.X, - Y: dy - p.Y, - } - on := p.Flags&0x01 != 0 - if on { - if on0 { - a.r.Add1(q) - } else { - a.r.Add2(q0, q) - } - } else { - if on0 { - // No-op. - } else { - mid := fixed.Point26_6{ - X: (q0.X + q.X) / 2, - Y: (q0.Y + q.Y) / 2, - } - a.r.Add2(q0, mid) - } - } - q0, on0 = q, on - } - // Close the curve. - if on0 { - a.r.Add1(start) - } else { - a.r.Add2(q0, start) - } -} - -// facePainter is like a raster.AlphaSrcPainter, with an additional Y offset -// (face.paintOffset) to the painted spans. -type facePainter struct { - a *face -} - -func (p facePainter) Paint(ss []raster.Span, done bool) { - m := p.a.masks - b := m.Bounds() - b.Min.Y = p.a.paintOffset - b.Max.Y = p.a.paintOffset + p.a.maxh - for _, s := range ss { - s.Y += p.a.paintOffset - if s.Y < b.Min.Y { - continue - } - if s.Y >= b.Max.Y { - return - } - if s.X0 < b.Min.X { - s.X0 = b.Min.X - } - if s.X1 > b.Max.X { - s.X1 = b.Max.X - } - if s.X0 >= s.X1 { - continue - } - base := (s.Y-m.Rect.Min.Y)*m.Stride - m.Rect.Min.X - p := m.Pix[base+s.X0 : base+s.X1] - color := uint8(s.Alpha >> 8) - for i := range p { - p[i] = color - } - } -} diff --git a/Godeps/_workspace/src/github.com/golang/freetype/truetype/glyph.go b/Godeps/_workspace/src/github.com/golang/freetype/truetype/glyph.go deleted file mode 100644 index c2935a58e..000000000 --- a/Godeps/_workspace/src/github.com/golang/freetype/truetype/glyph.go +++ /dev/null @@ -1,517 +0,0 @@ -// 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 - -import ( - "golang.org/x/image/font" - "golang.org/x/image/math/fixed" -) - -// 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 fixed.Int26_6 - // 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 fixed.Int26_6 - // Bounds is the glyph's bounding box. - Bounds fixed.Rectangle26_6 - // Points 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. - Points, Unhinted, InFontUnits []Point - // Ends is the point indexes of the end point of each contour. The length - // of Ends is the number of contours in the glyph. The i'th contour - // consists of points Points[Ends[i-1]:Ends[i]], where Ends[-1] is - // interpreted to mean zero. - Ends []int - - font *Font - scale fixed.Int26_6 - hinting font.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 fixed.Int26_6 - // 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 fixed.Int26_6, i Index, h font.Hinting) error { - g.Points = g.Points[:0] - g.Unhinted = g.Unhinted[:0] - g.InFontUnits = g.InFontUnits[:0] - g.Ends = g.Ends[:0] - g.font = f - g.hinting = h - g.scale = scale - g.pp1x = 0 - g.phantomPoints = [4]Point{} - g.metricsSet = false - - if h != font.HintingNone { - 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 != font.HintingNone { - pp1x = g.phantomPoints[0].X - } - if pp1x != 0 { - for i := range g.Points { - g.Points[i].X -= pp1x - } - } - - advanceWidth := g.phantomPoints[1].X - g.phantomPoints[0].X - if h != font.HintingNone { - 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 fixed.Int26_6(hdmx[0]) == scale>>6 { - advanceWidth = fixed.Int26_6(hdmx[2+i]) << 6 - break - } - } - } - } - advanceWidth = (advanceWidth + 32) &^ 63 - } - g.AdvanceWidth = advanceWidth - - // Set g.Bounds 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.Points) == 0 { - g.Bounds = fixed.Rectangle26_6{} - } else { - p := g.Points[0] - g.Bounds.Min.X = p.X - g.Bounds.Max.X = p.X - g.Bounds.Min.Y = p.Y - g.Bounds.Max.Y = p.Y - for _, p := range g.Points[1:] { - if g.Bounds.Min.X > p.X { - g.Bounds.Min.X = p.X - } else if g.Bounds.Max.X < p.X { - g.Bounds.Max.X = p.X - } - if g.Bounds.Min.Y > p.Y { - g.Bounds.Min.Y = p.Y - } else if g.Bounds.Max.Y < p.Y { - g.Bounds.Max.Y = p.Y - } - } - // Snap the box to the grid, if hinting is on. - if h != font.HintingNone { - g.Bounds.Min.X &^= 63 - g.Bounds.Min.Y &^= 63 - g.Bounds.Max.X += 63 - g.Bounds.Max.X &^= 63 - g.Bounds.Max.Y += 63 - g.Bounds.Max.Y &^= 63 - } - } - return nil -} - -func (g *GlyphBuf) load(recursion uint32, 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, fixed.Int26_6(0), fixed.Int26_6(0) - if g0+10 <= g1 { - glyf = g.font.glyf[g0:g1] - ne = int(int16(u16(glyf, 0))) - boundsXMin = fixed.Int26_6(int16(u16(glyf, 2))) - boundsYMax = fixed.Int26_6(int16(u16(glyf, 8))) - } - - // Create the phantom points. - uhm, pp1x := g.font.unscaledHMetric(i), fixed.Int26_6(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.Points), len(g.Points), true, true) - copy(g.phantomPoints[:], g.Points[len(g.Points)-4:]) - g.Points = g.Points[:len(g.Points)-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.Points), len(g.Ends) - program := g.loadSimple(glyf, ne) - g.addPhantomsAndScale(np0, np0, true, true) - pp1x = g.Points[len(g.Points)-4].X - if g.hinting != font.HintingNone { - if len(program) != 0 { - err := g.hinter.run( - program, - g.Points[np0:], - g.Unhinted[np0:], - g.InFontUnits[np0:], - g.Ends[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.Points[len(g.Points)-4:]) - } - g.Points = g.Points[:len(g.Points)-4] - if np0 != 0 { - // The hinting program expects the []Ends 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.Ends); i++ { - g.Ends[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.Ends = append(g.Ends, 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.Points) - np1 := np0 + int(g.Ends[len(g.Ends)-1]) - - // Decode the flags. - for i := np0; i < np1; { - c := uint32(glyf[offset]) - offset++ - g.Points = append(g.Points, Point{Flags: c}) - i++ - if c&flagRepeat != 0 { - count := glyf[offset] - offset++ - for ; count > 0; count-- { - g.Points = append(g.Points, Point{Flags: c}) - i++ - } - } - } - - // Decode the co-ordinates. - var x int16 - for i := np0; i < np1; i++ { - f := g.Points[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.Points[i].X = fixed.Int26_6(x) - } - var y int16 - for i := np0; i < np1; i++ { - f := g.Points[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.Points[i].Y = fixed.Int26_6(y) - } - - return program -} - -func (g *GlyphBuf) loadCompound(recursion uint32, 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.Points), len(g.Ends) - offset := loadOffset - for { - flags := u16(glyf, offset) - component := Index(u16(glyf, offset+2)) - dx, dy, transform, hasTransform := fixed.Int26_6(0), fixed.Int26_6(0), [4]int16{}, false - if flags&flagArg1And2AreWords != 0 { - dx = fixed.Int26_6(int16(u16(glyf, offset+4))) - dy = fixed.Int26_6(int16(u16(glyf, offset+6))) - offset += 8 - } else { - dx = fixed.Int26_6(int16(int8(glyf[offset+4]))) - dy = fixed.Int26_6(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] = int16(u16(glyf, offset+0)) - transform[3] = transform[0] - offset += 2 - case flags&flagWeHaveAnXAndYScale != 0: - transform[0] = int16(u16(glyf, offset+0)) - transform[3] = int16(u16(glyf, offset+2)) - offset += 4 - case flags&flagWeHaveATwoByTwo != 0: - transform[0] = int16(u16(glyf, offset+0)) - transform[1] = int16(u16(glyf, offset+2)) - transform[2] = int16(u16(glyf, offset+4)) - transform[3] = int16(u16(glyf, offset+6)) - offset += 8 - } - } - savedPP := g.phantomPoints - np0 := len(g.Points) - 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.Points); j++ { - p := &g.Points[j] - newX := 0 + - fixed.Int26_6((int64(p.X)*int64(transform[0])+1<<13)>>14) + - fixed.Int26_6((int64(p.Y)*int64(transform[2])+1<<13)>>14) - newY := 0 + - fixed.Int26_6((int64(p.X)*int64(transform[1])+1<<13)>>14) + - fixed.Int26_6((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.Points); j++ { - p := &g.Points[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 != font.HintingNone && offset+2 <= len(glyf) { - instrLen = int(u16(glyf, offset)) - offset += 2 - } - - g.addPhantomsAndScale(np0, len(g.Points), false, instrLen > 0) - points, ends := g.Points[np0:], g.Ends[ne0:] - g.Points = g.Points[:len(g.Points)-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.Points = append(g.Points, g.phantomPoints[:]...) - // Scale the points. - if simple && g.hinting != font.HintingNone { - g.InFontUnits = append(g.InFontUnits, g.Points[np1:]...) - } - for i := np1; i < len(g.Points); i++ { - p := &g.Points[i] - p.X = g.font.scale(g.scale * p.X) - p.Y = g.font.scale(g.scale * p.Y) - } - if g.hinting == font.HintingNone { - 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.Points[len(g.Points)-4].X - if dx := ((pp1x + 32) &^ 63) - pp1x; dx != 0 { - for i := np0; i < len(g.Points); i++ { - g.Points[i].X += dx - } - } - } - if simple { - g.Unhinted = append(g.Unhinted, g.Points[np1:]...) - } - // Round the 2nd and 4th phantom point to the grid. - p := &g.Points[len(g.Points)-3] - p.X = (p.X + 32) &^ 63 - p = &g.Points[len(g.Points)-1] - p.Y = (p.Y + 32) &^ 63 -} diff --git a/Godeps/_workspace/src/github.com/golang/freetype/truetype/hint.go b/Godeps/_workspace/src/github.com/golang/freetype/truetype/hint.go deleted file mode 100644 index 0315de511..000000000 --- a/Godeps/_workspace/src/github.com/golang/freetype/truetype/hint.go +++ /dev/null @@ -1,1763 +0,0 @@ -// Copyright 2012 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 - -// This file implements a Truetype bytecode interpreter. -// The opcodes are described at https://developer.apple.com/fonts/TTRefMan/RM05/Chap5.html - -import ( - "errors" - "math" - - "golang.org/x/image/math/fixed" -) - -const ( - twilightZone = 0 - glyphZone = 1 - numZone = 2 -) - -type pointType uint32 - -const ( - current pointType = 0 - unhinted pointType = 1 - inFontUnits pointType = 2 - numPointType = 3 -) - -// callStackEntry is a bytecode call stack entry. -type callStackEntry struct { - program []byte - pc int - loopCount int32 -} - -// hinter implements bytecode hinting. A hinter can be re-used to hint a series -// of glyphs from a Font. -type hinter struct { - stack, store []int32 - - // functions is a map from function number to bytecode. - functions map[int32][]byte - - // font and scale are the font and scale last used for this hinter. - // Changing the font will require running the new font's fpgm bytecode. - // Changing either will require running the font's prep bytecode. - font *Font - scale fixed.Int26_6 - - // gs and defaultGS are the current and default graphics state. The - // default graphics state is the global default graphics state after - // the font's fpgm and prep programs have been run. - gs, defaultGS graphicsState - - // points and ends are the twilight zone's points, glyph's points - // and glyph's contour boundaries. - points [numZone][numPointType][]Point - ends []int - - // scaledCVT is the lazily initialized scaled Control Value Table. - scaledCVTInitialized bool - scaledCVT []fixed.Int26_6 -} - -// graphicsState is described at https://developer.apple.com/fonts/TTRefMan/RM04/Chap4.html -type graphicsState struct { - // Projection vector, freedom vector and dual projection vector. - pv, fv, dv [2]f2dot14 - // Reference points and zone pointers. - rp, zp [3]int32 - // Control Value / Single Width Cut-In. - controlValueCutIn, singleWidthCutIn, singleWidth fixed.Int26_6 - // Delta base / shift. - deltaBase, deltaShift int32 - // Minimum distance. - minDist fixed.Int26_6 - // Loop count. - loop int32 - // Rounding policy. - roundPeriod, roundPhase, roundThreshold fixed.Int26_6 - roundSuper45 bool - // Auto-flip. - autoFlip bool -} - -var globalDefaultGS = graphicsState{ - pv: [2]f2dot14{0x4000, 0}, // Unit vector along the X axis. - fv: [2]f2dot14{0x4000, 0}, - dv: [2]f2dot14{0x4000, 0}, - zp: [3]int32{1, 1, 1}, - controlValueCutIn: (17 << 6) / 16, // 17/16 as a fixed.Int26_6. - deltaBase: 9, - deltaShift: 3, - minDist: 1 << 6, // 1 as a fixed.Int26_6. - loop: 1, - roundPeriod: 1 << 6, // 1 as a fixed.Int26_6. - roundThreshold: 1 << 5, // 1/2 as a fixed.Int26_6. - roundSuper45: false, - autoFlip: true, -} - -func resetTwilightPoints(f *Font, p []Point) []Point { - if n := int(f.maxTwilightPoints) + 4; n <= cap(p) { - p = p[:n] - for i := range p { - p[i] = Point{} - } - } else { - p = make([]Point, n) - } - return p -} - -func (h *hinter) init(f *Font, scale fixed.Int26_6) error { - h.points[twilightZone][0] = resetTwilightPoints(f, h.points[twilightZone][0]) - h.points[twilightZone][1] = resetTwilightPoints(f, h.points[twilightZone][1]) - h.points[twilightZone][2] = resetTwilightPoints(f, h.points[twilightZone][2]) - - rescale := h.scale != scale - if h.font != f { - h.font, rescale = f, true - if h.functions == nil { - h.functions = make(map[int32][]byte) - } else { - for k := range h.functions { - delete(h.functions, k) - } - } - - if x := int(f.maxStackElements); x > len(h.stack) { - x += 255 - x &^= 255 - h.stack = make([]int32, x) - } - if x := int(f.maxStorage); x > len(h.store) { - x += 15 - x &^= 15 - h.store = make([]int32, x) - } - if len(f.fpgm) != 0 { - if err := h.run(f.fpgm, nil, nil, nil, nil); err != nil { - return err - } - } - } - - if rescale { - h.scale = scale - h.scaledCVTInitialized = false - - h.defaultGS = globalDefaultGS - - if len(f.prep) != 0 { - if err := h.run(f.prep, nil, nil, nil, nil); err != nil { - return err - } - h.defaultGS = h.gs - // The MS rasterizer doesn't allow the following graphics state - // variables to be modified by the CVT program. - h.defaultGS.pv = globalDefaultGS.pv - h.defaultGS.fv = globalDefaultGS.fv - h.defaultGS.dv = globalDefaultGS.dv - h.defaultGS.rp = globalDefaultGS.rp - h.defaultGS.zp = globalDefaultGS.zp - h.defaultGS.loop = globalDefaultGS.loop - } - } - return nil -} - -func (h *hinter) run(program []byte, pCurrent, pUnhinted, pInFontUnits []Point, ends []int) error { - h.gs = h.defaultGS - h.points[glyphZone][current] = pCurrent - h.points[glyphZone][unhinted] = pUnhinted - h.points[glyphZone][inFontUnits] = pInFontUnits - h.ends = ends - - if len(program) > 50000 { - return errors.New("truetype: hinting: too many instructions") - } - var ( - steps, pc, top int - opcode uint8 - - callStack [32]callStackEntry - callStackTop int - ) - - for 0 <= pc && pc < len(program) { - steps++ - if steps == 100000 { - return errors.New("truetype: hinting: too many steps") - } - opcode = program[pc] - if top < int(popCount[opcode]) { - return errors.New("truetype: hinting: stack underflow") - } - switch opcode { - - case opSVTCA0: - h.gs.pv = [2]f2dot14{0, 0x4000} - h.gs.fv = [2]f2dot14{0, 0x4000} - h.gs.dv = [2]f2dot14{0, 0x4000} - - case opSVTCA1: - h.gs.pv = [2]f2dot14{0x4000, 0} - h.gs.fv = [2]f2dot14{0x4000, 0} - h.gs.dv = [2]f2dot14{0x4000, 0} - - case opSPVTCA0: - h.gs.pv = [2]f2dot14{0, 0x4000} - h.gs.dv = [2]f2dot14{0, 0x4000} - - case opSPVTCA1: - h.gs.pv = [2]f2dot14{0x4000, 0} - h.gs.dv = [2]f2dot14{0x4000, 0} - - case opSFVTCA0: - h.gs.fv = [2]f2dot14{0, 0x4000} - - case opSFVTCA1: - h.gs.fv = [2]f2dot14{0x4000, 0} - - case opSPVTL0, opSPVTL1, opSFVTL0, opSFVTL1: - top -= 2 - p1 := h.point(0, current, h.stack[top+0]) - p2 := h.point(0, current, h.stack[top+1]) - if p1 == nil || p2 == nil { - return errors.New("truetype: hinting: point out of range") - } - dx := f2dot14(p1.X - p2.X) - dy := f2dot14(p1.Y - p2.Y) - if dx == 0 && dy == 0 { - dx = 0x4000 - } else if opcode&1 != 0 { - // Counter-clockwise rotation. - dx, dy = -dy, dx - } - v := normalize(dx, dy) - if opcode < opSFVTL0 { - h.gs.pv = v - h.gs.dv = v - } else { - h.gs.fv = v - } - - case opSPVFS: - top -= 2 - h.gs.pv = normalize(f2dot14(h.stack[top]), f2dot14(h.stack[top+1])) - h.gs.dv = h.gs.pv - - case opSFVFS: - top -= 2 - h.gs.fv = normalize(f2dot14(h.stack[top]), f2dot14(h.stack[top+1])) - - case opGPV: - if top+1 >= len(h.stack) { - return errors.New("truetype: hinting: stack overflow") - } - h.stack[top+0] = int32(h.gs.pv[0]) - h.stack[top+1] = int32(h.gs.pv[1]) - top += 2 - - case opGFV: - if top+1 >= len(h.stack) { - return errors.New("truetype: hinting: stack overflow") - } - h.stack[top+0] = int32(h.gs.fv[0]) - h.stack[top+1] = int32(h.gs.fv[1]) - top += 2 - - case opSFVTPV: - h.gs.fv = h.gs.pv - - case opISECT: - top -= 5 - p := h.point(2, current, h.stack[top+0]) - a0 := h.point(1, current, h.stack[top+1]) - a1 := h.point(1, current, h.stack[top+2]) - b0 := h.point(0, current, h.stack[top+3]) - b1 := h.point(0, current, h.stack[top+4]) - if p == nil || a0 == nil || a1 == nil || b0 == nil || b1 == nil { - return errors.New("truetype: hinting: point out of range") - } - - dbx := b1.X - b0.X - dby := b1.Y - b0.Y - dax := a1.X - a0.X - day := a1.Y - a0.Y - dx := b0.X - a0.X - dy := b0.Y - a0.Y - discriminant := mulDiv(int64(dax), int64(-dby), 0x40) + - mulDiv(int64(day), int64(dbx), 0x40) - dotProduct := mulDiv(int64(dax), int64(dbx), 0x40) + - mulDiv(int64(day), int64(dby), 0x40) - // The discriminant above is actually a cross product of vectors - // da and db. Together with the dot product, they can be used as - // surrogates for sine and cosine of the angle between the vectors. - // Indeed, - // dotproduct = |da||db|cos(angle) - // discriminant = |da||db|sin(angle) - // We use these equations to reject grazing intersections by - // thresholding abs(tan(angle)) at 1/19, corresponding to 3 degrees. - absDisc, absDotP := discriminant, dotProduct - if absDisc < 0 { - absDisc = -absDisc - } - if absDotP < 0 { - absDotP = -absDotP - } - if 19*absDisc > absDotP { - val := mulDiv(int64(dx), int64(-dby), 0x40) + - mulDiv(int64(dy), int64(dbx), 0x40) - rx := mulDiv(val, int64(dax), discriminant) - ry := mulDiv(val, int64(day), discriminant) - p.X = a0.X + fixed.Int26_6(rx) - p.Y = a0.Y + fixed.Int26_6(ry) - } else { - p.X = (a0.X + a1.X + b0.X + b1.X) / 4 - p.Y = (a0.Y + a1.Y + b0.Y + b1.Y) / 4 - } - p.Flags |= flagTouchedX | flagTouchedY - - case opSRP0, opSRP1, opSRP2: - top-- - h.gs.rp[opcode-opSRP0] = h.stack[top] - - case opSZP0, opSZP1, opSZP2: - top-- - h.gs.zp[opcode-opSZP0] = h.stack[top] - - case opSZPS: - top-- - h.gs.zp[0] = h.stack[top] - h.gs.zp[1] = h.stack[top] - h.gs.zp[2] = h.stack[top] - - case opSLOOP: - top-- - if h.stack[top] <= 0 { - return errors.New("truetype: hinting: invalid data") - } - h.gs.loop = h.stack[top] - - case opRTG: - h.gs.roundPeriod = 1 << 6 - h.gs.roundPhase = 0 - h.gs.roundThreshold = 1 << 5 - h.gs.roundSuper45 = false - - case opRTHG: - h.gs.roundPeriod = 1 << 6 - h.gs.roundPhase = 1 << 5 - h.gs.roundThreshold = 1 << 5 - h.gs.roundSuper45 = false - - case opSMD: - top-- - h.gs.minDist = fixed.Int26_6(h.stack[top]) - - case opELSE: - opcode = 1 - goto ifelse - - case opJMPR: - top-- - pc += int(h.stack[top]) - continue - - case opSCVTCI: - top-- - h.gs.controlValueCutIn = fixed.Int26_6(h.stack[top]) - - case opSSWCI: - top-- - h.gs.singleWidthCutIn = fixed.Int26_6(h.stack[top]) - - case opSSW: - top-- - h.gs.singleWidth = h.font.scale(h.scale * fixed.Int26_6(h.stack[top])) - - case opDUP: - if top >= len(h.stack) { - return errors.New("truetype: hinting: stack overflow") - } - h.stack[top] = h.stack[top-1] - top++ - - case opPOP: - top-- - - case opCLEAR: - top = 0 - - case opSWAP: - h.stack[top-1], h.stack[top-2] = h.stack[top-2], h.stack[top-1] - - case opDEPTH: - if top >= len(h.stack) { - return errors.New("truetype: hinting: stack overflow") - } - h.stack[top] = int32(top) - top++ - - case opCINDEX, opMINDEX: - x := int(h.stack[top-1]) - if x <= 0 || x >= top { - return errors.New("truetype: hinting: invalid data") - } - h.stack[top-1] = h.stack[top-1-x] - if opcode == opMINDEX { - copy(h.stack[top-1-x:top-1], h.stack[top-x:top]) - top-- - } - - case opALIGNPTS: - top -= 2 - p := h.point(1, current, h.stack[top]) - q := h.point(0, current, h.stack[top+1]) - if p == nil || q == nil { - return errors.New("truetype: hinting: point out of range") - } - d := dotProduct(fixed.Int26_6(q.X-p.X), fixed.Int26_6(q.Y-p.Y), h.gs.pv) / 2 - h.move(p, +d, true) - h.move(q, -d, true) - - case opUTP: - top-- - p := h.point(0, current, h.stack[top]) - if p == nil { - return errors.New("truetype: hinting: point out of range") - } - p.Flags &^= flagTouchedX | flagTouchedY - - case opLOOPCALL, opCALL: - if callStackTop >= len(callStack) { - return errors.New("truetype: hinting: call stack overflow") - } - top-- - f, ok := h.functions[h.stack[top]] - if !ok { - return errors.New("truetype: hinting: undefined function") - } - callStack[callStackTop] = callStackEntry{program, pc, 1} - if opcode == opLOOPCALL { - top-- - if h.stack[top] == 0 { - break - } - callStack[callStackTop].loopCount = h.stack[top] - } - callStackTop++ - program, pc = f, 0 - continue - - case opFDEF: - // Save all bytecode up until the next ENDF. - startPC := pc + 1 - fdefloop: - for { - pc++ - if pc >= len(program) { - return errors.New("truetype: hinting: unbalanced FDEF") - } - switch program[pc] { - case opFDEF: - return errors.New("truetype: hinting: nested FDEF") - case opENDF: - top-- - h.functions[h.stack[top]] = program[startPC : pc+1] - break fdefloop - default: - var ok bool - pc, ok = skipInstructionPayload(program, pc) - if !ok { - return errors.New("truetype: hinting: unbalanced FDEF") - } - } - } - - case opENDF: - if callStackTop == 0 { - return errors.New("truetype: hinting: call stack underflow") - } - callStackTop-- - callStack[callStackTop].loopCount-- - if callStack[callStackTop].loopCount != 0 { - callStackTop++ - pc = 0 - continue - } - program, pc = callStack[callStackTop].program, callStack[callStackTop].pc - - case opMDAP0, opMDAP1: - top-- - i := h.stack[top] - p := h.point(0, current, i) - if p == nil { - return errors.New("truetype: hinting: point out of range") - } - distance := fixed.Int26_6(0) - if opcode == opMDAP1 { - distance = dotProduct(p.X, p.Y, h.gs.pv) - // TODO: metrics compensation. - distance = h.round(distance) - distance - } - h.move(p, distance, true) - h.gs.rp[0] = i - h.gs.rp[1] = i - - case opIUP0, opIUP1: - iupY, mask := opcode == opIUP0, uint32(flagTouchedX) - if iupY { - mask = flagTouchedY - } - prevEnd := 0 - for _, end := range h.ends { - for i := prevEnd; i < end; i++ { - for i < end && h.points[glyphZone][current][i].Flags&mask == 0 { - i++ - } - if i == end { - break - } - firstTouched, curTouched := i, i - i++ - for ; i < end; i++ { - if h.points[glyphZone][current][i].Flags&mask != 0 { - h.iupInterp(iupY, curTouched+1, i-1, curTouched, i) - curTouched = i - } - } - if curTouched == firstTouched { - h.iupShift(iupY, prevEnd, end, curTouched) - } else { - h.iupInterp(iupY, curTouched+1, end-1, curTouched, firstTouched) - if firstTouched > 0 { - h.iupInterp(iupY, prevEnd, firstTouched-1, curTouched, firstTouched) - } - } - } - prevEnd = end - } - - case opSHP0, opSHP1: - if top < int(h.gs.loop) { - return errors.New("truetype: hinting: stack underflow") - } - _, _, d, ok := h.displacement(opcode&1 == 0) - if !ok { - return errors.New("truetype: hinting: point out of range") - } - for ; h.gs.loop != 0; h.gs.loop-- { - top-- - p := h.point(2, current, h.stack[top]) - if p == nil { - return errors.New("truetype: hinting: point out of range") - } - h.move(p, d, true) - } - h.gs.loop = 1 - - case opSHC0, opSHC1: - top-- - zonePointer, i, d, ok := h.displacement(opcode&1 == 0) - if !ok { - return errors.New("truetype: hinting: point out of range") - } - if h.gs.zp[2] == 0 { - // TODO: implement this when we have a glyph that does this. - return errors.New("hinting: unimplemented SHC instruction") - } - contour := h.stack[top] - if contour < 0 || len(ends) <= int(contour) { - return errors.New("truetype: hinting: contour out of range") - } - j0, j1 := int32(0), int32(h.ends[contour]) - if contour > 0 { - j0 = int32(h.ends[contour-1]) - } - move := h.gs.zp[zonePointer] != h.gs.zp[2] - for j := j0; j < j1; j++ { - if move || j != i { - h.move(h.point(2, current, j), d, true) - } - } - - case opSHZ0, opSHZ1: - top-- - zonePointer, i, d, ok := h.displacement(opcode&1 == 0) - if !ok { - return errors.New("truetype: hinting: point out of range") - } - - // As per C Freetype, SHZ doesn't move the phantom points, or mark - // the points as touched. - limit := int32(len(h.points[h.gs.zp[2]][current])) - if h.gs.zp[2] == glyphZone { - limit -= 4 - } - for j := int32(0); j < limit; j++ { - if i != j || h.gs.zp[zonePointer] != h.gs.zp[2] { - h.move(h.point(2, current, j), d, false) - } - } - - case opSHPIX: - top-- - d := fixed.Int26_6(h.stack[top]) - if top < int(h.gs.loop) { - return errors.New("truetype: hinting: stack underflow") - } - for ; h.gs.loop != 0; h.gs.loop-- { - top-- - p := h.point(2, current, h.stack[top]) - if p == nil { - return errors.New("truetype: hinting: point out of range") - } - h.move(p, d, true) - } - h.gs.loop = 1 - - case opIP: - if top < int(h.gs.loop) { - return errors.New("truetype: hinting: stack underflow") - } - pointType := inFontUnits - twilight := h.gs.zp[0] == 0 || h.gs.zp[1] == 0 || h.gs.zp[2] == 0 - if twilight { - pointType = unhinted - } - p := h.point(1, pointType, h.gs.rp[2]) - oldP := h.point(0, pointType, h.gs.rp[1]) - oldRange := dotProduct(p.X-oldP.X, p.Y-oldP.Y, h.gs.dv) - - p = h.point(1, current, h.gs.rp[2]) - curP := h.point(0, current, h.gs.rp[1]) - curRange := dotProduct(p.X-curP.X, p.Y-curP.Y, h.gs.pv) - for ; h.gs.loop != 0; h.gs.loop-- { - top-- - i := h.stack[top] - p = h.point(2, pointType, i) - oldDist := dotProduct(p.X-oldP.X, p.Y-oldP.Y, h.gs.dv) - p = h.point(2, current, i) - curDist := dotProduct(p.X-curP.X, p.Y-curP.Y, h.gs.pv) - newDist := fixed.Int26_6(0) - if oldDist != 0 { - if oldRange != 0 { - newDist = fixed.Int26_6(mulDiv(int64(oldDist), int64(curRange), int64(oldRange))) - } else { - newDist = -oldDist - } - } - h.move(p, newDist-curDist, true) - } - h.gs.loop = 1 - - case opMSIRP0, opMSIRP1: - top -= 2 - i := h.stack[top] - distance := fixed.Int26_6(h.stack[top+1]) - - // TODO: special case h.gs.zp[1] == 0 in C Freetype. - ref := h.point(0, current, h.gs.rp[0]) - p := h.point(1, current, i) - if ref == nil || p == nil { - return errors.New("truetype: hinting: point out of range") - } - curDist := dotProduct(p.X-ref.X, p.Y-ref.Y, h.gs.pv) - - // Set-RP0 bit. - if opcode == opMSIRP1 { - h.gs.rp[0] = i - } - h.gs.rp[1] = h.gs.rp[0] - h.gs.rp[2] = i - - // Move the point. - h.move(p, distance-curDist, true) - - case opALIGNRP: - if top < int(h.gs.loop) { - return errors.New("truetype: hinting: stack underflow") - } - ref := h.point(0, current, h.gs.rp[0]) - if ref == nil { - return errors.New("truetype: hinting: point out of range") - } - for ; h.gs.loop != 0; h.gs.loop-- { - top-- - p := h.point(1, current, h.stack[top]) - if p == nil { - return errors.New("truetype: hinting: point out of range") - } - h.move(p, -dotProduct(p.X-ref.X, p.Y-ref.Y, h.gs.pv), true) - } - h.gs.loop = 1 - - case opRTDG: - h.gs.roundPeriod = 1 << 5 - h.gs.roundPhase = 0 - h.gs.roundThreshold = 1 << 4 - h.gs.roundSuper45 = false - - case opMIAP0, opMIAP1: - top -= 2 - i := h.stack[top] - distance := h.getScaledCVT(h.stack[top+1]) - if h.gs.zp[0] == 0 { - p := h.point(0, unhinted, i) - q := h.point(0, current, i) - p.X = fixed.Int26_6((int64(distance) * int64(h.gs.fv[0])) >> 14) - p.Y = fixed.Int26_6((int64(distance) * int64(h.gs.fv[1])) >> 14) - *q = *p - } - p := h.point(0, current, i) - oldDist := dotProduct(p.X, p.Y, h.gs.pv) - if opcode == opMIAP1 { - if fabs(distance-oldDist) > h.gs.controlValueCutIn { - distance = oldDist - } - // TODO: metrics compensation. - distance = h.round(distance) - } - h.move(p, distance-oldDist, true) - h.gs.rp[0] = i - h.gs.rp[1] = i - - case opNPUSHB: - opcode = 0 - goto push - - case opNPUSHW: - opcode = 0x80 - goto push - - case opWS: - top -= 2 - i := int(h.stack[top]) - if i < 0 || len(h.store) <= i { - return errors.New("truetype: hinting: invalid data") - } - h.store[i] = h.stack[top+1] - - case opRS: - i := int(h.stack[top-1]) - if i < 0 || len(h.store) <= i { - return errors.New("truetype: hinting: invalid data") - } - h.stack[top-1] = h.store[i] - - case opWCVTP: - top -= 2 - h.setScaledCVT(h.stack[top], fixed.Int26_6(h.stack[top+1])) - - case opRCVT: - h.stack[top-1] = int32(h.getScaledCVT(h.stack[top-1])) - - case opGC0, opGC1: - i := h.stack[top-1] - if opcode == opGC0 { - p := h.point(2, current, i) - h.stack[top-1] = int32(dotProduct(p.X, p.Y, h.gs.pv)) - } else { - p := h.point(2, unhinted, i) - // Using dv as per C Freetype. - h.stack[top-1] = int32(dotProduct(p.X, p.Y, h.gs.dv)) - } - - case opSCFS: - top -= 2 - i := h.stack[top] - p := h.point(2, current, i) - if p == nil { - return errors.New("truetype: hinting: point out of range") - } - c := dotProduct(p.X, p.Y, h.gs.pv) - h.move(p, fixed.Int26_6(h.stack[top+1])-c, true) - if h.gs.zp[2] != 0 { - break - } - q := h.point(2, unhinted, i) - if q == nil { - return errors.New("truetype: hinting: point out of range") - } - q.X = p.X - q.Y = p.Y - - case opMD0, opMD1: - top-- - pt, v, scale := pointType(0), [2]f2dot14{}, false - if opcode == opMD0 { - pt = current - v = h.gs.pv - } else if h.gs.zp[0] == 0 || h.gs.zp[1] == 0 { - pt = unhinted - v = h.gs.dv - } else { - pt = inFontUnits - v = h.gs.dv - scale = true - } - p := h.point(0, pt, h.stack[top-1]) - q := h.point(1, pt, h.stack[top]) - if p == nil || q == nil { - return errors.New("truetype: hinting: point out of range") - } - d := int32(dotProduct(p.X-q.X, p.Y-q.Y, v)) - if scale { - d = int32(int64(d*int32(h.scale)) / int64(h.font.fUnitsPerEm)) - } - h.stack[top-1] = d - - case opMPPEM, opMPS: - if top >= len(h.stack) { - return errors.New("truetype: hinting: stack overflow") - } - // For MPS, point size should be irrelevant; we return the PPEM. - h.stack[top] = int32(h.scale) >> 6 - top++ - - case opFLIPON, opFLIPOFF: - h.gs.autoFlip = opcode == opFLIPON - - case opDEBUG: - // No-op. - - case opLT: - top-- - h.stack[top-1] = bool2int32(h.stack[top-1] < h.stack[top]) - - case opLTEQ: - top-- - h.stack[top-1] = bool2int32(h.stack[top-1] <= h.stack[top]) - - case opGT: - top-- - h.stack[top-1] = bool2int32(h.stack[top-1] > h.stack[top]) - - case opGTEQ: - top-- - h.stack[top-1] = bool2int32(h.stack[top-1] >= h.stack[top]) - - case opEQ: - top-- - h.stack[top-1] = bool2int32(h.stack[top-1] == h.stack[top]) - - case opNEQ: - top-- - h.stack[top-1] = bool2int32(h.stack[top-1] != h.stack[top]) - - case opODD, opEVEN: - i := h.round(fixed.Int26_6(h.stack[top-1])) >> 6 - h.stack[top-1] = int32(i&1) ^ int32(opcode-opODD) - - case opIF: - top-- - if h.stack[top] == 0 { - opcode = 0 - goto ifelse - } - - case opEIF: - // No-op. - - case opAND: - top-- - h.stack[top-1] = bool2int32(h.stack[top-1] != 0 && h.stack[top] != 0) - - case opOR: - top-- - h.stack[top-1] = bool2int32(h.stack[top-1]|h.stack[top] != 0) - - case opNOT: - h.stack[top-1] = bool2int32(h.stack[top-1] == 0) - - case opDELTAP1: - goto delta - - case opSDB: - top-- - h.gs.deltaBase = h.stack[top] - - case opSDS: - top-- - h.gs.deltaShift = h.stack[top] - - case opADD: - top-- - h.stack[top-1] += h.stack[top] - - case opSUB: - top-- - h.stack[top-1] -= h.stack[top] - - case opDIV: - top-- - if h.stack[top] == 0 { - return errors.New("truetype: hinting: division by zero") - } - h.stack[top-1] = int32(fdiv(fixed.Int26_6(h.stack[top-1]), fixed.Int26_6(h.stack[top]))) - - case opMUL: - top-- - h.stack[top-1] = int32(fmul(fixed.Int26_6(h.stack[top-1]), fixed.Int26_6(h.stack[top]))) - - case opABS: - if h.stack[top-1] < 0 { - h.stack[top-1] = -h.stack[top-1] - } - - case opNEG: - h.stack[top-1] = -h.stack[top-1] - - case opFLOOR: - h.stack[top-1] &^= 63 - - case opCEILING: - h.stack[top-1] += 63 - h.stack[top-1] &^= 63 - - case opROUND00, opROUND01, opROUND10, opROUND11: - // The four flavors of opROUND are equivalent. See the comment below on - // opNROUND for the rationale. - h.stack[top-1] = int32(h.round(fixed.Int26_6(h.stack[top-1]))) - - case opNROUND00, opNROUND01, opNROUND10, opNROUND11: - // No-op. The spec says to add one of four "compensations for the engine - // characteristics", to cater for things like "different dot-size printers". - // https://developer.apple.com/fonts/TTRefMan/RM02/Chap2.html#engine_compensation - // This code does not implement engine compensation, as we don't expect to - // be used to output on dot-matrix printers. - - case opWCVTF: - top -= 2 - h.setScaledCVT(h.stack[top], h.font.scale(h.scale*fixed.Int26_6(h.stack[top+1]))) - - case opDELTAP2, opDELTAP3, opDELTAC1, opDELTAC2, opDELTAC3: - goto delta - - case opSROUND, opS45ROUND: - top-- - switch (h.stack[top] >> 6) & 0x03 { - case 0: - h.gs.roundPeriod = 1 << 5 - case 1, 3: - h.gs.roundPeriod = 1 << 6 - case 2: - h.gs.roundPeriod = 1 << 7 - } - h.gs.roundSuper45 = opcode == opS45ROUND - if h.gs.roundSuper45 { - // The spec says to multiply by √2, but the C Freetype code says 1/√2. - // We go with 1/√2. - h.gs.roundPeriod *= 46341 - h.gs.roundPeriod /= 65536 - } - h.gs.roundPhase = h.gs.roundPeriod * fixed.Int26_6((h.stack[top]>>4)&0x03) / 4 - if x := h.stack[top] & 0x0f; x != 0 { - h.gs.roundThreshold = h.gs.roundPeriod * fixed.Int26_6(x-4) / 8 - } else { - h.gs.roundThreshold = h.gs.roundPeriod - 1 - } - - case opJROT: - top -= 2 - if h.stack[top+1] != 0 { - pc += int(h.stack[top]) - continue - } - - case opJROF: - top -= 2 - if h.stack[top+1] == 0 { - pc += int(h.stack[top]) - continue - } - - case opROFF: - h.gs.roundPeriod = 0 - h.gs.roundPhase = 0 - h.gs.roundThreshold = 0 - h.gs.roundSuper45 = false - - case opRUTG: - h.gs.roundPeriod = 1 << 6 - h.gs.roundPhase = 0 - h.gs.roundThreshold = 1<<6 - 1 - h.gs.roundSuper45 = false - - case opRDTG: - h.gs.roundPeriod = 1 << 6 - h.gs.roundPhase = 0 - h.gs.roundThreshold = 0 - h.gs.roundSuper45 = false - - case opSANGW, opAA: - // These ops are "anachronistic" and no longer used. - top-- - - case opFLIPPT: - if top < int(h.gs.loop) { - return errors.New("truetype: hinting: stack underflow") - } - points := h.points[glyphZone][current] - for ; h.gs.loop != 0; h.gs.loop-- { - top-- - i := h.stack[top] - if i < 0 || len(points) <= int(i) { - return errors.New("truetype: hinting: point out of range") - } - points[i].Flags ^= flagOnCurve - } - h.gs.loop = 1 - - case opFLIPRGON, opFLIPRGOFF: - top -= 2 - i, j, points := h.stack[top], h.stack[top+1], h.points[glyphZone][current] - if i < 0 || len(points) <= int(i) || j < 0 || len(points) <= int(j) { - return errors.New("truetype: hinting: point out of range") - } - for ; i <= j; i++ { - if opcode == opFLIPRGON { - points[i].Flags |= flagOnCurve - } else { - points[i].Flags &^= flagOnCurve - } - } - - case opSCANCTRL: - // We do not support dropout control, as we always rasterize grayscale glyphs. - top-- - - case opSDPVTL0, opSDPVTL1: - top -= 2 - for i := 0; i < 2; i++ { - pt := unhinted - if i != 0 { - pt = current - } - p := h.point(1, pt, h.stack[top]) - q := h.point(2, pt, h.stack[top+1]) - if p == nil || q == nil { - return errors.New("truetype: hinting: point out of range") - } - dx := f2dot14(p.X - q.X) - dy := f2dot14(p.Y - q.Y) - if dx == 0 && dy == 0 { - dx = 0x4000 - } else if opcode&1 != 0 { - // Counter-clockwise rotation. - dx, dy = -dy, dx - } - if i == 0 { - h.gs.dv = normalize(dx, dy) - } else { - h.gs.pv = normalize(dx, dy) - } - } - - case opGETINFO: - res := int32(0) - if h.stack[top-1]&(1<<0) != 0 { - // Set the engine version. We hard-code this to 35, the same as - // the C freetype code, which says that "Version~35 corresponds - // to MS rasterizer v.1.7 as used e.g. in Windows~98". - res |= 35 - } - if h.stack[top-1]&(1<<5) != 0 { - // Set that we support grayscale. - res |= 1 << 12 - } - // We set no other bits, as we do not support rotated or stretched glyphs. - h.stack[top-1] = res - - case opIDEF: - // IDEF is for ancient versions of the bytecode interpreter, and is no longer used. - return errors.New("truetype: hinting: unsupported IDEF instruction") - - case opROLL: - h.stack[top-1], h.stack[top-3], h.stack[top-2] = - h.stack[top-3], h.stack[top-2], h.stack[top-1] - - case opMAX: - top-- - if h.stack[top-1] < h.stack[top] { - h.stack[top-1] = h.stack[top] - } - - case opMIN: - top-- - if h.stack[top-1] > h.stack[top] { - h.stack[top-1] = h.stack[top] - } - - case opSCANTYPE: - // We do not support dropout control, as we always rasterize grayscale glyphs. - top-- - - case opINSTCTRL: - // TODO: support instruction execution control? It seems rare, and even when - // nominally used (e.g. Source Sans Pro), it seems conditional on extreme or - // unusual rasterization conditions. For example, the code snippet at - // https://developer.apple.com/fonts/TTRefMan/RM05/Chap5.html#INSTCTRL - // uses INSTCTRL when grid-fitting a rotated or stretched glyph, but - // freetype-go does not support rotated or stretched glyphs. - top -= 2 - - default: - if opcode < opPUSHB000 { - return errors.New("truetype: hinting: unrecognized instruction") - } - - if opcode < opMDRP00000 { - // PUSHxxxx opcode. - - if opcode < opPUSHW000 { - opcode -= opPUSHB000 - 1 - } else { - opcode -= opPUSHW000 - 1 - 0x80 - } - goto push - } - - if opcode < opMIRP00000 { - // MDRPxxxxx opcode. - - top-- - i := h.stack[top] - ref := h.point(0, current, h.gs.rp[0]) - p := h.point(1, current, i) - if ref == nil || p == nil { - return errors.New("truetype: hinting: point out of range") - } - - oldDist := fixed.Int26_6(0) - if h.gs.zp[0] == 0 || h.gs.zp[1] == 0 { - p0 := h.point(1, unhinted, i) - p1 := h.point(0, unhinted, h.gs.rp[0]) - oldDist = dotProduct(p0.X-p1.X, p0.Y-p1.Y, h.gs.dv) - } else { - p0 := h.point(1, inFontUnits, i) - p1 := h.point(0, inFontUnits, h.gs.rp[0]) - oldDist = dotProduct(p0.X-p1.X, p0.Y-p1.Y, h.gs.dv) - oldDist = h.font.scale(h.scale * oldDist) - } - - // Single-width cut-in test. - if x := fabs(oldDist - h.gs.singleWidth); x < h.gs.singleWidthCutIn { - if oldDist >= 0 { - oldDist = +h.gs.singleWidth - } else { - oldDist = -h.gs.singleWidth - } - } - - // Rounding bit. - // TODO: metrics compensation. - distance := oldDist - if opcode&0x04 != 0 { - distance = h.round(oldDist) - } - - // Minimum distance bit. - if opcode&0x08 != 0 { - if oldDist >= 0 { - if distance < h.gs.minDist { - distance = h.gs.minDist - } - } else { - if distance > -h.gs.minDist { - distance = -h.gs.minDist - } - } - } - - // Set-RP0 bit. - h.gs.rp[1] = h.gs.rp[0] - h.gs.rp[2] = i - if opcode&0x10 != 0 { - h.gs.rp[0] = i - } - - // Move the point. - oldDist = dotProduct(p.X-ref.X, p.Y-ref.Y, h.gs.pv) - h.move(p, distance-oldDist, true) - - } else { - // MIRPxxxxx opcode. - - top -= 2 - i := h.stack[top] - cvtDist := h.getScaledCVT(h.stack[top+1]) - if fabs(cvtDist-h.gs.singleWidth) < h.gs.singleWidthCutIn { - if cvtDist >= 0 { - cvtDist = +h.gs.singleWidth - } else { - cvtDist = -h.gs.singleWidth - } - } - - if h.gs.zp[1] == 0 { - // TODO: implement once we have a .ttf file that triggers - // this, so that we can step through C's freetype. - return errors.New("truetype: hinting: unimplemented twilight point adjustment") - } - - ref := h.point(0, unhinted, h.gs.rp[0]) - p := h.point(1, unhinted, i) - if ref == nil || p == nil { - return errors.New("truetype: hinting: point out of range") - } - oldDist := dotProduct(p.X-ref.X, p.Y-ref.Y, h.gs.dv) - - ref = h.point(0, current, h.gs.rp[0]) - p = h.point(1, current, i) - if ref == nil || p == nil { - return errors.New("truetype: hinting: point out of range") - } - curDist := dotProduct(p.X-ref.X, p.Y-ref.Y, h.gs.pv) - - if h.gs.autoFlip && oldDist^cvtDist < 0 { - cvtDist = -cvtDist - } - - // Rounding bit. - // TODO: metrics compensation. - distance := cvtDist - if opcode&0x04 != 0 { - // The CVT value is only used if close enough to oldDist. - if (h.gs.zp[0] == h.gs.zp[1]) && - (fabs(cvtDist-oldDist) > h.gs.controlValueCutIn) { - - distance = oldDist - } - distance = h.round(distance) - } - - // Minimum distance bit. - if opcode&0x08 != 0 { - if oldDist >= 0 { - if distance < h.gs.minDist { - distance = h.gs.minDist - } - } else { - if distance > -h.gs.minDist { - distance = -h.gs.minDist - } - } - } - - // Set-RP0 bit. - h.gs.rp[1] = h.gs.rp[0] - h.gs.rp[2] = i - if opcode&0x10 != 0 { - h.gs.rp[0] = i - } - - // Move the point. - h.move(p, distance-curDist, true) - } - } - pc++ - continue - - ifelse: - // Skip past bytecode until the next ELSE (if opcode == 0) or the - // next EIF (for all opcodes). Opcode == 0 means that we have come - // from an IF. Opcode == 1 means that we have come from an ELSE. - { - ifelseloop: - for depth := 0; ; { - pc++ - if pc >= len(program) { - return errors.New("truetype: hinting: unbalanced IF or ELSE") - } - switch program[pc] { - case opIF: - depth++ - case opELSE: - if depth == 0 && opcode == 0 { - break ifelseloop - } - case opEIF: - depth-- - if depth < 0 { - break ifelseloop - } - default: - var ok bool - pc, ok = skipInstructionPayload(program, pc) - if !ok { - return errors.New("truetype: hinting: unbalanced IF or ELSE") - } - } - } - pc++ - continue - } - - push: - // Push n elements from the program to the stack, where n is the low 7 bits of - // opcode. If the low 7 bits are zero, then n is the next byte from the program. - // The high bit being 0 means that the elements are zero-extended bytes. - // The high bit being 1 means that the elements are sign-extended words. - { - width := 1 - if opcode&0x80 != 0 { - opcode &^= 0x80 - width = 2 - } - if opcode == 0 { - pc++ - if pc >= len(program) { - return errors.New("truetype: hinting: insufficient data") - } - opcode = program[pc] - } - pc++ - if top+int(opcode) > len(h.stack) { - return errors.New("truetype: hinting: stack overflow") - } - if pc+width*int(opcode) > len(program) { - return errors.New("truetype: hinting: insufficient data") - } - for ; opcode > 0; opcode-- { - if width == 1 { - h.stack[top] = int32(program[pc]) - } else { - h.stack[top] = int32(int8(program[pc]))<<8 | int32(program[pc+1]) - } - top++ - pc += width - } - continue - } - - delta: - { - if opcode >= opDELTAC1 && !h.scaledCVTInitialized { - h.initializeScaledCVT() - } - top-- - n := h.stack[top] - if int32(top) < 2*n { - return errors.New("truetype: hinting: stack underflow") - } - for ; n > 0; n-- { - top -= 2 - b := h.stack[top] - c := (b & 0xf0) >> 4 - switch opcode { - case opDELTAP2, opDELTAC2: - c += 16 - case opDELTAP3, opDELTAC3: - c += 32 - } - c += h.gs.deltaBase - if ppem := (int32(h.scale) + 1<<5) >> 6; ppem != c { - continue - } - b = (b & 0x0f) - 8 - if b >= 0 { - b++ - } - b = b * 64 / (1 << uint32(h.gs.deltaShift)) - if opcode >= opDELTAC1 { - a := h.stack[top+1] - if a < 0 || len(h.scaledCVT) <= int(a) { - return errors.New("truetype: hinting: index out of range") - } - h.scaledCVT[a] += fixed.Int26_6(b) - } else { - p := h.point(0, current, h.stack[top+1]) - if p == nil { - return errors.New("truetype: hinting: point out of range") - } - h.move(p, fixed.Int26_6(b), true) - } - } - pc++ - continue - } - } - return nil -} - -func (h *hinter) initializeScaledCVT() { - h.scaledCVTInitialized = true - if n := len(h.font.cvt) / 2; n <= cap(h.scaledCVT) { - h.scaledCVT = h.scaledCVT[:n] - } else { - if n < 32 { - n = 32 - } - h.scaledCVT = make([]fixed.Int26_6, len(h.font.cvt)/2, n) - } - for i := range h.scaledCVT { - unscaled := uint16(h.font.cvt[2*i])<<8 | uint16(h.font.cvt[2*i+1]) - h.scaledCVT[i] = h.font.scale(h.scale * fixed.Int26_6(int16(unscaled))) - } -} - -// getScaledCVT returns the scaled value from the font's Control Value Table. -func (h *hinter) getScaledCVT(i int32) fixed.Int26_6 { - if !h.scaledCVTInitialized { - h.initializeScaledCVT() - } - if i < 0 || len(h.scaledCVT) <= int(i) { - return 0 - } - return h.scaledCVT[i] -} - -// setScaledCVT overrides the scaled value from the font's Control Value Table. -func (h *hinter) setScaledCVT(i int32, v fixed.Int26_6) { - if !h.scaledCVTInitialized { - h.initializeScaledCVT() - } - if i < 0 || len(h.scaledCVT) <= int(i) { - return - } - h.scaledCVT[i] = v -} - -func (h *hinter) point(zonePointer uint32, pt pointType, i int32) *Point { - points := h.points[h.gs.zp[zonePointer]][pt] - if i < 0 || len(points) <= int(i) { - return nil - } - return &points[i] -} - -func (h *hinter) move(p *Point, distance fixed.Int26_6, touch bool) { - fvx := int64(h.gs.fv[0]) - pvx := int64(h.gs.pv[0]) - if fvx == 0x4000 && pvx == 0x4000 { - p.X += fixed.Int26_6(distance) - if touch { - p.Flags |= flagTouchedX - } - return - } - - fvy := int64(h.gs.fv[1]) - pvy := int64(h.gs.pv[1]) - if fvy == 0x4000 && pvy == 0x4000 { - p.Y += fixed.Int26_6(distance) - if touch { - p.Flags |= flagTouchedY - } - return - } - - fvDotPv := (fvx*pvx + fvy*pvy) >> 14 - - if fvx != 0 { - p.X += fixed.Int26_6(mulDiv(fvx, int64(distance), fvDotPv)) - if touch { - p.Flags |= flagTouchedX - } - } - - if fvy != 0 { - p.Y += fixed.Int26_6(mulDiv(fvy, int64(distance), fvDotPv)) - if touch { - p.Flags |= flagTouchedY - } - } -} - -func (h *hinter) iupInterp(interpY bool, p1, p2, ref1, ref2 int) { - if p1 > p2 { - return - } - if ref1 >= len(h.points[glyphZone][current]) || - ref2 >= len(h.points[glyphZone][current]) { - return - } - - var ifu1, ifu2 fixed.Int26_6 - if interpY { - ifu1 = h.points[glyphZone][inFontUnits][ref1].Y - ifu2 = h.points[glyphZone][inFontUnits][ref2].Y - } else { - ifu1 = h.points[glyphZone][inFontUnits][ref1].X - ifu2 = h.points[glyphZone][inFontUnits][ref2].X - } - if ifu1 > ifu2 { - ifu1, ifu2 = ifu2, ifu1 - ref1, ref2 = ref2, ref1 - } - - var unh1, unh2, delta1, delta2 fixed.Int26_6 - if interpY { - unh1 = h.points[glyphZone][unhinted][ref1].Y - unh2 = h.points[glyphZone][unhinted][ref2].Y - delta1 = h.points[glyphZone][current][ref1].Y - unh1 - delta2 = h.points[glyphZone][current][ref2].Y - unh2 - } else { - unh1 = h.points[glyphZone][unhinted][ref1].X - unh2 = h.points[glyphZone][unhinted][ref2].X - delta1 = h.points[glyphZone][current][ref1].X - unh1 - delta2 = h.points[glyphZone][current][ref2].X - unh2 - } - - var xy, ifuXY fixed.Int26_6 - if ifu1 == ifu2 { - for i := p1; i <= p2; i++ { - if interpY { - xy = h.points[glyphZone][unhinted][i].Y - } else { - xy = h.points[glyphZone][unhinted][i].X - } - - if xy <= unh1 { - xy += delta1 - } else { - xy += delta2 - } - - if interpY { - h.points[glyphZone][current][i].Y = xy - } else { - h.points[glyphZone][current][i].X = xy - } - } - return - } - - scale, scaleOK := int64(0), false - for i := p1; i <= p2; i++ { - if interpY { - xy = h.points[glyphZone][unhinted][i].Y - ifuXY = h.points[glyphZone][inFontUnits][i].Y - } else { - xy = h.points[glyphZone][unhinted][i].X - ifuXY = h.points[glyphZone][inFontUnits][i].X - } - - if xy <= unh1 { - xy += delta1 - } else if xy >= unh2 { - xy += delta2 - } else { - if !scaleOK { - scaleOK = true - scale = mulDiv(int64(unh2+delta2-unh1-delta1), 0x10000, int64(ifu2-ifu1)) - } - numer := int64(ifuXY-ifu1) * scale - if numer >= 0 { - numer += 0x8000 - } else { - numer -= 0x8000 - } - xy = unh1 + delta1 + fixed.Int26_6(numer/0x10000) - } - - if interpY { - h.points[glyphZone][current][i].Y = xy - } else { - h.points[glyphZone][current][i].X = xy - } - } -} - -func (h *hinter) iupShift(interpY bool, p1, p2, p int) { - var delta fixed.Int26_6 - if interpY { - delta = h.points[glyphZone][current][p].Y - h.points[glyphZone][unhinted][p].Y - } else { - delta = h.points[glyphZone][current][p].X - h.points[glyphZone][unhinted][p].X - } - if delta == 0 { - return - } - for i := p1; i < p2; i++ { - if i == p { - continue - } - if interpY { - h.points[glyphZone][current][i].Y += delta - } else { - h.points[glyphZone][current][i].X += delta - } - } -} - -func (h *hinter) displacement(useZP1 bool) (zonePointer uint32, i int32, d fixed.Int26_6, ok bool) { - zonePointer, i = uint32(0), h.gs.rp[1] - if useZP1 { - zonePointer, i = 1, h.gs.rp[2] - } - p := h.point(zonePointer, current, i) - q := h.point(zonePointer, unhinted, i) - if p == nil || q == nil { - return 0, 0, 0, false - } - d = dotProduct(p.X-q.X, p.Y-q.Y, h.gs.pv) - return zonePointer, i, d, true -} - -// skipInstructionPayload increments pc by the extra data that follows a -// variable length PUSHB or PUSHW instruction. -func skipInstructionPayload(program []byte, pc int) (newPC int, ok bool) { - switch program[pc] { - case opNPUSHB: - pc++ - if pc >= len(program) { - return 0, false - } - pc += int(program[pc]) - case opNPUSHW: - pc++ - if pc >= len(program) { - return 0, false - } - pc += 2 * int(program[pc]) - case opPUSHB000, opPUSHB001, opPUSHB010, opPUSHB011, - opPUSHB100, opPUSHB101, opPUSHB110, opPUSHB111: - pc += int(program[pc] - (opPUSHB000 - 1)) - case opPUSHW000, opPUSHW001, opPUSHW010, opPUSHW011, - opPUSHW100, opPUSHW101, opPUSHW110, opPUSHW111: - pc += 2 * int(program[pc]-(opPUSHW000-1)) - } - return pc, true -} - -// f2dot14 is a 2.14 fixed point number. -type f2dot14 int16 - -func normalize(x, y f2dot14) [2]f2dot14 { - fx, fy := float64(x), float64(y) - l := 0x4000 / math.Hypot(fx, fy) - fx *= l - if fx >= 0 { - fx += 0.5 - } else { - fx -= 0.5 - } - fy *= l - if fy >= 0 { - fy += 0.5 - } else { - fy -= 0.5 - } - return [2]f2dot14{f2dot14(fx), f2dot14(fy)} -} - -// fabs returns abs(x) in 26.6 fixed point arithmetic. -func fabs(x fixed.Int26_6) fixed.Int26_6 { - if x < 0 { - return -x - } - return x -} - -// fdiv returns x/y in 26.6 fixed point arithmetic. -func fdiv(x, y fixed.Int26_6) fixed.Int26_6 { - return fixed.Int26_6((int64(x) << 6) / int64(y)) -} - -// fmul returns x*y in 26.6 fixed point arithmetic. -func fmul(x, y fixed.Int26_6) fixed.Int26_6 { - return fixed.Int26_6((int64(x)*int64(y) + 1<<5) >> 6) -} - -// dotProduct returns the dot product of [x, y] and q. It is almost the same as -// px := int64(x) -// py := int64(y) -// qx := int64(q[0]) -// qy := int64(q[1]) -// return fixed.Int26_6((px*qx + py*qy + 1<<13) >> 14) -// except that the computation is done with 32-bit integers to produce exactly -// the same rounding behavior as C Freetype. -func dotProduct(x, y fixed.Int26_6, q [2]f2dot14) fixed.Int26_6 { - // Compute x*q[0] as 64-bit value. - l := uint32((int32(x) & 0xFFFF) * int32(q[0])) - m := (int32(x) >> 16) * int32(q[0]) - - lo1 := l + (uint32(m) << 16) - hi1 := (m >> 16) + (int32(l) >> 31) + bool2int32(lo1 < l) - - // Compute y*q[1] as 64-bit value. - l = uint32((int32(y) & 0xFFFF) * int32(q[1])) - m = (int32(y) >> 16) * int32(q[1]) - - lo2 := l + (uint32(m) << 16) - hi2 := (m >> 16) + (int32(l) >> 31) + bool2int32(lo2 < l) - - // Add them. - lo := lo1 + lo2 - hi := hi1 + hi2 + bool2int32(lo < lo1) - - // Divide the result by 2^14 with rounding. - s := hi >> 31 - l = lo + uint32(s) - hi += s + bool2int32(l < lo) - lo = l - - l = lo + 0x2000 - hi += bool2int32(l < lo) - - return fixed.Int26_6((uint32(hi) << 18) | (l >> 14)) -} - -// mulDiv returns x*y/z, rounded to the nearest integer. -func mulDiv(x, y, z int64) int64 { - xy := x * y - if z < 0 { - xy, z = -xy, -z - } - if xy >= 0 { - xy += z / 2 - } else { - xy -= z / 2 - } - return xy / z -} - -// round rounds the given number. The rounding algorithm is described at -// https://developer.apple.com/fonts/TTRefMan/RM02/Chap2.html#rounding -func (h *hinter) round(x fixed.Int26_6) fixed.Int26_6 { - if h.gs.roundPeriod == 0 { - // Rounding is off. - return x - } - if x >= 0 { - ret := x - h.gs.roundPhase + h.gs.roundThreshold - if h.gs.roundSuper45 { - ret /= h.gs.roundPeriod - ret *= h.gs.roundPeriod - } else { - ret &= -h.gs.roundPeriod - } - if x != 0 && ret < 0 { - ret = 0 - } - return ret + h.gs.roundPhase - } - ret := -x - h.gs.roundPhase + h.gs.roundThreshold - if h.gs.roundSuper45 { - ret /= h.gs.roundPeriod - ret *= h.gs.roundPeriod - } else { - ret &= -h.gs.roundPeriod - } - if ret < 0 { - ret = 0 - } - return -ret - h.gs.roundPhase -} - -func bool2int32(b bool) int32 { - if b { - return 1 - } - return 0 -} diff --git a/Godeps/_workspace/src/github.com/golang/freetype/truetype/opcodes.go b/Godeps/_workspace/src/github.com/golang/freetype/truetype/opcodes.go deleted file mode 100644 index 1880e1e63..000000000 --- a/Godeps/_workspace/src/github.com/golang/freetype/truetype/opcodes.go +++ /dev/null @@ -1,289 +0,0 @@ -// Copyright 2012 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 - -// The Truetype opcodes are summarized at -// https://developer.apple.com/fonts/TTRefMan/RM07/appendixA.html - -const ( - opSVTCA0 = 0x00 // Set freedom and projection Vectors To Coordinate Axis - opSVTCA1 = 0x01 // . - opSPVTCA0 = 0x02 // Set Projection Vector To Coordinate Axis - opSPVTCA1 = 0x03 // . - opSFVTCA0 = 0x04 // Set Freedom Vector to Coordinate Axis - opSFVTCA1 = 0x05 // . - opSPVTL0 = 0x06 // Set Projection Vector To Line - opSPVTL1 = 0x07 // . - opSFVTL0 = 0x08 // Set Freedom Vector To Line - opSFVTL1 = 0x09 // . - opSPVFS = 0x0a // Set Projection Vector From Stack - opSFVFS = 0x0b // Set Freedom Vector From Stack - opGPV = 0x0c // Get Projection Vector - opGFV = 0x0d // Get Freedom Vector - opSFVTPV = 0x0e // Set Freedom Vector To Projection Vector - opISECT = 0x0f // moves point p to the InterSECTion of two lines - opSRP0 = 0x10 // Set Reference Point 0 - opSRP1 = 0x11 // Set Reference Point 1 - opSRP2 = 0x12 // Set Reference Point 2 - opSZP0 = 0x13 // Set Zone Pointer 0 - opSZP1 = 0x14 // Set Zone Pointer 1 - opSZP2 = 0x15 // Set Zone Pointer 2 - opSZPS = 0x16 // Set Zone PointerS - opSLOOP = 0x17 // Set LOOP variable - opRTG = 0x18 // Round To Grid - opRTHG = 0x19 // Round To Half Grid - opSMD = 0x1a // Set Minimum Distance - opELSE = 0x1b // ELSE clause - opJMPR = 0x1c // JuMP Relative - opSCVTCI = 0x1d // Set Control Value Table Cut-In - opSSWCI = 0x1e // Set Single Width Cut-In - opSSW = 0x1f // Set Single Width - opDUP = 0x20 // DUPlicate top stack element - opPOP = 0x21 // POP top stack element - opCLEAR = 0x22 // CLEAR the stack - opSWAP = 0x23 // SWAP the top two elements on the stack - opDEPTH = 0x24 // DEPTH of the stack - opCINDEX = 0x25 // Copy the INDEXed element to the top of the stack - opMINDEX = 0x26 // Move the INDEXed element to the top of the stack - opALIGNPTS = 0x27 // ALIGN PoinTS - op_0x28 = 0x28 // deprecated - opUTP = 0x29 // UnTouch Point - opLOOPCALL = 0x2a // LOOP and CALL function - opCALL = 0x2b // CALL function - opFDEF = 0x2c // Function DEFinition - opENDF = 0x2d // END Function definition - opMDAP0 = 0x2e // Move Direct Absolute Point - opMDAP1 = 0x2f // . - opIUP0 = 0x30 // Interpolate Untouched Points through the outline - opIUP1 = 0x31 // . - opSHP0 = 0x32 // SHift Point using reference point - opSHP1 = 0x33 // . - opSHC0 = 0x34 // SHift Contour using reference point - opSHC1 = 0x35 // . - opSHZ0 = 0x36 // SHift Zone using reference point - opSHZ1 = 0x37 // . - opSHPIX = 0x38 // SHift point by a PIXel amount - opIP = 0x39 // Interpolate Point - opMSIRP0 = 0x3a // Move Stack Indirect Relative Point - opMSIRP1 = 0x3b // . - opALIGNRP = 0x3c // ALIGN to Reference Point - opRTDG = 0x3d // Round To Double Grid - opMIAP0 = 0x3e // Move Indirect Absolute Point - opMIAP1 = 0x3f // . - opNPUSHB = 0x40 // PUSH N Bytes - opNPUSHW = 0x41 // PUSH N Words - opWS = 0x42 // Write Store - opRS = 0x43 // Read Store - opWCVTP = 0x44 // Write Control Value Table in Pixel units - opRCVT = 0x45 // Read Control Value Table entry - opGC0 = 0x46 // Get Coordinate projected onto the projection vector - opGC1 = 0x47 // . - opSCFS = 0x48 // Sets Coordinate From the Stack using projection vector and freedom vector - opMD0 = 0x49 // Measure Distance - opMD1 = 0x4a // . - opMPPEM = 0x4b // Measure Pixels Per EM - opMPS = 0x4c // Measure Point Size - opFLIPON = 0x4d // set the auto FLIP Boolean to ON - opFLIPOFF = 0x4e // set the auto FLIP Boolean to OFF - opDEBUG = 0x4f // DEBUG call - opLT = 0x50 // Less Than - opLTEQ = 0x51 // Less Than or EQual - opGT = 0x52 // Greater Than - opGTEQ = 0x53 // Greater Than or EQual - opEQ = 0x54 // EQual - opNEQ = 0x55 // Not EQual - opODD = 0x56 // ODD - opEVEN = 0x57 // EVEN - opIF = 0x58 // IF test - opEIF = 0x59 // End IF - opAND = 0x5a // logical AND - opOR = 0x5b // logical OR - opNOT = 0x5c // logical NOT - opDELTAP1 = 0x5d // DELTA exception P1 - opSDB = 0x5e // Set Delta Base in the graphics state - opSDS = 0x5f // Set Delta Shift in the graphics state - opADD = 0x60 // ADD - opSUB = 0x61 // SUBtract - opDIV = 0x62 // DIVide - opMUL = 0x63 // MULtiply - opABS = 0x64 // ABSolute value - opNEG = 0x65 // NEGate - opFLOOR = 0x66 // FLOOR - opCEILING = 0x67 // CEILING - opROUND00 = 0x68 // ROUND value - opROUND01 = 0x69 // . - opROUND10 = 0x6a // . - opROUND11 = 0x6b // . - opNROUND00 = 0x6c // No ROUNDing of value - opNROUND01 = 0x6d // . - opNROUND10 = 0x6e // . - opNROUND11 = 0x6f // . - opWCVTF = 0x70 // Write Control Value Table in Funits - opDELTAP2 = 0x71 // DELTA exception P2 - opDELTAP3 = 0x72 // DELTA exception P3 - opDELTAC1 = 0x73 // DELTA exception C1 - opDELTAC2 = 0x74 // DELTA exception C2 - opDELTAC3 = 0x75 // DELTA exception C3 - opSROUND = 0x76 // Super ROUND - opS45ROUND = 0x77 // Super ROUND 45 degrees - opJROT = 0x78 // Jump Relative On True - opJROF = 0x79 // Jump Relative On False - opROFF = 0x7a // Round OFF - op_0x7b = 0x7b // deprecated - opRUTG = 0x7c // Round Up To Grid - opRDTG = 0x7d // Round Down To Grid - opSANGW = 0x7e // Set ANGle Weight - opAA = 0x7f // Adjust Angle - opFLIPPT = 0x80 // FLIP PoinT - opFLIPRGON = 0x81 // FLIP RanGe ON - opFLIPRGOFF = 0x82 // FLIP RanGe OFF - op_0x83 = 0x83 // deprecated - op_0x84 = 0x84 // deprecated - opSCANCTRL = 0x85 // SCAN conversion ConTRoL - opSDPVTL0 = 0x86 // Set Dual Projection Vector To Line - opSDPVTL1 = 0x87 // . - opGETINFO = 0x88 // GET INFOrmation - opIDEF = 0x89 // Instruction DEFinition - opROLL = 0x8a // ROLL the top three stack elements - opMAX = 0x8b // MAXimum of top two stack elements - opMIN = 0x8c // MINimum of top two stack elements - opSCANTYPE = 0x8d // SCANTYPE - opINSTCTRL = 0x8e // INSTRuction execution ConTRoL - op_0x8f = 0x8f - op_0x90 = 0x90 - op_0x91 = 0x91 - op_0x92 = 0x92 - op_0x93 = 0x93 - op_0x94 = 0x94 - op_0x95 = 0x95 - op_0x96 = 0x96 - op_0x97 = 0x97 - op_0x98 = 0x98 - op_0x99 = 0x99 - op_0x9a = 0x9a - op_0x9b = 0x9b - op_0x9c = 0x9c - op_0x9d = 0x9d - op_0x9e = 0x9e - op_0x9f = 0x9f - op_0xa0 = 0xa0 - op_0xa1 = 0xa1 - op_0xa2 = 0xa2 - op_0xa3 = 0xa3 - op_0xa4 = 0xa4 - op_0xa5 = 0xa5 - op_0xa6 = 0xa6 - op_0xa7 = 0xa7 - op_0xa8 = 0xa8 - op_0xa9 = 0xa9 - op_0xaa = 0xaa - op_0xab = 0xab - op_0xac = 0xac - op_0xad = 0xad - op_0xae = 0xae - op_0xaf = 0xaf - opPUSHB000 = 0xb0 // PUSH Bytes - opPUSHB001 = 0xb1 // . - opPUSHB010 = 0xb2 // . - opPUSHB011 = 0xb3 // . - opPUSHB100 = 0xb4 // . - opPUSHB101 = 0xb5 // . - opPUSHB110 = 0xb6 // . - opPUSHB111 = 0xb7 // . - opPUSHW000 = 0xb8 // PUSH Words - opPUSHW001 = 0xb9 // . - opPUSHW010 = 0xba // . - opPUSHW011 = 0xbb // . - opPUSHW100 = 0xbc // . - opPUSHW101 = 0xbd // . - opPUSHW110 = 0xbe // . - opPUSHW111 = 0xbf // . - opMDRP00000 = 0xc0 // Move Direct Relative Point - opMDRP00001 = 0xc1 // . - opMDRP00010 = 0xc2 // . - opMDRP00011 = 0xc3 // . - opMDRP00100 = 0xc4 // . - opMDRP00101 = 0xc5 // . - opMDRP00110 = 0xc6 // . - opMDRP00111 = 0xc7 // . - opMDRP01000 = 0xc8 // . - opMDRP01001 = 0xc9 // . - opMDRP01010 = 0xca // . - opMDRP01011 = 0xcb // . - opMDRP01100 = 0xcc // . - opMDRP01101 = 0xcd // . - opMDRP01110 = 0xce // . - opMDRP01111 = 0xcf // . - opMDRP10000 = 0xd0 // . - opMDRP10001 = 0xd1 // . - opMDRP10010 = 0xd2 // . - opMDRP10011 = 0xd3 // . - opMDRP10100 = 0xd4 // . - opMDRP10101 = 0xd5 // . - opMDRP10110 = 0xd6 // . - opMDRP10111 = 0xd7 // . - opMDRP11000 = 0xd8 // . - opMDRP11001 = 0xd9 // . - opMDRP11010 = 0xda // . - opMDRP11011 = 0xdb // . - opMDRP11100 = 0xdc // . - opMDRP11101 = 0xdd // . - opMDRP11110 = 0xde // . - opMDRP11111 = 0xdf // . - opMIRP00000 = 0xe0 // Move Indirect Relative Point - opMIRP00001 = 0xe1 // . - opMIRP00010 = 0xe2 // . - opMIRP00011 = 0xe3 // . - opMIRP00100 = 0xe4 // . - opMIRP00101 = 0xe5 // . - opMIRP00110 = 0xe6 // . - opMIRP00111 = 0xe7 // . - opMIRP01000 = 0xe8 // . - opMIRP01001 = 0xe9 // . - opMIRP01010 = 0xea // . - opMIRP01011 = 0xeb // . - opMIRP01100 = 0xec // . - opMIRP01101 = 0xed // . - opMIRP01110 = 0xee // . - opMIRP01111 = 0xef // . - opMIRP10000 = 0xf0 // . - opMIRP10001 = 0xf1 // . - opMIRP10010 = 0xf2 // . - opMIRP10011 = 0xf3 // . - opMIRP10100 = 0xf4 // . - opMIRP10101 = 0xf5 // . - opMIRP10110 = 0xf6 // . - opMIRP10111 = 0xf7 // . - opMIRP11000 = 0xf8 // . - opMIRP11001 = 0xf9 // . - opMIRP11010 = 0xfa // . - opMIRP11011 = 0xfb // . - opMIRP11100 = 0xfc // . - opMIRP11101 = 0xfd // . - opMIRP11110 = 0xfe // . - opMIRP11111 = 0xff // . -) - -// popCount is the number of stack elements that each opcode pops. -var popCount = [256]uint8{ - // 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f - 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 0, 0, 0, 5, // 0x00 - 0x0f - 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, // 0x10 - 0x1f - 1, 1, 0, 2, 0, 1, 1, 2, 0, 1, 2, 1, 1, 0, 1, 1, // 0x20 - 0x2f - 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 2, 2, 0, 0, 2, 2, // 0x30 - 0x3f - 0, 0, 2, 1, 2, 1, 1, 1, 2, 2, 2, 0, 0, 0, 0, 0, // 0x40 - 0x4f - 2, 2, 2, 2, 2, 2, 1, 1, 1, 0, 2, 2, 1, 1, 1, 1, // 0x50 - 0x5f - 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x60 - 0x6f - 2, 1, 1, 1, 1, 1, 1, 1, 2, 2, 0, 0, 0, 0, 1, 1, // 0x70 - 0x7f - 0, 2, 2, 0, 0, 1, 2, 2, 1, 1, 3, 2, 2, 1, 2, 0, // 0x80 - 0x8f - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x90 - 0x9f - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xa0 - 0xaf - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xb0 - 0xbf - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xc0 - 0xcf - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xd0 - 0xdf - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xe0 - 0xef - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xf0 - 0xff -} diff --git a/Godeps/_workspace/src/github.com/golang/freetype/truetype/truetype.go b/Godeps/_workspace/src/github.com/golang/freetype/truetype/truetype.go deleted file mode 100644 index 692e01526..000000000 --- a/Godeps/_workspace/src/github.com/golang/freetype/truetype/truetype.go +++ /dev/null @@ -1,639 +0,0 @@ -// 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 provides a parser for the TTF and TTC file formats. -// Those formats are documented at http://developer.apple.com/fonts/TTRefMan/ -// and http://www.microsoft.com/typography/otspec/ -// -// Some of a font's methods provide lengths or co-ordinates, e.g. bounds, font -// metrics and control points. All these methods take a scale parameter, which -// is the number of pixels in 1 em, expressed as a 26.6 fixed point value. For -// example, if 1 em is 10 pixels then scale is fixed.I(10), which is equal to -// fixed.Int26_6(10 << 6). -// -// To measure a TrueType font in ideal FUnit space, use scale equal to -// font.FUnitsPerEm(). -package truetype - -import ( - "fmt" - - "golang.org/x/image/math/fixed" -) - -// An Index is a Font's index of a rune. -type Index uint16 - -// A NameID identifies a name table entry. -// -// See https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6name.html -type NameID uint16 - -const ( - NameIDCopyright NameID = 0 - NameIDFontFamily = 1 - NameIDFontSubfamily = 2 - NameIDUniqueSubfamilyID = 3 - NameIDFontFullName = 4 - NameIDNameTableVersion = 5 - NameIDPostscriptName = 6 - NameIDTrademarkNotice = 7 - NameIDManufacturerName = 8 - NameIDDesignerName = 9 - NameIDFontDescription = 10 - NameIDFontVendorURL = 11 - NameIDFontDesignerURL = 12 - NameIDFontLicense = 13 - NameIDFontLicenseURL = 14 - NameIDPreferredFamily = 16 - NameIDPreferredSubfamily = 17 - NameIDCompatibleName = 18 - NameIDSampleText = 19 -) - -const ( - // A 32-bit encoding consists of a most-significant 16-bit Platform ID and a - // least-significant 16-bit Platform Specific ID. The magic numbers are - // specified at https://www.microsoft.com/typography/otspec/name.htm - unicodeEncoding = 0x00000003 // PID = 0 (Unicode), PSID = 3 (Unicode 2.0) - microsoftSymbolEncoding = 0x00030000 // PID = 3 (Microsoft), PSID = 0 (Symbol) - microsoftUCS2Encoding = 0x00030001 // PID = 3 (Microsoft), PSID = 1 (UCS-2) - microsoftUCS4Encoding = 0x0003000a // PID = 3 (Microsoft), PSID = 10 (UCS-4) -) - -// An HMetric holds the horizontal metrics of a single glyph. -type HMetric struct { - AdvanceWidth, LeftSideBearing fixed.Int26_6 -} - -// A VMetric holds the vertical metrics of a single glyph. -type VMetric struct { - AdvanceHeight, TopSideBearing fixed.Int26_6 -} - -// A FormatError reports that the input is not a valid TrueType font. -type FormatError string - -func (e FormatError) Error() string { - return "freetype: invalid TrueType format: " + string(e) -} - -// An UnsupportedError reports that the input uses a valid but unimplemented -// TrueType feature. -type UnsupportedError string - -func (e UnsupportedError) Error() string { - return "freetype: unsupported TrueType feature: " + string(e) -} - -// u32 returns the big-endian uint32 at b[i:]. -func u32(b []byte, i int) uint32 { - return uint32(b[i])<<24 | uint32(b[i+1])<<16 | uint32(b[i+2])<<8 | uint32(b[i+3]) -} - -// u16 returns the big-endian uint16 at b[i:]. -func u16(b []byte, i int) uint16 { - return uint16(b[i])<<8 | uint16(b[i+1]) -} - -// readTable returns a slice of the TTF data given by a table's directory entry. -func readTable(ttf []byte, offsetLength []byte) ([]byte, error) { - offset := int(u32(offsetLength, 0)) - if offset < 0 { - return nil, FormatError(fmt.Sprintf("offset too large: %d", uint32(offset))) - } - length := int(u32(offsetLength, 4)) - if length < 0 { - return nil, FormatError(fmt.Sprintf("length too large: %d", uint32(length))) - } - end := offset + length - if end < 0 || end > len(ttf) { - return nil, FormatError(fmt.Sprintf("offset + length too large: %d", uint32(offset)+uint32(length))) - } - return ttf[offset:end], nil -} - -// parseSubtables returns the offset and platformID of the best subtable in -// table, where best favors a Unicode cmap encoding, and failing that, a -// Microsoft cmap encoding. offset is the offset of the first subtable in -// table, and size is the size of each subtable. -// -// If pred is non-nil, then only subtables that satisfy that predicate will be -// considered. -func parseSubtables(table []byte, name string, offset, size int, pred func([]byte) bool) ( - bestOffset int, bestPID uint32, retErr error) { - - if len(table) < 4 { - return 0, 0, FormatError(name + " too short") - } - nSubtables := int(u16(table, 2)) - if len(table) < size*nSubtables+offset { - return 0, 0, FormatError(name + " too short") - } - ok := false - for i := 0; i < nSubtables; i, offset = i+1, offset+size { - if pred != nil && !pred(table[offset:]) { - continue - } - // We read the 16-bit Platform ID and 16-bit Platform Specific ID as a single uint32. - // All values are big-endian. - pidPsid := u32(table, offset) - // We prefer the Unicode cmap encoding. Failing to find that, we fall - // back onto the Microsoft cmap encoding. - if pidPsid == unicodeEncoding { - bestOffset, bestPID, ok = offset, pidPsid>>16, true - break - - } else if pidPsid == microsoftSymbolEncoding || - pidPsid == microsoftUCS2Encoding || - pidPsid == microsoftUCS4Encoding { - - bestOffset, bestPID, ok = offset, pidPsid>>16, true - // We don't break out of the for loop, so that Unicode can override Microsoft. - } - } - if !ok { - return 0, 0, UnsupportedError(name + " encoding") - } - return bestOffset, bestPID, nil -} - -const ( - locaOffsetFormatUnknown int = iota - locaOffsetFormatShort - locaOffsetFormatLong -) - -// A cm holds a parsed cmap entry. -type cm struct { - start, end, delta, offset uint32 -} - -// A Font represents a Truetype font. -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, hdmx, head, hhea, hmtx, kern, loca, maxp, name, os2, prep, vmtx []byte - - cmapIndexes []byte - - // Cached values derived from the raw ttf data. - cm []cm - locaOffsetFormat int - nGlyph, nHMetric, nKern int - fUnitsPerEm int32 - bounds fixed.Rectangle26_6 - // Values from the maxp section. - maxTwilightPoints, maxStorage, maxFunctionDefs, maxStackElements uint16 -} - -func (f *Font) parseCmap() error { - const ( - cmapFormat4 = 4 - cmapFormat12 = 12 - languageIndependent = 0 - ) - - offset, _, err := parseSubtables(f.cmap, "cmap", 4, 8, nil) - if err != nil { - return err - } - offset = int(u32(f.cmap, offset+4)) - if offset <= 0 || offset > len(f.cmap) { - return FormatError("bad cmap offset") - } - - cmapFormat := u16(f.cmap, offset) - switch cmapFormat { - case cmapFormat4: - language := u16(f.cmap, offset+4) - if language != languageIndependent { - return UnsupportedError(fmt.Sprintf("language: %d", language)) - } - segCountX2 := int(u16(f.cmap, offset+6)) - if segCountX2%2 == 1 { - return FormatError(fmt.Sprintf("bad segCountX2: %d", segCountX2)) - } - segCount := segCountX2 / 2 - offset += 14 - f.cm = make([]cm, segCount) - for i := 0; i < segCount; i++ { - f.cm[i].end = uint32(u16(f.cmap, offset)) - offset += 2 - } - offset += 2 - for i := 0; i < segCount; i++ { - f.cm[i].start = uint32(u16(f.cmap, offset)) - offset += 2 - } - for i := 0; i < segCount; i++ { - f.cm[i].delta = uint32(u16(f.cmap, offset)) - offset += 2 - } - for i := 0; i < segCount; i++ { - f.cm[i].offset = uint32(u16(f.cmap, offset)) - offset += 2 - } - f.cmapIndexes = f.cmap[offset:] - return nil - - case cmapFormat12: - if u16(f.cmap, offset+2) != 0 { - return FormatError(fmt.Sprintf("cmap format: % x", f.cmap[offset:offset+4])) - } - length := u32(f.cmap, offset+4) - language := u32(f.cmap, offset+8) - if language != languageIndependent { - return UnsupportedError(fmt.Sprintf("language: %d", language)) - } - nGroups := u32(f.cmap, offset+12) - if length != 12*nGroups+16 { - return FormatError("inconsistent cmap length") - } - offset += 16 - f.cm = make([]cm, nGroups) - for i := uint32(0); i < nGroups; i++ { - f.cm[i].start = u32(f.cmap, offset+0) - f.cm[i].end = u32(f.cmap, offset+4) - f.cm[i].delta = u32(f.cmap, offset+8) - f.cm[i].start - offset += 12 - } - return nil - } - return UnsupportedError(fmt.Sprintf("cmap format: %d", cmapFormat)) -} - -func (f *Font) parseHead() error { - if len(f.head) != 54 { - return FormatError(fmt.Sprintf("bad head length: %d", len(f.head))) - } - f.fUnitsPerEm = int32(u16(f.head, 18)) - f.bounds.Min.X = fixed.Int26_6(int16(u16(f.head, 36))) - f.bounds.Min.Y = fixed.Int26_6(int16(u16(f.head, 38))) - f.bounds.Max.X = fixed.Int26_6(int16(u16(f.head, 40))) - f.bounds.Max.Y = fixed.Int26_6(int16(u16(f.head, 42))) - switch i := u16(f.head, 50); i { - case 0: - f.locaOffsetFormat = locaOffsetFormatShort - case 1: - f.locaOffsetFormat = locaOffsetFormatLong - default: - return FormatError(fmt.Sprintf("bad indexToLocFormat: %d", i)) - } - return nil -} - -func (f *Font) parseHhea() error { - if len(f.hhea) != 36 { - return FormatError(fmt.Sprintf("bad hhea length: %d", len(f.hhea))) - } - f.nHMetric = int(u16(f.hhea, 34)) - if 4*f.nHMetric+2*(f.nGlyph-f.nHMetric) != len(f.hmtx) { - return FormatError(fmt.Sprintf("bad hmtx length: %d", len(f.hmtx))) - } - return nil -} - -func (f *Font) parseKern() error { - // Apple's TrueType documentation (http://developer.apple.com/fonts/TTRefMan/RM06/Chap6kern.html) says: - // "Previous versions of the 'kern' table defined both the version and nTables fields in the header - // as UInt16 values and not UInt32 values. Use of the older format on the Mac OS is discouraged - // (although AAT can sense an old kerning table and still make correct use of it). Microsoft - // Windows still uses the older format for the 'kern' table and will not recognize the newer one. - // Fonts targeted for the Mac OS only should use the new format; fonts targeted for both the Mac OS - // and Windows should use the old format." - // Since we expect that almost all fonts aim to be Windows-compatible, we only parse the "older" format, - // just like the C Freetype implementation. - if len(f.kern) == 0 { - if f.nKern != 0 { - return FormatError("bad kern table length") - } - return nil - } - if len(f.kern) < 18 { - return FormatError("kern data too short") - } - version, offset := u16(f.kern, 0), 2 - if version != 0 { - return UnsupportedError(fmt.Sprintf("kern version: %d", version)) - } - n, offset := u16(f.kern, offset), offset+2 - if n != 1 { - return UnsupportedError(fmt.Sprintf("kern nTables: %d", n)) - } - offset += 2 - length, offset := int(u16(f.kern, offset)), offset+2 - coverage, offset := u16(f.kern, offset), offset+2 - if coverage != 0x0001 { - // We only support horizontal kerning. - return UnsupportedError(fmt.Sprintf("kern coverage: 0x%04x", coverage)) - } - f.nKern, offset = int(u16(f.kern, offset)), offset+2 - if 6*f.nKern != length-14 { - return FormatError("bad kern table length") - } - return nil -} - -func (f *Font) parseMaxp() error { - if len(f.maxp) != 32 { - return FormatError(fmt.Sprintf("bad maxp length: %d", len(f.maxp))) - } - f.nGlyph = int(u16(f.maxp, 4)) - f.maxTwilightPoints = u16(f.maxp, 16) - f.maxStorage = u16(f.maxp, 18) - f.maxFunctionDefs = u16(f.maxp, 20) - f.maxStackElements = u16(f.maxp, 24) - return nil -} - -// scale returns x divided by f.fUnitsPerEm, rounded to the nearest integer. -func (f *Font) scale(x fixed.Int26_6) fixed.Int26_6 { - if x >= 0 { - x += fixed.Int26_6(f.fUnitsPerEm) / 2 - } else { - x -= fixed.Int26_6(f.fUnitsPerEm) / 2 - } - return x / fixed.Int26_6(f.fUnitsPerEm) -} - -// Bounds returns the union of a Font's glyphs' bounds. -func (f *Font) Bounds(scale fixed.Int26_6) fixed.Rectangle26_6 { - b := f.bounds - b.Min.X = f.scale(scale * b.Min.X) - b.Min.Y = f.scale(scale * b.Min.Y) - b.Max.X = f.scale(scale * b.Max.X) - b.Max.Y = f.scale(scale * b.Max.Y) - return b -} - -// FUnitsPerEm returns the number of FUnits in a Font's em-square's side. -func (f *Font) FUnitsPerEm() int32 { - return f.fUnitsPerEm -} - -// Index returns a Font's index for the given rune. -func (f *Font) Index(x rune) Index { - c := uint32(x) - for i, j := 0, len(f.cm); i < j; { - h := i + (j-i)/2 - cm := &f.cm[h] - if c < cm.start { - j = h - } else if cm.end < c { - i = h + 1 - } else if cm.offset == 0 { - return Index(c + cm.delta) - } else { - offset := int(cm.offset) + 2*(h-len(f.cm)+int(c-cm.start)) - return Index(u16(f.cmapIndexes, offset)) - } - } - return 0 -} - -// Name returns the Font's name value for the given NameID. It returns "" if -// there was an error, or if that name was not found. -func (f *Font) Name(id NameID) string { - x, platformID, err := parseSubtables(f.name, "name", 6, 12, func(b []byte) bool { - return NameID(u16(b, 6)) == id - }) - if err != nil { - return "" - } - offset, length := u16(f.name, 4)+u16(f.name, x+10), u16(f.name, x+8) - // Return the ASCII value of the encoded string. - // The string is encoded as UTF-16 on non-Apple platformIDs; Apple is platformID 1. - src := f.name[offset : offset+length] - var dst []byte - if platformID != 1 { // UTF-16. - if len(src)&1 != 0 { - return "" - } - dst = make([]byte, len(src)/2) - for i := range dst { - dst[i] = printable(u16(src, 2*i)) - } - } else { // ASCII. - dst = make([]byte, len(src)) - for i, c := range src { - dst[i] = printable(uint16(c)) - } - } - return string(dst) -} - -func printable(r uint16) byte { - if 0x20 <= r && r < 0x7f { - return byte(r) - } - return '?' -} - -// unscaledHMetric returns the unscaled horizontal metrics for the glyph with -// the given index. -func (f *Font) unscaledHMetric(i Index) (h HMetric) { - j := int(i) - if j < 0 || f.nGlyph <= j { - return HMetric{} - } - if j >= f.nHMetric { - p := 4 * (f.nHMetric - 1) - return HMetric{ - AdvanceWidth: fixed.Int26_6(u16(f.hmtx, p)), - LeftSideBearing: fixed.Int26_6(int16(u16(f.hmtx, p+2*(j-f.nHMetric)+4))), - } - } - return HMetric{ - AdvanceWidth: fixed.Int26_6(u16(f.hmtx, 4*j)), - LeftSideBearing: fixed.Int26_6(int16(u16(f.hmtx, 4*j+2))), - } -} - -// HMetric returns the horizontal metrics for the glyph with the given index. -func (f *Font) HMetric(scale fixed.Int26_6, i Index) HMetric { - h := f.unscaledHMetric(i) - h.AdvanceWidth = f.scale(scale * h.AdvanceWidth) - h.LeftSideBearing = f.scale(scale * h.LeftSideBearing) - return h -} - -// unscaledVMetric returns the unscaled vertical metrics for the glyph with -// the given index. yMax is the top of the glyph's bounding box. -func (f *Font) unscaledVMetric(i Index, yMax fixed.Int26_6) (v VMetric) { - j := int(i) - if j < 0 || f.nGlyph <= j { - return VMetric{} - } - if 4*j+4 <= len(f.vmtx) { - return VMetric{ - AdvanceHeight: fixed.Int26_6(u16(f.vmtx, 4*j)), - TopSideBearing: fixed.Int26_6(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 := fixed.Int26_6(int16(u16(f.os2, 68))) - sTypoDescender := fixed.Int26_6(int16(u16(f.os2, 70))) - return VMetric{ - AdvanceHeight: sTypoAscender - sTypoDescender, - TopSideBearing: sTypoAscender - yMax, - } - } - return VMetric{ - AdvanceHeight: fixed.Int26_6(f.fUnitsPerEm), - TopSideBearing: 0, - } -} - -// VMetric returns the vertical metrics for the glyph with the given index. -func (f *Font) VMetric(scale fixed.Int26_6, i Index) VMetric { - // 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 -} - -// Kern returns the horizontal adjustment for the given glyph pair. A positive -// kern means to move the glyphs further apart. -func (f *Font) Kern(scale fixed.Int26_6, i0, i1 Index) fixed.Int26_6 { - if f.nKern == 0 { - return 0 - } - g := uint32(i0)<<16 | uint32(i1) - lo, hi := 0, f.nKern - for lo < hi { - i := (lo + hi) / 2 - ig := u32(f.kern, 18+6*i) - if ig < g { - lo = i + 1 - } else if ig > g { - hi = i - } else { - return f.scale(scale * fixed.Int26_6(int16(u16(f.kern, 22+6*i)))) - } - } - return 0 -} - -// Parse returns a new Font for the given TTF or TTC data. -// -// For TrueType Collections, the first font in the collection is parsed. -func Parse(ttf []byte) (font *Font, err error) { - return parse(ttf, 0) -} - -func parse(ttf []byte, offset int) (font *Font, err error) { - if len(ttf)-offset < 12 { - err = FormatError("TTF data is too short") - return - } - originalOffset := offset - magic, offset := u32(ttf, offset), offset+4 - switch magic { - case 0x00010000: - // No-op. - case 0x74746366: // "ttcf" as a big-endian uint32. - if originalOffset != 0 { - err = FormatError("recursive TTC") - return - } - ttcVersion, offset := u32(ttf, offset), offset+4 - if ttcVersion != 0x00010000 { - // TODO: support TTC version 2.0, once I have such a .ttc file to test with. - err = FormatError("bad TTC version") - return - } - numFonts, offset := int(u32(ttf, offset)), offset+4 - if numFonts <= 0 { - err = FormatError("bad number of TTC fonts") - return - } - if len(ttf[offset:])/4 < numFonts { - err = FormatError("TTC offset table is too short") - return - } - // TODO: provide an API to select which font in a TrueType collection to return, - // not just the first one. This may require an API to parse a TTC's name tables, - // so users of this package can select the font in a TTC by name. - offset = int(u32(ttf, offset)) - if offset <= 0 || offset > len(ttf) { - err = FormatError("bad TTC offset") - return - } - return parse(ttf, offset) - default: - err = FormatError("bad TTF version") - return - } - n, offset := int(u16(ttf, offset)), offset+2 - if len(ttf) < 16*n+12 { - err = FormatError("TTF data is too short") - return - } - f := new(Font) - // Assign the table slices. - for i := 0; i < n; i++ { - x := 16*i + 12 - switch string(ttf[x : x+4]) { - case "cmap": - f.cmap, err = readTable(ttf, ttf[x+8:x+16]) - case "cvt ": - f.cvt, err = readTable(ttf, ttf[x+8:x+16]) - case "fpgm": - f.fpgm, err = readTable(ttf, ttf[x+8:x+16]) - case "glyf": - f.glyf, err = readTable(ttf, ttf[x+8:x+16]) - case "hdmx": - f.hdmx, err = readTable(ttf, ttf[x+8:x+16]) - case "head": - f.head, err = readTable(ttf, ttf[x+8:x+16]) - case "hhea": - f.hhea, err = readTable(ttf, ttf[x+8:x+16]) - case "hmtx": - f.hmtx, err = readTable(ttf, ttf[x+8:x+16]) - case "kern": - f.kern, err = readTable(ttf, ttf[x+8:x+16]) - case "loca": - f.loca, err = readTable(ttf, ttf[x+8:x+16]) - case "maxp": - f.maxp, err = readTable(ttf, ttf[x+8:x+16]) - case "name": - f.name, 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": - f.vmtx, err = readTable(ttf, ttf[x+8:x+16]) - } - if err != nil { - return - } - } - // Parse and sanity-check the TTF data. - if err = f.parseHead(); err != nil { - return - } - if err = f.parseMaxp(); err != nil { - return - } - if err = f.parseCmap(); err != nil { - return - } - if err = f.parseKern(); err != nil { - return - } - if err = f.parseHhea(); err != nil { - return - } - font = f - return -} |