﻿/* Font-program */
/* ACT generated Wed Jun 10 12:39:16 2015 */

FDEF[], 9

/* Set fv to X
       pv perpendicular to italic angle

   CALL[], 9 */

#BEGIN
#PUSHOFF
SVTCA[X]
#PUSH, 11, 10
RS[]
SWAP[]
RS[]
NEG[]
SPVFS[]
#PUSHON
#END
ENDF[]

FDEF[], 10

/* Set fv to italic angle
       pv to Y

   CALL[], 10 */

#BEGIN
#PUSHOFF
SVTCA[Y]
#PUSH, 10, 11
RS[]
SWAP[]
RS[]
SFVFS[]
#PUSHON
#END
ENDF[]

FDEF[], 16

/* Set fv to X
       pv perpendicular to adjusted italic angle

   CALL[], 16 */

#BEGIN
#PUSHOFF
SVTCA[X]
#PUSH, 6
RS[]
#PUSH, 7
RS[]
NEG[]
SPVFS[]
#PUSHON
#END
ENDF[]

FDEF[], 31

/* fn 31 equalizes two cvts below a given ppem size

   CALL[], <child cvt>, <parent cvt>, <ppem size>, 31 */

#BEGIN
#PUSHOFF

/* STACK: <child cvt>, <parent cvt>, <ppem size> */

#PUSH, 79 /* #samples/pixel */
CALL[]
DUP[]
#PUSH, 64
LTEQ[]
IF[] /* #samples/pixel <= 1 */

    /* STACK: <child cvt>, <parent cvt>, <ppem size>, <#samples/pixel> */

    POP[] /* #samples/pixel not involved */
    MPPEM[]

    /* STACK: <child cvt>, <parent cvt>, <ppem size>, <act ppem size> */

    GT[]
    IF[]
        RCVT[]
        WCVTP[]
    ELSE[]
        POP[]
        POP[]
    EIF[]

ELSE[] /* #samples/pixel > 1 */

    /* STACK: <child cvt>, <parent cvt>, <ppem size>, <#samples/pixel> */

    SWAP[]
    POP[] /* ppem Size not involved */
    #PUSH, 64

    /* STACK: <child cvt>, <parent cvt>, <#samples/pixel>, <1> */

    #PUSH, 4 /* child cvt */
    CINDEX[]
    RCVT[]
    #PUSH, 4 /* parent cvt */
    CINDEX[]
    RCVT[]
    SUB[]
    ABS[]

    /* STACK: <child cvt>, <parent cvt>, <#samples/pixel>, <1>, <|[child cvt] - [parent cvt]|> */

    ROLL[]
    MUL[]
    GT[]
    IF[] /* 1 > #samples/pixel * delta cvt */
        RCVT[]
        WCVTP[]
    ELSE[]
        POP[]
        POP[]
    EIF[]

EIF[]
#PUSHON
#END
ENDF[]

FDEF[], 40

/* Set fv to adjusted italic angle
       pv to Y

   CALL[], 40 */

#BEGIN
#PUSHOFF
SVTCA[Y]
#PUSH, 7
RS[]
#PUSH, 6
RS[]
SFVFS[]
#PUSHON
#END
ENDF[]

FDEF[], 70

/* fn changes <cvt> by <amount> (in �1/64 pixel) at
   ppem sizes <low ppem> to <high ppem> (inclusive)

   CALL[], <amount>, <cvt>, <low ppem>, <high ppem>, 70 */

#BEGIN
#PUSHOFF
MPPEM[]
GTEQ[]
SWAP[]
MPPEM[]
LTEQ[]
AND[]
IF[]
    DUP[]
    RCVT[]
    ROLL[]
    ADD[]
    WCVTP[]
ELSE[]
    POP[]
    POP[]
EIF[]
#PUSHON
#END
ENDF[]

FDEF[], 71

/* fn changes <cvt> by <amount> (in �1/64 pixel) at
   ppem size <ppem>

   CALL[], <amount>, <cvt>, <ppem>, 71 */

#BEGIN
#PUSHOFF
MPPEM[]
EQ[]
IF[]
    DUP[]
    RCVT[]
    ROLL[]
    ADD[]
    WCVTP[]
ELSE[]
    POP[]
    POP[]
EIF[]
#PUSHON
#END
ENDF[]

FDEF[], 72

/* fn moves <point> by <amount> (in �1/64 pixel) at
   ppem sizes <low ppem> to <high ppem> (inclusive)

   CALL[], <point>, <amount>, <low ppem>, <high ppem>, 72 */

#BEGIN
#PUSHOFF
MPPEM[]
GTEQ[]
SWAP[]
MPPEM[]
LTEQ[]
AND[]
IF[]
    SHPIX[]
ELSE[]
    POP[]
    POP[]
EIF[]
#PUSHON
#END
ENDF[]

FDEF[], 73

/* fn moves <point> by <amount> (in �1/64 pixel) at
   ppem size <ppem>

   CALL[], <point>, <amount>, <ppem>, 73 */

#BEGIN
#PUSHOFF
MPPEM[]
EQ[]
IF[]
    SHPIX[]
ELSE[]
    POP[]
    POP[]
EIF[]
#PUSHON
#END
ENDF[]

FDEF[], 74

/* if <flag> = anti-aliasing in s[2] (set by fn 84)
   fn changes <cvt> by <amount> (in �1/64 pixel) at
   ppem sizes <low ppem> to <high ppem> (inclusive)

   CALL[], <amount>, <cvt>, <low ppem>, <high ppem>, <flag>, 74 */

#BEGIN
#PUSHOFF
#PUSH, 2
RS[]
EQ[]
IF[]           /* if <flag> = s[2] then fwd to fn 70 */
    #PUSH, 70
    CALL[]
ELSE[]         /* else cleanup stack and bail out */
    POP[]
    POP[]
    POP[]
    POP[]
EIF[]
#PUSHON
#END
ENDF[]

FDEF[], 75

/* if <flag> = anti-aliasing in s[2] (set by fn 84)
   fn changes <cvt> by <amount> (in �1/64 pixel) at
   ppem size <ppem>

   CALL[], <amount>, <cvt>, <ppem>, <flag>, 75 */

#BEGIN
#PUSHOFF
#PUSH, 2
RS[]
EQ[]
IF[]           /* if <flag> = s[2] then fwd to fn 71 */
    #PUSH, 71
    CALL[]
ELSE[]         /* else cleanup stack and bail out */
    POP[]
    POP[]
    POP[]
EIF[]
#PUSHON
#END
ENDF[]

FDEF[], 76

/* if <flag> = anti-aliasing in s[2] (set by fn 84)
   fn moves <point> by <amount> (in �1/64 pixel) at
   ppem sizes <low ppem> to <high ppem> (inclusive)

   CALL[], <point>, <amount>, <low ppem>, <high ppem>, <flag>, 76 */

#BEGIN
#PUSHOFF
#PUSH, 2
RS[]
EQ[]
IF[]           /* if <flag> = s[2] then fwd to fn 72 */
    #PUSH, 72
    CALL[]
ELSE[]         /* else cleanup stack and bail out */
    POP[]
    POP[]
    POP[]
    POP[]
EIF[]
#PUSHON
#END
ENDF[]

FDEF[], 77

/* if <flag> = anti-aliasing in s[2] (set by fn 84)
   fn moves <point> by <amount> (in �1/64 pixel) at
   ppem size <ppem>

   CALL[], <point>, <amount>, <ppem>, <flag>, 77 */

#BEGIN
#PUSHOFF
#PUSH, 2
RS[]
EQ[]
IF[]           /* if <flag> = s[2] then fwd to fn 73 */
    #PUSH, 73
    CALL[]
ELSE[]         /* else cleanup stack and bail out */
    POP[]
    POP[]
    POP[]
EIF[]
#PUSHON
#END
ENDF[]

FDEF[], 78

/* apply minimum distance and round <dist> depending on s[2], <code>, and pv
   code = 0: position
   code = 1: distance
   code = 2: delta distance (for fractional inheritance)

   CALL[], <dist>, <code>, 78

   returns with rounded distance on stack */

#BEGIN
#PUSHOFF

/* STACK: <dist>, <code> */

SWAP[]
DUP[]
#PUSH, 0
LT[]
ROLL[]
ROLL[]
ABS[]

/* STACK: <negDist>, <code>, <|dist|> */

#PUSH, 0, 3 /* code */
CINDEX[]
EQ[]
IF[] /* position */

    /* STACK: <negDist>, <code>, <|dist|> */

    #PUSH, 64

    /* STACK: <negDist>, <code>, <|dist|>, <#samples/pixel> */

ELSE[]

    /* STACK: <negDist>, <code>, <|dist|> */

    #PUSH, 1, 3 /* code */
    CINDEX[]
    EQ[]
    IF[] /* distance */
        #PUSH, 5 /* minimum distance */
        RS[]
        MAX[]
    EIF[]

    #PUSH, 79 /* #samples/pixel */
    CALL[]

    /* STACK: <negDist>, <code>, <|dist|>, <#samples/pixel> */

EIF[]

SWAP[]
#PUSH, 98 /* round to virtual grid */
CALL[]

/* STACK: <negDist>, <code>, <[|dist|]> */

SWAP[]
POP[]

/* STACK: <negDist>, <[|dist|]> */

SWAP[]
IF[]
    NEG[]
EIF[]

/* STACK: <[dist]> */

#PUSHON
#END
ENDF[]

FDEF[], 79

/* depending on rendering environment and pv determine #samples/pixel for rounding etc.

   notice that for PVs other than X or Y, this method will default to X, reflecting the
   bias inherent in the asymmetrical nature of ClearType

   CALL[], 79

   returns the #samples/pixel in 26.6 */

#BEGIN
#PUSHOFF

#PUSH, 8, 0
GPV[]
POP[]
EQ[]
ADD[]
RS[]

#PUSHON
#END
ENDF[]

FDEF[], 80

/* depending on rendering environment and pv determine actual stroke optimization method

   CALL[], 80

   returns with method on stack (see fn 112 for definition of method) */

#BEGIN
#PUSHOFF

#PUSH, 12, 0
GPV[]
POP[]
EQ[]
ADD[]
RS[]

#PUSHON
#END
ENDF[]

FDEF[], 81

   /* adjust advance width to compensate for rasterizer's rounding errors 

   CALL[], <rsb>, 81 */

#BEGIN
#PUSHOFF

/* STACK: <rsb> */

SVTCA[X]
DUP[]
GC[O]

/* STACK: <rsb>, <rsb.x> */
#PUSH, 2
RS[]
DUP[]
#PUSH, 4096 /* fract AW value in 26.6 */
DIV[]
#PUSH, 4096 /* 64 in 26.6 */
MUL[]
EVEN[] /* fract AW bit not set */
SWAP[]
#PUSH, 256 /* comp AW value in 26.6 */
DIV[]
#PUSH, 4096 /* 64 in 26.6 */
MUL[]
EVEN[] /* comp AW bit not set */
AND[]
IF[]
    #PUSH, 32
    ADD[]
    FLOOR[]
EIF[]

SCFS[]

#PUSHON
#END
ENDF[]

FDEF[], 83

/* CALL[], <radicand>, 83

   returns with square root of radicand on stack */

#BEGIN
#PUSHOFF

/* STACK: <radicand> */

#PUSH, 0, 2
CINDEX[]

/* STACK: <radicand>, <low>, <high> */

