package font
import "github.com/go-text/typesetting/font/opentype/tables"
type Layout struct {
Scripts []Script
Features []Feature
FeatureVariations []tables .FeatureVariationRecord
}
func newLayout(table tables .Layout ) Layout {
fCount := len (table .FeatureList .Features )
out := Layout {
Scripts : make ([]Script , len (table .ScriptList .Scripts )),
Features : make ([]Feature , fCount ),
}
for i , s := range table .ScriptList .Scripts {
if langSys := s .DefaultLangSys ; langSys != nil {
sanitizeLangSys (langSys , fCount )
}
for i := range s .LangSys {
sanitizeLangSys (&s .LangSys [i ], fCount )
}
out .Scripts [i ] = Script {
Script : s ,
Tag : table .ScriptList .Records [i ].Tag ,
}
}
for i , f := range table .FeatureList .Features {
out .Features [i ] = Feature {
Feature : f ,
Tag : table .FeatureList .Records [i ].Tag ,
}
}
if table .FeatureVariations != nil {
out .FeatureVariations = table .FeatureVariations .FeatureVariationRecords
}
return out
}
func sanitizeLangSys(langSys *tables .LangSys , featuresCount int ) {
if int (langSys .RequiredFeatureIndex ) >= featuresCount {
langSys .RequiredFeatureIndex = 0xFFFF
}
}
type Script struct {
tables .Script
Tag Tag
}
type Feature struct {
tables .Feature
Tag Tag
}
func (la *Layout ) FindScript (script Tag ) int {
low , high := 0 , len (la .Scripts )
for low < high {
mid := low + (high -low )/2
p := la .Scripts [mid ].Tag
if script < p {
high = mid
} else if script > p {
low = mid + 1
} else {
return mid
}
}
return -1
}
func (la *Layout ) FindVariationIndex (coords []VarCoord ) int {
for i , record := range la .FeatureVariations {
if evaluateVarRec (record , coords ) {
return i
}
}
return -1
}
func evaluateVarRec(fv tables .FeatureVariationRecord , coords []VarCoord ) bool {
for _ , c := range fv .ConditionSet .Conditions {
if !evaluateCondition (c , coords ) {
return false
}
}
return true
}
func evaluateCondition(c tables .ConditionFormat1 , coords []VarCoord ) bool {
var coord VarCoord
if int (c .AxisIndex ) < len (coords ) {
coord = coords [c .AxisIndex ]
}
return c .FilterRangeMinValue <= coord && coord <= c .FilterRangeMaxValue
}
func (la *Layout ) FindFeatureIndex (featureTag Tag ) (uint16 , bool ) {
for i , feat := range la .Features {
if featureTag == feat .Tag {
return uint16 (i ), true
}
}
return 0 , false
}
type GSUB struct {
Layout
Lookups []GSUBLookup
}
type LookupOptions struct {
Flag uint16
MarkFilteringSet uint16
}
const UseMarkFilteringSet = 1 << 4
func (lo LookupOptions ) Props () uint32 {
flag := uint32 (lo .Flag )
if lo .Flag &UseMarkFilteringSet != 0 {
flag |= uint32 (lo .MarkFilteringSet ) << 16
}
return flag
}
type GSUBLookup struct {
LookupOptions
Subtables []tables .GSUBLookup
}
func newGSUB(table tables .Layout ) (GSUB , error ) {
out := GSUB {
Layout : newLayout (table ),
Lookups : make ([]GSUBLookup , len (table .LookupList .Lookups )),
}
for i , lk := range table .LookupList .Lookups {
subtables , err := lk .AsGSUBLookups ()
if err != nil {
return GSUB {}, err
}
for j , subtable := range subtables {
if ext , isExt := subtable .(tables .ExtensionSubs ); isExt {
subtables [j ], err = ext .Resolve ()
if err != nil {
return GSUB {}, err
}
}
switch subtable := subtable .(type ) {
case tables .MultipleSubs :
err = subtable .Sanitize ()
case tables .LigatureSubs :
err = subtable .Sanitize ()
case tables .ContextualSubs :
err = subtable .Sanitize (uint16 (len (out .Lookups )))
case tables .ReverseChainSingleSubs :
err = subtable .Sanitize ()
}
if err != nil {
return GSUB {}, err
}
}
out .Lookups [i ] = GSUBLookup {
LookupOptions : LookupOptions {
Flag : lk .LookupFlag ,
MarkFilteringSet : lk .MarkFilteringSet ,
},
Subtables : subtables ,
}
}
return out , nil
}
type GPOS struct {
Layout
Lookups []GPOSLookup
}
type GPOSLookup struct {
LookupOptions
Subtables []tables .GPOSLookup
}
func newGPOS(table tables .Layout ) (GPOS , error ) {
out := GPOS {
Layout : newLayout (table ),
Lookups : make ([]GPOSLookup , len (table .LookupList .Lookups )),
}
for i , lk := range table .LookupList .Lookups {
subtables , err := lk .AsGPOSLookups ()
if err != nil {
return GPOS {}, err
}
for j , subtable := range subtables {
if ext , isExt := subtable .(tables .ExtensionPos ); isExt {
subtables [j ], err = ext .Resolve ()
if err != nil {
return GPOS {}, err
}
}
switch subtable := subtable .(type ) {
case tables .SinglePos :
err = subtable .Sanitize ()
case tables .PairPos :
err = subtable .Sanitize ()
case tables .MarkBasePos :
err = subtable .Sanitize ()
case tables .MarkLigPos :
err = subtable .Sanitize ()
case tables .ContextualPos :
err = subtable .Sanitize (uint16 (len (out .Lookups )))
}
if err != nil {
return GPOS {}, err
}
}
out .Lookups [i ] = GPOSLookup {
LookupOptions : LookupOptions {
Flag : lk .LookupFlag ,
MarkFilteringSet : lk .MarkFilteringSet ,
},
Subtables : subtables ,
}
}
return out , nil
}
The pages are generated with Golds v0.8.7 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .