// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package sfnt

import (
	
)

// Platform IDs and Platform Specific IDs as per
// https://www.microsoft.com/typography/otspec/name.htm
const (
	pidUnicode   = 0
	pidMacintosh = 1
	pidWindows   = 3

	psidUnicode2BMPOnly        = 3
	psidUnicode2FullRepertoire = 4
	// Note that FontForge may generate a bogus Platform Specific ID (value 10)
	// for the Unicode Platform ID (value 0). See
	// https://github.com/fontforge/fontforge/issues/2728

	psidMacintoshRoman = 0

	psidWindowsSymbol = 0
	psidWindowsUCS2   = 1
	psidWindowsUCS4   = 10
)

// platformEncodingWidth returns the number of bytes per character assumed by
// the given Platform ID and Platform Specific ID.
//
// Very old fonts, from before Unicode was widely adopted, assume only 1 byte
// per character: a character map.
//
// Old fonts, from when Unicode meant the Basic Multilingual Plane (BMP),
// assume that 2 bytes per character is sufficient.
//
// Recent fonts naturally support the full range of Unicode code points, which
// can take up to 4 bytes per character. Such fonts might still choose one of
// the legacy encodings if e.g. their repertoire is limited to the BMP, for
// greater compatibility with older software, or because the resultant file
// size can be smaller.
func platformEncodingWidth(,  uint16) int {
	switch  {
	case pidUnicode:
		switch  {
		case psidUnicode2BMPOnly:
			return 2
		case psidUnicode2FullRepertoire:
			return 4
		}

	case pidMacintosh:
		switch  {
		case psidMacintoshRoman:
			return 1
		}

	case pidWindows:
		switch  {
		case psidWindowsSymbol:
			return 2
		case psidWindowsUCS2:
			return 2
		case psidWindowsUCS4:
			return 4
		}
	}
	return 0
}

// The various cmap formats are described at
// https://www.microsoft.com/typography/otspec/cmap.htm

var supportedCmapFormat = func(, ,  uint16) bool {
	switch  {
	case 0:
		return  == pidMacintosh &&  == psidMacintoshRoman
	case 4:
		return true
	case 6:
		return true
	case 12:
		return true
	}
	return false
}

func ( *Font) ( []byte, ,  uint32,  uint16) ([]byte, glyphIndexFunc, error) {
	switch  {
	case 0:
		return .makeCachedGlyphIndexFormat0(, , )
	case 4:
		return .makeCachedGlyphIndexFormat4(, , )
	case 6:
		return .makeCachedGlyphIndexFormat6(, , )
	case 12:
		return .makeCachedGlyphIndexFormat12(, , )
	}
	panic("unreachable")
}

func ( *Font) ( []byte, ,  uint32) ([]byte, glyphIndexFunc, error) {
	if  != 6+256 || + > .cmap.length {
		return nil, nil, errInvalidCmapTable
	}
	var  error
	,  = .src.view(, int(.cmap.offset+), int())
	if  != nil {
		return nil, nil, 
	}
	var  [256]byte
	copy([:], [6:])
	return , func( *Font,  *Buffer,  rune) (GlyphIndex, error) {
		,  := charmap.Macintosh.EncodeRune()
		if ! {
			// The source rune r is not representable in the Macintosh-Roman encoding.
			return 0, nil
		}
		return GlyphIndex([]), nil
	}, nil
}