#WBeginLoop83:

    #PUSH, 2 /* low */
    CINDEX[]
    #PUSH, 2 /* high */
    CINDEX[]
    GTEQ[]
    #PUSH, WOffset83a
    SWAP[]
    JROT[], (WOffset83a=#WEndLoop83) /* while low <= high */

    /* STACK: <radicand>, <low>, <high> */

    #PUSH, 2 /* low */
    CINDEX[]
    #PUSH, 2 /* high */
    CINDEX[]
    ADD[]
    #PUSH, 32
    MUL[]

    /* STACK: <radicand>, <low>, <high>, <mid> */

    DUP[]
    DUP[]
    #PUSH, 6 /* radicand */
    CINDEX[]
    SWAP[]
    DIV[]

    /* STACK: <radicand>, <low>, <high>, <mid>, <mid>, <radicand/mid> */

    LT[]
    IF[]

        /* STACK: <radicand>, <low>, <high>, <mid> */

        ROLL[]
        POP[]
        #PUSH, 1
        ADD[]
        SWAP[]

        /* STACK: <radicand>, <mid+1>, <high> */

    ELSE[]

        DUP[]
        DUP[]
        #PUSH, 6 /* radicand */
        CINDEX[]
        SWAP[]
        DIV[]

        GT[]
        IF[]

            /* STACK: <radicand>, <low>, <high>, <mid> */

            SWAP[]
            POP[]
            #PUSH, 1
            SUB[]

            /* STACK: <radicand>, <low>, <mid-1> */

        ELSE[]

            /* STACK: <radicand>, <low>, <high>, <mid> */

            ROLL[]
            POP[]
            SWAP[]
            POP[]
            DUP[]

            /* STACK: <radicand>, <mid>, <mid> */

        EIF[]

    EIF[]


    #PUSH, WOffset83b
    JMPR[], (WOffset83b=#WBeginLoop83)

#WEndLoop83:

/* STACK: <radicand>, <low>, <high> */

ADD[]
#PUSH, 32
MUL[]
SWAP[]
POP[]

/* STACK: <mid> */

#PUSHON
#END
ENDF[]

FDEF[], 84

/* fn determines current rasterizing environment and stores it in s[2] as follows:
     bit 0 (value   1) = Grey-Scaling
     bit 1 (value   2) = ClearType(tm)
     bit 2 (value   4) = Compatible Width ClearType
     bit 3 (value   8) = Vertical Direction (horizontally striped) ClearType
     bit 4 (value  16) = BGR as opposed to RGB Devices
     bit 5 (value  32) = ClearType on Rapier CE Devices
     bit 6 (value  64) = ClearType with fractional advance widths
     bit 7 (value 128) = ClearType with non-ClearType direction anti-aliasing
     bit 8 (value 256) = ClearType with gray full-pixel

   s[2] is used e.g. in fns 74 through 77

   To test against any combination of these flags, add up the respective values.

   specific to the current rasterizing environment fn stores the following parameters
     s[5] = minimum distance
     s[8] = #samples/pixel in x-direction
     s[9] = #samples/pixel in y-direction
     s[12] = stroke optimization method in x-direction
     s[13] = stroke optimization method in y-direction

   CALL[], 84 */
   /* Version 2.1 20120101 */

#BEGIN
#PUSHOFF
#PUSH,2,0
WS[]            /* s[2] = grey scaling: off (by default) */
#PUSH,35,1      /* 35 = MS Rasterizer version 1.7 */
GETINFO[]       /* 1 = tell GETINFO to give us the rasterizer version */
LTEQ[]          /* 35 <= version ? */
#PUSH,64,1      /* 64 = highest rasterizer version assigned to MS */
GETINFO[]       /* 1 = tell GETINFO to give us the rasterizer version */
GTEQ[]          /* 64 >= version ? */
AND[]           /* 35 <= version && version <= 64 ? */
IF[]            /* if so, we're running MS rasterizer version 1.7 or higher */
  #PUSH,4096,32 /* 4096 = flag returned by GETINFO if grey scaling bit is on */
  GETINFO[]     /* 32 = tell GETINFO to give us the grey scaling bit */
  EQ[]          /* 4096 == flag ? */
  IF[]          /* if so, we're running under grey scaling */
    #PUSH,2,1,2
    RS[]
    ADD[]
    WS[]        /* s[2] += grey scaling: on (by now) */
  EIF[]
  #PUSH,36,1      /* 36 = MS Rasterizer version 1.6+ (WinCE) or 1.8 (WinXP) */
  GETINFO[]       /* 1 = tell GETINFO to give us the rasterizer version */
  LTEQ[]          /* 36 <= version ? (already tested version <= 64) */
  IF[]            /* if so, we're running MS rasterizer version 1.6+ (WinCE) or 1.8 (WinXP) or higher */
    #PUSH,8192,64 /* 8192 = flag returned by GETINFO if ClearTypeTM bit is on */
    GETINFO[]     /* 64 = tell GETINFO to give us the ClearTypeTM bit */
    EQ[]          /* 8192 == flag ? */
    IF[]          /* if so, we're running under ClearTypeTM */
      #PUSH,2,2,2
      RS[]
      ADD[]
      WS[]        /* s[2] += ClearTypeTM: on (by now) */

      #PUSH,36,1    /* 36 = MS Rasterizer version 1.6+ (WinCE) */
      GETINFO[]
      EQ[]
      IF[] /***** we're running Rasterizer v1.6+ for WinCE with ClearType *****/

        #PUSH,2,32,2
        RS[]
        ADD[]
        WS[]        /* s[2] += Rapier CE: on (by now) */
        SVTCA[Y]
        MPPEM[]
        SVTCA[X]
        MPPEM[]
        GT[]
        IF[]
          #PUSH,2,8,2
          RS[]
          ADD[]
          WS[]
        EIF[]

      ELSE[] /***** we're running Rasterizer v1.8 (or higher) for WinXP with ClearType (or Win2k 2000 with ClearType patch) *****/

        #PUSH,16384,128 /* 16384 = flag returned by GETINFO if ClearTypeTM silly aw bit is on */
        GETINFO[]       /* 128 = tell GETINFO to give us the ClearTypeTM silly aw bit */
        EQ[]            /* 16384 == flag ? */
        IF[]            /* if so, we're running under ClearTypeTM silly aw */
          #PUSH,2,4,2
          RS[]
          ADD[]
          WS[]          /* s[2] += ClearTypeTM silly aw: on (by now) */
        EIF[]

        #PUSH,16384,128 /* 32768 = flag returned by GETINFO if ClearTypeTM in vertical direction bit is on */
        MUL[]           /* Assembler restriction: produce 32768 by multiplying 16384 by 2 (2 in F26.6 is 128) */
        #PUSH,256       /* 256 = tell GETINFO to give us the ClearTypeTM in vertical direction bit */
        GETINFO[]
        EQ[]            /* 32768 == flag ? */
        IF[]            /* if so, we're running ClearTypeTM in vertical direction */
        #PUSH,2,8,2
          RS[]
          ADD[]
          WS[]          /* s[2] += ClearTypeTM in vertical direction: on (by now) */
        EIF[]

        #PUSH,16384,256 /* 65536 = flag returned by GETINFO if ClearTypeTM in BGR order bit is on */
        MUL[]           /* Assembler restriction: produce 65536 by multiplying 16384 by 4 (4 in F26.6 is 256) */
        #PUSH,512       /* 512 = tell GETINFO to give us the ClearTypeTM in BGR order bit */
        GETINFO[]
        EQ[]            /* 65536 == flag ? */
        IF[]            /* if so, we're running under ClearTypeTM in BGR order */
          #PUSH,2,16,2
          RS[]
          ADD[]
          WS[]          /* s[2] += ClearTypeTM in BGR order: on (by now) */
        EIF[]

        #PUSH,38,1      /* 38 = MS Rasterizer version 1.9 */
        GETINFO[]       /* 1 = tell GETINFO to give us the rasterizer version */
        LTEQ[]          /* 38 <= version ? (already tested version <= 64) */
        IF[]            /* if so, we're running MS rasterizer version 1.9 (Windows Longhorn) or higher */

          #PUSH,16384,512  /* 131072 = flag returned by GETINFO if ClearTypeTM fractional advance widths bit is on */
          MUL[]            /* Assembler restriction: produce 131072 by multiplying 16384 by 8 (8 in F26.6 is 512) */
          #PUSH,1024       /* 1024 = tell GETINFO to give us the ClearTypeTM fractional advance widths bit */
          GETINFO[]
          EQ[]             /* 131072 == flag ? */
          IF[]             /* if so, we're running under ClearTypeTM fractional advance widths */
            #PUSH,2,64,2
            RS[]
            ADD[]
            WS[]           /* s[2] += ClearTypeTM fractional advance widths: on (by now) */
          EIF[]

          #PUSH,16384,1024 /* 262144 = flag returned by GETINFO if ClearTypeTM non-ClearType direction anti-aliasing bit is on */
          MUL[]            /* Assembler restriction: produce 262144 by multiplying 16384 by 16 (16 in F26.6 is 1024) */
          #PUSH,2048       /* 2048 = tell GETINFO to give us the ClearTypeTM non-ClearType direction anti-aliasing bit */
          GETINFO[]
          EQ[]             /* 262144 == flag ? */
          IF[]             /* if so, we're running under ClearTypeTM non-ClearType direction anti-aliasing */
            #PUSH,2,128,2
            RS[]
            ADD[]
            WS[]           /* s[2] += ClearTypeTM non-ClearType direction anti-aliasing: on (by now) */
          EIF[]

          #PUSH,40,1      /* 40 = Rasterizer v2.1 Windows 8, SubPixel */
          GETINFO[]       /* 1 = tell GETINFO to give us the rasterizer version */
          LTEQ[]          /* 40 <= version ? (already tested version <= 64) */
          IF[]            /* if so, we're running MS rasterizer version 2.1 (Windows 8) or higher */
            #PUSH,16384,2048 /* 524288 = flag returned by GETINFO if ClearTypeTM non-ClearType direction anti-aliasing bit is on */
            MUL[]            /* Assembler restriction: produce 524288 by multiplying 16384 by 32 (32 in F26.6 is 2048) */
            #PUSH,4096       /* 4096 = tell GETINFO to give us the ClearTypeTM gray full-pixel rendering bit */
            GETINFO[]
            EQ[]             /* 524288 == flag ? */
            IF[]             /* if so, we're running under ClearTypeTM gray full-pixel rendering */
            #PUSH,2,256,2
              RS[]
              ADD[]
              WS[]           /* s[2] += ClearTypeTM gray full-pixel rendering: on (by now) */
            EIF[]
          EIF[]

        EIF[] /* Vista or greater rasterizer */

      EIF[] /* Windows ClearType (Platt) */

    EIF[] /* ClearType Enabled */
  EIF[] /* ClearType enabled rasterizer */
EIF[] /* Microsoft Rasterizer */

/* store rasterizing environment specific parameters */

#PUSH, 0, 2
RS[]
EQ[]
IF[] /* for b&w */
  #PUSH, 5, 64, 8, 64, 9, 64, 12, 2, 13, 2
ELSE[]
  #PUSH, 1, 2
  RS[]
  EQ[]
  IF[] /* for grey-scaling */
    #PUSH, 5, 64, 8, 256, 9, 256, 12, 1, 13, 1
  ELSE[]
    #PUSH, 128, 2
    RS[]
    GT[]
    IF[] /* for ClearType */
      #PUSH, 5, 64, 8, 384, 9, 64
    ELSE[] /* for y-anti-aliased ClearType */
      #PUSH, 256, 2
      RS[]
      GT[]
      IF[] /* Gray ClearType */
        #PUSH, 5, 64, 8, 384, 9, 320
      ELSE[] /* Gray ClearType */
        #PUSH, 384, 2
        RS[]
        GT[]
        IF[] /* Gray ClearType */
          #PUSH, 5, 64, 8, 512, 9, 64
        ELSE[] /* Gray ClearType y-anti-aliased */
          #PUSH, 5, 64, 8, 256, 9, 256
        EIF[]
      EIF[]
    EIF[]

    #PUSH,16384,128 /* b&w aw? */
    GETINFO[]
    NEQ[]
    #PUSH,16384,512 /* fract aw? */
    MUL[]
    #PUSH,1024
    GETINFO[]
    NEQ[]
    AND[]
    IF[] /* natural widths */
      #PUSH, 12, 0, 13, 1
    ELSE[] /* compatible or fractional widths */
      #PUSH, 12, 0, 13, 1
    EIF[]

  EIF[]
EIF[]

WS[]
WS[]
WS[]
WS[]
WS[]

#PUSHON
#END
ENDF[]

FDEF[], 85

/* fn 85 equalizes double specified heights below a given ppem size

   CALL[], <rel cvt>, <ppem size>, <abs cvt>, 85 */
   /* Version 2.0 20141201 */

#BEGIN
#PUSHOFF

/* STACK: <rel cvt>, <ppem size>, <abs cvt> */

RCVT[] /* pick absolute (square) height */
#PUSH, 2, 78 /* 2 appears to work for heights and weights */
CALL[]
SWAP[]

/* STACK: <rel cvt>, <[abs cvt]>, <ppem size> */

#PUSH, 79 /* #samples/pixel */
CALL[]
DUP[]
#PUSH, 64
LTEQ[]
IF[] /* #samples/pixel = 1 (or less...) */

    /* STACK: <rel cvt>, <[abs cvt]>, <ppem size>, <#samples/pixel> */

    POP[]
    MPPEM[]
    LTEQ[] /* specified ppem size <= actual ppem size ? */
    IF[]

        /* STACK: <rel cvt>, <[abs cvt]> */

        #PUSH, 2
        CINDEX[]
        RCVT[] /* pick relative height (overshoot) */
        #PUSH, 1, 78
        CALL[]
        ADD[] /* add overshoot to square height */

        /* STACK: <rel cvt>, <[rel cvt] + [abs cvt]> */

    EIF[]

ELSE[] /* #samples/pixel > 1 */

    /* STACK: <rel cvt>, <[abs cvt]>, <ppem size>, <#samples/pixel> */

    SWAP[]
    MPPEM[]
    LTEQ[] /* specified ppem size <= actual ppem size */
    IF[]

      /* STACK: <rel cvt>, <[abs cvt]>, <#samples/pixel> */

      #PUSH, 3 /* rel cvt */
      CINDEX[]
      RCVT[]
      DUP[]
      ABS[]
      ROLL[]
      MUL[]
      #PUSH, 64

      /* STACK: <rel cvt>, <[abs cvt]>, <[rel cvt]>, <|[rel cvt]| * #samples/pixel>, <1> */

      GTEQ[] /* #samples/pixel greater than or equal to 1 pixel */
      IF[]

          /* STACK: <rel cvt>, <[abs cvt]>, <[rel cvt]> */

          #PUSH, 2, 78
          CALL[]
          ADD[] /* add overshoot to square height */

          /* STACK: <rel cvt>, <[rel cvt] + [abs cvt]> */

      ELSE[]

          /* STACK: <rel cvt>, <[abs cvt]>, <[rel cvt]> */

          POP[]

          /* STACK: <rel cvt>, <[abs cvt]> */

      EIF[]
    ELSE[]
          /* STACK: <rel cvt>,<abs cvt>,<#samples/pixel>*/
          POP[]
          /* STACK: <rel cvt>,<abs cvt>*/
    EIF[]

EIF[]

/* STACK: <rel cvt>, <[act cvt]> */

WCVTP[] /* make this the round height */
#PUSHON
#END
ENDF[]

FDEF[], 86

/* function to naturally space an accent above or below a base character

   CALL[], <child>, <parent>, <roundMethod>, <minDist?>, <distance>, 86

   convert distance (fUnits) to pixels, round, and space child from parent by result
   this essentially implements the functionality of an MDRP[m>RWh] instrunction for
   composites which lack a suitable implementation of "original" coordinates.
   roundMethod 0, 1, 2, and 3 round down to, to, up to, and to half virtual grid
   function assumes cvt #20 is reserved and can be used temporarily in here... 
   storage 16 contains a threshold ppem size. if zero, ignore the threshold, otherwise
   if less than or equal to threshold, use 64 (26.6) #samples/pixel. */

#BEGIN
#PUSHOFF

/* extract the sign from distance */
/* STACK: <child>, <parent>, <roundMethod>, <minDist?>, <distance> */

DUP[]
#PUSH, 0
LT[]
DUP[]
IF[]
    SWAP[]
    NEG[]
ELSE[]
    SWAP[]
EIF[]

/* scale distance using reserved cvt */
/* STACK: <child>, <parent>, <roundMethod>, <minDist?>, <negDist?>, <|distance|> */

#PUSH, 20, 20 /* reserved cvt */
ROLL[]
WCVTF[]
RCVT[]

/* determine if we are using a size threshold */
/* STACK: <child>, <parent>, <roundMethod>, <minDist?>, <negDist?>, <|distance|'> */

#PUSH, 16, 16 /* reserved storage for threshold */
RS[]
MPPEM[]
ROLL[]
RS[]
LTEQ[]
AND[] /* threshold must not be zero and <= ppem */
IF[]
    #PUSH, 64 /* #samples/pixel = 1 */
ELSE[]
/* round per round method and #samples/pixel in current pv */
/* STACK: <child>, <parent>, <roundMethod>, <minDist?>, <negDist?>, <|distance|'> */

    #PUSH, 79 /* #samples/pixel */
    CALL[]
EIF[]

SWAP[]
#PUSH, 97, 6 /* round to virtual grid, roundMethod */
MINDEX[]
ADD[]
CALL[] /* round to virtual grid */

/* STACK: <child>, <parent>, <minDist?>, <negDist?>, <[|distance|']> */

/* apply minimum distance, if applicable */
ROLL[]
IF[]
    #PUSH, 5 /* minimum distance */
    RS[]
    MAX[]
EIF[]

/* fold the sign back into distance */
/* STACK: <child>, <parent>, <negDist?> <[|distance|']> */

SWAP[]
IF[]
    NEG[]
EIF[]

/* move child by [distance'] */
/* STACK: <child>, <parent>, <[distance']> */

SWAP[]
SRP0[]
MSIRP[m]

/* STACK: */

#PUSHON
#END
ENDF[]

FDEF[], 87

/* fn places an accent <c0> <c1> on top of a base character <p0> <p1>
   fn uses the same constraint model as fn 111 (interpolate median),
   except that for composites there is no concept of original coordinates,
   hence the respective values are provided by the caller as <partialFactor>

   CALL[], <p0>, <c0>, <c1>, <p1>, <partialFactor>, 87 */

#BEGIN
#PUSHOFF

/* partialFactor: ((c0 + c1)/2 - p0)/(p1 - p0)
   target median: ((c0 + c1)/2 - p0)*(p1' - p0')/(p1 - p0)> + p0' = partialFactor*(p1' - p0')
   source median: (c0' + c1')/2
   primed coordinates are [N]ew, other coordinates are [O]riginal */

/* STACK: <c0>, <c1>, <p0>, <partialFactor>, <p1> */

#PUSH, 3 /* p0 */
CINDEX[]
MD[N]
MUL[]

/* STACK: <c0>, <c1>, <p0>, <((c0 + c1)/2 - p0)*(p1' - p0')/(p1 - p0)> */

SWAP[] /* p0 */
GC[N]
ADD[]

/* STACK: <c0>, <c1>, <targetMedian> */

#PUSH, 79 /* #samples/pixel */
CALL[]
SWAP[]

/* STACK: <c0>, <c1>, <#samples/pixel>, <targetMedian> */

#PUSH, 4 /* c0 */
CINDEX[]
#PUSH, 4 /* c1 */
CINDEX[]
MD[N]
#PUSH, 3 /* #samples/pixel */
CINDEX[]
MUL[]

/* STACK: <c0>, <c1>, <#samples/pixel>, <targetMedian>, <numVirtualPixels> */

ODD[]
DUP[]
ADD[]
#PUSH, 98
ADD[]
CALL[] /* round to (half) virtual grid */

/* STACK: <c0>, <c1>, <[targetMedian]> */

#PUSH, 3 /* c0 */
CINDEX[]
DUP[]
SRP0[]
GC[N]
ROLL[] /* c1 */
GC[N]
ADD[]
#PUSH, 32
MUL[]

/* STACK: <c0>, <targetMedian>, <sourceMedian> */

SUB[]

/* STACK: <c0>, <offset> */

MSIRP[m]

#PUSHON
#END
ENDF[]

FDEF[], 88

/* set up storage locations with the x and y components
   of the italic and adjusted italic angles as follows:

     s[ 6] = adjusted italic angle y
     s[ 7] = adjusted italic angle x
     s[10] = italic angle y
     s[11] = italic angle x

   while rendering in b&w, determines the optimal phase
   for positioning italic strokes

     s[ 4] = optimal phase

   CALL[], <riseCvt>, <runCvt>, 88 */

#BEGIN
#PUSHOFF

/* STACK: <riseCvt>, <runCvt> */

#PUSH, 0 /* Use twilight points to calculate stroke angles */
SZPS[]

#PUSH, 2, 3 /* riseCvt */
CINDEX[]
#PUSH, 1, 4 /* runCvt */
CINDEX[]

/* STACK: <riseCvt>, <runCvt>, <2>, <riseCvt>, <1>, <runCvt> */

SVTCA[X] /* Set twilight point 1 with italic run cvt in x */
MIAP[r]

SVTCA[Y] /* Set twilight point 2 with italic rise cvt in y */
MIAP[r]

#PUSH, 1, 2 /* and let the rasterizer do the math */
SPVTL[r]
GPV[]

#PUSH, 10 /* store the x and y components of the italic angle */
SWAP[]
NEG[]     /* notice that since we're essentially setting the pv to a line  */
WS[]      /* from (runCvt,0) to (0,riseCvt), the calculcated pv will be    */
#PUSH, 11 /* proportional to (runCvt,0) - (0,riseCvt) = (runCvt,-riseCvt). */
SWAP[]    /* Hence we have to mirror the result at the base line, which is */
WS[]      /* done by flipping (negating) the sign of the y component here. */

/* STACK: <riseCvt>, <runCvt> */

#PUSH, 2, 3 /* riseCvt */
CINDEX[]
#PUSH, 1, 4 /* runCvt */
CINDEX[]

SVTCA[X] /* same for the adjusted italic angle */
MIAP[R]  /* except to round the twilight point in x... */

SVTCA[Y]
MIAP[R]  /* ...and in y */

#PUSH, 1, 2
SPVTL[r]
GPV[]

#PUSH, 6
SWAP[]
NEG[]    /* same neg as above */
WS[]
#PUSH, 7
SWAP[]
WS[]

#PUSH, 1 /* restore graphics state */
SZPS[]

/* STACK: <riseCvt>, <runCvt> */

#PUSH, 0, 2
RS[]
EQ[]
IF[] /* running b&w? */

    /* STACK: <riseCvt>, <runCvt> */
    /* determine adjusted run' = run*[rise]/rise */

    RCVT[]
    SWAP[]
    RCVT[]
    DUP[]
    RTG[]
    ROUND[Bl]
    ROLL[]
    MUL[]
    SWAP[]
    DIV[]

    /* STACK: <run'> */
    /* determine phase = (run' - [run'])/2 = half the rounding error */

    DUP[]
    DUP[]
    #PUSH, 64
    LT[]
    IF[]
        CEILING[] /* optimize for "minimum italic angle" */
    ELSE[]
        FLOOR[] /* optimize for minimal number of jaggies */
    EIF[]
    SUB[]
    #PUSH, 32
    MUL[]

    /* STACK: <phase> */
    /* for its use on bottom italic edge, determine complement to full pixel */

    #PUSH, 64
    SWAP[]
    SUB[]

    /* and store in s[4] */

    #PUSH, 4
    SWAP[]
    WS[]

    /* STACK: */

ELSE[]

    /* STACK: <riseCvt>, <runCvt> */

    #PUSH, 4, 0
    WS[]
    POP[]
    POP[]

    /* STACK: */

EIF[]

RTG[]
SVTCA[X]

#PUSHON
#END
ENDF[]

FDEF[], 89

/* function rounds <cvt> depending on rendering environment and pv

   CALL[], <cvt>, 89 */

#BEGIN
#PUSHOFF

DUP[]
RCVT[]
#PUSH, 0, 78 /* roundDist */
CALL[]
WCVTP[]

#PUSHON
#END
ENDF[]

FDEF[], 90

/* below <ppem>: make both children the same as the (averaged) parent cvt
   at and above: calculate child cvt <ch0> as <fraction> of child cvt <ch1>

   CALL[], <p>, <ch0>, <fraction>, <ch1>, <ppem>, 90 */

#BEGIN
#PUSHOFF

/* STACK: <p>, <ch0>, <fraction>, <ch1>, <ppem> */

MPPEM[]
LTEQ[]
#PUSH, 64, 79 /* #samples/pixel */
CALL[]
LT[]
OR[]
IF[] /* at or above ppem limit or rounding to less than a pixel */ 

    /* STACK: <p>, <ch0>, <fraction>, <ch1> */

    DUP[]
    RCVT[]
    #PUSH, 1, 78 /* roundDist */
    CALL[]
    DUP[]
    ROLL[]
    ROLL[]

    /* STACK: <p>, <ch0>, <fraction>, <[ch1]>, <ch1>, <[ch1]> */

    WCVTP[]

    /* STACK: <p>, <ch0>, <fraction>, <[ch1]> */

    DUP[]
    #PUSH, 64, 4
    MINDEX[]
    SUB[]
    MUL[]
    SUB[]
    #PUSH, 1, 78 /* roundDist */
    CALL[]

    /* STACK: <p>, <ch0>, <[ch1] - [ch1]*(1-fraction)> */

    WCVTP[]
    POP[] /* parent not involved */

    /* STACK: */

ELSE[]

    /* STACK: <p>, <ch0>, <fraction>, <ch1> */

    SWAP[]
    POP[] /* fraction not involved */

    /* STACK: <p>, <ch0>, <ch1> */

    ROLL[]
    RCVT[]
    #PUSH, 1, 78 /* roundDist */
    CALL[]

    /* STACK: <ch0>, <ch1>, <[p]> */

    DUP[]
    ROLL[]
    SWAP[]

    /* STACK: <ch0>, <[p]>, <ch1>, <[p]> */

    WCVTP[]
    WCVTP[]

    /* STACK: */

EIF[]

#PUSHON
#END
ENDF[]

FDEF[], 91

/* below <ppem>: make child cvt <ch> the same as parent cvt <p>
   at and above: calculate child cvt <ch> as <fraction> of parent cvt <p>

   CALL[], <ch>, <fraction>, <p>, <ppem>, 91 */

#BEGIN
#PUSHOFF

/* STACK: <ch>, <fraction>, <p>, <ppem> */

MPPEM[]
LTEQ[]
#PUSH, 64, 79 /* #samples/pixel */
CALL[]
LT[]
OR[]
IF[] /* at or above ppem limit or rounding to less than a pixel */ 

    /* STACK: <ch>, <fraction>, <p> */

    RCVT[]
    DUP[]
    ROLL[]

    /* STACK: <ch>, <[p]>, <[p]>, <fraction> */

    #PUSH, 64
    SUB[]
    MUL[]
    ADD[]

    /* STACK: <ch>, <[p] + [p]*(fraction - 1)> */

ELSE[]

    /* STACK: <ch>, <fraction>, <p> */

    SWAP[]
    POP[] /* fraction not involved */

    RCVT[]

    /* STACK: <ch>, [p] */

EIF[]

#PUSH, 1, 78 /* roundDist */
CALL[]
WCVTP[]

/* STACK: */

#PUSHON
#END
ENDF[]

FDEF[], 92

/* function to calculate a child cvt <ch>
   as a <blend> of two parent cvts <p0>, <p1>

   CALL[], <ch>, <blend>, <p0>, <p1>, 92 */

#BEGIN
#PUSHOFF

/* STACK: <ch>, <blend>, <p0>, <p1> */

SWAP[]
RCVT[]
DUP[]

/* STACK: <ch>, <blend>, <p1>, <[p0]>, <[p0]> */

ROLL[]
RCVT[]

SWAP[]
SUB[]

/* STACK: <ch>, <blend>, <[p0]>, <[p1] - [p0]> */

DUP[]
ABS[]
#PUSH, 64
LTEQ[]

/* STACK: <ch>, <blend>, <[p0]>, <[p1] - [p0]>, <contrast <= 1 pixel(s)?> */

#PUSH, 4
CINDEX[]
DUP[]
#PUSH, 0
GTEQ[]
SWAP[]
#PUSH, 64
LTEQ[]
AND[]

AND[]

/* STACK: <ch>, <blend>, <[p0]>, <[p1] - [p0]>, <contrast <= 1 pixel(s) && blend >= 0 && blend <= 64?> */

#PUSH, 64, 79 /* #samples/pixel */
CALL[]
EQ[]

AND[]

/* STACK: <ch>, <blend>, <[p0]>, <[p1] - [p0]>, <contrast <= 1 pixel(s) && blend >= 0 && blend <= 64 && rounding to full pixel?> */

IF[]

    /* STACK: <ch>, <blend>, <[p0]>, <[p1] - [p0]> */

    ROLL[]
    GPV[]
    ABS[]
    SWAP[]
    ABS[]
    SWAP[]

    /* STACK: <ch>, <[p0]>, <[p1] - [p0]>, <blend>, <|pv.x|>, <|pv.y|> */

    GTEQ[] /* pv closer to x? */
    IF[]

        /* STACK: <ch>, <[p0]>, <[p1] - [p0]>, <blend> */
        /* bias towards p1: blend' := 1 - (1 - blend)� */

        #PUSH, 64, 64
        ROLL[]
        SUB[]
        DUP[]
        MUL[]
        SUB[]

        /* <ch>, <[p0]>, <[p1] - [p0]>, <1 - (1 - blend)�> */

    ELSE[]

        /* STACK: <ch>, <[p0]>, <[p1] - [p0]>, <blend> */
        /* bias towards p0: blend' := blend� */

        DUP[]
        MUL[]

    /* STACK: <ch>, <[p0]>, <[p1] - [p0]>, <blend�> */

    EIF[]

ELSE[]

    /* STACK: <ch>, <blend>, <[p0]>, <[p1] - [p0]> */
    /* use unbiased blend */

    ROLL[]

    /* STACK: <ch>, <[p0]>, <[p1] - [p0]>, <blend> */

EIF[]

/* STACK: <ch>, <[p0]>, <[p1] - [p0]>, <blend> */

MUL[]
#PUSH, 2, 78 /* roundDist */
CALL[]
ADD[]

/* STACK: <ch>, <[ch]> */

WCVTP[]

#PUSHON
#END
ENDF[]

FDEF[], 93

/* fn sets vectors to X (used in calculated calls)

   CALL[], 93 */

#BEGIN
#PUSHOFF
SVTCA[X]
#PUSHON
#END
ENDF[]

FDEF[], 94

/* fn sets vectors to Y (used in calculated calls)

   CALL[], 94 */

#BEGIN
#PUSHOFF
SVTCA[Y]
#PUSHON
#END
ENDF[]

FDEF[], 95

/* Set fv to X, pv perpendicular to italic angle (used in calculated calls)

   CALL[], 95 */

#BEGIN
#PUSHOFF
SFVTCA[X]
#PUSH, 11, 10
RS[]
SWAP[]
RS[]
NEG[]
SPVFS[]
#PUSHON
#END
ENDF[]

FDEF[], 96

/* Set fv to italic angle, pv to Y (used in calculated calls)

   CALL[], 96 */

#BEGIN
#PUSHOFF
#PUSH, 10, 11
RS[]
SWAP[]
RS[]
SFVFS[]
SPVTCA[Y]
#PUSHON
#END
ENDF[]

FDEF[], 97

/* round down to virtual grid

   CALL[], <#samples/pixel>, <argument>, 97

   returns with rounded argument on stack */

#BEGIN
#PUSHOFF

/* STACK: <#samples/pixel>, <argument> */
/* upscale argument by #samples/pixel */

#PUSH, 2 /* #samples/pixel */
CINDEX[]
MUL[]

/* do the rounding in upscaled domain */

FLOOR[] /* round down to super grid */

/* Downscaling uses a DIV[] operation, which is implemented as floor(numerator/denominator).
   For round(numerator/denominator) instead, add � denominator to numerator before dividing.
   But since the division in 26.6 has to multiply the numerator by 2^6 (64) before dividing,
   we have to divide said � denominator by 64 before adding, hence the 8192 (= 128 in 26.6). */

#PUSH, 2 /* #samples/pixel */
CINDEX[]
#PUSH, 8192
DIV[]
ADD[]

/* downscale rounded and adjusted argument */

SWAP[] /* #samples/pixel */
DIV[]

/* STACK: <[argument]> */

#PUSHON
#END
ENDF[]

FDEF[], 98

/* round to virtual grid

   CALL[], <#samples/pixel>, <argument>, 98

   returns with rounded argument on stack */

#BEGIN
#PUSHOFF

/* STACK: <#samples/pixel>, <argument> */

#PUSH, 2 /* #samples/pixel */
CINDEX[]
MUL[]

/* do the rounding in upscaled domain */

#PUSH, 32 /* round to super grid */
ADD[]
FLOOR[]

/* see above for adjustments below */

#PUSH, 2 /* #samples/pixel */
CINDEX[]
#PUSH, 8192
DIV[]
ADD[]

/* downscale rounded and adjusted argument */

SWAP[] /* #samples/pixel */
DIV[]

/* STACK: <[argument]> */

#PUSHON
#END
ENDF[]

FDEF[], 99

/* round up to virtual grid

   CALL[], <#samples/pixel>, <argument>, 99

   returns with rounded argument on stack */

#BEGIN
#PUSHOFF

/* STACK: <#samples/pixel>, <argument> */

#PUSH, 2 /* #samples/pixel */
CINDEX[]
MUL[]

/* do the rounding in upscaled domain */

CEILING[] /* round up to super grid */

/* see above for adjustments below */

#PUSH, 2 /* #samples/pixel */
CINDEX[]
#PUSH, 8192
DIV[]
ADD[]

/* downscale rounded and adjusted argument */

SWAP[] /* #samples/pixel */
DIV[]

/* STACK: <[argument]> */

#PUSHON
#END
ENDF[]

FDEF[], 100

/* round to half virtual grid

   CALL[], <#samples/pixel>, <argument>, 100

   returns with rounded argument on stack */

#BEGIN
#PUSHOFF

/* STACK: <#samples/pixel>, <argument> */

#PUSH, 2 /* #samples/pixel */
CINDEX[]
MUL[]

/* do the rounding in upscaled domain */

FLOOR[]
#PUSH, 32 /* round to half super grid */
ADD[]

/* see above for adjustments below */

#PUSH, 2 /* #samples/pixel */
CINDEX[]
#PUSH, 8192
DIV[]
ADD[]

/* downscale rounded and adjusted argument */

SWAP[] /* #samples/pixel */
DIV[]

/* STACK: <[argument]> */

#PUSHON
#END
ENDF[]

FDEF[], 101

/* determine actual distance to be used for emulating MDRP[<]
   instruction with rendering environment specific rounding

   CALL[], <p>, <c>, 101

   returns with rounded distance on stack */

#BEGIN
#PUSHOFF

/* STACK: <p>, <c> */

SWAP[]
MD[O]

/* round without minDist */

#PUSH, 2, 78 /* roundDist */
CALL[]

/* STACK: <[w]> */

#PUSHON
#END
ENDF[]

FDEF[], 102

/* determine actual distance to be used for emulating MDRP[>]
   instruction with rendering environment specific rounding

   CALL[], <p>, <c>, 102

   returns with rounded distance on stack */

#BEGIN
#PUSHOFF

/* STACK: <p>, <c> */

SWAP[]
MD[O]

/* round with minDist */

#PUSH, 1, 78 /* roundDist */
CALL[]

/* STACK: <[w]> */

#PUSHON
#END
ENDF[]

FDEF[], 103

/* determine actual distance to be used for emulating MIRP[<]
   instruction with rendering environment specific rounding

   CALL[], <p>, <c>, <cvt>, 103

   returns with rounded distance on stack */

#BEGIN
#PUSHOFF

/* STACK: <p>, <c>, <cvt> */

SWAP[] /* c */
ROLL[] /* p */
MD[O]
SWAP[] /* cvt */

/* STACK: <wNat>, <cvt> */
/* do cvt cut-in test */

RCVT[]
ABS[]
#PUSH, 2
CINDEX[]
ABS[]
#PUSH, 2
CINDEX[]
SUB[]
ABS[]
#PUSH, 3 /* cvt cut-in */
RS[]

/* STACK: <wNat>, <|wCvt|>, <||wNat| - |wCvt||>, <cvt cut-in> */

GT[]
IF[]

    /* STACK: <wNat>, <|wCvt|> */
    /* cvt cut-in test failed */

    POP[]
    DUP[]
    ABS[]

    /* else cvt cut-in test succeeded */

EIF[]

/* STACK: <wNat>, <|w|> */
/* round without minDist */

#PUSH, 2, 78 /* roundDist */
CALL[]

/* STACK: <wNat>, <[w]> */
/* inherit sign from wNat */

SWAP[]
#PUSH, 0
LT[]
IF[]
    NEG[]
EIF[]

/* STACK: <[w]> */

#PUSHON
#END
ENDF[]

FDEF[], 104

/* determine actual distance to be used for emulating MIRP[>]
   instruction with rendering environment specific rounding

   CALL[], <p>, <c>, <cvt>, 104

   returns with rounded distance on stack */

#BEGIN
#PUSHOFF

/* STACK: <p>, <c>, <cvt> */

SWAP[] /* c */
ROLL[] /* p */
MD[O]
SWAP[] /* cvt */

/* STACK: <wNat>, <cvt> */
/* do cvt cut-in test */

RCVT[]
ABS[]
#PUSH, 2
CINDEX[]
ABS[]
#PUSH, 2
CINDEX[]
SUB[]
ABS[]
#PUSH, 3 /* cvt cut-in */
RS[]

/* STACK: <wNat>, <|wCvt|>, <||wNat| - |wCvt||>, <cvt cut-in> */

GT[]
IF[]

    /* STACK: <wNat>, <|wCvt|> */
    /* cvt cut-in test failed */

    POP[]
    DUP[]
    ABS[]

    /* else cvt cut-in test succeeded */

EIF[]

/* STACK: <wNat>, <|w|> */
/* round with minDist */

#PUSH, 1, 78 /* roundDist */
CALL[]

/* STACK: <wNat>, <[w]> */
/* inherit sign from wNat */

SWAP[]
#PUSH, 0
LT[]
IF[]
    NEG[]
EIF[]

/* STACK: <[w]> */

#PUSHON
#END
ENDF[]

FDEF[], 105

/* emulate MDRP[<] instruction with rendering environment specific rounding

   CALL[], <p>, <c>, 105 */

#BEGIN
#PUSHOFF

/* STACK: <p>, <c> */

DUP[] /* c */
#PUSH, 3 /* p */
CINDEX[]
MD[O]
#PUSH, 2, 78 /* roundDist */
CALL[]

/* STACK: <p>, <c>, <[dist]> */

ROLL[]
SRP0[]
MSIRP[M]

#PUSHON
#END
ENDF[]

FDEF[], 106

/* emulate MDRP[>] instruction with rendering environment specific rounding

   CALL[], <p>, <c>, 106 */

#BEGIN
#PUSHOFF

/* STACK: <p>, <c> */

DUP[] /* c */
#PUSH, 3 /* p */
CINDEX[]
MD[O]
#PUSH, 1, 78 /* roundDist */
CALL[]

/* STACK: <p>, <c>, <[dist]> */

ROLL[]
SRP0[]
MSIRP[M]

#PUSHON
#END
ENDF[]

FDEF[], 107

/* emulate MIRP[<] instruction with rendering environment specific rounding

   CALL[], <p>, <c>, <cvt>, 107 */

#BEGIN
#PUSHOFF

/* STACK: <p>, <c>, <cvt> */

#PUSH, 3 /* p */
CINDEX[]
#PUSH, 3 /* c */
CINDEX[]
ROLL[] /* cvt */
#PUSH, 103 /* resActDist, cvt, noMinDist */
CALL[]

/* STACK: <p>, <c>, <[dist]> */

ROLL[]
SRP0[]
MSIRP[M]

#PUSHON
#END
ENDF[]

FDEF[], 108

/* emulate MIRP[>] instruction with rendering environment specific rounding

   CALL[], <p>, <c>, <cvt>, 108 */

#BEGIN
#PUSHOFF

/* STACK: <p>, <c>, <cvt> */

#PUSH, 3 /* p */
CINDEX[]
#PUSH, 3 /* c */
CINDEX[]
ROLL[] /* cvt */
#PUSH, 104 /* resActDist, cvt, minDist */
CALL[]

/* STACK: <p>, <c>, <[dist]> */

ROLL[]
SRP0[]
MSIRP[M]

#PUSHON
#END
ENDF[]

FDEF[], 109

/* fn symmetrically constrains a stroke <p>, <c> with <cvt>

   CALL[], <p>, <c>, <cvt>, 109 */

#BEGIN
#PUSHOFF

/* STACK: <p>, <c>, <cvt> */
/* determine old median */

#PUSH, 3 /* <p> */
CINDEX[]
GC[N]
#PUSH, 3 /* <c> */
CINDEX[]
GC[N]
ADD[]

/* STACK: <p>, <c>, <cvt>, <2*median> */
/* lock parent */

#PUSH, 4 /* p */
CINDEX[]
MDAP[r]

/* STACK: <p>, <c>, <cvt>, <2*median> */
/* link child */

#PUSH, 4 /* p */
CINDEX[]
#PUSH, 4 /* c */
CINDEX[]
#PUSH, 4 /* cvt */
MINDEX[]
DUP[]
#PUSH, 0
LT[]
IF[]
    POP[]
    #PUSH, 106 /* resMIRP, noCvt, minDist */
ELSE[]
    #PUSH, 108 /* resMIRP, cvt, minDist */
EIF[]
CALL[]

/* STACK: <p>, <c>, <2*median> */
/* determine new median */

#PUSH, 3 /* <p> */
CINDEX[]
GC[N]
#PUSH, 3 /* <c> */
CINDEX[]
GC[N]
ADD[]

/* STACK: <p>, <c>, <2*median>, <2*median'> */

SUB[]
#PUSH, 128
DIV[] /* floor to 1/64 for now */

/* STACK: <p>, <c>, <deltaMedian> */

DUP[]
ROLL[]
DUP[]
SRP0[]
SWAP[]
MSIRP[m]
SWAP[]
DUP[]
SRP0[]
SWAP[]
MSIRP[m]

/* STACK: */

#PUSHON
#END
ENDF[]

FDEF[], 110

/* calculate offset for emulation of interpolation of median of
   <c0> and <c1> between parents <p0> and <p1> using current pv and fv

   CALL[], <p0>, <c0>, <c1>, <p1>, 110

   returns with offset on stack */

#BEGIN
#PUSHOFF

/* STACK: <p0>, <c0>, <c1>, <p1> */

#PUSH, 3 /* c0 */
CINDEX[]
GC[O]
#PUSH, 3 /* c1 */
CINDEX[]
GC[O]
ADD[]

/* STACK: <p0>, <c0>, <c1>, <p1>, <c0 + c1> */

#PUSH, 5 /* p0 */
CINDEX[]
GC[O]
#PUSH, 128
MUL[]
SUB[]

/* STACK: <p0>, <c0>, <c1>, <p1>, <c0 + c1 - 2*p0> */

#PUSH, 2 /* p1 */
CINDEX[]
#PUSH, 6 /* p0 */
CINDEX[]
MD[N]
MUL[]

/* STACK: <p0>, <c0>, <c1>, <p1>, <(c0 + c1 - 2*p0)*(p1' - p0')> */

SWAP[] /* p1 */
#PUSH, 5 /* p0 */
CINDEX[]
MD[O]
#PUSH, 128
MUL[]

/* prevent inadvertent divide-by-zero e.g. on non-spacing glyphs */
DUP[]
IF[]
    DIV[]
ELSE[]
    POP[]
EIF[]

/* STACK: <p0>, <c0>, <c1>, <(c0 + c1 - 2*p0)*(p1' - p0')/(2*(p1 - p0))> */

#PUSH, 4 /* p0 */
MINDEX[]
GC[N]
ADD[]

/* STACK: <c0>, <c1>, <(c0'' + c1'')/2> */

ROLL[] /* c0 */
GC[N]
ROLL[] /* c1 */
GC[N]
ADD[]
#PUSH, 32
MUL[]

/* STACK: <(c0'' + c1'')/2>, <(c0' + c1')/2> */

SUB[]

/* STACK: <offset> */

#PUSHON
#END
ENDF[]

FDEF[], 111

/* emulate interpolation of median of <c0> and <c1>
   between parents <p0> and <p1> using current pv and fv

   CALL[], <p0>, <c0>, <c1>, <p1>, 111 */

#BEGIN
#PUSHOFF

/* STACK: <p0>, <c0>, <c1>, <p1> */

#PUSH, 4 /* p0 */
MINDEX[]
#PUSH, 4 /* c0 */
CINDEX[]
#PUSH, 4 /* c1 */
CINDEX[]
#PUSH, 4 /* p1 */
MINDEX[]
#PUSH, 110 /* calc offset for interpolation of median */
CALL[]

/* STACK: <c0>, <c1>, <offset> */

DUP[]

/* STACK: <c0>, <c1>, <offset>, <offset> */

ROLL[]
DUP[]
SRP0[]
SWAP[]

/* STACK: <c0>, <offset>, <c1>, <offset> */

MSIRP[m]

SWAP[]
DUP[]
SRP0[]
SWAP[]

/* STACK: <c0>, <offset> */

MSIRP[m]

#PUSHON
#END
ENDF[]

FDEF[], 112


/* adjust (unrounded) stroke phase to target phase according to <method>

   method 0: round to nearest virtual pixel
   method 1: apply method 2 below 2 pixel wide strokes else method 0
   method 2: optimize for max #black pixels
   method 3: optimize for one edge aligned

   right?: boolean indicating a left (false) or right (true) stroke)

   CALL[], <phase>, <weight>, <method>, <right?>, 112

   returns with (rounded) adjusted phase on stack */

#BEGIN
#PUSHOFF

/* STACK: <phase>, <weight>, <method>, <right?> */

SWAP[]

DUP[]
#PUSH, 1
EQ[]
IF[]

    /* STACK: <phase>, <weight>, <right?>, <method> */
    /* replace method depending on stroke weight */

    POP[]
    #PUSH, 2 /* weight */
    CINDEX[]
    #PUSH, 2, 78 /* roundDist */
    CALL[]
    #PUSH, 128
    LT[]
    DUP[]
    ADD[]
EIF[]

DUP[]
ADD[]
ADD[]

/* STACK: <phase>, <weight>, <method' = 2*method + right> */

DUP[]
#PUSH, 1
LTEQ[]
IF[] /* just round to nearest virtual pixel */

    POP[]
    POP[]

    /* STACK: <phase> */

ELSE[]
    DUP[]
    #PUSH, 5
    LTEQ[]
    IF[] /* optimize for max #black pixels */

        POP[]

        /* STACK: <phase>, <weight> */

        DUP[]
        FLOOR[]
        SUB[]

        /* STACK: <phase>, <fractWeight> */

        #PUSH, 64
        SWAP[]
        SUB[]

        /* STACK: <phase>, <1-fractWeight> */

        #PUSH, 0, 3 /* phase */
        CINDEX[]
        LT[]
        #PUSH, 3 /* phase */
        CINDEX[]
        #PUSH, 3 /* 1-fractWeight */
        CINDEX[]
        LT[]
        AND[]
        IF[] /* if 0 < phase < 1-fractWeight then need to adjust phase */

            /* STACK: <phase>, <1-fractWeight> */

            DUP[]
            #PUSH, 3
            CINDEX[]
            SUB[]

            /* STACK: <phase>, <1-fractWeight>, <1-fractWeight-phase> */

            ROLL[]
            GTEQ[]
            IF[] /* error from phase to 1-fractWeight >= error from 0 to phase */
                POP[]
                #PUSH, 0 /* target 0 as phase */
            EIF[]
            /* else target 1-fractWeight as phase, which is what's left on stack */

        ELSE[]

            /* STACK: <phase>, <1-fractWeight> */

            POP[]

        EIF[]

    ELSE[] /* optimize for one edge aligned */

        /* STACK: <phase>, <weight>, <method'> */

        #PUSH, 7
        EQ[]
        IF[] /* right flush */

            /* STACK: <phase>, <weight> */

            DUP[]
            FLOOR[]
            SUB[]

            /* STACK: <phase>, <fractWeight> */

            NEG[]
            SWAP[]
            POP[]

        ELSE[] /* left flush (and default) */

            /* STACK: <phase>, <weight> */

            POP[]
            POP[]
            #PUSH, 0

        EIF[]

    EIF[]

EIF[]

#PUSH, 2, 78 /* roundDist */
CALL[]

/* STACK: phase */

#PUSHON
#END
ENDF[]

FDEF[], 113

/* fn calculates delta phase for optimal position of
   stroke bordered by <p> and <c> according to <method>
   (see fn 112 for definition of method)

   CALL[], <p>, <c>, <method>, 113

   returns with delta phase in interval ]-�,+�] on stack */

#BEGIN
#PUSHOFF

/* STACK: <p>, <c>, <method> */

    /* use sequence of parameters <p> and <c> to determine if this is
       a "left" stroke (in which case we may add grey to the right), or
       a "right" stroke (in which case we may add grey to the left) */

#PUSH, 2 /* c */
CINDEX[]
#PUSH, 4 /* p */
CINDEX[]
MD[O]
#PUSH, 0
GTEQ[]
IF[]
    #PUSH, 0 /* "left" stroke */
ELSE[]
    ROLL[]
    ROLL[]
    SWAP[]
    ROLL[]
    #PUSH, 1 /* "right" stroke */
EIF[]

/* STACK: <p>, <c>, <method>, <right?> */

#PUSH, 4 /* p */
CINDEX[]
GC[N]
DUP[]
FLOOR[]
SUB[]
DUP[]

/* STACK: <p>, <c>, <method>, <right?>, <source phase>, <source phase> */

#PUSH, 5 /* c */
MINDEX[]
#PUSH, 6 /* p */
MINDEX[]
MD[N]

/* STACK: <method>, <right?>, <source phase>, <source phase>, <weight> */

#PUSH, 5 /* method */
MINDEX[]
#PUSH, 5 /* right? */
MINDEX[]
#PUSH, 112 /* adjust to target stroke phase */
CALL[]

/* STACK: <source phase>, <target phase> */

SWAP[]
SUB[]

/* STACK: <delta phase> */
/* minimze phase into interval ]-�,+�] */

NEG[]
#PUSH, 32
ADD[]
DUP[]
FLOOR[]
SUB[]
#PUSH, 32
SUB[]
NEG[]

#PUSHON
#END
ENDF[]

FDEF[], 114

/* emulate MIAP instruction with rendering environment specific rounding

   CALL[], <c>, <cvt>, 114 */

#BEGIN
#PUSHOFF

/* STACK: <c>, <cvt> */

#PUSH, 2 /* c */
CINDEX[]
GC[N]
DUP[]

/* STACK: <c>, <cvt>, <wNat>, <wNat> */

ROLL[]
DUP[]
#PUSH, 0
LT[]
IF[]

    /* STACK: <c>, <wNat>, <wNat>, <cvt> */

    POP[]

    /* cvt < 0 (no cvt used) => w = wNat */
    /* STACK: <c>, <wNat>, <w> */

    #PUSH, 2, 78 /* roundDist */
    CALL[]

ELSE[]

    RCVT[]

    /* STACK: <c>, <wNat>, <wNat>, <wCvt> */
    /* no cvt cut-in test (for eventual support of automatic small caps, superiors, and inferiors), pop wNat to use wCvt */

    SWAP[]
    POP[]

    /* leave value as rounded by cpgm */
    /* STACK: <c>, <wNat>, <w> */

EIF[]

SUB[]
NEG[]

/* STACK: <c>, <wDelta> */

#PUSH, 2
CINDEX[]
SRP0[]

MSIRP[M]

#PUSHON
#END
ENDF[]

FDEF[], 115

/* interpolates a point <p> in <dirFlag> between points <lsb> and <rsb>
   dirFlag: postRoundFlag*8 + dir
   dir: X = 0, Y = 1, X/ = 2, Y/ = 3, ...

   depending on rendering environment and pv may optimise point position

   CALL[], <dirFlag>, <p0>, <c>, <p1>, 115 */

#BEGIN
#PUSHOFF

/* STACK: <dirFlag>, <p0>, <p>, <p1> */
/* separate postRoundFlag from dir */

#PUSH, 4 /* dirFlag */
MINDEX[]
DUP[]
#PUSH, 512
DIV[]
DUP[]
#PUSH, 512
MUL[]
ROLL[]
SWAP[]
SUB[]

/* STACK:, <p0>, <p>, <p1>, <postRoundFlag>, <dir> */

DUP[]
#PUSH, 93 /* setV */
ADD[]
CALL[]

/* STACK: <p0>, <p>, <p1>, <postRoundFlag>, <dir> */

#PUSH, 5 /* p0 */
CINDEX[]
SRP1[]
ROLL[] /* p1 */
SRP2[]
ROLL[] /* p */
DUP[]
IP[]

/* STACK: <p0>, <postRoundFlag>, <dir>, <p> */

ROLL[] /* postRoundFlag */
IF[]

    /* STACK: <p0>, <dir>, <p> */

    #PUSH, 93, 4096, 4 /* setV, 64, dir */
    MINDEX[]
    MUL[]
    ODD[]
    ADD[]
    CALL[]

    /* STACK: <p0>, <p> */

    SWAP[]
    POP[]
    DUP[] /* p */
    SRP0[]
    DUP[]
    GC[N]
    DUP[]
    #PUSH, 2, 78 /* roundDist */
    CALL[]
    SWAP[]
    SUB[]

    /* STACK: <p>, <[p.c]-p.c> */

ELSE[]

    /* STACK: <p0>, <dir>, <p> */

    SWAP[]
    POP[]

    /* STACK: <p0>, <p> */

    DUP[]
    ROLL[]
    DUP[] /* p0 */
    SRP0[]
    MD[N]

    #PUSH, 2, 78 /* roundDist */
    CALL[]

    /* STACK: <p>, <[p.dist]> */

EIF[]

MSIRP[M]

/* STACK: */

#PUSHON
#END
ENDF[]

FDEF[], 116

/* constrains a stroke in <dir>, defined by parent <p> and child <c>,
   and by cvt <cvt>, and interpolates it between points <gp0> and <gp1>
   dir: X = 0, Y = 1, X/ = 2
   sof: (stroke optimization flags ||, |<, and >| ) don't = 0, do = 1, leftBias = 2, rightBias = 3

   CALL[], <dir>, <gp0>, <p>, <c>, <cvt>, <gp1>, <sof>, 116 */

#BEGIN
#PUSHOFF

/* STACK: <dir>, <gp0>, <p>, <c>, <cvt>, <gp1>, <sof> */

#PUSH, 93, 4096, 9 /* setV, 64, dir */
CINDEX[]
MUL[]
ODD[]
ADD[]
CALL[]

/* constrain stroke */

#PUSH, 5 /* p */
CINDEX[]
#PUSH, 5 /* c */
CINDEX[]
#PUSH, 5 /* cvt */
MINDEX[]
#PUSH, 109 /* symDist */
CALL[]

/* STACK: <dir>, <gp0>, <p>, <c>, <gp1>, <sof> */

#PUSH, 93, 7 /* setV, dir */
CINDEX[]
ADD[]
CALL[]

#PUSH, 5 /* gp0 */
CINDEX[]
#PUSH, 5 /* p */
CINDEX[]
#PUSH, 5 /* c */
CINDEX[]
#PUSH, 5 /* gp1 */
CINDEX[]
#PUSH, 111 /* interpolate median */
CALL[]

/* STACK: <dir>, <gp0>, <p>, <c>, <gp1>, <sof> */

#PUSH, 93, 4096, 8 /* setV, 64, dir */
MINDEX[]
MUL[]
ODD[]
ADD[]
CALL[]

/* STACK: <gp0>, <p>, <c>, <gp1>, <sof> */

DUP[]
#PUSH, 0
GT[]
IF[] /* optimize stroke position */

    #PUSH, 80
    CALL[]

    /* STACK: <gp0>, <p>, <c>, <gp1>, <sof>, <som> */

    #PUSH, 5 /* p */
    CINDEX[]
    #PUSH, 5 /* c */
    CINDEX[]
    #PUSH, 7 /* p */
    CINDEX[]
    #PUSH, 7 /* c */
    CINDEX[]
    #PUSH, 5 /* som */
    CINDEX[]
    #PUSH, 113 /* get delta phase for optimal stroke position */
    CALL[]
    #PUSH, 2
    SLOOP[]
    SHPIX[]

    /* STACK: <gp0>, <p>, <c>, <gp1>, <sof>, <som> */

    #PUSH, 0
    GT[]
    #PUSH, 2 /* sof */
    CINDEX[]
    #PUSH, 1
    GT[]
    AND[]
    IF[]

        /* STACK: <gp0>, <p>, <c>, <gp1>, <sof> */
        /* determine total side-bearing space to see if we need to bias the black body */

        #PUSH, 4 /* p */
        CINDEX[]
        #PUSH, 6 /* gp0 */
        CINDEX[]
        MD[N]
        #PUSH, 3 /* gp1 */
        CINDEX[]
        #PUSH, 5 /* c */
        CINDEX[]
        MD[N]
        ADD[]
        DUP[]
        #PUSH, 64
        GT[]
        IF[]

            /* STACK: <gp0>, <p>, <c>, <gp1>, <sof>, <totSBS> */
            /* enough total side-bearing space left, leave it alone */
            POP[]

        ELSE[]

            /* STACK: <gp0>, <p>, <c>, <gp1>, <sof>, <totSBS> */
            /* 1 pixel or less total side-bearing space left */

            #PUSH, 0
            GT[]
            IF[]

                /* STACK: <gp0>, <p>, <c>, <gp1>, <sof> */
                /* any total side-bearing space left at all */

                DUP[]
                #PUSH, 2
                EQ[]
                IF[]

                    /* STACK: <gp0>, <p>, <c>, <gp1>, <sof> */
                    /* move stroke flush left */

                    #PUSH, 4 /* p */
                    CINDEX[]
                    #PUSH, 4 /* c */
                    CINDEX[]
                    #PUSH, 7 /* gp0 */
                    CINDEX[]
                    #PUSH, 7 /* p */
                    CINDEX[]
                    MD[N]
                    #PUSH, 2
                    SLOOP[]
                    SHPIX[]

                ELSE[]

                    /* STACK: <gp0>, <p>, <c>, <gp1>, <sof> */
                    /* move stroke flush left */

                    #PUSH, 4 /* p */
                    CINDEX[]
                    #PUSH, 4 /* c */
                    CINDEX[]
                    #PUSH, 4 /* gp1 */
                    CINDEX[]
                    #PUSH, 6 /* c */
                    CINDEX[]
                    MD[N]
                    #PUSH, 2
                    SLOOP[]
                    SHPIX[]

                EIF[]

            EIF[]

        EIF[]

    EIF[]

EIF[]

/* STACK: <gp0>, <p>, <c>, <gp1>, <sof> */

POP[]
POP[]
POP[]
POP[]
POP[]

/* STACK: */

#PUSHON
#END
ENDF[]

FDEF[], 117

/* fn tries to place and constrain two strokes <p0,c0,cvt0> and <p1,c1,cvt1>
   between grandparents <gp0> and <gp1> in direction <dir>
   dir: X = 0, Y = 1, X/ = 2
   X/ (italic) is not yet implemented; to do so properly will need to factor
   the italic phase optimization part out of fn 131 and make it available to
   this fn.   

   CALL[], <dir>, <gp0>, <p0>, <c0>, <cvt0>, <p1>, <c1>, <cvt1>, <gp1>, 117 */

#BEGIN
#PUSHOFF

/* STACK: <dir>, <gp0>, <p0>, <c0>, <cvt0>, <p1>, <c1>, <cvt1>, <gp1> */

#PUSH, 93, 4096, 11 /* setV, dir */
CINDEX[]
MUL[]
ODD[]
ADD[]
CALL[]

/* STACK: <dir>, <gp0>, <p0>, <c0>, <cvt0>, <p1>, <c1>, <cvt1>, <gp1> */
/* interpolate black body */

#PUSH, 7 /* p0 */
CINDEX[]
#PUSH, 7 /* c0 */
CINDEX[]
#PUSH, 6 /* p1 */
CINDEX[]
#PUSH, 6 /* c1 */
CINDEX[]
#PUSH, 12 /* gp0 */
CINDEX[]
#PUSH, 12 /* p0 */
CINDEX[]
#PUSH, 9 /* c1 */
CINDEX[]
#PUSH, 8 /* gp1 */
CINDEX[]
#PUSH, 110 /* calc offset for interpolation of median */
CALL[]
#PUSH, 4
SLOOP[]
SHPIX[]

/* STACK: <dir>, <gp0>, <p0>, <c0>, <cvt0>, <p1>, <c1>, <cvt1>, <gp1> */
/* constrain stroke0 */

#PUSH, 7 /* p0 */
CINDEX[]
#PUSH, 7 /* c0 */
CINDEX[]
#PUSH, 7 /* cvt0 */
MINDEX[]
#PUSH, 109 /* symDist */
CALL[]

/* STACK: <dir>, <gp0>, <p0>, <c0>, <p1>, <c1>, <cvt1>, <gp1> */
/* constrain stroke1 */

#PUSH, 4 /* p1 */
CINDEX[]
#PUSH, 4 /* c1 */
CINDEX[]
#PUSH, 4 /* cvt1 */
MINDEX[]
#PUSH, 109 /* symDist */
CALL[]

/* STACK: <dir>, <gp0>, <p0>, <c0>, <p1>, <c1>, <gp1> */

#PUSH, 80
CALL[]

/* STACK: <dir>, <gp0>, <p0>, <c0>, <p1>, <c1>, <gp1>, <som> */
/* determine phase0 for optimal position of stroke0 */

#PUSH, 6 /* p0 */
CINDEX[]
#PUSH, 6 /* c0 */
CINDEX[]
#PUSH, 3 /* som */
CINDEX[]
#PUSH, 113 /* get delta phase for optimal stroke position */
CALL[]

/* STACK: <dir>, <gp0>, <p0>, <c0>, <p1>, <c1>, <gp1>, <som>, <phase0> */
/* forward to stroke1 position */

#PUSH, 5 /* p1 */
CINDEX[]
#PUSH, 5 /* c1 */
CINDEX[]
#PUSH, 3 /* phase0 */
CINDEX[]
#PUSH, 2
SLOOP[]
SHPIX[]

/* STACK: <dir>, <gp0>, <p0>, <c0>, <p1>, <c1>, <gp1>, <som>, <phase0> */
/* determine phase1 for optimal position of stroke1 */

DUP[]
#PUSH, 6 /* p1 */
CINDEX[]
#PUSH, 6 /* c1 */
CINDEX[]
#PUSH, 5 /* som */
CINDEX[]
#PUSH, 113 /* get delta phase for optimal stroke position */
CALL[]
ADD[]

/* STACK: <dir>, <gp0>, <p0>, <c0>, <p1>, <c1>, <gp1>, <som>, <phase0>, <phase1> */
/* undo forwarding to stroke1 position */

#PUSH, 6 /* p1 */
CINDEX[]
#PUSH, 6 /* c1 */
CINDEX[]
#PUSH, 4 /* phase0 */
CINDEX[]
NEG[]
#PUSH, 2
SLOOP[]
SHPIX[]

/* STACK: <dir>, <gp0>, <p0>, <c0>, <p1>, <c1>, <gp1>, <som>, <phase0>, <phase1> */
/* determine double average phase error */

#PUSH, 2 /* phase0 */
CINDEX[]
#PUSH, 2 /* phase1 */
CINDEX[]
ADD[]

/* STACK: <dir>, <gp0>, <p0>, <c0>, <p1>, <c1>, <gp1>, <som>, <phase0>, <phase1>, <2*phaseError> */

DUP[]
#PUSH, 64
GTEQ[]
IF[]

    /* STACK: <dir>, <gp0>, <p0>, <c0>, <p1>, <c1>, <gp1>, <som>, <phase0>, <phase1>, <2*phaseError> */
    /* double average phase error >= 1 pixel, correct to the left */

    POP[]
    #PUSH, 64
    SUB[]
    SWAP[]
    #PUSH, 64
    SUB[]
    SWAP[]

ELSE[]

    /* STACK: <dir>, <gp0>, <p0>, <c0>, <p1>, <c1>, <gp1>, <som>, <phase0>, <phase1>, <2*phaseError> */

    #PUSH, -64
    LT[]
    IF[]

        /* STACK: <dir>, <gp0>, <p0>, <c0>, <p1>, <c1>, <gp1>, <som>, <phase0>, <phase1>, <2*phaseError> */
        /* double average phase error < -1 pixel, correct to the right */

        #PUSH, 64
        ADD[]
        SWAP[]
        #PUSH, 64
        ADD[]
        SWAP[]

    EIF[]

EIF[]

/* STACK: <dir>, <gp0>, <p0>, <c0>, <p1>, <c1>, <gp1>, <som>, <phase0>, <phase1> */
/* apply corrected optimal phase0 to stroke0 */

#PUSH, 8 /* p0 */
CINDEX[]
#PUSH, 8 /* c0 */
CINDEX[]
#PUSH, 4 /* phase0 */
MINDEX[]
#PUSH, 2
SLOOP[]
SHPIX[]

/* STACK: <dir>, <gp0>, <p0>, <c0>, <p1>, <c1>, <gp1>, <som>, <phase1> */
/* apply corrected optimal phase1 to stroke1 */

#PUSH, 5 /* p1 */
CINDEX[]
#PUSH, 5 /* c1 */
CINDEX[]
ROLL[] /* phase1 */
#PUSH, 2
SLOOP[]
SHPIX[]

/* STACK: <dir>, <gp0>, <p0>, <c0>, <p1>, <c1>, <gp1>, <som> */

DUP[]
#PUSH, 0
GT[]
IF[]

    /* STACK: <dir>, <gp0>, <p0>, <c0>, <p1>, <c1>, <gp1>, <som> */
    /* determine total side-bearing space to see if we need to bias the black body */

    #PUSH, 6 /* p0 */
    CINDEX[]
    #PUSH, 8 /* gp0 */
    CINDEX[]
    MD[N]
    #PUSH, 3 /* gp1 */
    CINDEX[]
    #PUSH, 5 /* c1 */
    CINDEX[]
    MD[N]
    ADD[]
    DUP[]
    #PUSH, 64
    GT[]
    IF[]

        /* enough total side-bearing space left, leave it alone */
        POP[]

    ELSE[]

        /* 1 pixel or less total side-bearing space left */
        #PUSH, 0
        GT[]
        IF[]

            /* STACK: <dir>, <gp0>, <p0>, <c0>, <p1>, <c1>, <gp1>, <som> */
            /* any total side-bearing space left at all, move black-body flush left and start over */

            #PUSH, 6 /* p0 */
            CINDEX[]
            #PUSH, 6 /* c0 */
            CINDEX[]
            #PUSH, 6 /* p1 */
            CINDEX[]
            #PUSH, 6 /* c1 */
            CINDEX[]
            #PUSH, 11 /* gp0 */
            CINDEX[]
            #PUSH, 11 /* p0 */
            CINDEX[]
            MD[N]
            #PUSH, 4
            SLOOP[]
            SHPIX[]

            /* STACK: <dir>, <gp0>, <p0>, <c0>, <p1>, <c1>, <gp1>, <som> */
            /* optimize position of stroke0 forwarding phase0 to stroke1 */

            #PUSH, 6 /* p0 */
            CINDEX[]
            #PUSH, 6 /* c0 */
            CINDEX[]
            #PUSH, 6 /* p1 */
            CINDEX[]
            #PUSH, 6 /* c1 */
            CINDEX[]
            #PUSH, 10 /* p0 */
            CINDEX[]
            #PUSH, 10 /* c0 */
            CINDEX[]
            #PUSH, 7 /* som */
            CINDEX[]
            #PUSH, 113 /* get delta phase for optimal stroke position */
            CALL[]
            #PUSH, 4 /* apply to both strokes */
            SLOOP[]
            SHPIX[]

            /* STACK: <dir>, <gp0>, <p0>, <c0>, <p1>, <c1>, <gp1>, <som> */
            /* optimize position of stroke1 */

            #PUSH, 4 /* p1 */
            CINDEX[]
            #PUSH, 4 /* c1 */
            CINDEX[]
            #PUSH, 5 /* c1 */
            CINDEX[]
            #PUSH, 7 /* p1 */
            CINDEX[]
            #PUSH, 5 /* som */
            CINDEX[]
            #PUSH, 113 /* get delta phase for optimal stroke position */
            CALL[]
            #PUSH, 2 /* apply to second stroke only */
            SLOOP[]
            SHPIX[]

        ELSE[]

            /* STACK: <dir>, <gp0>, <p0>, <c0>, <p1>, <c1>, <gp1>, <som> */
            /* no total side-bearing space left, move stroke1 left by 1 pixel */

            #PUSH, 4 /* p1 */
            CINDEX[]
            #PUSH, 4 /* c1 */
            CINDEX[]
            #PUSH, -64, 2
            SLOOP[]
            SHPIX[]

        EIF[]

    EIF[]

EIF[]

/* STACK: <dir>, <gp0>, <p0>, <c0>, <p1>, <c1>, <gp1>, <som> */

POP[]
POP[]
POP[]
POP[]
POP[]
POP[]
POP[]
POP[]

#PUSHON
#END
ENDF[]

FDEF[], 118

/* fn to set pv perpendicular to p1 and c0' such that distance
   c0'<---p0 measures cvt or natural distance if cvt = -1.
   used as support to ResX|YDDist and ResX|YDLink

   CALL[], <p1>, <p0>, <c0>, <cvt>, 118 */

#BEGIN
#PUSHOFF

/* STACK: <p1>, <p0>, <c0>, <cvt> */

#PUSH, 4 /* p1 */
CINDEX[]
#PUSH, 3 /* c0 */
CINDEX[]
SDPVTL[R]
#PUSH, 3 /* p0 */
CINDEX[]
#PUSH, 3 /* c0 */
CINDEX[]
ROLL[] /* cvt */
DUP[]
#PUSH, 0
LT[]
IF[]
    POP[]
    #PUSH, 101 /* resActDist, noCvt, noMinDist */
ELSE[]
    #PUSH, 104 /* resActDist, cvt, minDist */
EIF[]
CALL[]
ABS[]

/* STACK: <p1>, <p0>, <c0>, <w> */

#PUSH, 4 /* p1 */
CINDEX[]
#PUSH, 4 /* p0 */
CINDEX[]
SPVTL[r]
#PUSH, 4 /* p1 */
CINDEX[]
#PUSH, 4 /* p0 */
CINDEX[]
MD[N]

/* STACK: <p1>, <p0>, <c0>, <w>, <d> */
/* test if solution exists at all */

DUP[]
DUP[]
MUL[]
#PUSH, 3 /* w */
CINDEX[]
DUP[]
MUL[]
LTEQ[]
#PUSH, 0, 3 /* d */
CINDEX[]
EQ[]
OR[]

/* STACK: <p1>, <p0>, <c0>, <w>, <d>, <d� <= w� or d = 0?> */

IF[]

    /* STACK: <p1>, <p0>, <c0>, <w>, <d> */
    /* solution doesn't exist, hence prepare to bail out */

    POP[]
    POP[]
    SWAP[]
    POP[]
    SPVTL[R]

ELSE[]

    /* STACK: <p1>, <p0>, <c0>, <w>, <d> */
    /* solution exists, hence continue computation */

    DUP[]
    MUL[]
    #PUSH, 2 /* w */
    CINDEX[]
    DUP[]
    MUL[]
    SUB[]
    DUP[]

    /* STACK: <p1>, <p0>, <c0>, <w>, <d� - w�>, <d� - w�> */

    #PUSH, 83 /* sqrt */
    CALL[]

    /* STACK: <p1>, <p0>, <c0>, <w>, <d� - w�>, <sqrt(d� - w�)> */

    ROLL[] /* w */
    MUL[]

    /* STACK: <p1>, <p0>, <c0>, <d� - w� =: dx>, <w�sqrt(d� - w�) =: dy> */

    #PUSH, 5 /* p1 */
    CINDEX[]
    #PUSH, 5 /* p0 */
    CINDEX[]
    SDPVTL[R]
    #PUSH, 4 /* p0 */
    CINDEX[]
    #PUSH, 4 /* c0 */
    MINDEX[]
    MD[O]

    #PUSH, 0
    LT[]
    IF[]
        NEG[] /* dy */
    EIF[]

    /* STACK: <p1>, <p0>, <dx>, <dy> */

    #PUSH, 4 /* p1 */
    MINDEX[]
    DUP[]
    SVTCA[X]
    GC[N]
    SWAP[]
    SVTCA[Y]
    GC[N]

    /* STACK: <p0>, <dx>, <dy>, <p1.x>, <p1.y> */

    #PUSH, 5 /* p0 */
    MINDEX[]
    DUP[]
    SVTCA[X]
    GC[N]
    SWAP[]
    SVTCA[Y]
    GC[N]

    /* STACK: <dx>, <dy>, <p1.x>, <p1.y>, <p0.x>, <p0.y> */

    #PUSH, 0 /* enter twilight zone */
    SZPS[]

    SVTCA[Y]
    #PUSH, 0
    SWAP[]
    SCFS[]
    SVTCA[X]
    #PUSH, 0
    SWAP[]
    SCFS[]

    /* STACK: <dx>, <dy>, <p1.x>, <p1.y> */

    SVTCA[Y]
    DUP[]
    #PUSH, 1
    SWAP[]
    SCFS[]
    #PUSH, 2
    SWAP[]
    SCFS[]
    SVTCA[X]
    DUP[]
    #PUSH, 1
    SWAP[]
    SCFS[]
    #PUSH, 2
    SWAP[]
    SCFS[]

    /* STACK: <dx>, <dy> */

    SWAP[]

    /* STACK: <dy>, <dx> */

    #PUSH, 2, 0, 1
    SFVTL[r]
    SWAP[]
    SHPIX[]

    /* STACK: <dy> */

    #PUSH, 2, 0, 1
    SFVTL[R]
    SWAP[]
    SHPIX[]

    /* STACK: */

    #PUSH, 2, 1
    SPVTL[R]

    #PUSH, 1 /* leave twilight zone */
    SZPS[]

EIF[]

#PUSHON
#END
ENDF[]

FDEF[], 119

/* align c with p unless fv is perpendicular to pv
   fv and pv assumed to be set prior to calling fn 119
   used as support to ResX|YDDist and ResX|YDLink

   CALL[], <p>, <c>, 119 */

#BEGIN
#PUSHOFF

/* STACK: <p>, <c> */

SWAP[]
SRP0[]

/* STACK: <c> */

GFV[]
GPV[]

/* STACK: <c>, <fv.x>, <fv.y>, <pv.x>, <pv.y> */

ROLL[]
MUL[]
SWAP[]
ROLL[]
MUL[]
ADD[]
ABS[]

/* STACK: <c>, <|pv.y*fv.y + pv.x*fv.x|> */

#PUSH, 16384, 1024
MUL[]

/* the above dot product multiplies two 2.14 numbers in 26.6 arithmetic yielding a 2.22 number (2^14 * 2^14 / 2^6 = 2^22)
   like the rasterizer, we're comparing this number to 1/16: |fv1�pv| < 1/16 means fv1 is within �arcsin(1/16) or �3.5833� perpendicular to pv
   in 2.22 format 1/16 is 2^18, but since the assembler won't allow us to push 2^18 = 262144, we make up this number as a multiplication
   the multiplication, in turn, is again done in 26.6 format, hence we multiply 16384 with 1024 (2^14 * 2^10 / 2^6 = 2^18) */

LT[]
IF[]

    /* fv is approximately perpendicular to pv which by itself is perpendicular
       to a line from p to c' (with c' the twilight point 2 computed in fn 118),
       i.e. fv is approximately parallel to line from p to c'. Given the usage
       of fn 119 this means that fv is approximately coincident with said line,
       or c is approximately aligned already, hence simply touch the point, but
       without involving the pv */

    /* STACK: <c> */

    #PUSH, 0
    SHPIX[]

ELSE[]

    /* STACK: <c> */

    ALIGNRP[]

EIF[]

/* STACK: */

#PUSHON
#END
ENDF[]

FDEF[], 120

/* support to ResX|YDDist and ResX|YDLink where fv0 and fv1 are x or y

   CALL[], <p0>, <c0>, <p1>, <c1>, <cvt0>, <cvt1>, <fv0>, <fv1>, 120 */

#BEGIN
#PUSHOFF

/* STACK: <p0>, <c0>, <p1>, <c1>, <cvt0>, <cvt1>, <fv0>, <fv1> */

#PUSH, 6 /* p1 */
CINDEX[]
#PUSH, 9 /* p0 */
CINDEX[]
#PUSH, 9 /* c0 */
CINDEX[]
#PUSH, 7 /* cvt0 */
MINDEX[]
#PUSH, 118
CALL[]

/* STACK: <p0>, <c0>, <p1>, <c1>, <cvt1>, <fv0>, <fv1> */

SWAP[]
#PUSH, 0 /* x? */
EQ[]
IF[]
  SFVTCA[X]
ELSE[]
  SFVTCA[Y]
EIF[]

/* STACK: <p0>, <c0>, <p1>, <c1>, <cvt1>, <fv1> */

#PUSH, 4 /* p1 */
CINDEX[]
#PUSH, 6 /* c0 */
MINDEX[]
#PUSH, 119
CALL[]

/* STACK: <p0>, <p1>, <c1>, <cvt1>, <fv1> */

#PUSH, 5 /* p0 */
CINDEX[]
#PUSH, 5 /* p1 */
MINDEX[]
#PUSH, 5 /* c1 */
CINDEX[]
#PUSH, 5 /* cvt1 */
MINDEX[]
#PUSH, 118
CALL[]

/* STACK: <p0>, <c1>, <fv1> */

#PUSH, 0 /* x? */
EQ[]
IF[]
  SFVTCA[X]
ELSE[]
  SFVTCA[Y]
EIF[]

/* STACK: <p0>, <c1> */

#PUSH, 119
CALL[]

/* STACK: */

#PUSHON
#END
ENDF[]

FDEF[], 121

/* support to ResX|YDDist and ResX|YDLink where fv0 is x or y while fv1 is to-line

   CALL[], <p0>, <c0>, <p1>, <c1>, <cvt0>, <cvt1>, <fv0>, <fv1.p0>, <fv1.p1>, 121 */

#BEGIN
#PUSHOFF

/* STACK: <p0>, <c0>, <p1>, <c1>, <cvt0>, <cvt1>, <fv0>, <fv1.p0>, <fv1.p1> */

#PUSH, 7 /* p1 */
CINDEX[]
#PUSH, 10 /* p0 */
CINDEX[]
#PUSH, 10 /* c0 */
CINDEX[]
#PUSH, 8 /* cvt0 */
MINDEX[]
#PUSH, 118
CALL[]

/* STACK: <p0>, <c0>, <p1>, <c1>, <cvt1>, <fv0>, <fv1.p0>, <fv1.p1> */

ROLL[]
#PUSH, 0 /* x? */
EQ[]
IF[]
  SFVTCA[X]
ELSE[]
  SFVTCA[Y]
EIF[]

/* STACK: <p0>, <c0>, <p1>, <c1>, <cvt1>, <fv1.p0>, <fv1.p1> */

#PUSH, 5 /* p1 */
CINDEX[]
#PUSH, 7 /* c0 */
MINDEX[]
#PUSH, 119
CALL[]

/* STACK: <p0>, <p1>, <c1>, <cvt1>, <fv1.p0>, <fv1.p1> */

#PUSH, 6 /* p0 */
CINDEX[]
#PUSH, 6 /* p1 */
MINDEX[]
#PUSH, 6 /* c1 */
CINDEX[]
#PUSH, 6 /* cvt1 */
MINDEX[]
#PUSH, 118
CALL[]

/* STACK: <p0>, <c1>, <fv1.p0>, <fv1.p1> */

SFVTL[r]

/* STACK: <p0>, <c1> */

#PUSH, 119
CALL[]

/* STACK: */

#PUSHON
#END
ENDF[]

FDEF[], 122

/* support to ResX|YDDist and ResX|YDLink where fv0 is to-line while fv1 is x or y

   CALL[], <p0>, <c0>, <p1>, <c1>, <cvt0>, <cvt1>, <fv0.p0>, <fv0.p1>, <fv1>, 122 */

#BEGIN
#PUSHOFF

/* STACK: <p0>, <c0>, <p1>, <c1>, <cvt0>, <cvt1>, <fv0.p0>, <fv0.p1>, <fv1> */

#PUSH, 7 /* p1 */
CINDEX[]
#PUSH, 10 /* p0 */
CINDEX[]
#PUSH, 10 /* c0 */
CINDEX[]
#PUSH, 8 /* cvt0 */
MINDEX[]
#PUSH, 118
CALL[]

/* STACK: <p0>, <c0>, <p1>, <c1>, <cvt1>, <fv0.p0>, <fv0.p1>, <fv1> */

ROLL[]
ROLL[]
SFVTL[r]

/* STACK: <p0>, <c0>, <p1>, <c1>, <cvt1>, <fv1> */

#PUSH, 4 /* p1 */
CINDEX[]
#PUSH, 6 /* c0 */
MINDEX[]
#PUSH, 119
CALL[]

/* STACK: <p0>, <p1>, <c1>, <cvt1>, <fv1> */

#PUSH, 5 /* p0 */
CINDEX[]
#PUSH, 5 /* p1 */
MINDEX[]
#PUSH, 5 /* c1 */
CINDEX[]
#PUSH, 5 /* cvt1 */
MINDEX[]
#PUSH, 118
CALL[]

/* STACK: <p0>, <c1>, <fv1> */

#PUSH, 0 /* x? */
EQ[]
IF[]
  SFVTCA[X]
ELSE[]
  SFVTCA[Y]
EIF[]

/* STACK: <p0>, <c1> */

#PUSH, 119
CALL[]

/* STACK: */

#PUSHON
#END
ENDF[]

FDEF[], 123

/* support to ResX|YDDist and ResX|YDLink where both fv0 and fv1 are to-line

   CALL[], <p0>, <c0>, <p1>, <c1>, <cvt0>, <cvt1>, <fv0.p0>, <fv0.p1>, <fv1.p0>, <fv1.p1>, 123 */

#BEGIN
#PUSHOFF

/* STACK: <p0>, <c0>, <p1>, <c1>, <cvt0>, <cvt1>, <fv0.p0>, <fv0.p1>, <fv1.p0>, <fv1.p1> */

#PUSH, 8 /* p1 */
CINDEX[]
#PUSH, 11 /* p0 */
CINDEX[]
#PUSH, 11 /* c0 */
CINDEX[]
#PUSH, 9 /* cvt0 */
MINDEX[]
#PUSH, 118
CALL[]

/* STACK: <p0>, <c0>, <p1>, <c1>, <cvt1>, <fv0.p0>, <fv0.p1>, <fv1.p0>, <fv1.p1> */

#PUSH, 4 /* fv0.p0 */
MINDEX[]
#PUSH, 4 /* fv0.p1 */
MINDEX[]
SFVTL[r]

/* STACK: <p0>, <c0>, <p1>, <c1>, <cvt1>, <fv1.p0>, <fv1.p1> */

#PUSH, 5 /* p1 */
CINDEX[]
#PUSH, 7 /* c0 */
MINDEX[]
#PUSH, 119
CALL[]

/* STACK: <p0>, <p1>, <c1>, <cvt1>, <fv1.p0>, <fv1.p1> */

#PUSH, 6 /* p0 */
CINDEX[]
#PUSH, 6 /* p1 */
MINDEX[]
#PUSH, 6 /* c1 */
CINDEX[]
#PUSH, 6 /* cvt1 */
MINDEX[]
#PUSH, 118
CALL[]

/* STACK: <p0>, <c1>, <fv1.p0>, <fv1.p1> */

SFVTL[r]

/* STACK: <p0>, <c1> */

#PUSH, 119
CALL[]

/* STACK: */

#PUSHON
#END
ENDF[]

FDEF[], 124

/* determine on which side of edge p0->p1 is c
   by calculating vector product (c - p0) ^ (p1 - p0)

   CALL[], <p0>, <c>, <p1>, 124

   returns with vector product on stack
   if vector product < 0 then c is on the left of p0->p1
   if vector product > 0 then c is on the right of p0->p1
   else c is exactly on p0->p1 */

#BEGIN
#PUSHOFF

/* STACK: <p0>, <c>, <p1> */

SPVTCA[X]
#PUSH, 3 /* p0 */
CINDEX[]
#PUSH, 3 /* c */
CINDEX[]
MD[O]
#PUSH, 4 /* p0 */
CINDEX[]
#PUSH, 3 /* p1 */
CINDEX[]
MD[O]

/* STACK: <p0>, <c>, <p1>, <a.x>, <b.x> */

SPVTCA[Y]
#PUSH, 5 /* p0 */
CINDEX[]
#PUSH, 5 /* c */
MINDEX[]
MD[O]
#PUSH, 5 /* p0 */
MINDEX[]
#PUSH, 5 /* p1 */
MINDEX[]
MD[O]

/* STACK: <a.x>, <b.x>, <a.y>, <b.y> */

#PUSH, 4 /* a.x */
MINDEX[]
MUL[]

ROLL[] /* b.x */
ROLL[] /* a.y */
MUL[]

SUB[]

/* STACK: <b.y*a.x - b.x*a.y> */

#PUSHON
#END
ENDF[]

FDEF[], 125

/* fn interpolates a pair of diagonal links between grand-parents gp0 and gp1 along pv
   pv: X = 0, Y = 1, X/ = 2; fv0 and fv1: x and y components in 2.14

   CALL[], <pv>, <gp0>, <p0>, <c0>, <cvt0>, <p1>, <c1>, <cvt1>, <gp1>, <fv0.x>, <fv0.y>, <fv1.x>, fv1.y>, 125 */

#BEGIN
#PUSHOFF

/* interpolate parents between grand-parents along pv */
/* STACK: <pv>, <gp0>, <p0>, <c0>, <cvt0>, <p1>, <c1>, <cvt1>, <gp1>, <fv0.x>, <fv0.y>, <fv1.x>, fv1.y> */

#PUSH, 93, 14 /* pv */
CINDEX[]
ADD[]
CALL[]

#PUSH, 12 /* gp0 */
MINDEX[]
SRP1[]
#PUSH, 5 /* gp1 */
MINDEX[]
SRP2[]

#PUSH, 10 /* p0 */
CINDEX[]
IP[]
#PUSH, 7 /* p1 */
CINDEX[]
IP[]

/* determine if this is a crisscrossed stroke */
/* STACK: <pv>, <p0>, <c0>, <cvt0>, <p1>, <c1>, <cvt1>, <fv0.x>, <fv0.y>, <fv1.x>, fv1.y> */

#PUSH, 10 /* p0 */
CINDEX[]
#PUSH, 10 /* c0 */
CINDEX[]
#PUSH, 9 /* p1 */
CINDEX[]
#PUSH, 124 /* c0 on which side of edge p0->p1? */
CALL[]
#PUSH, 0
LT[]

#PUSH, 11 /* p0 */
CINDEX[]
#PUSH, 8 /* c1 */
CINDEX[]
#PUSH, 10 /* p1 */
CINDEX[]
#PUSH, 124 /* c1 on which side of edge p0->p1? */
CALL[]
#PUSH, 0
LT[]

EQ[]
IF[]

    /* both childern on same side of parent edge p0>->p1
       hence re-align children with parents perp to dpv. */
    /* STACK: <pv>, <p0>, <c0>, <cvt0>, <p1>, <c1>, <cvt1>, <fv0.x>, <fv0.y>, <fv1.x>, fv1.y> */

    #PUSH, 7 /* p1 */
    CINDEX[]
    #PUSH, 11 /* p0 */
    CINDEX[]
    SDPVTL[R]

    #PUSH, 4 /* fv0.x */
    CINDEX[]
    #PUSH, 4 /* fv0.y */
    CINDEX[]
    SFVFS[]

    #PUSH, 10 /* p0 */
    CINDEX[]
    SRP0[]
    #PUSH, 9 /* c0 */
    CINDEX[]
    MDRP[m<rBl]

    #PUSH, 2 /* fv1.x */
    CINDEX[]
    #PUSH, 2 /* fv1.y */
    CINDEX[]
    SFVFS[]

    #PUSH, 7 /* p1 */
    CINDEX[]
    SRP0[]
    #PUSH, 6 /* c1 */
    CINDEX[]
    MDRP[m<rBl]

ELSE[]

    /* childern on opposite sides of "parent edge" p0>->p1
       hence re-align children with parents per method for crisscrossed strokes */
    /* STACK: <pv>, <p0>, <c0>, <cvt0>, <p1>, <c1>, <cvt1>, <fv0.x>, <fv0.y>, <fv1.x>, fv1.y> */

    #PUSH, 7 /* p1 */
    CINDEX[]
    #PUSH, 11 /* p0 */
    CINDEX[]
    #PUSH, 11 /* c0 */
    CINDEX[]
    #PUSH, -1, 118 /* no cvt0, no minDist */
    CALL[]

    /* STACK: <pv>, <p0>, <c0>, <cvt0>, <p1>, <c1>, <cvt1>, <fv0.x>, <fv0.y>, <fv1.x>, fv1.y> */

    #PUSH, 4 /* fv0.x */
    CINDEX[]
    #PUSH, 4 /* fv0.y */
    CINDEX[]
    SFVFS[]

    /* STACK: <pv>, <p0>, <c0>, <cvt0>, <p1>, <c1>, <cvt1>, <fv0.x>, <fv0.y>, <fv1.x>, fv1.y> */

    #PUSH, 7 /* p1 */
    CINDEX[]
    #PUSH, 10 /* c0 */
    CINDEX[]
    #PUSH, 119
    CALL[]

    /* STACK: <pv>, <p0>, <c0>, <cvt0>, <p1>, <c1>, <cvt1>, <fv0.x>, <fv0.y>, <fv1.x>, fv1.y> */

    #PUSH, 10 /* p0 */
    CINDEX[]
    #PUSH, 8 /* p1 */
    CINDEX[]
    #PUSH, 8 /* c1 */
    CINDEX[]
    #PUSH, -1, 118 /* no cvt1, no minDist */
    CALL[]

    /* STACK: <pv>, <p0>, <c0>, <cvt0>, <p1>, <c1>, <cvt1>, <fv0.x>, <fv0.y>, <fv1.x>, fv1.y> */

    #PUSH, 2 /* fv1.x */
    CINDEX[]
    #PUSH, 2 /* fv1.y */
    CINDEX[]
    SFVFS[]

    /* STACK: <p0>, <c1> */

    #PUSH, 10 /* p0 */
    CINDEX[]
    #PUSH, 7 /* c1 */
    CINDEX[]
    #PUSH, 119
    CALL[]

EIF[]

/* determine pre-link medians, measuring perpendicularly to p0->p1 */
/* STACK: <pv>, <p0>, <c0>, <cvt0>, <p1>, <c1>, <cvt1>, <fv0.x>, <fv0.y>, <fv1.x>, fv1.y> */

#PUSH, 10 /* p0 */
CINDEX[]
GC[N]
#PUSH, 10 /* c0 */
CINDEX[]
GC[N]
ADD[]

#PUSH, 8 /* p1 */
CINDEX[]
GC[N]
#PUSH, 8 /* c1 */
CINDEX[]
GC[N]
ADD[]

/* links */
/* STACK: <pv>, <p0>, <c0>, <cvt0>, <p1>, <c1>, <cvt1>, <fv0.x>, <fv0.y>, <fv1.x>, fv1.y>, <median0>, <median1> */

#PUSH, 6 /* fv0.x */
CINDEX[]
#PUSH, 6 /* fv0.y */
CINDEX[]
SFVFS[]

#PUSH, 12 /* p0 */
CINDEX[]
#PUSH, 12 /* c0 */
CINDEX[]
#PUSH, 12 /* cvt0 */
MINDEX[]
DUP[]
#PUSH, 0
LT[]
IF[]
    POP[]
    #PUSH, 106 /* resMIRP, noCvt, minDist */
ELSE[]
    #PUSH, 108 /* resMIRP, cvt, minDist */
EIF[]
CALL[]

/* STACK: <pv>, <p0>, <c0>, <p1>, <c1>, <cvt1>, <fv0.x>, <fv0.y>, <fv1.x>, fv1.y>, <median0>, <median1> */

#PUSH, 4 /* fv1.x */
CINDEX[]
#PUSH, 4 /* fv1.y */
CINDEX[]
SFVFS[]

#PUSH, 9 /* p1 */
CINDEX[]
#PUSH, 9 /* c1 */
CINDEX[]
#PUSH, 9 /* cvt1 */
MINDEX[]
DUP[]
#PUSH, 0
LT[]
IF[]
    POP[]
    #PUSH, 106 /* resMIRP, noCvt, minDist */
ELSE[]
    #PUSH, 108 /* resMIRP, cvt, minDist */
EIF[]
CALL[]

/* subtract post-link medians from pre-link ones */
/* STACK: <pv>, <p0>, <c0>, <p1>, <c1>, <fv0.x>, <fv0.y>, <fv1.x>, fv1.y>, <median0>, <median1> */

SWAP[]

#PUSH, 10 /* p0 */
CINDEX[]
GC[N]
#PUSH, 10 /* c0 */
CINDEX[]
GC[N]
ADD[]

SUB[]
#PUSH, 32
MUL[]

SWAP[]

#PUSH, 8 /* p1 */
CINDEX[]
GC[N]
#PUSH, 8 /* c1 */
CINDEX[]
GC[N]
ADD[]

SUB[]
#PUSH, 32
MUL[]

/* finally move points by respective deltas */
/* STACK: <pv>, <p0>, <c0>, <p1>, <c1>, <fv0.x>, <fv0.y>, <fv1.x>, fv1.y>, <delta0>, <delta1> */

#PUSH, 1, 12 /* pv */
CINDEX[]
EQ[]
IF[]
    SFVTCA[Y]
ELSE[]
    SFVTCA[X]
EIF[]

#PUSH, 10 /* p0 */
MINDEX[]
DUP[]
SRP0[]
#PUSH, 3 /* delta0 */
CINDEX[]
MSIRP[m]

#PUSH, 6 /* fv0.x */
MINDEX[]
#PUSH, 6 /* fv0.y */
MINDEX[]
SFVFS[]

#PUSH, 7 /* c0 */
MINDEX[]
DUP[]
SRP0[]
ROLL[] /* delta0 */
MSIRP[m]

/* STACK: <pv>, <p1>, <c1>, <fv1.x>, fv1.y>, <delta1> */

#PUSH, 1, 7 /* pv */
MINDEX[]
EQ[]
IF[]
    SFVTCA[Y]
ELSE[]
    SFVTCA[X]
EIF[]

#PUSH, 5 /* p1 */
MINDEX[]
DUP[]
SRP0[]
#PUSH, 2 /* delta1 */
CINDEX[]
MSIRP[m]

ROLL[] /* fv0.x */
ROLL[] /* fv0.y */
SFVFS[]

SWAP[] /* c1 */
DUP[]
SRP0[]
SWAP[] /* delta1 */
MSIRP[m]

/* STACK: */

#PUSHON
#END
ENDF[]

FDEF[], 126

/* glue code to fn 125 where both fv0 and fv1 are x or y

   CALL[], <pv>, <gp0>, <p0>, <c0>, <cvt0>, <p1>, <c1>, <cvt1>, <gp1>, <fv0>, <fv1>, 126 */

#BEGIN
#PUSHOFF

/* STACK: <pv>, <gp0>, <p0>, <c0>, <cvt0>, <p1>, <c1>, <cvt1>, <gp1>, <fv0>, <fv1> */

SWAP[] /* fv0 */
#PUSH, 1
EQ[]
IF[]
    #PUSH, 0, 16384
ELSE[]
    #PUSH, 16384, 0
EIF[]

ROLL[] /* fv1 */
#PUSH, 1
EQ[]
IF[]
    #PUSH, 0, 16384
ELSE[]
    #PUSH, 16384, 0
EIF[]

#PUSH, 125 /* resIPDDLink */
CALL[]

#PUSHON
#END
ENDF[]

FDEF[], 127

/* glue code to fn 125 where fv0 is to line and fv1 is x or y

   CALL[], <pv>, <gp0>, <p0>, <c0>, <cvt0>, <p1>, <c1>, <cvt1>, <gp1>, <fv0.0>, <fv0.1>, <fv1>, 127 */

#BEGIN
#PUSHOFF

/* STACK: <pv>, <gp0>, <p0>, <c0>, <cvt0>, <p1>, <c1>, <cvt1>, <gp1>, <fv0.0>, <fv0.1>, <fv1> */

ROLL[] /* fv0.0 */
ROLL[] /* fv0.1 */
SFVTL[r]
GFV[]

ROLL[] /* fv1 */
#PUSH, 1
EQ[]
IF[]
    #PUSH, 0, 16384
ELSE[]
    #PUSH, 16384, 0
EIF[]

#PUSH, 125 /* resIPDDLink */
CALL[]

#PUSHON
#END
ENDF[]

FDEF[], 128

/* glue code to fn 125 where fv0 is x or y and fv1 is to line

   CALL[], <pv>, <gp0>, <p0>, <c0>, <cvt0>, <p1>, <c1>, <cvt1>, <gp1>, <fv0>, <fv1.0>, <fv1.1>, 128 */

#BEGIN
#PUSHOFF

/* STACK: <pv>, <gp0>, <p0>, <c0>, <cvt0>, <p1>, <c1>, <cvt1>, <gp1>, <fv0>, <fv1.0>, <fv1.1> */

SFVTL[r]

#PUSH, 1
EQ[]
IF[]
    #PUSH, 0, 16384
ELSE[]
    #PUSH, 16384, 0
EIF[]

GFV[]

#PUSH, 125 /* resIPDDLink */
CALL[]

#PUSHON
#END
ENDF[]

FDEF[], 129

/* glue code to fn 125 where both fv0 and fv1 are to line

   CALL[], <pv>, <gp0>, <p0>, <c0>, <cvt0>, <p1>, <c1>, <cvt1>, <gp1>, <fv0.0>, <fv0.1>, <fv1.0>, <fv1.1>, 129 */

#BEGIN
#PUSHOFF

/* STACK: <pv>, <gp0>, <p0>, <c0>, <cvt0>, <p1>, <c1>, <cvt1>, <gp1>, <fv0.0>, <fv0.1>, <fv1.0>, <fv1.1> */

#PUSH, 4 /* fv0.0 */
MINDEX[]
#PUSH, 4 /* fv0.1 */
MINDEX[]
SFVTL[r]
GFV[]
#PUSH, 4 /* fv1.0 */
MINDEX[]
#PUSH, 4 /* fv1.1 */
MINDEX[]
SFVTL[r]
GFV[]
#PUSH, 125 /* resIPDDLink */
CALL[]

#PUSHON
#END
ENDF[]

FDEF[], 130

/* extrapolate x-coordinate of <p> to base line along italic angle
   returns with extrapolated x-coordinate on stack

   CALL[], <p>, 130 */

#BEGIN
#PUSHOFF

DUP[]
SVTCA[X]
GC[N]
SWAP[]
SVTCA[Y]
GC[N]

/* STACK: <p.x>, <p.y> */

#PUSH, 10 /* rise */
RS[]
#PUSH, 11 /* run */
RS[]

/* STACK: <p.x>, <p.y>, <rise>, <run> */

ROLL[]
MUL[]
SWAP[]
DIV[]
SUB[]

/* STACK: <p.x - p.y*run/rise> */

#PUSHON
#END
ENDF[]

FDEF[], 131

/* constrains an italic stroke, defined by parents <p0> and <p1>, by
   children <c0> and <c1>, and by cvts <cvt0> and <cvt1>, and inter-
   polates it between points <lsb> and <rsb>

   for b&w stroke additionally optimizes the resulting pixel pattern

   CALL[], <lsb>, <rsb>, <p0>, <p1>, <c0>, <c1>, <cvt0>, <cvt1>, 131 */

#BEGIN
#PUSHOFF

/* STACK: <lsb>, <rsb>, <p0>, <p1>, <c0>, <c1>, <cvt0>, <cvt1> */

#PUSH, 9 /* pv perp italic, fv X */
CALL[]

/* lock parent edge */

#PUSH, 6 /* p0 */
CINDEX[]
MDAP[r]

#PUSH, 5 /* p1 */
CINDEX[]
RDTG[]
MDRP[m<RBl]

/* link child edge */

#PUSH, 6 /* p0 */
CINDEX[]
#PUSH, 5 /* c0 */
CINDEX[]
#PUSH, 4 /* cvt0 */
CINDEX[]
DUP[]
#PUSH, 0
LT[]
IF[]
    POP[]
    #PUSH, 106 /* resMIRP, noCvt, minDist */
ELSE[]
    #PUSH, 108 /* resMIRP, cvt, minDist */
EIF[]
CALL[]

#PUSH, 5 /* p1 */
CINDEX[]
#PUSH, 4 /* c1 */
CINDEX[]
#PUSH, 3 /* cvt1 */
CINDEX[]
DUP[]
#PUSH, 0
LT[]
IF[]
    POP[]
    #PUSH, 106 /* resMIRP, noCvt, minDist */
ELSE[]
    #PUSH, 108 /* resMIRP, cvt, minDist */
EIF[]
CALL[]

RTG[]

/* STACK: <lsb>, <rsb>, <p0>, <p1>, <c0>, <c1>, <cvt0>, <cvt1> */
/* interpolate median of p0 and c0 between lsb and rsb */

#PUSH, 8 /* lsb */
CINDEX[]
#PUSH, 7 /* p0 */
CINDEX[]
#PUSH, 6 /* c0 */
CINDEX[]
#PUSH, 10 /* rsb */
CINDEX[]
#PUSH, 111 /* interpolate median */
CALL[]

/* STACK: <lsb>, <rsb>, <p0>, <p1>, <c0>, <c1>, <cvt0>, <cvt1> */
/* if the two actual parent->child distances round to the same stroke weight */

#PUSH, 6 /* p0 */
CINDEX[]
#PUSH, 5 /* c0 */
CINDEX[]
#PUSH, 4 /* cvt0 */
MINDEX[]
DUP[]
#PUSH, 0
LT[]
IF[]
    POP[]
    #PUSH, 102 /* resActDist, noCvt, minDist */
ELSE[]
    #PUSH, 104 /* resActDist, cvt, minDist */
EIF[]
CALL[]

/* STACK: <lsb>, <rsb>, <p0>, <p1>, <c0>, <c1>, <cvt1>, <[dist0]> */

#PUSH, 5 /* p1 */
CINDEX[]
#PUSH, 4 /* c1 */
CINDEX[]
#PUSH, 4 /* cvt1 */
MINDEX[]
DUP[]
#PUSH, 0
LT[]
IF[]
    POP[]
    #PUSH, 102 /* resActDist, noCvt, minDist */
ELSE[]
    #PUSH, 104 /* resActDist, cvt, minDist */
EIF[]
CALL[]

/* STACK: <lsb>, <rsb>, <p0>, <p1>, <c0>, <c1>, <[dist0]>, <[dist1]> */

EQ[]
IF[]

    /* STACK: <lsb>, <rsb>, <p0>, <p1>, <c0>, <c1> */
    /* adjust median of p1 and c1 in parallel */

    RDTG[]
    #PUSH, 4 /* p0 */
    CINDEX[]
    SRP0[]
    #PUSH, 3 /* p1 */
    CINDEX[]
    MDRP[m<RBl]

    #PUSH, 2 /* c0 */
    CINDEX[]
    SRP0[]
    #PUSH, 1 /* c1 */
    CINDEX[]
    MDRP[m<RBl]

    #PUSH, 5 /* rsb */
    MINDEX[]
    POP[]
    #PUSH, 5 /* lsb */
    MINDEX[]
    POP[]

    /* STACK: <p0>, <p1>, <c0>, <c1> */

ELSE[]

    /* STACK: <lsb>, <rsb>, <p0>, <p1>, <c0>, <c1> */
    /* interpolate median of p1 and c1 between lsb and rsb independently */

    #PUSH, 6 /* lsb */
    MINDEX[]
    #PUSH, 4 /* p1 */
    CINDEX[]
    #PUSH, 3 /* c1 */
    CINDEX[]
    #PUSH, 8 /* rsb */
    MINDEX[]
    #PUSH, 111 /* interpolate median */
    CALL[]

    /* STACK: <p0>, <p1>, <c0>, <c1> */

EIF[]

/* STACK: <p0>, <p1>, <c0>, <c1> */
/* for b&w only optimize pixel pattern */

#PUSH, 0, 2
RS[]
EQ[]
IF[]

    /* STACK: <p0>, <p1>, <c0>, <c1> */
    /* extrapolate c0 to base line */

    RDTG[]
    #PUSH, 2 /* c0 */
    CINDEX[]
    #PUSH, 130
    CALL[]

    /* extrapolate p0 to base line */

    #PUSH, 5 /* p0 */
    CINDEX[]
    #PUSH, 130
    CALL[]

    /* get parentPhase from extrapolated x-coordinate */

    DUP[]
    DUP[]
    ROUND[Bl]
    SUB[]

    #PUSH, 4 /* targetPhase */
    RS[]

    /* STACK: <p0>, <p1>, <c0>, <c1>, <c0.x'>, <p0.x'>, <parentPhase>, <targetPhase> */
    /* shifting parent edge by deltaPhase optimizes stepping pattern on parent edge */

    SVTCA[X]
    SWAP[]
    SUB[]

    /* STACK: <p0>, <p1>, <c0>, <c1>, <c0.x'>, <p0.x'>, <deltaPhase> */
    /* minimize the positioning error by mapping deltaPhase from [-63,63] to [-32,31] */

    #PUSH, 96
    ADD[]
    DUP[]
    ROUND[Bl]
    SUB[]
    #PUSH, 32
    SUB[]

    /* STACK: <p0>, <p1>, <c0>, <c1>, <c0.x'>, <p0.x'>, <deltaPhase> */
    /* save minimized deltaPhase for child edge and shift parent edge */

    DUP[]
    #PUSH, 8 /* p0 */
    MINDEX[]
    #PUSH, 8 /* p1 */
    MINDEX[]
    ROLL[]
    #PUSH, 2
    SLOOP[]
    SHPIX[]

    /* STACK: <c0>, <c1>, <c0.x'>, <p0.x'>, <deltaPhase> */
    /* since child edge is linked perpendicular to italic angle,
       the resulting stroke would include unnecessary pixels,
       hence determine phase of distance between extrapolated
       x-coordinates (deltaDeltaPhase) */

    ROLL[]
    ROLL[]
    SUB[]
    DUP[]
    ROUND[Bl]
    SUB[]

    /* STACK: <c0>, <c1>, <deltaPhase>, <deltaDeltaPhase> */
    /* subtract from deltaPhase (don't shift quite as far...) */

    SUB[]

    /* STACK: <c0>, <c1>, <deltaPhase'> */
    /* shift parent edge */

    #PUSH, 2
    SLOOP[]
    SHPIX[]

    /* STACK: */

ELSE[]

    /* STACK: <p0>, <p1>, <c0>, <c1> */

    POP[]
    POP[]
    POP[]
    POP[]

    /* STACK: */

EIF[]

RTG[]

#PUSHON
#END
ENDF[]

FDEF[], 132

/* for monochrome only: stack points <p> through <c> on top of <p> below <ppem>

   CALL[], <p>, <c>, <ppem>, 132 */

#BEGIN
#PUSHOFF

/* STACK: <p>, <c>, <ppem> */

MPPEM[]
GT[]
#PUSH, 1, 2
RS[]
GTEQ[]
AND[]
IF[]

    /* STACK: <p>, <c> */

    SWAP[]
    SRP0[]
    DUP[]
    SVTCA[X]
    ALIGNRP[]
    SVTCA[Y]
    ALIGNRP[]

ELSE[]

    /* STACK: <p>, <c> */

    POP[]
    POP[]
EIF[]

#PUSHON
#END
ENDF[]

FDEF[], 133

/* support fn for fns 134 and 135

   CALL[], <align?>, <from>, <to>, 133 */

#BEGIN
#PUSHOFF

SWAP[]

/* STACK: <align?>, <to>, <from> */

#WBeginLoop133:

#PUSH, 2 /* to */
CINDEX[]
#PUSH, 2 /* from */
CINDEX[]
GTEQ[]
IF[]

    /* STACK: <align?>, <to>, <from> */

    DUP[]
    #PUSH, 4 /* align? */
    CINDEX[]
    IF[]
        ALIGNRP[]
    ELSE[]
        IP[]
    EIF[]

    #PUSH, 1
    ADD[]

    #PUSH, WOffset133
    JMPR[], (WOffset133=#WBeginLoop133)

EIF[]

/* STACK: <align?>, <to>, <from> */

POP[]
POP[]
POP[]

#PUSHON
#END
ENDF[]

FDEF[], 134

/* support fn for italic IUP[?]
   assume pv and fv are set externally

   CALL[], <p0>, <p1>, 134 */

#BEGIN
#PUSHOFF

/* STACK: <p0>, <p1> */

#PUSH, 2 /* p0 */
CINDEX[]
GC[O]
#PUSH, 2 /* p1 */
CINDEX[]
GC[O]
EQ[]

/* STACK: <p0>, <p1>, <eq?> */

ROLL[] /* p0 */
DUP[]
DUP[]
SRP0[]
SRP1[]
#PUSH, 1
ADD[]
ROLL[] /* p1 */
DUP[]
SRP2[]
#PUSH, 1
SUB[]

/* STACK: <eq?>, <from>, <to> */

#PUSH, 133
CALL[]

#PUSHON
#END
ENDF[]

FDEF[], 135

/* support fn for italic IUP[?]
   assume pv and fv are set externally

   CALL[], <p0>, <end>, <start>, <p1>, 135 */

#BEGIN
#PUSHOFF

/* STACK: <p0>, <end>, <start>, <p1> */

#PUSH, 4 /* p0 */
CINDEX[]
GC[O]
#PUSH, 2 /* p1 */
CINDEX[]
GC[O]
EQ[]

/* STACK: <p0>, <end>, <start>, <p1>, <eq?> */

SWAP[]
DUP[]
SRP2[]
#PUSH, 1
SUB[]
SWAP[]
DUP[]

#PUSH, 6 /* p0 */
MINDEX[]
DUP[]
DUP[]
SRP0[]
SRP1[]
#PUSH, 1
ADD[]
#PUSH, 6 /* end */
MINDEX[]

/* STACK: <start>, <to>, <eq?>, <eq?>, <from>, <end> */

#PUSH, 133
CALL[]

ROLL[]
ROLL[]
#PUSH, 133
CALL[]

#PUSHON
#END
ENDF[]

FDEF[], 150
/* Function 150 takes 5 arguments */
/* VERSION 1.0 20120420 */

/* This function moves a point between a PPEM range */
/* for the given rasterizer mode (in Store 2) ClearType */
/* CALL[],<point>,<amount>,<low PPEM>,<high PPEM>, <rasterizer mode>, 150 */
/* <low ppem> Lowest PPEM range to be modified (inclusive) */
/* <high ppem> Highest PPEM range to be modified (inclusive) */
/* <Point> point to be modified */
/* <amount> Amount to move point, in � 64ths */
/* <rasterizer mode> value in store 2 */
/* 150 Function number */
#BEGIN
#PUSHOFF
#PUSH, 2
RS[] /* read store 2 */
EQ[] /* is it = to the last arg? */
IF[] /* if so . . . */
    GPV[] /* Save current PV on stack to restore */
    SPVTCA[Y] /* We should only MPPEM with Y PV */
    ROLL[]
    MPPEM[] /* check cur. size against high ppem */
    GTEQ[]
    #PUSH, 4
    MINDEX[]
    MPPEM[] /* and low ppem */
    LTEQ[]
    AND[]
    IF[] /* if it's between, then */
        SPVFS[] /* Restore orig PV */
        SHPIX[] /* move the point by the amount */
    ELSE[]
       SPVFS[] /* Restore orig PV */
       POP[] /* otherwise remove the remaining arguments */
       POP[]
    EIF[]

ELSE[]
    POP[] /* remove the remaining arguments if the first test fails */
    POP[]
    POP[]
    POP[]
EIF[]
#END
#PUSHON
ENDF[]

FDEF[], 151
/* Function 151 takes 5 arguments */
/* VERSION 1.0 20120420 */

/* This function moves a point between a PPEM range */
/* for the given set of rasterizer flags (in Store 2) */
/* CALL[],<point>,<amount>,<low PPEM>,<high PPEM>, <rasterizer mode>, 151 */
/* <low ppem> Lowest PPEM range to be modified (inclusive) */
/* <high ppem> Highest PPEM range to be modified (inclusive) */
/* <Point> point to be modified */
/* <amount> Amount to move point, in � 64ths */
/* <rasterizer flag> bit of a value in store 2 */
/* Function 151 differs from Function 150 in that instead of requiring an */
/* exact match with the value in store 2, a given set of flags (or bit values) */
/* can be referenced. For example, if the function should execute */
/* in any situation where ClearType with fractional AWs is enabled, */
/* (c.f. Function 84) irrespective of other flags (e.g. BGR as opposed */
/* to RGB Devices or non-ClearType direction anti-aliasing) then one */
/* would use a <rasterizer flag> value of 64. (c.f. Function 84.) */
/* The rasterizer values for <rasterizer mode> are defined in the function */
/* 84 header. */
/* EXAMPLE: */
/* If one wanted the move to occur if either subpixel positioned or full gray pixel */
/* then one would take the 64 (from subpixel positioned) and the 256 (from */
/* gray full-pixel) and add them to get 320. With a value of 320, the point will */
/* get moved if either subpixel positioned or full gray pixel is enabled. */
/* If one wanted to move to occur always if ClearType was on, independent of */
/* any subtype or spacing flag, one would set the rasterizer mode to 2. */

/* 151 Function number */
#BEGIN
#PUSHOFF
#PUSH, 152 /* Call function 152 with the rasterizer mode on the top of stack */
CALL[]
IF[] /* if so . . . */
    GPV[] /* Save current PV on stack to restore */
    SPVTCA[Y] /* We should only MPPEM with Y PV */
    ROLL[]
    MPPEM[] /* check cur. size against high ppem */
    GTEQ[]
    #PUSH, 4
    MINDEX[]
    MPPEM[] /* and low ppem */
    LTEQ[]
    AND[]
    IF[] /* if it's between, then */
        SPVFS[] /* Restore orig PV */
        SHPIX[] /* move the point by the amount */
    ELSE[]
        SPVFS[] /* Restore orig PV */
        POP[] /* otherwise remove the remaining arguments */
        POP[]
    EIF[]

ELSE[]
    POP[] /* remove the remaining arguments if the first test fails */
    POP[]
    POP[]
    POP[]
EIF[]
#END
#PUSHON
ENDF[]

FDEF[], 152
/* Function 152 takes 1 argument, a "bitfield" flag. */
/* VERSION 1.0 20111117 */
/*
Function 152 is intended to take a set of one or more bits as input and do an AND (e.g. mask) of those
bits with the set of flags returned by Function 84. Then determine if there is at least one
of these resultant bits that are set.

Function 152 returns TRUE if the match is successful, and FALSE if it is not successful.

If the parameter is zero, indicating no flags, then the function returns FALSE.

This function takes a maxiumum of 32 bit flags.

USES: Storage 2 (FN 84)
RETURNS: 0 or 1
*/

#BEGIN
#PUSHOFF
/* Input parameter is a set of one or more flags */

DUP[]
#PUSH, 2     /* Read FN 84 flags */
RS[]
EQ[]         /* If a simple match, return TRUE */
#PUSH, 1
SWAP[]

#PUSH, BEcln
SWAP[]
JROT[], (BEcln=#LEndClear)  /* Jump to end and clean up stack. */
POP[]
#PUSH, 0, 2
RS[]         /* Read FN 84 flags */
#PUSH, BEclr /* If no FN 84 flags, return FALSE */
SWAP[]

JROF[], (BEclr=#LEndClear)

POP[]
#PUSH, 2
RS[]
SWAP[]
#PUSH, 32   /* Maximum number of bits to loop through */
/* TopLoop: */
#LTopLoop:
   /* STACK
   Loop Iteration Count
   Updated (shifted) Input Value
   Updated (shifted) FN 84 Flag
   */
  DUP[]
  NOT[]
  IF[]    /* Exit the loop when done */
    POP[]
    POP[]
    POP[]
    #PUSH, 0, BDEnd /* 73  End */

    JMPR[], (BDEnd=#LEndFn)

  EIF[]
  ROLL[]
  ROLL[]
  DUP[]
  ROLL[]
  DUP[]
  ROLL[]
  SWAP[]
  /* STACK
  Updated (shifted) FN 84 Flag
  Updated (shifted) Input Value
  Updated (shifted) FN 84 Flag
  Updated (Shifted) Input Value
  Loop Interation Count
  */

  /* Check to see if the lower-order bit is set in the FN 84 Flag */
  #PUSH, 4096 /* Convert to 26.6 by multiply by 64 x 64 */
  MUL[]
  ODD[]
  IF[]
    /* Check to see if the lower-order bit is set in the Input Value */
    #PUSH, 4096
    MUL[]
    ODD[]
    IF[]
      /* We can early out here once we find our first match */
      POP[]
      POP[]
      POP[]
      #PUSH, 1, BTEnd  /* 1 is the TRUE return code */
      JMPR[], (BTEnd=#LEndFn)
    EIF[]
  ELSE[]
    POP[]
  EIF[]
  /* STACK
  Updated (shifted) FN 84 Flag
  Updated (shifted) Input Value
  Loop Interation Count
  */
  /* Shift both the Input Value and the FN 84 Flag each one bit right */
  #PUSH, 128  /* 2 in 26.6 */
  DIV[]
  DUP[]
  NOT[]
  IF[]
    POP[]
    POP[]
    POP[]
    #PUSH, 0, BPEnd /* 0 is end condition of FALSE */

    JMPR[], (BPEnd=#LEndFn)

  EIF[]
  SWAP[]
  #PUSH, 128  /* 2 in 26.6 */
  DIV[]
  DUP[]
  NOT[]
  IF[]
    POP[]
    POP[]
    POP[]
    #PUSH, 0, BZEnd /* End */

    JMPR[], (BZEnd=#LEndFn) 

  EIF[]
  ROLL[]
  #PUSH, 1
  SUB[]
  #PUSH, WReLoop  /* -77 TopLoop */

JMPR[], (WReLoop=#LTopLoop)

/* EndClear: */
#LEndClear:
SWAP[]
POP[]
#LEndFn:
/* End: */
#END
#PUSHON
ENDF[]

FDEF[], 153
/* Function 153 takes 1 argument, a "bitfield" flag. */
/* VERSION 1.0 20111117 */
/*
Function 153 is intended to take a set of one or more bits as input and do an AND (e.g. mask) of those
bits with the set of flags returned by Function 84. Then determine if ALL
of these resultant bits from the mask are set.

Function 153 returns TRUE if the match is successful, and FALSE if it is not successful.

If the parameter is zero, indicating no flags, then the function returns FALSE.

This function takes a maxiumum of 32 flags.

USES: Storage 2 (FN 84)
RETURNS: 0 or 1
*/

#BEGIN
#PUSHOFF
/* Input parameter is a set of one or more flags */

DUP[]
#PUSH, 2     /* Read FN 84 flags */
RS[]
EQ[]         /* If a simple match, return TRUE */
#PUSH, 1
SWAP[]

#PUSH, BEcln
SWAP[]
JROT[], (BEcln=#LEndClear)  /* Jump to end and clean up stack. */
POP[]
#PUSH, 0, 2
RS[]         /* Read FN 84 flags */
#PUSH, BEclr /* If no FN 84 flags, return FALSE */
SWAP[]

JROF[], (BEclr=#LEndClear)

POP[]
#PUSH, 0, 2   /* 0 is the boolean tracking success, start off with FALSE */
RS[]
ROLL[]
#PUSH, 32   /* Maximum number of bits to loop through */
/* TopLoop: */
#LTopLoop:
   /* STACK
   Loop Iteration Count
   Updated (shifted) Input Value
   Updated (shifted) FN 84 Flag
   Conditional boolean tracking success
   */
  DUP[]
  NOT[]
  IF[]    /* Exit the loop when done */
    POP[]
    POP[]
    POP[]
    #PUSH, BDEnd /* 73  End */

    JMPR[], (BDEnd=#LEndFn)

  EIF[]
  ROLL[]
  ROLL[]
  DUP[]
  ROLL[]
  DUP[]
  ROLL[]
  SWAP[]
  /* STACK
  Updated (shifted) FN 84 Flag
  Updated (shifted) Input Value
  Updated (shifted) FN 84 Flag
  Updated (Shifted) Input Value
  Loop Interation Count
  Conditional boolean tracking success
  */

  /* Check to see if the lower-order bit is set in the FN 84 Flag */
  #PUSH, 4096 /* Convert to 26.6 by multiply by 64 x 64 */
  MUL[]
  ODD[]
  IF[]
    /* Check to see if the lower-order bit is set in the Input Value */
    #PUSH, 4096
    MUL[]
    ODD[]
    IF[]
      #PUSH, 4
      MINDEX[]
      #PUSH, 1  /* Set TRUE return code */
      OR[]      /* We OR this because we will immediately exit if we fail this test */
      #PUSH, 4
      MINDEX[]
      #PUSH, 4
      MINDEX[]
      #PUSH, 4
      MINDEX[]
    ELSE[]
      POP[]
      POP[]
      POP[]
      POP[]
      #PUSH, BTEnd , 0  /* 0 is the FALSE return code */
      SWAP[]
      JMPR[], (BTEnd=#LEndFn)

    EIF[]
  ELSE[]
    POP[]
  EIF[]
  #PUSH, 4 /* Can this be cleaned up and integrated with the code below? */
  MINDEX[]
  SWAP[]
  /* STACK
  Updated (shifted) FN 84 Flag
  Conditional boolean tracking success
  Updated (shifted) Input Value
  Loop Interation Count
  */
  /* Shift both the Input Value and the FN 84 Flag each one bit right */
  #PUSH, 128  /* 2 in 26.6 */
  DIV[]
  DUP[]
  NOT[]
  IF[]
    ROLL[]
    NOT[]
    ROLL[]
    AND[]
    SWAP[]
    POP[]
    SWAP[]
    POP[]
    #PUSH, BPEnd /* 29  End */

    JMPR[], (BPEnd=#LEndFn)

  EIF[]
  ROLL[]
  #PUSH, 128  /* 2 in 26.6 */
  DIV[]
  DUP[]
  NOT[]
  IF[]
    POP[]
    POP[]
    SWAP[]
    POP[]
    #PUSH, BZEnd /* End */

    JMPR[], (BZEnd=#LEndFn)

  EIF[]
  #PUSH, 4
  MINDEX[]
  #PUSH, 1
  SUB[]
  #PUSH, WReLoop  /* -77 TopLoop */

JMPR[], (WReLoop=#LTopLoop)

/* EndClear: */
#LEndClear:
SWAP[]
POP[]
#LEndFn:
/* End: */
#END
#PUSHON
ENDF[]






