// SPDX-License-Identifier: Unlicense OR BSD-3-Clause

package font

import (
	
	
	

	
)

// This file implements the logic needed to use a cmap.

var (
	_ Cmap = cmap0(nil)
	_ Cmap = cmap4(nil)
	_ Cmap = (*cmap6or10)(nil)
	_ Cmap = cmap12(nil)
	_ Cmap = cmap13(nil)

	_ CmapIter = (*cmap0Iter)(nil)
	_ CmapIter = (*cmap4Iter)(nil)
	_ CmapIter = (*cmap6Or10Iter)(nil)
	_ CmapIter = (*cmap12Iter)(nil)
	_ CmapIter = (*cmap13Iter)(nil)
)

// CmapIter is an iterator over a Cmap.
type CmapIter interface {
	// Next returns true if the iterator still has data to yield
	Next() bool

	// Char must be called only when `Next` has returned `true`
	Char() (rune, GID)
}

// Cmap stores a compact representation of a cmap,
// offering both on-demand rune lookup and full rune range.
// It is conceptually equivalent to a map[rune]GID, but is often
// implemented more efficiently.
type Cmap interface {
	// Iter returns a new iterator over the cmap
	// Multiple iterators may be used over the same cmap
	// The returned interface is garanted not to be nil.
	Iter() CmapIter

	// Lookup avoid the construction of a map and provides
	// an alternative when only few runes need to be fetched.
	// It returns a default value and false when no glyph is provided.
	Lookup(rune) (GID, bool)
}

// ProcessCmap sanitize the given 'cmap' subtable, and select the best encoding
// when several subtables are given.
// When present, the variation selectors are returned.
// [os2FontPage] is used for legacy arabic fonts.
//
// The returned values are copied from the input 'cmap', meaning they do not
// retain any reference on the input storage.
func ( tables.Cmap,  tables.FontPage) (Cmap, UnicodeVariations, error) {
	var (
		 []cmapID
		   []Cmap
		           UnicodeVariations
	)
	for ,  := range .Records {
		 := cmapID{platform: .PlatformID, encoding: .EncodingID}
		switch table := .Subtable.(type) {
		case tables.CmapSubtable0:
			 = append(, newCmap0())
			 = append(, )
		case tables.CmapSubtable2:
			// we dont support this deprecated format
			continue
		case tables.CmapSubtable4:
			,  := newCmap4()
			if  != nil {
				return nil, nil, 
			}
			 = append(, )
			 = append(, )
		case tables.CmapSubtable6:
			 = append(, newCmap6())
			 = append(, )
		case tables.CmapSubtable10:
			 = append(, newCmap10())
			 = append(, )
		case tables.CmapSubtable12:
			 = append(, newCmap12())
			 = append(, )
		case tables.CmapSubtable13:
			 = append(, newCmap13())
			 = append(, )
		case tables.CmapSubtable14:
			// quoting the spec :
			// This subtable format must only be used under platform ID 0 and encoding ID 5.
			if !(.platform == 0 && .encoding == 5) {
				return nil, nil, errors.New("invalid cmap subtable format 14 platform or encoding")
			}
			 = newUnicodeVariations()
		}
	}

	// now find the best cmap, following harfbuzz/src/hb-ot-cmap-table.hh

	// Prefer symbol if available.
	if  := findSubtable(cmapID{tables.PlatformMicrosoft, tables.PEMicrosoftSymbolCs}, );  != -1 {
		 := []
		switch  {
		case tables.FPNone:
			 = remaperSymbol{}
		case tables.FPSimpArabic:
			 = remaperPUASimp{}
		case tables.FPTradArabic:
			 = remaperPUATrad{}
		}
		return , , nil
	}

	/* 32-bit subtables. */
	if  := findSubtable(cmapID{tables.PlatformMicrosoft, tables.PEMicrosoftUcs4}, );  != -1 {
		return [], , nil
	}
	if  := findSubtable(cmapID{tables.PlatformUnicode, tables.PEUnicodeFull13}, );  != -1 {
		return [], , nil
	}
	if  := findSubtable(cmapID{tables.PlatformUnicode, tables.PEUnicodeFull}, );  != -1 {
		return [], , nil
	}

	/* 16-bit subtables. */
	if  := findSubtable(cmapID{tables.PlatformMicrosoft, tables.PEMicrosoftUnicodeCs}, );  != -1 {
		return [], , nil
	}
	if  := findSubtable(cmapID{tables.PlatformUnicode, tables.PEUnicodeBMP}, );  != -1 {
		return [], , nil
	}
	if  := findSubtable(cmapID{tables.PlatformUnicode, 2}, );  != -1 { // deprecated
		return [], , nil
	}
	if  := findSubtable(cmapID{tables.PlatformUnicode, 1}, );  != -1 { // deprecated
		return [], , nil
	}
	if  := findSubtable(cmapID{tables.PlatformUnicode, 0}, );  != -1 { // deprecated
		return [], , nil
	}

	/* MacRoman subtable. */
	if  := findSubtable(cmapID{tables.PlatformMac, 0}, );  != -1 {
		 := []
		return remaperMacroman{}, , nil
	}
	/* Any other Mac subtable; we just map ASCII for these. */
	if  := findSubtable(cmapID{tables.PlatformMac, 0xFFFF}, );  != -1 {
		 := []
		return remaperAscii{}, , nil
	}

	// uuh... fallback to the first cmap and hope for the best
	if len() != 0 {
		return [0], , nil
	}
	return nil, nil, errors.New("unsupported cmap table")
}

