// 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 (
	
	
)

// 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 ( *GlyphBuf) ( *Font,  fixed.Int26_6,  Index,  font.Hinting) error {
	.Points = .Points[:0]
	.Unhinted = .Unhinted[:0]
	.InFontUnits = .InFontUnits[:0]
	.Ends = .Ends[:0]
	.font = 
	.hinting = 
	.scale = 
	.pp1x = 0
	.phantomPoints = [4]Point{}
	.metricsSet = false

	if  != font.HintingNone {
		if  := .hinter.init(, );  != nil {
			return 
		}
	}
	if  := .load(0, , true);  != nil {
		return 
	}
	// 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
	if  != font.HintingNone {
		 = .phantomPoints[0].X
	}
	if  != 0 {
		for  := range .Points {
			.Points[].X -= 
		}
	}

	 := .phantomPoints[1].X - .phantomPoints[0].X
	if  != font.HintingNone {
		if len(.hdmx) >= 8 {
			if  := u32(.hdmx, 4);  > 3+uint32() {
				for  := .hdmx[8:]; uint32(len()) >= ;  = [:] {
					if fixed.Int26_6([0]) == >>6 {
						 = fixed.Int26_6([2+]) << 6
						break
					}
				}
			}
		}
		 = ( + 32) &^ 63
	}
	.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(.Points) == 0 {
		.Bounds = fixed.Rectangle26_6{}
	} else {
		 := .Points[0]
		.Bounds.Min.X = .X
		.Bounds.Max.X = .X
		.Bounds.Min.Y = .Y
		.Bounds.Max.Y = .Y
		for ,  := range .Points[1:] {
			if .Bounds.Min.X > .X {
				.Bounds.Min.X = .X
			} else if .Bounds.Max.X < .X {
				.Bounds.Max.X = .X
			}
			if .Bounds.Min.Y > .Y {
				.Bounds.Min.Y = .Y
			} else if .Bounds.Max.Y < .Y {
				.Bounds.Max.Y = .Y
			}
		}
		// Snap the box to the grid, if hinting is on.
		if  != font.HintingNone {
			.Bounds.Min.X &^= 63
			.Bounds.Min.Y &^= 63
			.Bounds.Max.X += 63
			.Bounds.Max.X &^= 63
			.Bounds.Max.Y += 63
			.Bounds.Max.Y &^= 63
		}
	}
	return nil
}

