func()

in font/sfnt/gpos.go [21:157]


func (f *Font) parseGPOSKern(buf []byte) ([]byte, []kernFunc, error) {
	// https://docs.microsoft.com/en-us/typography/opentype/spec/gpos

	if f.gpos.length == 0 {
		return buf, nil, nil
	}
	const headerSize = 10 // GPOS header v1.1 is 14 bytes, but we don't support FeatureVariations
	if f.gpos.length < headerSize {
		return buf, nil, errInvalidGPOSTable
	}

	buf, err := f.src.view(buf, int(f.gpos.offset), headerSize)
	if err != nil {
		return buf, nil, err
	}

	// check for version 1.0/1.1
	if u16(buf) != 1 || u16(buf[2:]) > 1 {
		return buf, nil, errUnsupportedGPOSTable
	}
	scriptListOffset := u16(buf[4:])
	featureListOffset := u16(buf[6:])
	lookupListOffset := u16(buf[8:])

	// get all feature indices for latn script
	buf, featureIdxs, err := f.parseGPOSScriptFeatures(buf, int(f.gpos.offset)+int(scriptListOffset), hexScriptLatn)
	if err != nil {
		return buf, nil, err
	}
	if len(featureIdxs) == 0 {
		// get all feature indices for DFLT script
		buf, featureIdxs, err = f.parseGPOSScriptFeatures(buf, int(f.gpos.offset)+int(scriptListOffset), hexScriptDFLT)
		if err != nil {
			return buf, nil, err
		}
		if len(featureIdxs) == 0 {
			return buf, nil, nil
		}
	}

	// get all lookup indices for kern features
	buf, lookupIdx, err := f.parseGPOSFeaturesLookup(buf, int(f.gpos.offset)+int(featureListOffset), featureIdxs, hexFeatureKern)
	if err != nil {
		return buf, nil, err
	}

	// LookupTableList: lookupCount,[]lookups
	buf, numLookupTables, err := f.src.varLenView(buf, int(f.gpos.offset)+int(lookupListOffset), 2, 0, 2)
	if err != nil {
		return buf, nil, err
	}

	var kernFuncs []kernFunc

lookupTables:
	for _, n := range lookupIdx {
		if n > numLookupTables {
			return buf, nil, errInvalidGPOSTable
		}
		tableOffset := int(f.gpos.offset) + int(lookupListOffset) + int(u16(buf[2+n*2:]))

		// LookupTable: lookupType, lookupFlag, subTableCount, []subtableOffsets, markFilteringSet
		buf, numSubTables, err := f.src.varLenView(buf, tableOffset, 8, 4, 2)
		if err != nil {
			return buf, nil, err
		}

		flags := u16(buf[2:])

		subTableOffsets := make([]int, numSubTables)
		for i := 0; i < int(numSubTables); i++ {
			subTableOffsets[i] = int(tableOffset) + int(u16(buf[6+i*2:]))
		}

		switch lookupType := u16(buf); lookupType {
		case 2: // PairPos table
		case 9:
			// Extension Positioning table defines an additional u32 offset
			// to allow subtables to exceed the 16-bit limit.
			for i := range subTableOffsets {
				buf, err = f.src.view(buf, subTableOffsets[i], 8)
				if err != nil {
					return buf, nil, err
				}
				if format := u16(buf); format != 1 {
					return buf, nil, errUnsupportedExtensionPosFormat
				}
				if lookupType := u16(buf[2:]); lookupType != 2 {
					continue lookupTables
				}
				subTableOffsets[i] += int(u32(buf[4:]))
			}
		default: // other types are not supported
			continue
		}

		if flags&0x0010 > 0 {
			// useMarkFilteringSet enabled, skip as it is not supported
			continue
		}

		for _, subTableOffset := range subTableOffsets {
			buf, err = f.src.view(buf, int(subTableOffset), 4)
			if err != nil {
				return buf, nil, err
			}
			format := u16(buf)

			var lookupIndex indexLookupFunc
			buf, lookupIndex, err = f.makeCachedCoverageLookup(buf, subTableOffset+int(u16(buf[2:])))
			if err != nil {
				return buf, nil, err
			}

			switch format {
			case 1: // Adjustments for Glyph Pairs
				buf, kern, err := f.parsePairPosFormat1(buf, subTableOffset, lookupIndex)
				if err != nil {
					return buf, nil, err
				}
				if kern != nil {
					kernFuncs = append(kernFuncs, kern)
				}
			case 2: // Class Pair Adjustment
				buf, kern, err := f.parsePairPosFormat2(buf, subTableOffset, lookupIndex)
				if err != nil {
					return buf, nil, err
				}
				if kern != nil {
					kernFuncs = append(kernFuncs, kern)
				}
			}
		}
	}

	return buf, kernFuncs, nil
}