// cmapID groups the platform and encoding of a Cmap subtable.
type cmapID struct {
	platform tables.PlatformID
	encoding tables.EncodingID
}

func ( cmapID) ( bool) uint32 {
	if  {
		.encoding = 0
	}
	return uint32(.platform)<<16 | uint32(.encoding)
}

// findSubtable returns the cmap index for the given platform and encoding, or -1 if not found.
// as a special case, if [id.encoding] is 0xFFFF, encoding is ignored
func findSubtable( cmapID,  []cmapID) int {
	 := .encoding == 0xFFFF
	 := .key()
	// binary search
	for ,  := 0, len();  < ; {
		 :=  + (-)/2
		 := [].key()
		if  <  {
			 = 
		} else if  <  {
			 =  + 1
		} else {
			return 
		}
	}
	return -1
}

// ---------------------------------- Format 0 ----------------------------------

// use Macintosh encoding, storing indexIntoEncoding -> glyphIndex
type cmap0 map[rune]uint8

func newCmap0( tables.CmapSubtable0) cmap0 {
	 := make(cmap0)
	for ,  := range .GlyphIdArray {
		if  == 0 {
			continue
		}
		[tables.DecodeMacintoshByte(byte())] = 
	}
	return 
}

type cmap0Iter struct {
	data cmap0
	keys []rune
	pos  int
}

func ( *cmap0Iter) () bool {
	return .pos < len(.keys)
}

func ( *cmap0Iter) () (rune, GID) {
	 := .keys[.pos]
	.pos++
	return , GID(.data[])
}

func ( cmap0) () CmapIter {
	 := make([]rune, 0, len())
	for  := range  {
		 = append(, )
	}
	return &cmap0Iter{data: , keys: }
}

func ( cmap0) ( rune) (GID, bool) {
	,  := [] // will be 0 if r is not in s
	return GID(), 
}

// ---------------------------------- Format 4 ----------------------------------

// if indexes is nil, delta is used
type cmapEntry16 struct {
	// we prefere not to keep a link to a buffer (via an offset)
	// and eagerly resolve it
	indexes    []tables.GlyphID // length end - start + 1
	end, start uint16
	delta      uint16 // arithmetic modulo 0xFFFF
}

type cmap4 []cmapEntry16

func newCmap4( tables.CmapSubtable4) (cmap4, error) {
	 := len(.EndCode)
	 := make(cmap4, )
	for  := range  {
		 := cmapEntry16{
			end:   .EndCode[],
			start: .StartCode[],
			delta: .IdDelta[],
		}
		 := int(.IdRangeOffsets[])

		// some fonts use 0xFFFF for idRangeOff for the last segment
		if .start != 0xFFFF &&  != 0 {
			// we resolve the indexes
			.indexes = make([]tables.GlyphID, .end-.start+1)
			 := /2 +  - 
			if len(.GlyphIDArray) < 2*(+len(.indexes)) {
				return nil, errors.New("invalid cmap subtable format 4 glyphs array length")
			}
			for  := range .indexes {
				 :=  + 
				.indexes[] = tables.GlyphID(binary.BigEndian.Uint16(.GlyphIDArray[2*:]))
			}
		}
		[] = 
	}
	return , nil
}