func ( *Font) ( []byte, ,  uint32) ([]byte, glyphIndexFunc, error) {
	const  = 14
	if + > .cmap.length {
		return nil, nil, errInvalidCmapTable
	}
	var  error
	,  = .src.view(, int(.cmap.offset+), )
	if  != nil {
		return nil, nil, 
	}
	 += 

	 := u16([6:])
	if &1 != 0 {
		return nil, nil, errInvalidCmapTable
	}
	 /= 2
	if  > maxCmapSegments {
		return nil, nil, errUnsupportedNumberOfCmapSegments
	}

	 := 8*uint32() + 2
	if + > .cmap.length {
		return nil, nil, errInvalidCmapTable
	}
	,  = .src.view(, int(.cmap.offset+), int())
	if  != nil {
		return nil, nil, 
	}
	 += 

	 := make([]cmapEntry16, )
	for  := range  {
		[] = cmapEntry16{
			end:    u16([0*len()+0+2*:]),
			start:  u16([2*len()+2+2*:]),
			delta:  u16([4*len()+2+2*:]),
			offset: u16([6*len()+2+2*:]),
		}
	}
	 := .cmap.offset + 
	 := .cmap.length - 

	return , func( *Font,  *Buffer,  rune) (GlyphIndex, error) {
		if uint32() > 0xffff {
			return 0, nil
		}

		 := uint16()
		for ,  := 0, len();  < ; {
			 :=  + (-)/2
			 := &[]
			if  < .start {
				 = 
			} else if .end <  {
				 =  + 1
			} else if .offset == 0 {
				return GlyphIndex( + .delta), nil
			} else {
				 := uint32(.offset) + 2*uint32(-len()+int(-.start))
				if  >  || +2 >  {
					return 0, errInvalidCmapTable
				}
				if  == nil {
					 = &Buffer{}
				}
				,  := .view(&.src, int(+), 2)
				if  != nil {
					return 0, 
				}
				return GlyphIndex(u16()), nil
			}
		}
		return 0, nil
	}, nil
}

func ( *Font) ( []byte, ,  uint32) ([]byte, glyphIndexFunc, error) {
	const  = 10
	if + > .cmap.length {
		return nil, nil, errInvalidCmapTable
	}
	var  error
	,  = .src.view(, int(.cmap.offset+), )
	if  != nil {
		return nil, nil, 
	}
	 += 

	 := u16([6:])
	 := u16([8:])

	 := 2 * uint32()
	if + > .cmap.length {
		return nil, nil, errInvalidCmapTable
	}

	if  != 0 {
		,  = .src.view(, int(.cmap.offset+), int())
		if  != nil {
			return nil, nil, 
		}
		 += 
	}

	 := make([]uint16, )
	for  := range  {
		[] = u16([2*:])
	}

	return , func( *Font,  *Buffer,  rune) (GlyphIndex, error) {
		if uint16() <  {
			return 0, nil
		}

		 := int(uint16() - )
		if  >= len() {
			return 0, nil
		}
		return GlyphIndex([]), nil
	}, nil
}

func ( *Font) ( []byte, ,  uint32) ([]byte, glyphIndexFunc, error) {
	const  = 16
	if + > .cmap.length {
		return nil, nil, errInvalidCmapTable
	}
	var  error
	,  = .src.view(, int(.cmap.offset+), )
	if  != nil {
		return nil, nil, 
	}
	 := u32([4:])
	if .cmap.length <  ||  > .cmap.length- {
		return nil, nil, errInvalidCmapTable
	}
	 += 

	 := u32([12:])
	if  > maxCmapSegments {
		return nil, nil, errUnsupportedNumberOfCmapSegments
	}

	 := 12 * 
	if + !=  {
		return nil, nil, errInvalidCmapTable
	}
	,  = .src.view(, int(.cmap.offset+), int())
	if  != nil {
		return nil, nil, 
	}
	 += 

	 := make([]cmapEntry32, )
	for  := range  {
		[] = cmapEntry32{
			start: u32([0+12*:]),
			end:   u32([4+12*:]),
			delta: u32([8+12*:]),
		}
	}

	return , func( *Font,  *Buffer,  rune) (GlyphIndex, error) {
		 := uint32()
		for ,  := 0, len();  < ; {
			 :=  + (-)/2
			 := &[]
			if  < .start {
				 = 
			} else if .end <  {
				 =  + 1
			} else {
				return GlyphIndex( - .start + .delta), nil
			}
		}
		return 0, nil
	}, nil
}

type cmapEntry16 struct {
	end, start, delta, offset uint16
}

type cmapEntry32 struct {
	start, end, delta uint32
}