func ( *GlyphBuf) ( uint32,  Index,  bool) ( error) {
	// The recursion limit here is arbitrary, but defends against malformed glyphs.
	if  >= 32 {
		return UnsupportedError("excessive compound glyph recursion")
	}
	// Find the relevant slice of g.font.glyf.
	var ,  uint32
	if .font.locaOffsetFormat == locaOffsetFormatShort {
		 = 2 * uint32(u16(.font.loca, 2*int()))
		 = 2 * uint32(u16(.font.loca, 2*int()+2))
	} else {
		 = u32(.font.loca, 4*int())
		 = u32(.font.loca, 4*int()+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.
	, , ,  := []byte(nil), 0, fixed.Int26_6(0), fixed.Int26_6(0)
	if +10 <=  {
		 = .font.glyf[:]
		 = int(int16(u16(, 0)))
		 = fixed.Int26_6(int16(u16(, 2)))
		 = fixed.Int26_6(int16(u16(, 8)))
	}

	// Create the phantom points.
	,  := .font.unscaledHMetric(), fixed.Int26_6(0)
	 := .font.unscaledVMetric(, )
	.phantomPoints = [4]Point{
		{X:  - .LeftSideBearing},
		{X:  - .LeftSideBearing + .AdvanceWidth},
		{X: .AdvanceWidth / 2, Y:  + .TopSideBearing},
		{X: .AdvanceWidth / 2, Y:  + .TopSideBearing - .AdvanceHeight},
	}
	if len() == 0 {
		.addPhantomsAndScale(len(.Points), len(.Points), true, true)
		copy(.phantomPoints[:], .Points[len(.Points)-4:])
		.Points = .Points[:len(.Points)-4]
		// TODO: also trim g.InFontUnits and g.Unhinted?
		return nil
	}

	// Load and hint the contours.
	if  < 0 {
		if  != -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")
		}
		 = .font.scale(.scale * ( - .LeftSideBearing))
		if  := .loadCompound(, , , , );  != nil {
			return 
		}
	} else {
		,  := len(.Points), len(.Ends)
		 := .loadSimple(, )
		.addPhantomsAndScale(, , true, true)
		 = .Points[len(.Points)-4].X
		if .hinting != font.HintingNone {
			if len() != 0 {
				 := .hinter.run(
					,
					.Points[:],
					.Unhinted[:],
					.InFontUnits[:],
					.Ends[:],
				)
				if  != nil {
					return 
				}
			}
			// Drop the four phantom points.
			.InFontUnits = .InFontUnits[:len(.InFontUnits)-4]
			.Unhinted = .Unhinted[:len(.Unhinted)-4]
		}
		if  {
			copy(.phantomPoints[:], .Points[len(.Points)-4:])
		}
		.Points = .Points[:len(.Points)-4]
		if  != 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  := ;  < len(.Ends); ++ {
				.Ends[] += 
			}
		}
	}
	if  && !.metricsSet {
		.metricsSet = true
		.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 ( *GlyphBuf) ( []byte,  int) ( []byte) {
	 := loadOffset
	for  := 0;  < ; ++ {
		.Ends = append(.Ends, 1+int(u16(, )))
		 += 2
	}

	// Note the TrueType hinting instructions.
	 := int(u16(, ))
	 += 2
	 = [ : +]
	 += 

	if  == 0 {
		return 
	}

	 := len(.Points)
	 :=  + int(.Ends[len(.Ends)-1])

	// Decode the flags.
	for  := ;  < ; {
		 := uint32([])
		++
		.Points = append(.Points, Point{Flags: })
		++
		if &flagRepeat != 0 {
			 := []
			++
			for ;  > 0; -- {
				.Points = append(.Points, Point{Flags: })
				++
			}
		}
	}

	// Decode the co-ordinates.
	var  int16
	for  := ;  < ; ++ {
		 := .Points[].Flags
		if &flagXShortVector != 0 {
			 := int16([])
			++
			if &flagPositiveXShortVector == 0 {
				 -= 
			} else {
				 += 
			}
		} else if &flagThisXIsSame == 0 {
			 += int16(u16(, ))
			 += 2
		}
		.Points[].X = fixed.Int26_6()
	}
	var  int16
	for  := ;  < ; ++ {
		 := .Points[].Flags
		if &flagYShortVector != 0 {
			 := int16([])
			++
			if &flagPositiveYShortVector == 0 {
				 -= 
			} else {
				 += 
			}
		} else if &flagThisYIsSame == 0 {
			 += int16(u16(, ))
			 += 2
		}
		.Points[].Y = fixed.Int26_6()
	}

	return 
}

func ( *GlyphBuf) ( uint32,  HMetric,  Index,
	 []byte,  bool) error {

	// Flags for decoding a compound glyph. These flags are documented at
	// http://developer.apple.com/fonts/TTRefMan/RM06/Chap6glyf.html.
	const (
		 = 1 << iota
		
		
		
		
		
		
		
		
		
		
	)
	,  := len(.Points), len(.Ends)
	 := loadOffset
	for {
		 := u16(, )
		 := Index(u16(, +2))
		, , ,  := fixed.Int26_6(0), fixed.Int26_6(0), [4]int16{}, false
		if & != 0 {
			 = fixed.Int26_6(int16(u16(, +4)))
			 = fixed.Int26_6(int16(u16(, +6)))
			 += 8
		} else {
			 = fixed.Int26_6(int16(int8([+4])))
			 = fixed.Int26_6(int16(int8([+5])))
			 += 6
		}
		if & == 0 {
			return UnsupportedError("compound glyph transform vector")
		}
		if &(||) != 0 {
			 = true
			switch {
			case & != 0:
				[0] = int16(u16(, +0))
				[3] = [0]
				 += 2
			case & != 0:
				[0] = int16(u16(, +0))
				[3] = int16(u16(, +2))
				 += 4
			case & != 0:
				[0] = int16(u16(, +0))
				[1] = int16(u16(, +2))
				[2] = int16(u16(, +4))
				[3] = int16(u16(, +6))
				 += 8
			}
		}
		 := .phantomPoints
		 := len(.Points)
		 :=  && (& != 0)
		if  := .load(+1, , );  != nil {
			return 
		}
		if & == 0 {
			.phantomPoints = 
		}
		if  {
			for  := ;  < len(.Points); ++ {
				 := &.Points[]
				 := 0 +
					fixed.Int26_6((int64(.X)*int64([0])+1<<13)>>14) +
					fixed.Int26_6((int64(.Y)*int64([2])+1<<13)>>14)
				 := 0 +
					fixed.Int26_6((int64(.X)*int64([1])+1<<13)>>14) +
					fixed.Int26_6((int64(.Y)*int64([3])+1<<13)>>14)
				.X, .Y = , 
			}
		}
		 = .font.scale(.scale * )
		 = .font.scale(.scale * )
		if & != 0 {
			 = ( + 32) &^ 63
			 = ( + 32) &^ 63
		}
		for  := ;  < len(.Points); ++ {
			 := &.Points[]
			.X += 
			.Y += 
		}
		// TODO: also adjust g.InFontUnits and g.Unhinted?
		if & == 0 {
			break
		}
	}

	 := 0
	if .hinting != font.HintingNone && +2 <= len() {
		 = int(u16(, ))
		 += 2
	}

	.addPhantomsAndScale(, len(.Points), false,  > 0)
	,  := .Points[:], .Ends[:]
	.Points = .Points[:len(.Points)-4]
	for  := range  {
		[].Flags &^= flagTouchedX | flagTouchedY
	}

	if  == 0 {
		if !.metricsSet {
			copy(.phantomPoints[:], [len()-4:])
		}
		return nil
	}

	// Hint the compound glyph.
	 := [ : +]
	// Temporarily adjust the ends to be relative to this compound glyph.
	if  != 0 {
		for  := range  {
			[] -= 
		}
	}
	// Hinting instructions of a composite glyph completely refer to the
	// (already) hinted subglyphs.
	.tmp = append(.tmp[:0], ...)
	if  := .hinter.run(, , .tmp, .tmp, );  != nil {
		return 
	}
	if  != 0 {
		for  := range  {
			[] += 
		}
	}
	if !.metricsSet {
		copy(.phantomPoints[:], [len()-4:])
	}
	return nil
}

func ( *GlyphBuf) (,  int, ,  bool) {
	// Add the four phantom points.
	.Points = append(.Points, .phantomPoints[:]...)
	// Scale the points.
	if  && .hinting != font.HintingNone {
		.InFontUnits = append(.InFontUnits, .Points[:]...)
	}
	for  := ;  < len(.Points); ++ {
		 := &.Points[]
		.X = .font.scale(.scale * .X)
		.Y = .font.scale(.scale * .Y)
	}
	if .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  {
		 := .Points[len(.Points)-4].X
		if  := (( + 32) &^ 63) - ;  != 0 {
			for  := ;  < len(.Points); ++ {
				.Points[].X += 
			}
		}
	}
	if  {
		.Unhinted = append(.Unhinted, .Points[:]...)
	}
	// Round the 2nd and 4th phantom point to the grid.
	 := &.Points[len(.Points)-3]
	.X = (.X + 32) &^ 63
	 = &.Points[len(.Points)-1]
	.Y = (.Y + 32) &^ 63
}