type cmap4Iter struct {
	data cmap4
	pos1 int // into data
	pos2 int // either into data[pos1].indexes or an offset between start and end
}

func ( *cmap4Iter) () bool {
	return .pos1 < len(.data)
}

func ( *cmap4Iter) () ( rune,  GID) {
	 := .data[.pos1]
	if .indexes == nil {
		 = rune(.pos2 + int(.start))
		 = GID(uint16(.pos2) + .start + .delta)
		if uint16(.pos2) == .end-.start {
			// we have read the last glyph in this part
			.pos2 = 0
			.pos1++
		} else {
			.pos2++
		}
	} else { // pos2 is the array index
		 = rune(.pos2) + rune(.start)
		 = GID(.indexes[.pos2])
		if  != 0 {
			 += GID(.delta)
		}
		if .pos2 == len(.indexes)-1 {
			// we have read the last glyph in this part
			.pos2 = 0
			.pos1++
		} else {
			.pos2++
		}
	}

	return , 
}

func ( cmap4) () CmapIter { return &cmap4Iter{data: } }

func ( cmap4) ( rune) (GID, bool) {
	if uint32() > 0xffff {
		return 0, false
	}
	// binary search
	 := uint16()
	for ,  := 0, len();  < ; {
		 :=  + (-)/2
		 := []
		if  < .start {
			 = 
		} else if .end <  {
			 =  + 1
		} else if .indexes == nil {
			return GID( + .delta), true
		} else {
			 := .indexes[-.start]
			if  == 0 {
				return 0, false
			}
			return GID(uint16() + .delta), true
		}
	}
	return 0, false
}

// ---------------------------------- Format 6 and 10  ----------------------------------

type cmap6or10 struct {
	entries   []tables.GlyphID
	firstCode rune
}

func newCmap6( tables.CmapSubtable6) cmap6or10 {
	return cmap6or10{entries: .GlyphIdArray, firstCode: rune(.FirstCode)}
}

func newCmap10( tables.CmapSubtable10) cmap6or10 {
	return cmap6or10{entries: .GlyphIdArray, firstCode: rune(.StartCharCode)}
}

type cmap6Or10Iter struct {
	data cmap6or10
	pos  int // index into data.entries
}

func ( *cmap6Or10Iter) () bool {
	return .pos < len(.data.entries)
}

func ( *cmap6Or10Iter) () (rune, GID) {
	 := .data.entries[.pos]
	 := rune(.pos) + .data.firstCode
	 := GID()
	.pos++
	return , 
}

func ( cmap6or10) () CmapIter {
	return &cmap6Or10Iter{data: }
}

func ( cmap6or10) ( rune) (GID, bool) {
	if  < .firstCode {
		return 0, false
	}
	 := int( - .firstCode)
	if  >= len(.entries) {
		return 0, false
	}
	return GID(.entries[]), true
}

// ---------------------------------- Format 12 ----------------------------------

type cmap12 []tables.SequentialMapGroup

func newCmap12( tables.CmapSubtable12) cmap12 { return .Groups }

type cmap12Iter struct {
	data cmap12
	pos1 int // into data
	pos2 int // offset from start
}

func ( *cmap12Iter) () bool { return .pos1 < len(.data) }

func ( *cmap12Iter) () ( rune,  GID) {
	 := .data[.pos1]
	 = rune(.pos2 + int(.StartCharCode))
	 = GID(.pos2 + int(.StartGlyphID))
	if uint32(.pos2) == .EndCharCode-.StartCharCode {
		// we have read the last glyph in this part
		.pos2 = 0
		.pos1++
	} else {
		.pos2++
	}

	return , 
}

func ( cmap12) () CmapIter { return &cmap12Iter{data: } }

func ( cmap12) ( rune) (GID, bool) {
	 := uint32()
	// binary search
	for ,  := 0, len();  < ; {
		 :=  + (-)/2
		 := []
		if  < .StartCharCode {
			 = 
		} else if .EndCharCode <  {
			 =  + 1
		} else {
			return GID( - .StartCharCode + .StartGlyphID), true
		}
	}
	return 0, false
}

// ---------------------------------- Format 13 ----------------------------------

type cmap13 []tables.SequentialMapGroup

