package cff
import (
"errors"
"fmt"
ps "github.com/go-text/typesetting/font/cff/interpreter"
ot "github.com/go-text/typesetting/font/opentype"
"github.com/go-text/typesetting/font/opentype/tables"
)
func (f *CFF ) LoadGlyph (glyph tables .GlyphID ) ([]ot .Segment , ps .PathBounds , error ) {
if int (glyph ) >= len (f .Charstrings ) {
return nil , ps .PathBounds {}, errGlyph
}
var (
psi ps .Machine
loader type2CharstringHandler
index byte = 0
err error
)
if f .fdSelect != nil {
index , err = f .fdSelect .fontDictIndex (glyph )
if err != nil {
return nil , ps .PathBounds {}, err
}
}
subrs := f .localSubrs [index ]
err = psi .Run (f .Charstrings [glyph ], subrs , f .globalSubrs , &loader )
return loader .cs .Segments , loader .cs .Bounds , err
}
type type2CharstringHandler struct {
cs ps .CharstringReader
nominalWidthX float64
width float64
}
func (type2CharstringHandler ) Context () ps .Context { return ps .Type2Charstring }
func (met *type2CharstringHandler ) Apply (state *ps .Machine , op ps .Operator ) error {
var err error
if !op .IsEscaped {
switch op .Operator {
case 11 :
return state .Return ()
case 14 :
if state .ArgStack .Top > 0 {
met .width = met .nominalWidthX + state .ArgStack .Vals [0 ]
}
met .cs .ClosePath ()
return ps .ErrInterrupt
case 10 :
return ps .LocalSubr (state )
case 29 :
return ps .GlobalSubr (state )
case 21 :
if state .ArgStack .Top > 2 {
met .width = met .nominalWidthX + state .ArgStack .Vals [0 ]
}
err = met .cs .Rmoveto (state )
case 22 :
if state .ArgStack .Top > 1 {
met .width = met .nominalWidthX + state .ArgStack .Vals [0 ]
}
err = met .cs .Hmoveto (state )
case 4 :
if state .ArgStack .Top > 1 {
met .width = met .nominalWidthX + state .ArgStack .Vals [0 ]
}
err = met .cs .Vmoveto (state )
case 1 , 18 :
met .cs .Hstem (state )
case 3 , 23 :
met .cs .Vstem (state )
case 19 , 20 :
if state .ArgStack .Top &1 != 0 {
met .width = met .nominalWidthX + state .ArgStack .Vals [0 ]
}
met .cs .Hintmask (state )
return nil
case 5 :
met .cs .Rlineto (state )
case 6 :
met .cs .Hlineto (state )
case 7 :
met .cs .Vlineto (state )
case 8 :
met .cs .Rrcurveto (state )
case 24 :
err = met .cs .Rcurveline (state )
case 25 :
err = met .cs .Rlinecurve (state )
case 26 :
met .cs .Vvcurveto (state )
case 27 :
met .cs .Hhcurveto (state )
case 30 :
met .cs .Vhcurveto (state )
case 31 :
met .cs .Hvcurveto (state )
default :
err = fmt .Errorf ("invalid operator %s in charstring" , op )
}
} else {
switch op .Operator {
case 34 :
err = met .cs .Hflex (state )
case 35 :
err = met .cs .Flex (state )
case 36 :
err = met .cs .Hflex1 (state )
case 37 :
err = met .cs .Flex1 (state )
default :
err = fmt .Errorf ("invalid operator %s in charstring" , op )
}
}
state .ArgStack .Clear ()
return err
}
func (f *CFF2 ) LoadGlyph (glyph tables .GlyphID , coords []tables .Coord ) ([]ot .Segment , ps .PathBounds , error ) {
if int (glyph ) >= len (f .Charstrings ) {
return nil , ps .PathBounds {}, errGlyph
}
var (
psi ps .Machine
loader cff2CharstringHandler
index byte = 0
err error
)
if f .fdSelect != nil {
index , err = f .fdSelect .fontDictIndex (glyph )
if err != nil {
return nil , ps .PathBounds {}, err
}
}
font := f .fonts [index ]
loader .coords = coords
loader .vars = f .VarStore
loader .setVSIndex (int (font .defaultVSIndex ))
err = psi .Run (f .Charstrings [glyph ], font .localSubrs , f .globalSubrs , &loader )
return loader .cs .Segments , loader .cs .Bounds , err
}
type cff2CharstringHandler struct {
cs ps .CharstringReader
coords []tables .Coord
vars tables .ItemVarStore
scalars []float32
}
func (cff2CharstringHandler ) Context () ps .Context { return ps .Type2Charstring }
func (met *cff2CharstringHandler ) setVSIndex (index int ) error {
if len (met .vars .ItemVariationDatas ) == 0 {
return nil
}
if index >= len (met .vars .ItemVariationDatas ) {
return fmt .Errorf ("invalid 'vsindex' %d" , index )
}
vars := met .vars .ItemVariationDatas [index ]
k := int32 (len (vars .RegionIndexes ))
met .scalars = append (met .scalars [:0 ], make ([]float32 , k )...)
for i , regionIndex := range vars .RegionIndexes {
region := met .vars .VariationRegionList .VariationRegions [regionIndex ]
met .scalars [i ] = region .Evaluate (met .coords )
}
return nil
}
func (met *cff2CharstringHandler ) blend (state *ps .Machine ) error {
if state .ArgStack .Top < 1 {
return errors .New ("missing n argument for blend operator" )
}
n := int32 (state .ArgStack .Pop ())
k := int32 (len (met .scalars ))
if state .ArgStack .Top < n *(k +1 ) {
return errors .New ("missing arguments for blend operator" )
}
if len (met .coords ) != 0 {
args := state .ArgStack .Vals [state .ArgStack .Top -n *(k +1 ) : state .ArgStack .Top ]
for i := int32 (0 ); i < n ; i ++ {
baseValue := args [i ]
deltas := args [n +i *k : n +(i +1 )*k ]
v := 0.
for ik , delta := range deltas {
v += float64 (met .scalars [ik ]) * delta
}
args [i ] = baseValue + v
}
}
state .ArgStack .Top -= n * k
return nil
}
func (met *cff2CharstringHandler ) Apply (state *ps .Machine , op ps .Operator ) error {
var err error
if !op .IsEscaped {
switch op .Operator {
case 1 , 18 :
met .cs .Hstem (state )
case 3 , 23 :
met .cs .Vstem (state )
case 4 :
err = met .cs .Vmoveto (state )
case 5 :
met .cs .Rlineto (state )
case 6 :
met .cs .Hlineto (state )
case 7 :
met .cs .Vlineto (state )
case 8 :
met .cs .Rrcurveto (state )
case 10 :
return ps .LocalSubr (state )
case 15 :
if state .ArgStack .Top < 1 {
return errors .New ("missing argument for vsindex operator" )
}
err = met .setVSIndex (int (state .ArgStack .Pop ()))
case 16 :
return met .blend (state )
case 19 , 20 :
met .cs .Hintmask (state )
return nil
case 21 :
err = met .cs .Rmoveto (state )
case 22 :
err = met .cs .Hmoveto (state )
case 24 :
err = met .cs .Rcurveline (state )
case 25 :
err = met .cs .Rlinecurve (state )
case 26 :
met .cs .Vvcurveto (state )
case 27 :
met .cs .Hhcurveto (state )
case 29 :
return ps .GlobalSubr (state )
case 30 :
met .cs .Vhcurveto (state )
case 31 :
met .cs .Hvcurveto (state )
default :
err = fmt .Errorf ("invalid operator %s in charstring" , op )
}
} else {
switch op .Operator {
case 34 :
err = met .cs .Hflex (state )
case 35 :
err = met .cs .Flex (state )
case 36 :
err = met .cs .Hflex1 (state )
case 37 :
err = met .cs .Flex1 (state )
default :
err = fmt .Errorf ("invalid operator %s in charstring" , op )
}
}
state .ArgStack .Clear ()
return err
}
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 .