func newCmap13( tables.CmapSubtable13) cmap13 { return .Groups }

type cmap13Iter struct {
	data cmap13
	pos1 int // into data
	pos2 int // offset from start
}

func ( *cmap13Iter) () bool {
	return .pos1 < len(.data)
}

func ( *cmap13Iter) () ( rune,  GID) {
	 := .data[.pos1]
	 = rune(.pos2 + int(.StartCharCode))
	 = GID(.StartGlyphID)
	if uint32(.pos2) == .EndCharCode-.StartCharCode {
		// we have read the last glyph in this part
		.pos2 = 0
		.pos1++
	} else {
		.pos2++
	}

	return , 
}

func ( cmap13) () CmapIter { return &cmap13Iter{data: } }

func ( cmap13) ( rune) (GID, bool) {
	 := uint32()
	// binary search
	for ,  := 0, len();  < ; {
		 :=  + (-)/2
		 := []
		if  < .StartCharCode {
			 = 
		} else if .EndCharCode <  {
			 =  + 1
		} else {
			return GID(.StartGlyphID), true
		}
	}
	return 0, false
}

// -------------------------------- Unicode selectors --------------------------------

type unicodeRange struct {
	start           rune
	additionalCount uint8 // 0 for a singleton range
}

type uvsMapping struct {
	unicode rune
	glyphID tables.GlyphID
}

type variationSelector struct {
	defaultUVS    []unicodeRange
	nonDefaultUVS []uvsMapping
	varSelector   rune
}

func ( variationSelector) ( rune) (GID, uint8) {
	// binary search
	for ,  := 0, len(.defaultUVS);  < ; {
		 :=  + (-)/2
		 := .defaultUVS[]
		if  < .start {
			 = 
		} else if .start+rune(.additionalCount) <  {
			 =  + 1
		} else {
			return 0, VariantUseDefault
		}
	}

	for ,  := 0, len(.nonDefaultUVS);  < ; {
		 :=  + (-)/2
		 := .nonDefaultUVS[].unicode
		if  <  {
			 = 
		} else if  <  {
			 =  + 1
		} else {
			return GID(.nonDefaultUVS[].glyphID), VariantFound
		}
	}

	return 0, VariantNotFound
}

// same as binary.BigEndian.Uint32, but for 24 bit uint
func parseUint24( [3]byte) rune {
	return rune([0])<<16 | rune([1])<<8 | rune([2])
}

type UnicodeVariations []variationSelector

func newUnicodeVariations( tables.CmapSubtable14) UnicodeVariations {
	 := make([]variationSelector, len(.VarSelectors))
	for ,  := range .VarSelectors {
		 := variationSelector{
			varSelector:   parseUint24(.VarSelector),
			defaultUVS:    make([]unicodeRange, len(.DefaultUVS.Ranges)),
			nonDefaultUVS: make([]uvsMapping, len(.NonDefaultUVS.Ranges)),
		}
		for ,  := range .DefaultUVS.Ranges {
			.defaultUVS[] = unicodeRange{start: parseUint24(.StartUnicodeValue), additionalCount: .AdditionalCount}
		}
		for ,  := range .NonDefaultUVS.Ranges {
			.nonDefaultUVS[] = uvsMapping{unicode: parseUint24(.UnicodeValue), glyphID: .GlyphID}
		}
		[] = 
	}
	return 
}

const (
	// VariantNotFound is returned when the font does not have a glyph for
	// the given rune and selector.
	VariantNotFound = iota
	// VariantUseDefault is returned when the regular glyph should be used (ignoring the selector).
	VariantUseDefault
	// VariantFound is returned when the font has a variant for the glyph and selector.
	VariantFound
)

// GetGlyphVariant returns the glyph index to used to [r] combined with [selector],
// with one of the tri-state flags [VariantNotFound, VariantUseDefault, VariantFound]
func ( UnicodeVariations) (,  rune) (GID, uint8) {
	// binary search
	for ,  := 0, len();  < ; {
		 :=  + (-)/2
		 := [].varSelector
		if  <  {
			 = 
		} else if  <  {
			 =  + 1
		} else {
			return [].getGlyph()
		}
	}
	return 0, VariantNotFound
}

// Handle legacy font with remap
// TODO: the Iter() and RuneRanges() method does not include the additional mapping

type remaperSymbol struct {
	Cmap
}

func ( remaperSymbol) ( rune) (GID, bool) {
	// try without map first
	if ,  := .Cmap.Lookup();  {
		return , true
	}

	if  <= 0x00FF {
		/* For symbol-encoded OpenType fonts, we duplicate the
		 * U+F000..F0FF range at U+0000..U+00FF.  That's what
		 * Windows seems to do, and that's hinted about at:
		 * https://docs.microsoft.com/en-us/typography/opentype/spec/recom
		 * under "Non-Standard (Symbol) Fonts". */
		 := 0xF000 + 
		return .()
	}

	return 0, false
}

type remaperPUASimp struct {
	Cmap
}

func ( remaperPUASimp) ( rune) (GID, bool) {
	// try without map first
	if ,  := .Cmap.Lookup();  {
		return , true
	}

	if  := puaSimpLookup();  != 0 {
		return .(rune())
	}

	return 0, false
}

type remaperPUATrad struct {
	Cmap
}

func ( remaperPUATrad) ( rune) (GID, bool) {
	// try without map first
	if ,  := .Cmap.Lookup();  {
		return , true
	}

	if  := puaTradLookup();  != 0 {
		return .(rune())
	}

	return 0, false
}

type remaperAscii struct {
	Cmap
}

func lookupAscii( Cmap,  rune) (GID, bool) {
	if  < 0x80 {
		return .Lookup()
	}
	return 0, false
}

func ( remaperAscii) ( rune) (GID, bool) { return lookupAscii(.Cmap, ) }

type remaperMacroman struct {
	Cmap
}

func ( remaperMacroman) ( rune) (GID, bool) {
	if ,  := lookupAscii(.Cmap, );  {
		return , 
	}
	if  := unicodeToMacroman();  != 0 {
		return .Cmap.Lookup()
	}

	return 0, false
}

// assume u is not in ASCII range
func unicodeToMacroman( rune) rune {
	 := [...]struct {
		  uint16
		 uint8
	}{
		{0x00A0, 0xCA},
		{0x00A1, 0xC1},
		{0x00A2, 0xA2},
		{0x00A3, 0xA3},
		{0x00A5, 0xB4},
		{0x00A7, 0xA4},
		{0x00A8, 0xAC},
		{0x00A9, 0xA9},
		{0x00AA, 0xBB},
		{0x00AB, 0xC7},
		{0x00AC, 0xC2},
		{0x00AE, 0xA8},
		{0x00AF, 0xF8},
		{0x00B0, 0xA1},
		{0x00B1, 0xB1},
		{0x00B4, 0xAB},
		{0x00B5, 0xB5},
		{0x00B6, 0xA6},
		{0x00B7, 0xE1},
		{0x00B8, 0xFC},
		{0x00BA, 0xBC},
		{0x00BB, 0xC8},
		{0x00BF, 0xC0},
		{0x00C0, 0xCB},
		{0x00C1, 0xE7},
		{0x00C2, 0xE5},
		{0x00C3, 0xCC},
		{0x00C4, 0x80},
		{0x00C5, 0x81},
		{0x00C6, 0xAE},
		{0x00C7, 0x82},
		{0x00C8, 0xE9},
		{0x00C9, 0x83},
		{0x00CA, 0xE6},
		{0x00CB, 0xE8},
		{0x00CC, 0xED},
		{0x00CD, 0xEA},
		{0x00CE, 0xEB},
		{0x00CF, 0xEC},
		{0x00D1, 0x84},
		{0x00D2, 0xF1},
		{0x00D3, 0xEE},
		{0x00D4, 0xEF},
		{0x00D5, 0xCD},
		{0x00D6, 0x85},
		{0x00D8, 0xAF},
		{0x00D9, 0xF4},
		{0x00DA, 0xF2},
		{0x00DB, 0xF3},
		{0x00DC, 0x86},
		{0x00DF, 0xA7},
		{0x00E0, 0x88},
		{0x00E1, 0x87},
		{0x00E2, 0x89},
		{0x00E3, 0x8B},
		{0x00E4, 0x8A},
		{0x00E5, 0x8C},
		{0x00E6, 0xBE},
		{0x00E7, 0x8D},
		{0x00E8, 0x8F},
		{0x00E9, 0x8E},
		{0x00EA, 0x90},
		{0x00EB, 0x91},
		{0x00EC, 0x93},
		{0x00ED, 0x92},
		{0x00EE, 0x94},
		{0x00EF, 0x95},
		{0x00F1, 0x96},
		{0x00F2, 0x98},
		{0x00F3, 0x97},
		{0x00F4, 0x99},
		{0x00F5, 0x9B},
		{0x00F6, 0x9A},
		{0x00F7, 0xD6},
		{0x00F8, 0xBF},
		{0x00F9, 0x9D},
		{0x00FA, 0x9C},
		{0x00FB, 0x9E},
		{0x00FC, 0x9F},
		{0x00FF, 0xD8},
		{0x0131, 0xF5},
		{0x0152, 0xCE},
		{0x0153, 0xCF},
		{0x0178, 0xD9},
		{0x0192, 0xC4},
		{0x02C6, 0xF6},
		{0x02C7, 0xFF},
		{0x02D8, 0xF9},
		{0x02D9, 0xFA},
		{0x02DA, 0xFB},
		{0x02DB, 0xFE},
		{0x02DC, 0xF7},
		{0x02DD, 0xFD},
		{0x03A9, 0xBD},
		{0x03C0, 0xB9},
		{0x2013, 0xD0},
		{0x2014, 0xD1},
		{0x2018, 0xD4},
		{0x2019, 0xD5},
		{0x201A, 0xE2},
		{0x201C, 0xD2},
		{0x201D, 0xD3},
		{0x201E, 0xE3},
		{0x2020, 0xA0},
		{0x2021, 0xE0},
		{0x2022, 0xA5},
		{0x2026, 0xC9},
		{0x2030, 0xE4},
		{0x2039, 0xDC},
		{0x203A, 0xDD},
		{0x2044, 0xDA},
		{0x20AC, 0xDB},
		{0x2122, 0xAA},
		{0x2202, 0xB6},
		{0x2206, 0xC6},
		{0x220F, 0xB8},
		{0x2211, 0xB7},
		{0x221A, 0xC3},
		{0x221E, 0xB0},
		{0x222B, 0xBA},
		{0x2248, 0xC5},
		{0x2260, 0xAD},
		{0x2264, 0xB2},
		{0x2265, 0xB3},
		{0x25CA, 0xD7},
		{0xF8FF, 0xF0},
		{0xFB01, 0xDE},
		{0xFB02, 0xDF},
	}
	 := sort.Search(len(), func( int) bool { return  <= rune([].) })
	if  < len() && rune([].) ==  {
		return rune([].)
	}
	return 0
}

// ---------------------------- efficent rune set support -----------------------------------------

// CmapRuneRanger is implemented by cmaps whose coverage is defined in terms
// of rune ranges
type CmapRuneRanger interface {
	// RuneRanges returns a list of (start, end) rune pairs, both included.
	// `dst` is an optional buffer used to reduce allocations
	RuneRanges(dst [][2]rune) [][2]rune
}

var (
	_ CmapRuneRanger = cmap4(nil)
	_ CmapRuneRanger = (*cmap6or10)(nil)
	_ CmapRuneRanger = cmap12(nil)
	_ CmapRuneRanger = cmap13(nil)
)

func ( cmap4) ( [][2]rune) [][2]rune {
	if cap() < len() {
		 = make([][2]rune, 0, len())
	}
	 = [:0]
	for ,  := range  {
		,  := rune(.start), rune(.end)
		if  := len();  != 0 && [-1][1] ==  {
			// grow the previous range
			[-1][1] = 
		} else {
			 = append(, [2]rune{, })
		}
	}
	return 
}

func ( *cmap6or10) ( [][2]rune) [][2]rune {
	if cap() < 1 {
		 = [][2]rune{{}}
	}
	 = [:1]
	[0] = [2]rune{.firstCode, .firstCode + rune(len(.entries)) - 1}
	return 
}

func ( cmap12) ( [][2]rune) [][2]rune {
	if cap() < len() {
		 = make([][2]rune, 0, len())
	}
	 = [:0]
	for ,  := range  {
		,  := rune(.StartCharCode), rune(.EndCharCode)
		if  := len();  != 0 && [-1][1] ==  {
			// grow the previous range
			[-1][1] = 
		} else {
			 = append(, [2]rune{, })
		}
	}
	return 
}

func ( cmap13) ( [][2]rune) [][2]rune { return cmap12().RuneRanges() }