共用方式為


The TrueType Instruction Set (OpenType 1.8)

TrueType provides instructions for each of the following tasks and a set of general purpose instructions. This chapter describes the TrueType instruction set. Instruction descriptions are organized by category based on their function.

  • Pushing data onto the interpreter stack
  • Managing the Storage Area
  • Managing the Control Value Table
  • Modifying Graphics State settings
  • Managing outlines
  • General purpose instructions

Anatomy of a TrueType Instruction

TrueType instructions are uniquely specified by their opcodes. For convenience, this book will refer to instructions by their names. Each instruction name is a mnemonic intended to aid in remembering that instruction’s function. For example, the MDAP instruction stands for Move Direct Absolute Point. Similarly, RUTG is short for Round Up To Grid. A brief description of each instruction clarifying the mnemonic marks the start of a new instruction.

One name may actually refer to several different but closely related instructions. A bracketed list of Boolean values follows each name to uniquely specify a particular variant of a given instruction. The Boolean list can be converted to a binary number and that number added to the base opcode for the instruction to obtain the opcode for any instruction variant.

To obtain the opcode for any instruction, take the lower of the two opcode values given in the code range and add the unsigned binary number represented by the list of binary digits. The left most bit is the most significant. For example, given an instruction with the opcode range 0xCO–0xDF and five Boolean flags (a through e) the opcode for a given instruction base can be computed as shown:

Opcode = 0xC0 + a · 24 + b · 23 + c · 22 + d · 21 + e · 20

If these flags were set to 11101 the code would be computed as follows:

0xC0 + 1 · 24 + 1 · 23 + 1 · 22 + 0 · 21 + 1 · 20

  • = 0xC0 + 0x10 + 0x8 + 0x4 + 0x1
  • = 0xC0 + 0x1D = 0xDD

Instruction opcodes are part of the instruction stream, a sequence of opcodes and data. The instruction stream is not a stack. While the stream of opcodes and data on the instruction stream is gradually used up, no new data is added to the instruction stream by the execution of another instruction (i.e. there is no equivalent of a push instruction that adds data to the instruction stream). It is possible to alter the flow of control through the instruction stream using one of the jump instructions described in a later section.

The instruction stream is shown as a sequence of opcodes and data. Since the instruction stream is 1-byte wide, words will be broken up into high bytes and low bytes with high bytes appearing first in the stream. For added readability, instruction names are used in illustrations instead of opcodes. An arrow will point to the next instruction awaiting execution.

A sequence has the NPUSHB instruction and following data. A separate sequence has the NPUSHW instruction with following data.
Figure 3–1 The instruction stream with a push byte instruction (left) and a push word instruction (right)

A few instructions known collectively as push instructions move data from the instruction stream to the interpreter stack. These instructions are unique in taking their arguments from the instruction stream. All other TrueType instructions take any data needed from the stack at the time they are executed. Any results produced by a TrueType instruction are pushed onto the interpreter stack.

An instruction that expects two arguments and pushes a third would expect the two arguments to be at the top of the stack. Any result pushed by that instruction appears at the top of the stack.

Representation of a stack with three elements 'a', 'b' and 'c'.
The listing a b c denotes a stack consisting of three elements with a being at the top of the stack, b being in the middle, and c at the bottom as shown.

To easily remember the order in which stack values are handled during arithmetic or logical operations, imagine writing the stack values from left to right, starting with the bottom value. Then insert the operator between the two furthest right elements. For example, subtract a,b would be interpreted as (b-a):

c b - a

GT a,b would be interpreted as (b>a):

c b > a

The statement push d, e means push d then push e adding two elements to the stack as shown.

Representation of a stack of elements 'a', 'b' and 'c', with another element 'd' pushed onto the top, and then another element 'e' subsequently pushed on top.

To indicate that the top two stack elements are to be removed the statement would be pop e, d.

Representation of a stack with element 'e' popped of the top, then another element 'd' popped off the top, leaving three elements 'a', 'b' and 'c'.

It has already been noted that the bracketed list of binary digits that follows the instruction name uniquely identifies an instruction variant. This is done by having the bits represent a list of Boolean flags that can be set to TRUE with a value of 1 or to FALSE with a value of 0. Binary digits that follow the name can also be grouped to form a larger binary number. In such cases, the documentation specifies the meaning associated with each possible numerical combination.

An instruction specification consists of the instruction name followed by its bracketed Boolean flags. Additional information describing the flags and explaining the stack interaction and any Graphics State dependencies is provided in tabular form:

Code Rangethe range of hexadecimal codes identifying this instruction and its variants
Flagsan explanation of the meaning of a bracketed binary number
From ISany arguments taken from the instruction stream by push instructions
Popsany arguments popped from the stack
Pushesany arguments pushed onto the stack
Usesany state variables whose value this instruction depends upon
Setsany state variables set by this instruction

Instruction descriptions include illustrations intended to clarify stack interactions, Graphics State effects, and changes to interpreter tables.

In the case of instructions that move points, an illustration will be provided to clarify the direction and magnitude of the movement. In these illustrations, shades of gray will be used to indicate the sequence in which points have been moved. The darker the fill, the more recently a point has been moved.

Data types

The instruction stream

Instruction opcodes are always bytes. Values in the instruction stream are bytes.

The stack

Values pushed onto the stack or popped from the stack are always 32 bit quantities (LONG or ULONG). When values that are less than 32 bits are pushed onto the stack, bytes are expanded to 32 bit quantities by padding the upper bits with zeroes and words are sign extended to 32 bits. In cases where two instruction stream bytes are combined to form a word, the high order bits appear first in the instruction stream.

Note: On a 16-bit system, such as Windows, all stack operations are on 16-bit values (SHORT or USHORT). Care must be taken to avoid overflow. It is also important to note that F26dot6 values (used for internal scalar math) are represented instead as 10 dot 6 values (i.e. the upper 16 bits are not supported).

Representation of a hexadecimal byte value FF being zero extended to a 32-bit value 0000 00FF.
Figure 3–2 A byte padded to a 32 bit long word (ULONG)
Representation of two hexadecimal byte values FF and D2 treated as a word that is extended to a 32-bit value FFFF FFD2.
Figure 3–3 A word sign extended to a 32 bit long word (ULONG)

All values on the stack are signed. Instructions, however, interpret these 32-bit quantities in a variety of ways. The interpreter variously understands quantities as integers and as fixed point numbers.

Values such as pixel coordinates are represented as 32-bit quantities consisting of 26 bits of whole number and 6 bits of fraction. These are fixed point numbers with the data type name F26Dot6.

The setting of the freedom_vector and projection_vector are represented as 2.14 fixed point numbers. The upper 16 bits of the 32 bit quantity are ignored.

A given set of 32 bits will have a different value depending upon how it is interpreted. The following 32 bit value interpreted as an integer has the value 264.

A 32-bit binary representation of the decimal value 264 (bits 8 and 4 are set).

The same 32 bit quantity interpreted as an F26Dot6 fixed point number has the value 4.125.

A 32-bit binary value with six fractional bits (bits 0 to 5) and 26 integer bits (bits 6 to 31). Bits 8 and 4 are set, representing the value 4.125.

The figure below gives several examples of expressing pixel values as 26.6 words.

Binary representations of four 26.6 values.

Pushing data onto the interpreter stack

Most TrueType instructions take their arguments from the interpreter stack. A few instructions, however, take their arguments from the instruction stream. Their purpose is to move data from the instruction stream to the interpreter stack. Collectively these instructions are known as the push instructions.

PUSH N Bytes

NPUSHB[ ]
Code Range0x40
From ISn: number of bytes to push (1 byte interpreted as an integer) b1, b2,...bn: sequence of n bytes
Pushesb1, b2, bn: sequence of n bytes each padded to 32 bits (ULONG)

Takes n unsigned bytes from the instruction stream, where n is an unsigned integer in the range (0..255), and pushes them onto the stack. n itself is not pushed onto the stack.

A sequence has the NPUshB instruction followed by an operand value n followed by n bytes of data. Also, data bytes 1 to n are pushed onto the stack.

PUSH N Words

NPUSHW[ ]
Code Range0x41
From ISn: number of words to push (one byte interpreted as an integer) w1, w2,...wn: sequence of n words formed from pairs of bytes, the high byte appearing first
Pushesw1, w2,...wn: sequence of n words each sign extended to 32 bits (LONG)

Takes n 16-bit signed words from the instruction stream, where n is an unsigned integer in the range (0..255), and pushes them onto the stack. n itself is not pushed onto the stack.

A sequence has the NPUSHW instruction followed by an operand value n followed by n words of data. Also, data words 1 to n are pushed onto the stack.

PUSH Bytes

PUSHB[abc]
Code Range0xB0 – 0xB7
abcnumber of bytes to be pushed - 1
From ISb0, b1,..bn: sequence of n + 1 bytes
Pushesb0, b1, ...,bn: sequence of n + 1 bytes each padded to 32 bits (ULONG)

Takes the specified number of bytes from the instruction stream and pushes them onto the interpreter stack.

The variables a, b, and c are binary digits representing numbers from 000 to 111 (0-7 in binary). Because the actual number of bytes (n) is from 1 to 8, 1 is automatically added to the ABC figure to obtain the actual number of bytes pushed.

A sequence has the PUSHB[abc] instruction followed by n bytes of data. Also, data bytes 1 to n are pushed onto the stack.

Example:

A sequence has the PUSHB[010] instruction followed by three bytes of data. Also, the three bytes of data are pushed onto the stack.

PUSH Words

PUSHW[abc]
Code Range0xB8 - 0xBF
abcnumber of words to be pushed - 1.
From ISw0,w1,..wn: sequence of n+1 words formed from pairs of bytes, the high byte appearing first
Pushesw0, w1,...wn: sequence of n+1 words each sign extended to 32 bits (LONG)

Takes the specified number of words from the instruction stream and pushes them onto the interpreter stack.

The variables a, b, and c are binary digits representing numbers from 000 to 111 (0-7 binary). Because the actual number of bytes (n) is from 1 to 8, 1 is automatically added to the abc figure to obtain the actual number of bytes pushed.

A sequence has the PUSHW[abc] instruction followed by n words (byte pairs) of data. Also, data words 1 to n are pushed onto the stack.

Example:

A sequence has the PUSHW[001] instruction followed by two words (four bytes) of data. Also, the two words of data are pushed onto the stack.

Managing the Storage Area

The interpreter Storage Area is a block of memory that can be used to store and later access 32 bit values. Instructions exist for writing values to the Storage Area and retrieving values from the Storage Area. Attempting to read a value from a storage location that has not previously had a value written to it will yield unpredictable results.

Read Store

RS[ ]
Code Range0x43
Popslocation: Storage Area location (ULONG)
Pushesvalue: Storage Area value (ULONG)
GetsStorage Area value

This instruction reads a 32 bit value from the Storage Area location popped from the stack and pushes the value read onto the stack. It pops an address from the stack and pushes the value found in that Storage Area location to the top of the stack. The number of available storage locations is specified in the maxProfile table in the font file.

A location is popped off the stack, and a value is pushed onto the stack.

Example:

A sequence has the RS[] instruction. Also, a storage area holds the value 0x0000 001B at location 2. Also, 2 is popped off the stack, and the value 0x0000 001B is pushed onto the stack.
The effect of the RS instruction is to push the value 0x1B of the Storage Area onto the Stack.

Write Store

WS[ ]
Code Range0x42
Popsvalue: Storage Area value (ULONG)
location: Storage Area location (ULONG)
Pushes
GetsStorage Area value

This instruction writes a 32 bit value into the storage location indexed by locations. It works by popping a value and then a location from the stack. The value is placed in the Storage Area location specified by that address. The number of storage locations is specified in the maxProfile table in the font file.

A value and then a location are popped of the stack. Also, the value is stored at that location in a storage area.

Example:

A sequence has the WS[] instruction. Also, the value 0x0000 0118 is popped off the stack, then the location 3A is popped off the stack, and the value 0x0000 0118 is stored at location 3A.
Write the value 0x0000 0118 to location 3A in the Storage Area.

Managing the Control Value Table

The Control Value Table stores information that is accessed by the indirect instructions. Values can be written to the CVT in FUnits or pixel units as proves convenient. Values read from the CVT are always in pixels (F26Dot6). This table, unlike the Storage Area, is initialized by the font and is automatically scaled.

Write Control Value Table in Pixel units

WCVTP[ ]
Code Range0x44
Popsvalue: number in pixels (F26Dot6 fixed point number)
location: Control Value Table location (ULONG)
Pushes
SetsControl Value Table entry

Pops a location and a value from the stack and puts that value in the specified location in the Control Value Table. This instruction assumes the value is in pixels and not in FUnits.

A pixel value and a location are popped off the stack. Tthe value is stored at that location in the Control Value Table.

Write Control Value Table in FUnits

WCVTF[ ]
Code Range0x70
Popsvalue: number in FUnits (ULONG)
location: Control Value Table location (ULONG)
Pushes
SetsControl Value Table entry

Pops a location and a value from the stack and puts the specified value in the specified address in the Control Value Table. This instruction assumes the value is expressed in FUnits and not pixels. The value is scaled before being written to the table.

An FUnit value and a location are popped of the stack. The value is stored at that location in the Control Value Table.

Read Control Value Table

RCVT[ ]
Code Range0x45
Popslocation: CVT entry number (ULONG)
Pushesvalue: CVT value (F26Dot6)
GetsControl Value Table entry

Pops a location from the stack and pushes the value in the location specified in the Control Value Table onto the stack.

A location is popped off the stack. The Control Value Table has a certain value at that location. That value is pushed onto the stack.

Managing the Graphics State

Instructions can be used to set the value of Graphics State variables and, in some cases, to retrieve their current value.

Getting a value

Instructions that retrieve the value of a state variable have names that begin with the word get. Get instructions will return the value of the state variable in question by placing that value on the top of the stack.

The illustration shows the effect of a GPV or get projection_vector instruction. It takes the x and y components of the projection_vector from the Graphics State and places them on the stack.

A projection vector variable has (x, y) values of (1, 0). 0 is pushed onto the stack, then 1 is pushed onto the stack.

Setting a value

Instructions that change the value of a Graphics State variable have a name that begins with the word set. Set instructions expect their arguments to be at the top of the interpreter stack

1 is popped off the stack, then 0 is popped off the stack. (1, 0) are set as the (x, y) values of a projection vector variable.
Figure 3–4 Setting the value of the Graphics State variable projection_vector

In addition to simple sets and gets, some instructions exist to simplify management of the values of state variables. For example, a number of instructions exist to set the direction of the freedom_vector and the projection_vector. In setting a vector, it is possible to set it to either of the coordinate axes, to the direction specified by a line, or to a direction specified by values taken from the stack. An instruction exists that directly sets the freedom_vector to the same value as the projection_vector.

Set freedom and projection Vectors To Coordinate Axis

SVTCA[a]
Code Range0x00 - 0x01
a0: set vectors to the y-axis
1: set vectors to the x-axis
Pops-
Pushes-
Setsprojection_vector
freedom_vector

Sets both the projection_vector and freedom_vector to the same one of the coordinate axes.

The SVTCA is a shortcut for using both the SFVTCA and SPVTCA instructions. SVTCA[1] is equivalent to SFVTCA[1] followed by SPVTCA[1]. This instruction ensures that both movement and measurement are along the same coordinate axis.

Example:

SVTCA[1]

Projection and freedom vectors are both set in the x direction.
Sets both measurement and movement to the x direction.

SVTCA[0]

Projection and freedom vectors are both set in the y direction.
Sets both measurement and movement to the y direction.

Set Projection_Vector To Coordinate Axis

SPVTCA[a]
Code Range0x02 - 0x03
a0: set the projection_vector to the y-axis
1: set the projection_vector to the x-axis
Pops-
Pushes-
Setsprojection_vector

Sets the projection_vector to one of the coordinate axes depending on the value of the flag a.

Example:

SPVTCA[0]

The projection vector is set in the y direction.
Sets the projection_vector to the y-axis assuring the measurement will be in that direction.

Set Freedom_Vector to Coordinate Axis

SFVTCA[a]
Code Range0x04 - 0x05
a0: set the freedom_vector to the y-axis
1: set the freedom_vector to the x-axis
Pops-
Pushes-
Setsfreedom_vector

Sets the freedom_vector to one of the coordinate axes depending upon the value of the flag a.

Example:

SFVTCA[0]

The freedom vector is set in the y direction.
Sets the freedom_vector to the y-axis ensuring that movement will be along that axis.

Set Projection_Vector To Line

SPVTL[a]
Code Range0x06 - 0x07
a0: sets projection_vector to be parallel to line segment from p1 to p2
1: sets projection_vector to be perpendicular to line segment from p1 to p2; the vector is rotated counter clockwise 90 degrees
Popsp1: point number (ULONG)
p2: point number (ULONG)
Pushes-
Usespoint p1 in the zone pointed at by zp2
point p2 in the zone pointed at by zp1
Setsprojection_vector

Sets the projection_vector to a unit vector parallel or perpendicular to the line segment from point p1 to point p2.

Example:

A sequence has the SPVTL[a] instruction. Value p1, then p2, are popped off the stack. The projection vector is set in the same direction as a line from p1 to p2.
If parallel, the projection_vector points from p1 toward p2 as shown.
The projection vector is set in a direction perpendicular to the direction of the projection vector in the previous figure.
If perpendicular the projection_vector is obtained by rotating the parallel vector in a counter clockwise manner as shown.

Case 1:

SPVTL[1]

A sequence has the SPVTL[0] instruction. The values 7 and 14 are popped off the stack. The projection vector is set in the same direction as a line from point 7 to point 14.
Sets the projection_vector to be parallel to the line from point 7 to point 14.

Case 2:

SPVTL[1]

A sequence has the SPVTL[1] instruction. The values 7 and 14 popped off the stack. The projection vector is set in the direction perpendicular to a line from point 7 to point 14.
Sets the projection_vector to be perpendicular to the line from point 7 to point 14.

Case 3:

SPVTL[1]

A sequence has the SPVTL[1] instruction. The values 14 and 7 are popped off the stack. The projection vector is set in the direction perpendicular to a line from point 14 to point 7.
The order in which the points are specified matters. This instruction sets the projection_vector to be perpendicular to the line from point 14 to point 7.

Set Freedom_Vector To Line

SFVTL[a]
Code Range0x08 - 0x09
a0: set freedom_vector to be parallel to the line segment defined by points p1 and p2
1: set freedom_vector perpendicular to the line segment defined by points p1 and p2; the vector is rotated counter clockwise 90 degrees
Popsp1: point number (ULONG)
p2: point number (ULONG)
Pushes-
Setsfreedom_vector
Usespoint p1 in the zone pointed at by zp2
point p2 in the zone pointed at by zp1
The values p1 and p2 are popped off the stack. A line is shown from p1 to p2.
Sets the freedom_vector to a unit vector parallel or perpendicular to the line segment defined by points p1 and p2.
The freedom vector is set in the same direction as the line in the previous figure.
If parallel the freedom_vector points from p1 toward p2 as shown.
The freedom vector is set perpendicular to the line in the previous figure.
If perpendicular the freedom_vector is obtained by rotating the parallel vector in a counter clockwise manner as shown.

Set Freedom_Vector To Projection Vector

SFVTPV[ ]
Code0x0E
Pops-
Pushes-
Setsfreedom_vector

Sets the freedom_vector to be the same as the projection_vector.

The projection vector and the freedom vector have different directions.
Before
The projection vector and the freedom vector have the same direction.
After

Set Dual Projection_Vector To Line

SDPVTL[a]
Code Range0x86 - 0x87
a0: Vectors are parallel to line
1: Vectors are perpendicular to line
Popsp1: first point number (ULONG)
p2: p2: second point number (ULONG)
Pushes-
Setsdual_projection_vector and projection_vector
Usespoint p1 in the zone pointed at by zp2
point p2 in the zone pointed at by zp1

Pops two point numbers from the stack and uses them to specify a line that defines a second, dual_projection_vector. This dual_projection_vector uses coordinates from the scaled outline before any grid-fitting took place. It is used only with the IP, GC, MD, MDRP and MIRP instructions. Those instructions will use the dual_projection_vector when they measure distances between ungrid-fitted points. The dual_projection_vector will disappear when any other instruction that sets the projection_vector is used.

A sequence has the SDPVTL[a] instruction. The values p1 and p2 are popped from the stack. A projection vector is set in the direction of the line from p1 to p2. A separate line is shown with p1 and p2 in different positions, and a dual projection vector is set in the direction of that line.
NOTE: The dual_projection_vector is set parallel to the points as they appeared in the original outline before any grid-fitting took place.

Set Projection_Vector From Stack

SPVFS[ ]
Code Range0x0A
Popsy: y component of projection_vector (2.14 fixed point number padded with zeroes)
x: x component of projection_vector (2.14 fixed point number padded with zeroes)
Pushes-
Setsprojection_vector

Sets the direction of the projection_vector, using values x and y taken from the stack, so that its projections onto the x and y-axes are x and y, which are specified as signed (two’s complement) fixed-point (2.14) numbers. The square root of (x2 + y2) must be equal to 0x4000 (hex).

If values are to be saved and used by a glyph program, font program or preprogram across different resolutions, extreme care must be used. The values taken from or put on the stack are 2.14 fixed-point values for the x and y components of the vector in question. The values are based on the normalized vector lengths. More simply, the values must always be set such that (X**2 + Y**2) is 1.

If a TrueType program uses specific values for X and Y to set the vectors to certain angles, these values will not produce identical results across different aspect ratios. Values that work correctly at 1:1 aspect ratios (such as VGA and 8514) will not necessarily yield the desired results at a ratio of 1.33:1 (e.g. the EGA).

By the same token, if a TrueType program is making use of the values returned by GPV and GFV, the values returned for a specific angle will vary with the aspect ratio in use at the time.

A sequence has the instructino SPVFS[]. The values y, then x, are popped from the stack.

Example:

SPVFS[ ]

The values 0x0000 0000 and 0x0000 4000 are popped from the stack. The projection vector is set in the direction of the x axis.
Sets the projection_vector to a unit vector that points in the direction of the x axis

Set Freedom_Vector From Stack

SFVFS[ ]
Code0x0B
Popsy: y component of freedom_vector (2.14 fixed point number padded with zeroes)
x: x component of freedom_vector (2.14 fixed point number padded with zeroes)
Pushes-
Setsfreedom_vector

Sets the direction of the freedom_vector using the values x and y taken from the stack. The vector is set so that its projections onto the x and y -axes are x and y, which are specified as signed (two’s complement) fixed-point (2.14) numbers. The square root of (x2 + y2) must be equal to 0x4000 (hex).

If values are to be saved and used by a glyph program, font program or preprogram across different resolutions, extreme care must be used. The values taken from or put on the stack are 2.14 fixed-point values for the x and y components of the vector in question. The values are based on the normalized vector lengths. More simply, the values must always be set such that (X**2 + Y**2) is 1.

If a TrueType program uses specific values for X and Y to set the vectors to certain angles, these values will not produce identical results across different aspect ratios. Values that work correctly at 1:1 aspect ratios (such as VGA and 8514) will not necessarily yield the desired results at a ratio of 1.33:1 (e.g. the EGA).

By the same token, if a TrueType program is making use of the values returned by GPV and GFV, the values returned for a specific angle will vary with the aspect ratio in use at the time.

A sequence has the SFVFS[] instruction. The values y, then x, are popped from the stack.

Example:

The values 0x0000 4000 and 0x0000 0000 are popped from the stack. The freedom vector is set in the direction of the y axis.
Sets the freedom_vector to a unit vector that points in the direction of the y axis.

Get Projection_Vector

GPV[ ]
Code Range0x0C
Pops-
Pushesx: x component of projection_vector (2.14 fixed point number padded with zeroes)
y : y component of projection_vector (2.14 fixed point number padded with zeroes)
Getsprojection_vector

Pushes the x and y components of the projection_vector onto the stack as two 2.14 numbers.

If values are to be saved and used by a glyph program, font program or preprogram across different resolutions, extreme care must be used. The values taken from or put on the stack are 2.14 fixed-point values for the x and y components of the vector in question. The values are based on the normalized vector lengths. More simply, the values must always be set such that (X**2 + Y**2) is 1.

If a TrueType program uses specific values for X and Y to set the vectors to certain angles, these values will not produce identical results across different aspect ratios. Values that work correctly at 1:1 aspect ratios (such as VGA and 8514) will not necessarily yield the desired results at a ratio of 1.33:1 (e.g. the EGA).

By the same token, if a TrueType program is making use of the values returned by GPV and GFV, the values returned for a specific angle will vary with the aspect ratio in use at the time.

A sequence has the GPV[] instruction. A projection vector variable holds (x, y) values. The value x is pushed onto the stack, then y is pushed onto the stack.

Example:

Case 1:

The projection vector is in the direction of the x axis.
The stack entry 0x4000 which when interpreted as a 2.14 number is simply 1. This command reveals that, in this case, the projection_vector is a unit vector that points in the x direction.

Case 2:

The projection vector is in the direction of the y axis. A sequence has the GPV[] instruction. The values 0x0000 4000 and 0x0000 0000 are pushed onto the stack.
Here the projection_vector is a unit vector that points in the direction of the y axis.

Case 3:

The projection vector points at an angle of 45 degrees. A sequence has the GPV[] instruction. The values 0x0000 2D41 and 0x0000 2D41 are pushed onto the stack.
NOTE: 0x2D41 is the hex equivalent of sqrt(2)/2 . As a result of this instruction, the projection_vector is set to a 45 degree angle relative to the x-axis.

Get Freedom_Vector

GFV[ ]
Code Range0x0D
Pops-
Pushesx: x-component of freedom_vector (2.14 number padded with zeroes)
y: y component of freedom_vector (2.14 number padded with zeroes)
Getsfreedom_vector

Puts the x and y components of the freedom_vector on the stack. The freedom_vector is put onto the stack as two 2.14 coordinates.

If values are to be saved and used by a glyph program, font program or preprogram across different resolutions, extreme care must be used. The values taken from or put on the stack are 2.14 fixed-point values for the x and y components of the vector in question. The values are based on the normalized vector lengths. More simply, the values must always be set such that (X**2 + Y**2) is 1.

If a TrueType program uses specific values for X and Y to set the vectors to certain angles, these values will not produce identical results across different aspect ratios. Values that work correctly at 1:1 aspect ratios (such as VGA and 8514) will not necessarily yield the desired results at a ratio of 1.33:1 (e.g. the EGA).

By the same token, if a TrueType program is making use of the values returned by GPV and GFV, the values returned for a specific angle will vary with the aspect ratio in use at the time.

A sequence has the GFV[] instruction. A freedom vector variable holds (x, y) values. The value x is pushed onto the stack, then y is pushed onto the stack.

Example:

GFV[ ]

The freedom vector points at a downward angle. The values -11596 and 11565 are pushed onto the stack.

Set Reference Point 0

SRP0[ ]
Code Range0x10
Popsp: point number (ULONG)
Pushes-
Setsrp0
AffectsIP, MDAP, MIAP, MIRP, MSIRP, SHC, SHE, SHP

Pops a point number from the stack and sets rp0 to that point number.

A value p is popped from the stack. A variable rp0 is set to the value p.

Set Reference Point 1

SRP1[ ]
Code Range0x11
Popsp: point number (ULONG)
Pushes-
Setsrp1
AffectsIP, MDAP, MDRP, MIAP, MSIRP, SHC, SHE, SHP

Pops a point number from the stack and sets rp1 to that point number.

A value p is popped from the stack. A variable rp1 is set to the value p.

Set Reference Point 2

SRP2[ ]
Code Range0x12
Popsp: point number (ULONG)
Pushes-
Setsrp2

Pops a point number from the stack and sets rp2 to that point number.

A value p is popped from the stack. A variable rp2 is set to the value p.

Set Zone Pointer 0

SZP0[ ]
Code Range0x13
Popsn: zone number (ULONG)
Pushes-
Setszp0
AffectsALIGNPTS, ALIGNRP, DELTAP1, DELTAP2, DELTAP3, IP, ISECT, MD, MDAP, MIAP, MIRP, MSIRP, SHC, SHE, SHP, UTP

Pops a zone number, n, from the stack and sets zp0 to the zone with that number. If n is 0, zp0 points to zone 0. If n is 1, zp0 points to zone 1. Any other value for n is an error.

A value n is popped from the stack. A variable zp0 is set to the enumeration value En.

Example:

A sequence has the SZP0[] instruction. The value 1 is popped from the stack. zp0 is set to E1.

Set Zone Pointer 1

SZP1[ ]
Code Range0x14
Popsn: zone number (ULONG)
Pushes-
Setszp1
AffectsALIGNRPTS, ALIGNRP, IP, MD, MDRP, MSIRP, SHC, SHE, SHP, SFVTL, SPVTL

Pops a zone number, n, from the stack and sets zp1 to the zone with that number. If n is 0, zp1 points to zone 0. If n is 1, zp1 points to zone 1. Any other value for n is an error.

A value n is popped from the stack. A variable zp1 is set to the enumeration value En.

Example:

A sequence has the SZP1[] instruction. The value 0 is popped from the stack. zp1 is set to E0.

Set Zone Pointer 2

SZP2[ ]
Code Range0x15
Popsn: zone number (ULONG)
Pushes-
Setszp2
AffectsISECT, IUP, GC, SHC, SHP, SFVTL, SHPIX, SPVTL, SC

Pops a zone number, n, from the stack and sets zp2 to the zone with that number. If n is 0, zp2 points to zone 0. If n is 1, zp2 points to zone 1. Any other value for n is an error.

A value n is popped from the stack. A variable zp2 is set to the enumeration value En.

Set Zone PointerS

SZPS[ ]
Code Range0x16
Popsn: zone number (ULONG)
Pushes-
Setszp0, zp1, zp2
AffectsALIGNPTS, ALIGNRP, DELTAP1, DELTAP2, DELTAP3, GC, IP, ISECT, IUP, MD, MDAP, MDRP, MIAP, MIRP, MSIRP, SC, SFVTL, SHPIX, SPVTL, SHC, SHE, SHP, SPVTL, UTP

Pops a zone number from the stack and sets all of the zone pointers to point to the zone with that number. If n is 0, all three zone pointers will point to zone 0. If n is 1, all three zone pointers will point to zone 1. Any other value for n is an error.

A value n is popped from the stack. Variables zp0, zp1 and zp2 are set to the enumeration value En.

Round To Half Grid

RTHG[ ]
Code Range0x19
Pops-
Pushes-
Setsround_state
AffectsMDAP, MDRP, MIAP, MIRP, ROUND
Usesfreedom_vector, projection_vector

Sets the round_state variable to state 0 (hg). In this state, the coordinates of a point are rounded to the nearest half grid line.

Example

The instruction is RTHG[]. Freedom and project vectors point in the direction of the x axis. On a design space grid, a point n is moved right to a half grid line horizontally halfway between the main grid lines.

Round To Grid

RTG[ ]
Code Range0x18
Pops-
Pushes-
Setsround_state
AffectsMDAP, MDRP, MIAP, MIRP, ROUND
Usesfreedom_vector, projection_vector

Sets the round_state variable to state 1 (g). In this state, distances are rounded to the closest grid line.

Example

The instruction is RTG[]. Freedom and project vectors point in the direction of the x axis. On a design space grid, a point n to the right of the half grid line is moved right to the main grid line on the right.

Round To Double Grid

RTDG[ ]
Code Range0x3D
Pops-
Pushes-
Setsround_state
AffectsMDAP, MDRP, MIAP, MIRP, ROUND
Usesfreedom_vector, projection_vector

Sets the round_state variable to state 2 (dg). In this state, distances are rounded to the closest half or integer pixel.

Example

The instruction is RTDG[]. Freedom and project vectors point in the direction of the x axis. On a design space grid, a point n to the left of the half grid line is moved right to the half grid line.
The instruction is RTDG[]. Freedom and project vectors point in the direction of the x axis. On a design space grid, a point n to the right of the half grid line is moved right to the main grid line on the right.

Round Down To Grid

RDTG[ ]
Code Range0x7D
Pops-
Pushes-
Setsround_state
AffectsMDAP, MDRP, MIAP, MIRP, ROUND
Usesfreedom_vector, projection_vector

Sets the round_state variable to state 3 (dtg). In this state, distances are rounded down to the closest integer grid line.

Example

The instruction is RDTG[]. Freedom and project vectors point in the direction of the x axis. On a design space grid, a point n to the right of the half grid line is moved left to the main grid line on the left.

Round Up To Grid

RUTG[ ]
Code Range0x7C
Pops-
Pushes-
Setsround_state
AffectsMDAP, MDRP, MIAP, MIRP, ROUND
Usesfreedom_vector, projection_vector

Sets the round_state variable to state 4 (utg). In this state distances are rounded up to the closest integer pixel boundary

Example

The instruction is RUTG[]. Freedom and project vectors point in the direction of the x axis. On a design space grid, a point n to the left of the half grid line is moved right to the main grid line on the right.

Round OFF

ROFF[ ]
Code Range0x7A
Pops-
Pushes-
Setsround_state
AffectsMDAP, MDRP, MIAP, MIRP, ROUND
Usesfreedom_vector, projection_vector

Sets the round_state variable to state 5 (off). In this state rounding is turned off.

Example

The instruction is ROFF[]. Freedom and project vectors point in the direction of the x axis. On a design space grid, a point is within the grid but not aligned to any main or half grid line.

Super ROUND

SROUND[ ]
Code Range0x76
Popsn: number decomposed to obtain period, phase, threshold
Pushes-
Setsround_state
AffectsMDAP, MDRP, MIAP, MIRP, ROUND

SROUND allows you fine control over the effects of the round_state variable by allowing you to set the values of three components of the round_state: period, phase, and threshold.

More formally, SROUND maps the domain of 26.6 fixed point numbers into a set of discrete values that are separated by equal distances. SROUND takes one argument from the stack, n, which is decomposed into a period, phase and threshold.

The period specifies the length of the separation or space between rounded values in terms of grid spacing.

Three lines represent real numbers. On the first line, numbers are indicated from 0 to 2 in increments of 0.5; the period is 0.5. On the second line, numbers 0, 1 and 2 are indicated; the period is 1.0. On the third line, numbers 0 and 2 are indicated; the period is 2.0.
Two lines represent real numbers. On the first line, numbers 0, 1 and 2 are indicated; phase is 0. On the second line, 0 is shown for reference, and numbers 0.25, 1.25 and 2.25 are indicated; phase is 0.25.
The phase specifies the offset of the values from multiples of the period.

The threshold specifies the part of the domain that is mapped onto each value. More intuitively, the threshold tells a value when to “fall forward” to the next largest integer.

Two number lines are shown, one labeled 'RTG' and one labeled 'RUTG'. On the RTG line, numbers from -0.5 to 1 in increments of 0.5 are shown for reference, and the number 0 is indicated; period is 1.0; threshold is period/2, or 0.5. On the second line, 0 and 1 are indicated; period is 1.0; threshold is period minus 1, or 0.

Only the lower 8 bits of the argument n are used. For SROUND gridPeriod is equal to 1.0 pixel. The byte is encoded as follows: bits 7 and 6 encode the period, bits 5 and 4 encode the phase and bits 3, 2, 1 and 0 encode the threshold as shown here.

period

0period = gridPeriod/2
1period = gridPeriod
2period = gridPeriod * 2
3Reserved

phase

0phase = 0
1phase = period/4
2phase = period/2
3phase = gridPeriod * 3/4

threshold

0threshold = period -1
1threshold = -3/8 * period
2threshold = -2/8 * period
3threshold = -1/8 * period
4threshold = 0/8 * period
5threshold = 1/8 * period
6threshold = 2/8 * period
7threshold =3/8 * period
8threshold = 4/8 * period
9threshold = 5/8 * period
10threshold = 6/8 * period
11threshold = 7/8 * period
12threshold = 8/8 * period
13threshold = 9/8 * period
14threshold = 10/8 * period
15threshold = 11/8 * period

For example, SROUND(01:01:1000) maps numbers into the values 0.25, 1.25, 2.25, The numbers from -0.25 to 0.75 are mapped into 0.25. The range of numbers [0.75, 1.75) map into 1.25. Similarly, the numbers from [1.75, 2.75) map into the number 2.25 and so on.

On a number line, numbers -0.25, 0, 0.75 are shown for reference. The number 0.25 is indicated; 1.25 is also indicated. Phase is 0.25; period is shown going from 0.25 to 1.25; threshold is shown going from -0.25 to 0.75.

Rounding occurs after compensation for engine characteristics, so the steps in the rounding of a number n are:

  • add engine compensation to n.
  • subtract the phase from n.
  • add the threshold to n.
  • truncate n to the next lowest periodic value (ignore the phase).
  • add the phase back to n.
  • if rounding caused a positive number to become negative, set n to the positive round value closest to 0.
  • if rounding caused a negative number of become positive, set n to the negative round value closest to 0.
  • the period parameters can have values of 1/2 pixel, 1 pixel, or 2 pixels.
  • the phase parameters can have values of 0 pixels, 1/4 pixel, 1/2 pixel, or 3/4 pixel.
  • the threshold parameters can have values of -3/8 period, -2/8 period, 11/8 period. It can also have the special value largest-number-smaller-than-period which causes rounding equivalent to CEILING.

Super ROUND 45 degrees

S45ROUND[ ]
Code Range0x77
Popsn: ULONG decomposed to obtain period, phase, threshold (ULONG)
Pushes-
Setsround_state
AffectsMDAP, MDRP, MIAP, MIRP, ROUND

S45ROUND is analogous to SROUND. The gridPeriod is SQRT(2)/2 pixels rather than 1 pixel. It is useful for measuring at a 45 degree angle with the coordinate axes.

Set LOOP variable

SLOOP[ ]
Code Range0x17
Popsn: value for loop Graphics State variable (integer)
Pushes-
Setsloop
AffectsALIGNRP, FLIPPT, IP, SHP, SHPIX

Pops a value, n, from the stack and sets the loop variable count to that value. The loop variable works with the SHP[a], SHPIX[a], IP[ ], FLIPPT[ ], and ALIGNRP[ ]. The value n indicates the number of times the instruction is to be repeated. After the instruction executes, the loop variable is reset to 1.

A value n is popped from the stack and set as the value for a loop variable.

Set Minimum_Distance

SMD[ ]
Code Range0x1A
Popsdistance: value for minimum_distance (F26Dot6)
Pushes-
Setsminimum_distance

Pops a value from the stack and sets the minimum_distance variable to that value. The distance is assumed to be expressed in sixty-fourths of a pixel.

A value is popped from the stack and set as the value for a minimum distance variable.

INSTRuction execution ConTRoL

INSTCTRL[ ]
Code Range0x8E
Popss: selector flag (int32)
value: USHORT (padded to 32 bits) used to set value of instruction_control.
Pushes-
Setsinstruction_control

Sets the instruction control state variable making it possible to turn on or off the execution of instructions and to regulate use of parameters set in the CVT program. INSTCTRL[ ] can only be executed in the CVT program.

This instruction clears and sets various control flags in the rasterizer. The selector flag determines valid values for the value argument. The value determines the new setting of the raterizer control flag. In this version there are three flags in use:

  • Selector flag 1 is used to inhibit grid-fitting. If s=1, valid values for the value argument are 0 (FALSE) and 1 (TRUE). If the value argument is set to TRUE (v=1), any instructions associated with glyphs will not be executed. For example, to inhibit grid-fitting when a glyph is being rotated or stretched, use the following sequence on the preprogram:

    PUSHB[000] 6    /* ask GETINFO to check for stretching or rotation */
    GETINFO[]       /* will push TRUE if glyph is stretched or rotated */
    IF[]            /* tests value at top of stack */
    PUSHB[000] 1    /* value for INSTCTRL */
    PUSHB[000] 1    /* selector for INSTCTRL */
    INSTRCTRL[]     /* based on selector and value will turn grid-fitting off */
    EIF[]
    
  • Selector flag 2 is used to establish that any parameters set in the CVT program should be ignored when instructions associated with glyphs are executed. These include, for example, the values for scantype and the CVT cut-in. If s=1, valid values for the value argument are 0 (FALSE) and 2 (TRUE). If the value argument is set to TRUE (v=2), the default values of those parameters will be used regardless of any changes that may have been made in those values by the preprogram. If the value argument is set to FALSE (v=0), parameter values changed by the CVT program will be used in glyph instructions.

  • Selector flag 3 is used to control some aspects of how some specific instructions are interpreted when ClearType™ is being used. If the selector is enabled, a font will be rendered in native ClearType mode, as opposed to backwards compatibility mode. If the value argument is set to TRUE (v=4) then the interpreter will be in native ClearType mode. If the value argument is set to FALSE (v=0) then the interpreter will be in backwards compatibility mode.

A selector and a value are popped from the stack. The value is set as the valur for an instruction control variable.

SCAN conversion ConTRoL

SCANCTRL[ ]
Code Range0x85
Popsn: flags indicating when to turn on dropout control mode (16 bit word padded to 32 bits)
Pushes-
Setsscan_control

SCANCTRL is used to set the value of the Graphics State variable scan_control which in turn determines whether the scan converter will activate dropout control for this glyph. Use of the dropout control mode is determined by three conditions:

  1. Is the glyph rotated?
  2. Is the glyph stretched?
  3. Is the current setting for ppem less than a specified threshold?

The interpreter pops a word from the stack and looks at the lower 16 bits.

Bits 0-7 represent the threshold value for ppem. A value of FF in bits 0-7 means invoke dropout_control for all sizes. A value of 0 in bits 0-7 means never invoke dropout_control.

Bits 8-13 are used to turn on dropout_control in cases where the specified conditions are met. Bits 8, 9 and 10 are used to turn on the dropout_control mode (assuming other conditions do not block it). Bits 11, 12, and 13 are used to turn off the dropout mode unless other conditions force it. Bits 14 and 15 are reserved for future use.

Bit Meaning if set
8 Set dropout_control to TRUE if other conditions do not block and ppem is less than or equal to the threshold value.
9 Set dropout_control to TRUE if other conditions do not block and the glyph is rotated
10 Set dropout_control to TRUE if other conditions do not block and the glyph is stretched.
11 Set dropout_control to FALSE unless ppem is less than or equal to the threshold value.
12 Set dropout_control to FALSE unless the glyph is rotated.
13 Set dropout_control to FALSE unless the glyph is stretched.
14 Reserved for future use.
15 Reserved for future use.

For example

0x0000No dropout control is invoked
0x01FFAlways do dropout control
0x0A10Do dropout control if the glyph is rotated and has less than 16 pixels per-em

The scan converter can operate in either a “normal” mode or in a “fix dropout” mode depending on the value of a set of enabling and disabling flags.

SCANTYPE

SCANTYPE[ ]
Code Range0x8D
Popsn: 16 bit integer
Pushes-
Setsscan_control

Pops a 16-bit integer whose value is used to determine which rules the scan converter will use. If the value of the argument is 0, the fast scan converter will be used. If the value of the integer is 1 or 2, simple dropout control will be used. If the value of the integer is 4 or 5, smart dropout control will be used. More specifically,

  • if n=0 rules 1, 2, and 3 are invoked (simple dropout control scan conversion including stubs)
  • if n=1 rules 1, 2, and 4 are invoked (simple dropout control scan conversion excluding stubs)
  • if n=2 rules 1 and 2 only are invoked (fast scan conversion; dropout control turned off)
  • if n=3 same as n = 2
  • if n = 4 rules 1, 2, and 5 are invoked (smart dropout control scan conversion including stubs)
  • if n = 5 rules 1, 2, and 6 are invoked (smart dropout control scan conversion excluding stubs)
  • if n = 6 same as n = 2
  • if n = 7 same as n = 2

The scan conversion rules are shown here:

Rule 1If a pixel’s center falls within the glyph outline, that pixel is turned on.
Rule 2If a contour falls exactly on a pixel’s center, that pixel is turned on.
Rule 3If a scan line between two adjacent pixel centers (either vertical or horizontal) is intersected by both an on-Transition contour and an off-Transition contour and neither of the pixels was already turned on by rules 1 and 2, turn on the left-most pixel (horizontal scan line) or the bottom-most pixel (vertical scan line). This is “Simple” dropout control.
Rule 4Apply Rule 3 only if the two contours continue to intersect other scan lines in both directions. That is, do not turn on pixels for ‘stubs.’ The scanline segments that form a square with the intersected scan line segment are examined to verify that they are intersected by two contours. It is possible that these could be different contours than the ones intersecting the dropout scan line segment. This is very unlikely but may have to be controlled with grid-fitting in some exotic glyphs.
Rule 5If a scan line between two adjacent pixel centers (either vertical or horizontal) is intersected by both an on-Transition contour and an off-Transition contour and neither of the pixels was already turned on by rules 1 and 2, turn on the pixel which is closer to the midpoint between the on-Transition contour and off-Transition contour. This is “Smart” dropout control.
Rule 6Apply Rule 5 only if the two contours continue to intersect other scan lines in both directions. That is, do not turn on pixels for ‘stubs.’

New fonts wishing to use the new modes of the ScanType instruction, but still wishing to work correctly on old rasterizers that don’t recognize the new modes should:

  1. First execute a ScanType instruction using an old mode which will give the best approximation to the desired new mode (e.g. Simple Stubs for Smart Stubs), and then
  2. Immediately execute another ScanType instruction with the desired new mode.

Set Control Value Table Cut In

SCVTCI[ ]
Code Range0x1D
Popsn: value for cut_in (F26Dot6)
Pushes-
Setscontrol_value_cut_in
AffectsMIAP, MIRP

Sets the control_value_cut_in in the Graphics State. The value n is expressed in sixty-fourths of a pixel.

A value is popped from the stack and set as the value for the cut in variable.

Increasing the value of the cut_in will increase the range of sizes for which CVT values will be used instead of the original outline value.

Set Single_Width_Cut_In

SSWCI[ ]
Code Range0x1E
Popsn: value for single_width_cut_in (F26dot6)
Pushes-
Setssingle_width_cut_in
AffectsMIAP, MIRP

Sets the single_width_cut_in in the Graphics State. The value n is expressed in sixty-fourths of a pixel.

A value is popped from the stack and set as the value for the single width cut in variable.

Set Single-width

SSW[ ]
Code Range0x1F
Popsn: value for single_width_value (FUnits)
Pushes-
Setssingle_width_value

Sets the single_width_value in the Graphics State. The single_width_value is expressed in FUnits.

A value is popped from the stack and set as the value for the single width value variable.

Set the auto_flip Boolean to ON

FLIPON[ ]
Code Range0x4D
Pops-
Pushes-
Setsauto_flip
AffectsMIRP

Sets the auto_flip Boolean in the Graphics State to TRUE causing the MIRP instructions to ignore the sign of Control Value Table entries. The default auto_flip Boolean value is TRUE.

An auto flip variable is set to 1.

Set the auto_flip Boolean to OFF

FLIPOFF[ ]
Code Range0x4E
Pops-
Pushes-
Setsauto_flip
AffectsMIRP

Set the auto_flip Boolean in the Graphics State to FALSE causing the MIRP instructions to use the sign of Control Value Table entries. The default auto_flip Boolean value is TRUE.

An auto flip variable is set to 0.

Set Angle_Weight

SANGW[ ]
Code Range0x7E
Popsweight: value for angle_weight
Pushes-
Setsangle_weight

SANGW is no longer needed because of dropped support to the AA (Adjust Angle) instruction. AA was the only instruction that used angle_weight in the global graphics state.

Pops a weight value from the stack and sets the value of the angle_weight state variable accordingly

A weight value is popped from the stack and is set as the value of an angle weight variable.

Set Delta_Base in the graphics state

SDB[ ]
Code Range0x5E
Pops-
Pushes-
Setsdelta_base
AffectsDELTAP1, DELTAP2, DELTAP3, DELTAC1, DELTAC2, DELTAC3

Pops a number, n, and sets delta_base to the value n. The default for delta_base is 9.

A value is popped from the stack and is set as the value of a delta base variable.

Set Delta_Shift in the graphics state

SDS[ ]
Code Range0x5F
Popsn: value for the delta_shift (ULONG)
Pushes-
Setsdelta_shift
AffectsDELTAP1, DELTAP2, DELTAP3, DELTAC1, DELTAC2, DELTAC3

Sets delta_shift to the value n. The default for delta_shift is 3.

A value is popped from the stack and is set as the value of a delta shift variable.

Reading and writing data

The following instructions make it possible to get and to set a point coordinate, to measure the distance between two points, and to determine the current settings for pixels per em and point size.

Get Coordinate projected onto the projection_vector

GC[a]
Code Range0x46 - 0x47
a0: use current position of point p
1: use the position of point p in the original outline
Popsp: point number (ULONG)
Pushesvalue: coordinate location (F26Dot6)
Useszp2, projection_vector

Measures the coordinate value of point p on the current projection_vector and pushes the value onto the stack.

Example

The following example shows that the value returned by GC is dependent upon the current position of the projection_vector. Note that point p is at the position (300,420) in the coordinate grid.

A point p is shown in an x,y coordinate grid.

GC[1] 9

First, the projection vector is in the direction of the x axis, and the value 300 is pushed onto the stack. Second, the projection vector is in the direction of the y axis, and the value 420 is pushed onto the stack. Third, the project vector points in the direction of a line from (300,420) to (0,0), and the value -516 is pushed onto the stack.
The projection_vector is parallel to the line from (0,0) to (300,420)

Sets Coordinate From the Stack using projection_vector and freedom_vector

SCFS[ ]
Code Range0x48
Popsvalue: distance from origin to move point (F26Dot6)
p: point number (ULONG)
Pushes-
Useszp2, freedom_vector, projection_vector

Moves point p from its current position along the freedom_vector so that its component along the projection_vector becomes the value popped off the stack.

A value and a point number p are popped from the stack.

Measure Distance

MD[a]
Code Range0x49 - 0x4A
a0: measure distance in grid-fitted outline
1: measure distance in original outline
Popsp1: point number (ULONG)
p2: point number (ULONG)
Pushesdistance (F26Dot6)
Useszp1 with point p1, zp0 with point p2, projection_vector

Measures the distance between outline point p1 and outline point p2. The value returned is in pixels (F26Dot6) If distance is negative, it was measured against the projection vector. Reversing the order in which the points are listed will change the sign of the result.

Point numbers p1 and p2 are popped from the stack, and a distance value is pushed onto the stack. For MD[0], the distance is determined from the original positions of p1 and p2. For MD[1], the distance is determined for p1 and p2 fitted to the grid.

Example:

In the illustration below MD[1] between points 25 and 31 will return a smaller value than MD[0] at 10 pixels per em on a 72 dpi device. The difference is due to the effects of grid-fitting which, at this size, stretches out the counter.

The projection vector points in the direction of the x axis. The outline for the digit 8 is shown twice: first with original point positions, then with grid-fitted point positions.

Measure Pixels Per EM

MPPEM[ ]
Code Range0x4B
Pops-
Pushesppem: pixels per em (ULONG)

This instruction pushes the number of pixels per em onto the stack. Pixels per em is a function of the resolution of the rendering device and the current point size and the current transformation matrix. This instruction looks at the projection_vector and returns the number of pixels per em in that direction.

The ppem value is pushed onto the stack.

Measure Point Size

MPS[ ]
Code Range0x4C
Pops-
PushespointSize: the size in points of the current glyph (F26Dot6)

Pushes the current point size onto the stack.

Measure point size can be used to obtain a value which serves as the basis for choosing whether to branch to an alternative path through the instruction stream. It makes it possible to treat point sizes below or above a certain threshold differently

The point size value is pushed onto the stack.
The raster bitmaps for lowercase g are shown at three sizes.
12, 18, and 36 point Helvetica g at 72 dpi

Managing outlines

The following set of instructions make it possible to move the points that make up a glyph outline. They are the instructions that accomplish the actual work of grid-fitting. They include instructions to move points, shift points or groups of points, flip points from off to on the curve or vice versa, and to interpolate points

FLIP PoinT

FLIPPT[ ]
Code Range0x80
Popsp: point number (ULONG)
Pushes-
Usesloop, p is referenced in zp0

Flips points that are off the curve so that they are on the curve and points that are on the curve so that they are off the curve. The point is not marked as touched. The result of a FLIPPT instruction is that the contour describing part of a glyph outline is redefined

A point number p is popped from the stack.
A point is located off a convex curve.
Before
A point is located at the connection of two line segments.
After

FLIP RanGe ON

FLIPRGON[ ]
Code Range0x81
Popshighpoint: highest point number in range of points to be flipped (ULONG)
lowpoint: lowest point number in range of points to be flipped (ULONG)
Pushes-

Flips a range of points beginning with lowpoint and ending with highpoint so that any off the curve points become on the curve points. The points are not marked as touched

A highpoint value is popped from the stack, then a lowpoint value is popped from the stack.

Example:

Control points 1 to 5 define a convex curve, with points 1, 3 and 5 off the curve.
Before
Control points 1 to 5 are all on curve points, and define two line segments connected at point 3.
After

Will make all off curve points between point 0 and point 5 into on curve points as shown

FLIP RanGe OFF

FLIPRGOFF[ ]
Code Range0x82
Popshighpoint: highest point number in range of points to be flipped (ULONG)
lowpoint: lowest point number in range of points to be flipped (ULONG)
Pushes-

Flips a range of points beginning with lowpoint and ending with highpoint so that any off the curve points become on the curve points. The points are not marked as touched.

NOTE: This instruction changes the curve but the position of the points is unaffected. Accordingly, points affected by this instruction are not marked as touched.

Two values, highpoint and lowpoint, are popped from the stack.

Example:

Control points 5 to 9 are all on curve points and define connected line segments.
Before
Control points 5 and 9 are on cur points; points 6 to 8 are off curve. These define a contour passing through points 5 and 9.
After

SHift Point by the last point

SHP[a]
Code Range0x32 - 0x33
a0: uses rp2 in the zone pointed to by zp1
1: uses rp1 in the zone pointed to by zp0
Popsp: point to be shifted (ULONG)
Pushes-
Useszp0 with rp1 or zp1 with rp2 depending on flag
zp2 with point p
loop, freedom_vector, projection_vector

Shift point p by the same amount that the reference point has been shifted. Point p is shifted along the freedom_vector so that the distance between the new position of point p and the current position of point p is the same as the distance between the current position of the reference point and the original position of the reference point.

NOTE: Point p is shifted from its current position, not its original position. The distance that the reference point has shifted is measured between its current position and the original position.

In the illustration below rp is the original position of the reference point, rp' is the current position of the reference point, p is the original position of point p, p' is the current position, p" the position after it is shifted by the SHP instruction. (White indicates original position, gray is current position, black is position to which this instruction moves a point

The freedom and projection vectors point in the direction of the x axis. A reference point rp is shown in its original position and its current position after it was shifted. Another point p is shown in its original position, its current position, and a new position after being shifted by the same amount the reference point was shifted.

SHift Contour by the last point

SHC[a]
Code Range0x34 - 0x35
a0: uses rp2 in the zone pointed to by zp1
1: uses rp1 in the zone pointed to by zp0
Popsc: contour to be shifted (ULONG)
Pushes-
Useszp0 with rp1 or zp1 with rp2 depending on flag
zp2 with contour c
freedom_vector, projection_vector

Shifts every point on contour c by the same amount that the reference point has been shifted. Each point is shifted along the freedom_vector so that the distance between the new position of the point and the old position of that point is the same as the distance between the current position of the reference point and the original position of the reference point. The distance is measured along the projection_vector. If the reference point is one of the points defining the contour, the reference point is not moved by this instruction.

This instruction is similar to SHP, but every point on the contour is shifted.

SHift Zone by the last pt

SHZ[a]
Code Range0x36 - 0x37
a0: the reference point rp2 is in the zone pointed to by zp1
1: the reference point rp1 is in the zone pointed to by zp0
Popse: zone to be shifted (ULONG)
Pushes-
Useszp0 with rp1 or zp1 with rp2 depending on flag
freedom_vector, projection_vector

Shift the points in the specified zone (Z1 or Z0) by the same amount that the reference point has been shifted. The points in the zone are shifted along the freedom_vector so that the distance between the new position of the shifted points and their old position is the same as the distance between the current position of the reference point and the original position of the reference point.

SHZ[a] uses zp0 with rp1 or zp1 with rp2. This instruction is similar to SHC, but all points in the zone are shifted, not just the points on a single contour.

SHift point by a PIXel amount

SHPIX[ ]
Code Range0x38
Popsamount: magnitude of the shift (F26Dot6)
p1, p2,...pn: points to be shifted (ULONG)
Pushes-
Useszp2, loop, freedom_vector

Shifts the points specified by the amount stated. When the loop variable is used, the amount to be shifted is put onto the stack only once. That is, if loop = 3, then the contents of the top of the stack should be point p1, point p2, point p3, amount. The value amount is expressed in sixty-fourths of a pixel.

SHPIX is unique in relying solely on the direction of the freedom_vector. It makes no use of the projection_vector. Measurement is made in the direction of the freedom_vector.

Example

The instruction shifts points 27, 28, and 29 by 80/64 or 1.25 pixels in the direction of the freedom vector. The distance is measured in the direction of the freedom_vector; the projection vector is ignored.

SHPIX[]

The freedom vector points in the direction of the x axis; the projection vector is ignored. Points 27, 28 and 29 are moved 1.25 pixels in the x direction.

Move Stack Indirect Relative Point

MSIRP[a]
Code Range0x3A - 0x3B
a0: Do not set rp0 to p
1: Set rp0 to p
Popsd: distance (F26Dot6)
p: point number (ULONG)
Pushes-
Useszp1 with point p and zp0 with rp0, freedom_vector, projection_vector.
SetsAfter it has moved the point this instruction sets rp1 = rp0, rp2 = point p, and if a=1, rp0 is set to point p.

Makes the distance between a point p and rp0 equal to the value specified on the stack. The distance on the stack is in fractional pixels (F26Dot6). An MSIRP has the same effect as a MIRP instruction except that it takes its value from the stack rather than the Control Value Table. As a result, the cut_in does not affect the results of a MSIRP. Additionally, MSIRP is unaffected by the round_state.

The freedom and projection vectors point in the direction of the x axis. A value d and a point number p are popped from the stack. Point p is moved right so that it is distance d along the projection vector from reference point rp0.

Move Direct Absolute Point

MDAP[a]
Code Range0x2E - 0x2F
a0: do not round the value
1: round the value
Popsp: point number (ULONG)
Pushes-
Setsrp0 = rp1 = point p
Useszp0, round_state, projection_vector, freedom_vector.

Sets the reference points rp0 and rp1 equal to point p. If a=1, this instruction rounds point p to the grid point specified by the state variable round_state. If a=0, it simply marks the point as touched in the direction(s) specified by the current freedom_vector. This command is often used to set points in the twilight zone.

Point number p is popped from the stack.

Example:

MDAP[0]

When a=0, the point is simply marked as touched and the values of rp0 and rp1 set to point p.

The freedom and projection vectors point in the direction of the y axis. A point p is located within a design grid cell, not aligned to the grid. Reference points rp0 and rp1 are set to point p.
MDAP[1] assuming that the round_state is round to grid and the freedom_vector is a shown.
The freedom and projection vectors point in the direction of the y axis. A point p has an original position within a design grid cell, not aligned to the grid, but it is shifted down to the grid line. Reference points rp0 and rp1 are set to point p.

Move Indirect Absolute Point

MIAP[a]
Code Range0x3E - 0x3F
a0: don’t round the distance and don’t look at the control_value_cut_in
1: round the distance and look at the control_value_cut_in
Popsn: CVT entry number (ULONG)
p: point number (ULONG)
Pushes-
Setsrp0 = rp1 = point p
Useszp0, round_state, control_value_cut_in, freedom_vector, projection_vector

Moves point p to the absolute coordinate position specified by the nth Control Value Table entry. The coordinate is measured along the current projection_vector. If a=1, the position will be rounded as specified by round_state. If a=1, and if the device space difference between the CVT value and the original position is greater than the control_value_cut_in, then the original position will be rounded (instead of the CVT value.)

Rounding is done as if the entire coordinate system has been rotated to be consistent with the projection_vector. That is, if round_state is set to 1, and the projection_vector and freedom_vector are at a 45° angle to the x-axis, then a MIAP[1] of a point to 2.9 pixels will round to 3.0 pixels along the projection_vector.

The a Boolean above controls both rounding and the use of the control_value_cut_in. If you would like the meaning of this Boolean to specify only whether or not the MIAP[ ] instruction should look at the control_value_cut_in value, use the ROFF[ ] instruction to turn off rounding.

This instruction can be used to create Twilight Zone points.

Example:

MIAP[1] 4 7

case 1:

rounding is OFF

Freedom and projection vectors point in the direction of the y axis.

The point is moved to the position specified in the CVT.

An entry in the Control Value Table at location 7 has a value of 13.6. A point is moved up so that its y coordinate is 13.6.

case 2:

The cut_in test succeeds and rounding is RTG.

The value in the CVT is subjected to the rounding rule and then the point is moved to the rounded position.

Freedom and projection vectors point in the direction of the y axis. An entry in the Control Value Table at location 7 has a value of 13.6. A point is moved up to y = 13.6, but then is moved further to y = 14.

case 3:

The cut_in test fails and rounding is OFF.

Here the point is not moved.

Freedom and projection vectors point in the direction of the y axis. An entry in the Control Value Table at location 7 has a value of 13.6. A point shown in the design grid is not moved.

case 4:

The cut_in test fails and rounding is RTG.

In this case the point is moved to the nearest grid position.

Freedom and projection vectors point in the direction of the y axis. An entry in the Control Value Table at location 7 has a value of 13.6. A point is moved up to a rounded y coordinate less than 13.6.

Move Direct Relative Point

MDRP[abcde]
Code Range0xC0 - 0xDF
a0: do not set rp0 to point p after move
1: do set rp0 to point p after move
b0: do not keep distance greater than or equal to minimum_distance
1: keep distance greater than or equal to minimum_distance
c0: do not round distance
1: round the distance
dedistance type for engine characteristic compensation
Popsp: point number (ULONG)
Pushes-
Setsafter point p is moved, rp1 is set equal to rp0, rp2 is set equal to point p; if the a flag is set to TRUE, rp0 is set equal to point
Useszp0 with rp0 and zp1 with point p, round_state, single_width_value, single_width_cut_in, freedom_vector, projection_vector.

MDRP moves point p along the freedom_vector so that the distance from its new position to the current position of rp0 is the same as the distance between the two points in the original uninstructed outline, and then adjusts it to be consistent with the Boolean settings. Note that it is only the original positions of rp0 and point p and the current position of rp0 that determine the new position of point p along the freedom_vector.

MDRP is typically used to control the width or height of a glyph feature using a value which comes from the original outline. Since MDRP uses a direct measurement and does not reference the control_value_cut_in, it is used to control measurements that are unique to the glyph being instructed. Where there is a need to coordinate the control of a point with the treatment of points in other glyphs in the font, a MIRP instruction is needed.

Though MDRP does not refer to the CVT, its effect does depend upon the single-width cut-in value. If the device space distance between the measured value taken from the uninstructed outline and the single_width_value is less than the single_width_cut_in, the single_width_value will be used in preference to the outline distance. In other words, if the two distances are sufficiently close (differ by less than the single_width_cut_in), the single_width_value will be used.

The setting of the round_state Graphics State variable will determine whether and how the distance of point p from point q is rounded. If the round bit is not set, the value will be unrounded. If the round bit is set, the effect will depend upon the choice of rounding state. The value of the minimum distance variable is the smallest possible value the distance between two points can be rounded to.

Distances measured with the MDRP instruction must be either black, white or gray. Indicating this value in Booleans de allows the interpreter to compensate for engine characteristics as needed. The value de specifies the distance type as described in the chapter, “Instructing Glyphs.” Three values are possible: Gray=0, Black=1, White=2.

Example 1:

Graphics State Settings

Freedom and projection vectors point in the direction of the x axis.
Before MDRP
rp07
rp1?
rp2?

Case 1:

Freedom and projection vectors point in the direction of the x axis when MDRP[00001] is processed.
After MDRP[00001] 8
rp07
rp17
rp28

Case 2:

Freedom and projection vectors point in the direction of the x axis when MDRP[10001] is processed.
After MDRP[10001] 8
rp08
rp17
rp28

Example 2:

Point p is moved so that its distance from rp1 is the same as it was in the original outline.

For example 2, the freedom and projection vectors point in the direction of the x axis.
Original positions of point p and reference point rp1 are shown. rp1 has been moved before this instruction is processed. Point p is moved so that its distance from rp1 along the x axis is the same as the original distance between p and rp1.

Move Indirect Relative Point

MIRP[abcde]
Code Range0xE0 - 0xFF
a0: Do not set rp0 to p
1: Set rp0 to p
b0: Do not keep distance greater than or equal to minimum_distance
1: Keep distance greater than or equal to minimum_distance
c0: Do not round the distance and do not look at the control_value_cut_in
1: Round the distance and look at the control_value_cut_in value
dedistance type for engine characteristic compensation
Popsn: CVT entry number (ULONG)
p: point number (ULONG)
Pushes-
Useszp0 with rp0 and zp1 with point p. round_state, control_value_cut_in, single_width_value, single_width_cut_in, freedom_vector, projection_vector
SetsAfter it has moved the point this instruction sets rp1 = rp0, rp2 = point p, and if a = 1, rp0 is set to point p.

A MIRP instruction makes it possible to preserve the distance between two points subject to a number of qualifications. Depending upon the setting of Boolean flag b, the distance can be kept greater than or equal to the value established by the minimum_distance state variable. Similarly, the instruction can be set to round the distance according to the round_state graphics state variable. The value of the minimum distance variable is the smallest possible value the distance between two points can be rounded to. Additionally, if the c Boolean is set, the MIRP instruction acts subject to the control_value_cut_in. If the difference between the actual measurement and the value in the CVT is sufficiently small (less than the cut_in_value), the CVT value will be used and not the actual value. If the device space difference between this distance from the CVT and the single_width_value is smaller than the single_width_cut_in, then use the single_width_value rather than the outline or Control Value Table distance.

MIRP measures distance relative to point rp0. More formally, MIRP moves point p along the freedom_vector so that the distance from p to rp0 is equal to the distance stated in the reference CVT entry (assuming that the cut_in test succeeds)

The c Boolean above controls both rounding and the use of Control Value Table entries. If you would like the meaning of this Boolean to specify only whether or not the MIRP[ ] instruction should look at the control_value_cut_in, use the ROFF[ ] instruction to turn off rounding. In this manner, it is possible to specify rounding off and no cut_in.

The value de specifies the distance type as described in th chapter, “Instructing Glyphs.” Three values are possible: Gray=0, Black=1, White=2.

Example 1:

MIRP[00110] 3 17

case 1:

The cut_in test succeeds and rounding is off.

The point is moved so that the distance from RP0 is equal to that given in CVT entry 17.

Freedom and project vectors point in the direction of the x axis. An entry at location 17 in the Control Value Table has a value of 20.7. Original positions of a point and a reference point rp0 are shown. The other point is moved up so that its distance from rp0 along the y axis is 20.7 pixels.

case 2:

The cut_in test succeeds and rounding is set to RTG.

The distance in the CVT is rounded and the point is moved by the rounded distance.

Freedom and project vectors point in the direction of the x axis. An entry at location 17 in the Control Value Table has a value of 20.7. Original positions of a point and a reference point rp0 are shown. The other point is moved up so that its distance from rp0 along the y axis is 20.7 pixels, and then is further moved to a distinace of 21 pixels.

case 3:

The cut_in test fails and the round_state is OFF.

The point is not moved.

Freedom and project vectors point in the direction of the x axis. An entry at location 17 in the Control Value Table has a value of 13.6. A point shown in the design grid is not moved.

case 4:

The cut_in test fails and the round_state is RTG.

The current position of the point is rounded to the grid.

Freedom and project vectors point in the direction of the x axis. An entry at location 17 in the Control Value Table has a value of 13.6. A point is moved up to the next integral y coordinate.

ALIGN Relative Point

ALIGNRP[ ]
Code Range0x3C
Popsp: point number (ULONG
Pushes-
Useszp1 with point p, zp0 with rp0, loop, freedom_vector, projection_vector.

Reduces the distance between rp0 and point p to zero. Since distance is measured along the projection_vector and movement is along the freedom_vector, the effect of the instruction is to align points.

A point number p is popped from the grid.

case 1:

The projection and freedom vectors point in the direction of the x axis. A point p is moved right so that its distance from reference point rp0 along the projection vector is 0.

case 2:

The projection and freedom vectors point in the direction of the y axis. A point p is moved down so that its distance from reference point rp0 along the projection vector is 0.
Adjust Angle (No Longer Supported)

moves point p to the InterSECTion of two lines

ISECT[ ]
Code Range0x0F
Popsb1: end point of line 2 (ULONG)
b0: start point of line 2 (ULONG)
a1: end point of line 1 (ULONG)
a0: start point of line 1 (ULONG)
p: point to move (ULONG)
Pushes-
Useszp2 with point p, zp1 with line A, zp0 with line B

Puts point p at the intersection of the lines A and B. The points a0 and a1 define line A. Similarly, b0 and b1 define line B. ISECT ignores the freedom_vector in moving point p.

Values b1, b0, a1 and a0 are popped from the stack, then point number p is popped from the stack.

Example:

ISECT[ ] 21 9 5 4 7

Intersecting lines are shown from point 9 to point 5, and from point 4 to point 7. Point 21 is moved to the position where the two lines intersect.
NOTE: If lines are parallel to each other, the point is put into the middle of the two lines.

Example:

ISECT[ ] 21 9 5 4 7

Parallel lines are shown from point 9 to point 5, and from point 4 to point 7. Point 21 is moved to the position in the middle.

ALIGN Points

ALIGNPTS[ ]
Code Range0x27
Popsp1: point number (ULONG)
p2: point number (ULONG)
Pushes-
Useszp1 with point p1, zp0 with point p2, freedom_vector, projection_vector.

Makes the distance between point 1 and point 2 zero by moving both along the freedom_vector to the average of both their projections along the projection_vector.

Point numberes p1 and p2 are popped from the stack.

Example:

ALIGNPTS[] 3 7

Freedom and projection vectors point in the direction of the y axis. Point 3 is moved down and point 7 is moved up so they have the same y coordinate.

Interpolate Point by the last relative stretch

IP[ ]
Code Range0x39
Popsp: point number (ULONG)
Pushes-
Useszp0 with rp1, zp1 with rp2, zp2 with point p, loop, freedom_vector, projection_vector

Moves point p so that its relationship to rp1 and rp2 is the same as it was in the original uninstructed outline. Measurements are made along the projection_vector, and movement to satisfy the interpolation relationship is constrained to be along the freedom_vector. This instruction is illegal if rp1 and rp2 have the same position on the projection_vector.

Freedom and projection vectors point in the direction of the x axis. A point number p is popped from the stack. Reference points rp1 and rp2 are moved right to new positions. Point p is moved right to a new position relative to new positions of rp1 and rp2.

In the example shown, assume that the points referenced by rp1 and rp2 are moved as shown. An IP instruction is then used to preserve their relative relationship with point p. After the IP the following should be true

  • D(p, rp1)/D(p',rp1') = D(p,rp2)/D(p', rp2')

In other words, the relative distance is preserved.

UnTouch Point

UTP[ ]
Code Range0x29
Popsp: point number (ULONG)
Pushes-
Useszp0 with point p, freedom_vector

Marks point p as untouched. A point may be touched in the x direction, the y direction, both, or neither. This instruction uses the current freedom_vector to determine whether to untouch the point in the x-direction, the y direction, or both. Points that are marked as untouched will be moved by an IUP (interpolate untouched points) instruction. Using UTP you can ensure that a point will be affected by IUP even if it was previously touched.

Interpolate Untouched Points through the outline

IUP[a]
Code Range0x30 - 0x31
a0: interpolate in the y-direction
1: interpolate in the x-direction
Pops-
Pushes-
Useszp2, freedom_vector, projection_vector

Considers a glyph contour by contour, moving any untouched points in each contour that are between a pair of touched points. If the coordinates of an untouched point were originally between those of the touched pair, it is linearly interpolated between the new coordinates, otherwise the untouched point is shifted by the amount the nearest touched point is shifted.

This instruction operates on points in the glyph zone pointed to by zp2. This zone should almost always be zone 1. Applying IUP to zone 0 is an error.

Consider three consecutive points all on the same contour. Two of the three points, p1 and p3 have been touched. Point p2 is untouched. The effect of an IUP in the x-direction is to move point p2 so that is in the same relative position to points p1 and p3 before they were moved.

The IUP instruction does not touch the points it moves. Thus the untouched points affected by an IUP instruction will be affected by subsequent IUP instructions unless they are touched by an intervening instruction. In this case, the first interpolation is ignored and the point is moved based on its original position.

Freedom and projection vectors point in the direction of the x axis. Points p1 and p3 have been moved to the right. Point p2 is then moved to the right.

Managing exceptions

DELTA instructions can be used to alter the outline of a glyph at a particular size. They are generally used to turn on or off specific pixels. Delta instructions work by moving points (DELTAP’s) or by changing a value in the Control Value Table (DELTAC’s).

More formally, the DELTA instructions take a variable number of arguments from the stack and allow the use of an exception of the form: at size x apply the movement d to point p (or at size x add or subtract an amount less than or equal to the Control Value Table entry c). DELTAs take a list of exceptions of the form: relative ppem value, the magnitude of the exception and the point number to which the exception is to be applied.

Each DELTA instruction works on a range of sizes as specified below. As a result, sizes are specified in relative pixels per em (ppem), that is relative to the delta_base. The default value for delta_base is 9 ppem. To set delta_base to another value, use the SDB instruction.

The DELTAP1 and DELTAC1 instructions allow values to be changed for glyphs at 9 through 24 ppem, assuming the default value for delta_base. Lowering the value for delta_base allows you to invoke exceptions at a smaller number of ppem.

DELTAP2 and DELTAC2 are triggered at 16 ppem higher than the value set for DELTAP1 and DELTAC1, and consequently the formula for the relative ppem is

ppem - 16 - delta_base.

DELTAP3 and DELTAC3 are triggered at 16 ppem higher than the value set for DELTAP2 and DELTAC2, or 32 ppem higher than the value set for DELTAP1 and DELTAC1, and consequently the formula for the relative ppem is:

ppem - 32 - delta_base.

DELTA*1delta_base through delta_base + 15 ppem
DELTA*2delta_base + 16 ppem through delta_base + 31 ppem
DELTA*3delta_base + 32 ppem through delta_base + 47 ppem

In specifying a DELTA instruction, the high 4 bits of arg1 describe the relative ppem value that will activate the exception.

The low 4 bits of arg1 describe the magnitude of the exception. The amount the point moves is a function of the exception stated and the Graphics State variable delta_shift. To set delta_shift, use the SDS instruction

Bits within a value are divided into to fields: high-order bits contain a relative ppem; the low-order bits contain a magnitude.
NOTE: Always observe that DELTA instructions expect the argument list to be sorted according to ppem. The lowest ppem should be deepest on the stack, and the highest ppem should be topmost on the stack.

In the descriptions of the instructions that follow, pi is a point number, ci is a Control Value Table entry number and argi is a byte composed of two parts: the relative ppem (ppem - delta_base) and the magnitude of the exception.

Increasing the delta_shift will allow for more fine control over pixel movement at the sacrifice of total range of movement. A step is the minimal amount that a delta instruction can move a point. Points can be moved in integral multiples of steps.

The size of a step is 1 divided by 2 to the power delta_shift. The range of movement produced by a given delta_shift can be calculated by taking the number of steps allowed (16) and dividing it by 2 to the power delta_shift. For example, a delta_shift equal to 2 allows the smallest movement to be ± 1/4 pixel (because 22 equals 4) and the largest movement to be ± 2 pixels (16/4 = 4 pixels of movement). A delta_shift of 5 allows the smallest movement to be ± 1/32 pixel (because 25 equals 32), but the largest movement is limited to ± 1/4 pixel. (16/32 = 1/2 a pixel of movement).

Internally, the value obtained for the exception is stored as a 4 bit binary number. As a result, the desired output range must be converted to a number between 0 and 15 before being converted to binary. Here is the internal remapping table for the DELTA instructions.

NOTE: that zero is lacking in the output range.

Number of Steps → Exception
-8 0
-7 1
-6 2
-5 3
-4 4
-3 5
-2 6
-1 7
1 8
2 9
3 10
4 11
5 12
6 13
7 14
8 15

DELTA exception P1

DELTAP1[ ]
Code Range0x5D
Popsn: number of pairs of exception specifications and points (ULONG)
p1, arg1, p2, arg2, ..., pnn argn: n pairs of exception specifications and points (pairs of ULONGs)
Pushes-
Useszp0, delta_base, delta_shift

DELTAP1 moves the specified points at the size and by the amount specified in the paired argument. An arbitrary number of points and arguments can be specified.

The grouping [pi, argi] can be executed n times. The value of argi may vary between iterations.

DELTA exception P2

DELTAP2[ ]
Code Range0x71
Popsn: number of pairs of exception specifications and points (ULONG)
p1, arg1, p2, arg2, ..., pnn argn: n pairs of exception specifications and points (pairs of ULONGs)
Pushes-
Useszp0, delta_shift, delta_base

DELTAP2 moves the specified points at the size and by the amount specified in the paired argument. An arbitrary number of points and arguments can be specified.

The grouping [pi, argi] can be executed n times. The value of argi may vary between iterations.

DELTA exception P3

DELTAP3[ ]
Code Range0x72
Popsn: number of pairs of exception specifications and points (ULONG)
p1, arg1, p2, arg2, ..., pnn argn: n pairs of exception specifications and points (pairs of ULONGs)
Pushes-
Useszp0, delta_base, delta_shift

DELTAP3 moves the specified points at the size and by the amount specified in the paired argument. An arbitrary number of point and arguments can be specified.

The grouping [pi, argi] can be executed n times. The value of argi may vary between iterations.

DELTA exception C1

DELTAC1[ ]
Code Range0x73
Popsn: number of pairs of exception specifications and CVT entry numbers (ULONG)
c1, arg1, c2, arg2,..., cn, argn: (pairs of ULONGs)
Pushes-

DELTAC1 changes the value in each CVT entry specified at the size and by the amount specified in its paired argument.

The grouping [ci, argi] can be executed n times. The value of argi may vary between iterations.

DELTA exception C2

DELTAC2[ ]
Code Range0x74
Popsn: number of pairs of exception specifications and CVT entry numbers (ULONG)
c1, arg1, c2, arg2,..., cn, argn: (pairs of ULONGs)
Pushes-

DELTAC2 changes the value in each CVT entry specified at the size and by the amount specified in its paired argument.

The grouping [ci, argi] can be executed n times. The value of argi may vary between iterations.

DELTA exception C3

DELTAC3[ ]
Code Range0x75
Popsn: number of pairs of exception specifications and CVT entry numbers (ULONG)
c1, arg1, c2, arg2,..., cn, argn: (pairs of ULONGs)
Pushes-

DELTAC3 changes the value in each CVT entry specified at the size and by the amount specified in its paired argument.

The grouping [ci, argi] can be executed n times. The value of argi may vary between iterations.

Example of DELTA exceptions

Assume that you want to move point 15 of your glyph 1/8 of a pixel along the freedom_vector at 12 pixels per em. Assume that delta_base has the default value 9 and delta_shift the default value 3.

To specify that the exception should be made at 12 ppem, you subtract the delta_base, which is 9, from 12 and store the result, which is 3, in the high nibble of argi.

To specify that the point is to be moved 1/8 of a pixel, multiply 1/8 by 2 raised to the power delta_shift. In other words, you multiply 1/8 by 2 raised to the third power (or 8)yielding 1. This value must be mapped to an internal value which using the table shown is 8.

Putting these two results together yields a 3 in the high nibble and an 8 in the low nibble or 56 (00111000, in binary).

To obtain this single exception, the top of the stack is: 56, 15, 1.

    (iteration)
    (point number)
    (arg1: ppem and magnitude)

Now if the interpreter executes

DELTAP1[ ]

then this instruction will move point 15 of the glyph (at 12 ppem) 1/8 of a pixel along the freedom_vector.

Managing the stack

The following set of instructions make it possible to manage elements on the stack. They make it possible to duplicate the element at the top of the stack, remove the top element from the stack, clear the stack, swap the top two stack elements, determine the number of elements currently on the stack, copy a specified element to the top of the stack, move a specified element to the top of the stack, and rearrange the order of the top three elements on the stack.

Duplicate top stack element

DUP[ ]
Code Range0x20
Popse: stack element (ULONG)
Pushese, e (two ULONGs)

Duplicates the element at the top of the stack.

An element e is popped from the stack, then two instances of the element e are pushed onto the stack.

POP top stack element

POP[ ]
Code Range0x21
Popse: stack element (ULONG)
Pushes-

Pops the top element of the stack.

An element e is popped from the stack.

Clear the entire stack

CLEAR[ ]
Code Range0x22
Popsall the items on the stack (ULONGs)
Pushes-

Clears all elements from the stack.

Elements en to e1 are popped from the stack.

SWAP the top two elements on the stack

SWAP[ ]
Code Range0x23
Popse2: stack element (ULONG)
e1: stack element (ULONG)
Pushese1, e2 (pair of ULONGs)

Swaps the top two elements of the stack making the old top element the second from the top and the old second element the top element.

Elements e2 then e1 are popped from the stack. Then, element e2 is pushed onto the stack, followed by element e1.

Returns the DEPTH of the stack

DEPTH[ ]
Code Range0x24
Pops-
Pushesn: number of elements (ULONG)

Pushes n, the number of elements currently in the stack onto the stack.

A value n is pushed onto the stack.

Example:

A stack has three elements. The value 3 is then pushed onto the stack.

Copy the INDEXed element to the top of the stack

CINDEX[ ]
Code Range0x25
Popsk : stack element number
Pushesek: indexed element (ULONG)

Puts a copy of the kth stack element on the top of the stack.

A value k is popped from the stack. Then, an element equal to the kth element is pushed onto the stack.

Example:

The value 3 is popped from the stack, and four elements, e1 to e4, remain on the stack. An element equal to e3 is pushed onto the stack.

Move the INDEXed element to the top of the stack

MINDEX[ ]
Code Range0x26
Popsk : stack element number
Pushesek: indexed element

Moves the indexed element to the top of the stack.

A value k is popped from the stack. Then the kth element is pushed onto the stack.

MINDEX[ ]

The value 3 is popped from the stack, and four elements, e1 to e4 remain on the stack. Then, element is pushed onto a modified stack containing elements e1, e2 and e4.

ROLL the top three stack elements

ROLL[ ]
Code Range0x8a
Popsa, b, c (top three stack elements)
Pushesb, a, c (elements reordered)

Performs a circular shift of the top three objects on the stack with the effect being to move the third element to the top of the stack and to move the first two elements down one position. ROLL is equivalent to MINDEX[ ] 3.

Elements a, b and c are popped from the stack. Then, the elements b, a and c are pushed onto the stack.

Managing the flow of control

This section describes those instructions that make it possible to alter the sequence in which items in the instruction stream are executed. The IF and JMP instructions and their variants work by testing the value of an element on the stack and changing the value of the instruction pointer accordingly.

IF test

IF[ ]
Code Range0x58
Popse: stack element (ULONG)
Pushes-

Tests the element popped off the stack: if it is zero (FALSE), the instruction pointer is jumped to the next ELSE or EIF instruction in the instruction stream. If the element at the top of the stack is nonzero (TRUE), the next instruction in the instruction stream is executed. Execution continues until an ELSE instruction is encountered or an EIF instruction ends the IF. If an else statement is found before the EIF, the instruction pointer is moved to the EIF statement.

case 1:

Element at top of stack is TRUE; instruction pointer is unaffected. IF terminates with EIF.

The IF[] instruction is processed. The value 1 is popped from the stack. The next instruction to be processed is the instruction immediately following the IF[] instruction.

case 2:

Element at top of stack is TRUE. The instruction stream is sequentially executed until ELSE is encountered whereupon the instruction pointer jumps to the EIF statement that terminates the IF.

The IF[] instruction has been processed, and the value 1 was popped from the stack. Processing continued with instructions following IF[]. Then, the ELSE[] instruction is encountered. The instruction pointer skips following instructions until the EIF[] instruction.

case 3:

Element at the top of the stack is FALSE; instruction pointer is moved to the ELSE statement; instructions are then executed sequentially; EIF ends the IF statement.

The IF[] instruction is processed, and the value 0 is popped from the stack. The instruction pointer skips instructions until the ELSE[] instruction is encountered. The following instructions are processed until the EIF[] instruction is encountered.

ELSE

ELSE[ ]
Code Range0x1B
Pops-
Pushes-

Marks the start of the sequence of instructions that are to be executed if an IF instruction encounters a FALSE value on the stack. This sequence of instructions is terminated with an EIF instruction.

End IF

EIF[ ]
Code Range0x59
Pops-
Pushes-

Marks the end of an IF[ ] instruction.

Jump Relative On True

JROT[ ]
Code Range0x78
Popsb: Boolean (ULONG)
offset: number of bytes to move instruction pointer (LONG)
Pushes-

Obtains an offset and tests a Boolean value. If the Boolean is TRUE, the signed offset will be added to the instruction pointer and execution will be resumed at the address obtained. Otherwise, the jump is not taken. The jump is relative to the position of the instruction itself. That is, the instruction pointer is still pointing at the JROT[ ] instruction when offset is added to obtain the new address.

A boolean value b is popped from the stack, then an offset is popped from the stack.

Example:

case 1:

Boolean is FALSE.

The JROT[] instruction is processed. The values 0 and 4 are popped from the stack. Processing continues with the instruction following the JROT instruction.

case 2:

Boolean is TRUE.

he JROT[] instruction is processed. The values 1 and 4 are popped from the stack. The instruction pointer skips to the 4th instruction after the JROT instruction, and processing continues.

JuMP

JMPR[ ]
Code Range0x1C
Popsoffset: number of bytes to move instruction pointer (LONG)
Pushes-

The signed offset is added to the instruction pointer and execution is resumed at the new location in the instruction steam. The jump is relative to the position of the instruction itself. That is, the instruction pointer is still pointing at the JROT[ ] instruction when offset is added to obtain the new address.

An offset is popped from the stack.

Jump Relative On False

JROF[ ]
Code Range0x79
Popse: stack element (ULONG)
offset: number of bytes to move instruction pointer (LONG)
Pushes-

In the case where the Boolean is FALSE, the signed offset will be added to the instruction pointer and execution will be resumed there; otherwise, the jump is not taken. The jump is relative to the position of the instruction itself. That is, the instruction pointer is still pointing at the JROT[ ] instruction when offset is added to obtain the new address.

An element e is popped from the stack, then an offset is popped from the stack.

case 1:

element is FALSE.

The instruction JROF[] is processed. The values 0 and 4 are popped from the stack. The instruction pointer skips to the 4th instruction after the JROF instruction, and processing continues.

case 2:

element is TRUE.

The JROF[] instruction is processed. The values 1 and 4 are popped from the stack. Processing continues with the instruction following the JROF instruction.

Logical functions

The TrueType instruction set includes a set of logical functions that can be used to test the value of a stack element or to compare the values of two stack elements. The logical functions compare 32 bit values (ULONG) and return a Boolean value to the top of the stack.

To easily remember the order in which stack values are handled during logical operations, imagine writing the stack values from left to right, starting with the bottom value. Then insert the operator between the two furthest right elements. For example:

A stack contains elements a, b and c.

GT a,b would be interpreted as (b>a):

c b > a

Less Than

LT[ ]
Code Range0x50
Popse2: stack element (ULONG)
e1: stack element (ULONG)
PushesBoolean value (ULONG in the range [0,1])

First pops e2, then pops e1 off the stack and compares them: if e1 is less than e2, 1, signifying TRUE, is pushed onto the stack. If e1 is not less than e2, 0, signifying FALSE, is placed onto the stack.

Elements e2, then e1, are popped from the stack, then a boolean value is pushed onto the stack.

Example:

LT[ ]

The values 15 and 20 are popped from the stack, then the value 0 (false) is pushed onto the stack.

Less Than or Equal

LTEQ[ ]
Code Range0x51
Popse2: stack element (ULONG)
e1: stack element (ULONG)
PushesBoolean value (ULONG in the range [0,1])

Pops e2 and e1 off the stack and compares them. If e1 is less than or equal to e2, 1, signifying TRUE, is pushed onto the stack. If e1 is not less than or equal to e2, 0, signifying FALSE, is placed onto the stack.

Two elements are popped from the stack: e2, then e1. A boolean value is pushed onto the stack.

Example:

LTEQ[ ]

Two values, 20 and 20, are popped from the stack. The value 1 (true) is pushed onto the stack.

Greater Than

GT[ ]
Code Range0x52
Popse2: stack element (ULONG)
e1: stack element (ULONG)
PushesBoolean value (ULONG in the range [0,1])

First pops e2 then pops e1 off the stack and compares them. If e1 is greater than e2, 1, signifying TRUE, is pushed onto the stack. If e1 is not greater than e2, 0, signifying FALSE, is placed onto the stack.

Elements e2, then e1, are popped from the stack. A boolean value is pushed onto the stack.

Example:

GT[ ]

Two values, 20 and 20, are popped from the stack. The value 0 (false) is pushed onto the stack.

Greater Than or Equal

GTEQ[ ]
Code Range0x53
Popse2: stack element (ULONG)
e1: stack element (ULONG)
PushesBoolean value (ULONG in the range [0,1])

Pops e1 and e2 off the stack and compares them. If e1 is greater than or equal to e2, 1, signifying TRUE, is pushed onto the stack. If e1 is not greater than or equal to e2, 0, signifying FALSE, is placed onto the stack.

Elements e2, then e1, are popped from the stack. Then, a boolean value is pushed onto the stack.

Example:

GTEQ[ ]

The values 15 and 20 are popped from the stack. Then the value 1 (true) is pushed onto the stack.

EQual

EQ[ ]
Code Range0x54
Popse2: stack element (ULONG)
e1: stack element (ULONG)
PushesBoolean value (ULONG in the range [0,1])

Pops e1 and e2 off the stack and compares them. If they are equal, 1, signifying TRUE is pushed onto the stack. If they are not equal, 0, signifying FALSE is placed onto the stack.

Elements e1 and e2 are popped from the stack. A boolean value is pushed onto the stack.

Example:

EQ[ ]

The values 20 and -12 are popped from the stack. Then the value 0 (false) is pushed onto the stack.

Not EQual

NEQ[ ]
Code Range0x55
Popse2: stack element (ULONG)
e1: stack element (ULONG)
PushesBoolean value (ULONG in the range [0,1])

Pops e1 and e2 from the stack and compares them. If they are not equal, 1, signifying TRUE, is pushed onto the stack. If they are equal, 0, signifying FALSE, is placed on the stack.

Elements e1 and e2 are popped from the stack. Then, a boolean value is pushed onto the stack.

Example:

NEQ[ ]

The values 20 and -12 are popped from the stack. Then the value 1 (true) is pushed onto the stack.

ODD

ODD[ ]
Code Range0x56
Popse1: stack element (F26Dot6)
Boolean value
PushesBoolean value (ULONG in the range [0,1])
Usesround_state

Tests whether the number at the top of the stack is odd. Pops e1 from the stack and rounds it as specified by the round_state before testing it. After the value is rounded, it is shifted from a fixed point value to an integer value (any fractional values are ignored). If the integer value is odd, one, signifying TRUE, is pushed onto the stack. If it is even, zero, signifying FALSE is placed onto the stack.

An element e1 is popped from the stack. Then a boolean value is pushed onto the stack.

Example:

ODD[ ]

This example assumes that round_state is RTG.

The value 22.7 is popped from the stack, and the value 1 (true) is pushed onto the stack.

EVEN

EVEN[ ]
Code Range0x57
Popse1: stack element (F26Dot6)
PushesBoolean value (ULONG in the range [0,1])
Usesround_state

Tests whether the number at the top of the stack is even. Pops e1 off the stack and rounds it as specified by the round_state before testing it. If the rounded number is even, one, signifying TRUE, is pushed onto the stack if it is odd, zero, signifying FALSE, is placed onto the stack.

An element e1 is popped from the stack, and a boolean value is pushed onto the stack.

Example:

EVEN[ ]

This example assumes that round_state is RTG.

The value 22.7 is popped from the stack, and the value 0 (false) is pushed onto the stack.

logical AND

AND[ ]
Code Range0x5A
Popse1: stack element (ULONG)
e2: stack element (ULONG)
Pushes( e1 and e2 ): logical and of e1 and e2 (ULONG)

Pops e1 and e2 off the stack and pushes onto the stack the result of a logical and of the two elements. Zero is returned if either or both of the elements are FALSE (have the value zero). One is returned if both elements are TRUE (have a non zero value).

Elements e1 and e2 are popped from the stack. A value equal to logical and of e1 and e2 is pushed onto the stack.

Example:

case 1:

AND[ ]

The values 1 and 33 are popped from the stack, and the value 1 (true) is pushed onto the stack.

case 2:

AND[ ]

The values 1 and 0 are popped from the stack, and the value 0 (false) is pushed onto the stack.

logical OR

OR[ ]
Code Range0x5B
Popse1: stack element (ULONG)
e2: stack element (ULONG)
Pushes( e1 or e2 ): logical and of e1 and e2 (ULONG)

Pops e1 and e2 off the stack and pushes onto the stack the result of a logical or operation between the two elements. Zero is returned if both of the elements are FALSE. One is returned if either both of the elements are TRUE.

Elements e1 and e2 are popped from the stack. A value equal to logical or of e1 and e2 is pushed onto the stack.

Example:

case 1:

OR[ ]

The values 44 and 0 are popped from the stack, and the value 1 (true) is pushed onto the stack.

case 2:

OR[ ]

The values 0 and 0 are popped from the stack, and the value 0 (false) is pushed onto the stack.

logical NOT

NOT[ ]
Code Range0x5C
Popse: stack element (ULONG)
Pushes(not e): logical negation of e (ULONG)

Pops e off the stack and returns the result of a logical NOT operation performed on e. If originally zero, one is pushed onto the stack if originally nonzero, zero is pushed onto the stack.

An element e is poppoed from the stack, and a value equal to not e is pushed onto the stack.

Example:

case 1:

The value 42.1 is popped from the stack, and the value 0 (false) is pushed onto the stack.

case 2:

The value 0 is popped from the stack, and the value 1 (true) is pushed onto the stack.

Arithmetic and math instructions

These instructions perform arithmetic on stack values. Values are treated as signed (two’s complement) 26.6 fixed-point numbers (F26Dot6) and give results in the same form. There is no overflow or underflow protection for these instructions.

To easily remember the order in which stack values are handled during arithmetic operations, imagine writing the stack values from left to right, starting with the bottom value. Then insert the operator between the two furthest right elements. For example:

A stack contains values a, b and c.

subtract a,b would be interpreted as (b-a): c b - a

ADD

ADD[ ]
Code Range0x60
Popsn1, n2 (F26Dot6)
Pushes(n2 + n1)

Pops n1 and n2 off the stack and pushes the sum of the two elements onto the stack.

Values n1 and n2 are popped from the stack, and a value equal to n2 + n1 is pushed onto the stack.

SUBtract

SUB[ ]
Code Range0x61
Popsn1, n2 (F26Dot6)
Pushes(n2 - n1): difference

Pops n1 and n2 off the stack and pushes the difference between the two elements onto the stack.

Values n1 and n2 are popped from the stack, and a value equal to n2 - n1 is pushed onto the stack.

DIVide

DIV[ ]
Code Range0x62
Popsn1: divisor (F26Dot6)
n2: dividend (F26Dot6)
Pushes n2/n1 (F26Dot6)

Pops n1 and n2 off the stack and pushes onto the stack the quotient obtained by dividing n2 by n1. Note that this truncates rather than rounds the value. The TrueType Rasterizer v.1.7 and later will catch any division-by-zero errors.

Values n1 and n2 are popped from the stack, and a value equal to n2/n1 is pushed onto the stack.

MULtiply

MUL[ ]
Code Range0x63
Popsn1, n2: multiplier and multiplicand (F26Dot6)
Pushesn1 * n2 (F26Dot6)

Pops n1 and n2 off the stack and pushes onto the stack the product of the two elements.

Values n1 and n2 are popped from the stack, and a value equal to n2 * n1 is pushed onto the stack.

ABSolute value

ABS[ ]
Code Range0x64
Popsn
Pushes|n|: absolute value of n (F26Dot6)

Pops n off the stack and pushes onto the stack the absolute value of n.

A value n is popped from the stack, and a value equal to the absolute value of n is pushed onto the stack.

Example:

case 1:

The value -21.1 is popped from the stack, and the value 21.1 is pushed onto the stack.

case 2:

The value 14.0 is popped from the stack, and the value 14.0 is pushed onto the stack.

NEGate

NEG[ ]
Code Range0x65
Popsn1
Pushes-n1: negation of n1 (F26Dot6)

This instruction pops n1 off the stack and pushes onto the stack the negated value of n1.

A value n is popped from the stack, and a value equal to -n is pushed onto the stack.

NEG[ ]

The value 44.66 is popped from the stack, and the value -44.66 is pushed onto the stack.

FLOOR

FLOOR[ ]
Code Range0x66
Popsn1: number whose floor is desired (F26Dot6)
Pushesn : floor of n1 (F26Dot6)

Pops n1 and returns n, the greatest integer value less than or equal to n1.

A value n1 is popped from the stack, and a value n is pushed onto the stack.

Example:

FLOOR[ ]

case 1:

The value 15.8 is popped from the stack, and the value 15 is pushed onto the stack.

case 2:

The value 15.3 is popped from the stack, and the value 15 is pushed onto the stack.

case 3:

The value -0.8 is popped from the stack, and the value -1 is pushed onto the stack.

CEILING

CEILING[ ]
Code Range0x67
Popsn1: number whose ceiling is desired (F26Dot6)
Pushesn: ceiling of n1 (F26Dot6)

Pops n1 and returns n, the least integer value greater than or equal to n1. For instance, the ceiling of 15 is 15, but the ceiling of 15.3 is 16. The ceiling of -0.8 is 0. (n is the least integer value greater than or equal to n1)

A value n1 is popped from the stack. A value n is pushed onto the stack.

Example:

CEILING[ ]

case 1:

The value 223.0 is popped from the stack, and the value 223.0 is pushed onto the stack.

case 2:

The value 223.3 is popped from the stack, and the value 224.0 is pushed onto the stack.

MAXimum of top two stack elements

MAX[ ]
Code Range0x8B
Popse1: stack element (ULONG)
e2: stack element (ULONG)
Pushesmaximum of e1 and e2

Pops two elements, e1 and e2, from the stack and pushes the larger of these two quantities onto the stack.

Elements e1 and e2 are popped from the stack. A value equal to the maximum of e1 and e2 is pushed onto the stack.

MINimum of top two stack elements

MIN[ ]
Code Range0x8C
Popse1: stack element (ULONG)
e2: stack element (ULONG)
Pushesminimum of e1 and e2

Pops two elements, e1 and e2, from the stack and pushes the smaller of these two quantities onto the stack.

Elements e1 and e2 are popped from the stack. A value equal to the minimum of e1 and e2 is pushed onto the stack.

Compensating for the engine characteristics

The following two functions make it possible to compensate for the engine characteristic. Each takes value and make the compensation. In addition to the engine compensation, ROUND, rounds the value according to the round_state. NROUND only compensates for the engine.

ROUND value

ROUND[ab]
Flagsab: distance type for engine characteristic compensation
Popsn1
Pushesn2
Code0x68 - 0x6B

Rounds a value according to the state variable round_state while compensating for the engine. n1 is popped off the stack and, depending on the engine characteristics, is increased or decreased by a set amount. The number obtained is then rounded and pushed back onto the stack as n2.

The value ab specifies the distance type as described in the chapter, “Instructing Glyphs.” Three values are possible: Gray=0, Black=1, White=2.

No ROUNDing of value

NROUND[ab]
Flagsab: distance type for engine characteristic compensation
Popsn1
Pushesn2
Code0x6C - 0x6F

NROUND[ab] does the same operation as ROUND[ab] (above), except that it does not round the result obtained after compensating for the engine characteristics. n1 is popped off the stack and, depending on the engine characteristics, increases or decreases by a set amount. This figure is then pushed back onto the stack as n2.

The value ab specifies the distance type as described in the chapter, “Instructing Glyphs.” Three values are possible: Gray=0, Black=1, White=2.

Defining and using functions and instructions

The following instructions make it possible to define and use both functions and new instructions.

In addition to a simple call function, there is a loop and call function.

An IDEF or instruction definition call makes it possible to patch old scalers in order to add newly defined instructions.

Function DEFinition

FDEF[ ]
Code Range0x2C
Popsf: function identifier number (integer in the range 0 to n-1 where n is specified in the 'maxp' table )
Pushes-

Marks the start of a function definition. The argument f is a number that uniquely identifies this function. A function definition can appear only in the Font Program or the CVT program. Functions may not exceed 64K in size

A function identifier f is popped from the stack.

END Function definition

ENDF[ ]
Code Range0x2D
Pops-
Pushes-

Marks the end of a function definition or an instruction definition.

CALL function

CALL[ ]
Code Range0x2B
Popsf: function identifier number (integer in the range 0 to n-1 where n is specified in the 'maxp' table )
Pushes-

Calls the function identified by the number f.

The function identifier f is popped from the stack.

LOOP and CALL function

LOOPCALL[ ]
Code Range0x2A
Popsf: function number integer in the range 0 to n-1 where n is specified in the 'maxp' table
count: number of times to call the function (signed word)
Pushes-

Calls the function f, count number of times.

A function identifier f and a count are popped from the stack.

Example:

Assume the Font Program contains this:

PUSHB(000), 17push 17 onto the stack
FDEF[ ]start defining function 17
...contents of function
...
ENDF[ ]end the definition
PUSHB(000),5push count
PUSHB(000),17push function number
LOOPCALL[ ]call function17, 5 times

Instruction DEFinition

IDEF[ ]
Code Range0x89
Popsopcode (8 bit code padded with zeroes to ULONG)
Pushes-

Begins the definition of an instruction. The instruction definition terminates when at ENDF, which is encountered in the instruction stream. Subsequent executions of the opcode popped will be directed to the contents of this instruction definition (IDEF). IDEFs should be defined in the Font Program or the CVT Program. An IDEF affects only undefined opcodes. If the opcode in question is already defined, the interpreter will ignore the IDEF. This is to be used as a patching mechanism for future instructions. Instructions may not exceed 64K in size.

Debugging

The TrueType instruction set provides the following instruction as an aid to debugging.

DEBUG call

DEBUG[ ]
Code Range0x4F
Popsnumber (ULONG)
Pushes-

This instruction is only for debugging purposes and should not be a part of a finished font. Some implementations may not support this instruction.

A number is popped from the stack.

Miscellaneous instructions

The following instruction obtains information about the current glyph and the scaler version.

GET INFOrmation

GETINFO[ ]
Code Range0x88
Popsselector (integer)
Pushesresult (integer)

GETINFO is used to obtain data about the font scaler version and the characteristics of the current glyph. The instruction pops a selector used to determine the type of information desired and pushes a result onto the stack.

Selector bit 0 indicates that the scaler version number is the desired information. Selector bit 1 indicates a request for glyph rotation status. Selector bit 2 asks whether the glyph has been stretched. Selector bit 3 asks if OpenType Font Variations are supported. Selector bit 4 asks if vertical phantom points are being used. Selector bit 5 asks whether the glyph is being rasterized for grayscale.

Selector bit 3 indicates a query as to whether or not OpenType Font Variations are supported. The result is returned in bit 10: if bit 10 is set, Font Variations are supported.

Selector bit 4 indicates a query as to whether vertical phantom points are supported. The result is returned in bit 11: if bit 11 is set, vertical phantom points are supported. Note: on MS Rasterizer, this method is not supported until MS Rasterizer 2.2 — version number 41 or later. For versions prior to version 41, see the note below.

The following selectors are for ClearType information. Selector bit 6 indicates that ClearType is enabled. Selector bit 7 indicates that “compatible-width” ClearType is enabled. Selector bit 8 indicates that symmetrical smoothing ClearType is enabled. And, selector bit 9 indicates that ClearType is processing the LCD stripes in BGR (Blue, Green, Red) order.

The result pushed onto the stack contains the requested information. More precisely, bits 0 through 7 comprise the Scaler version number. Refer to the table below for the meaning of the version numbers. Version numbers 0, 4 through 32, and 43 through 255 are reserved.

Note: On MS Rasterizer, selector bit 4 could not be reliably used to query for support of vertical phantom points prior to MS Rasterizer v.2.2, though support for vertical phantom points was added in MS Rasterizer v.1.7. Before hinting vertical phantom points or asking for grayscale information, use GETINFO to check that the rasterizer in use is version number 35 or later. Before checking if ClearType is enabled, make sure that the rasterizer is version number is 36 or greater. For the other ClearType bits, make sure that the rasterizer is version number 37 or greater.

Bit 8 is set to 1 if the current glyph has been rotated. It is zero otherwise.

Bit 9 is set to 1 if the current glyph has been stretched. It is set to 0 otherwise.

Bit 10 is set to 1 if OpenType Font Variations are supported (for MS Rasterizer v.2.2 and later). It is set to 0 otherwise.

Bit 11 is set to 1 if vertical phantom points are used (for MS Rasterizer v.2.2 and later). It is set to zero otherwise.

Bit 12 is set to 1 if the rasterization is for grayscale using the font smoothing technique (for MS rasterizer v.1.7 and later).

Bit 13 is set to 1 if ClearType is enabled (for MS rasterizer v.1.6+ or MS rasterizer v.1.8 and later). It is set to 0 otherwise.

Bit 14 is set to 1 if ClearType widths are compatible with bi-level and grayscale widths (for MS Rasterizer v.1.8 and later). It is set to 0 if the widths are the natural ClearType widths.

Bit 15 is set to 1 if ClearType symmetrical smoothing is being used (for MS Rasterizer v.1.8 and later). It is set to 0 otherwise.

Bit 16 is set to 1 if ClearType is processing the LCD stripes in BGR (Blue, Green, Red) order (for MS Rasterizer v.1.8 and later). It is set to 0 otherwise.

Bit 17 is set to 1 if ClearType sub-pixel text is being used (for MS Rasterizer 2.0 and later). In this case, any hints on the right side-bearing point are ignored. Hints to sharpen stems may also have minimal effect. It is set to 0 otherwise.

Bit 18 is set to 1 if ClearType symmetric rendering is being used (for MS Rasterizer v.2.0 and later). Depending on the horizontal LCD stripe orientation, this can impact the rendering of horizontal features. It is set to 0 otherwise.

Bit 19 is set to 1 if ClearType gray rendering is being used (for MS Rasterizer v.2.1 and later). It is set to 0 otherwise.

When the selector is set to request more than one piece of information, that information is OR’d together and pushed onto the stack. For example, a selector value of 6 requests both information on rotation and stretching and will result in the setting of both bits 8 and 9.

The following table encapsulates the above information.

Query Selector BitQuery Selector Bit MaskResult BitsResult Bit MaskVersion Requirements
Version00x000000010-70x000000FFAll
Glyph Rotation10x0000000280x00000100All
Glyph Stretched20x0000000490x00000200All
Font Variations30x00000008100x00000400(>= 5 && <=32) || (>= 41 && <= 64)
Vertical Phantom Points40x00000010110x00000800(>= 5 && <=32) || (>= 41 && <= 64)
Windows Font Smoothing Grayscale50x00000020120x00001000(>= 34 && <= 64)
ClearType enabled60x00000040130x00002000(>= 36 && <= 64)
ClearType compatible widths enabled70x00000080140x00004000(>= 37 && <= 64)
ClearType Horizontal LCD stripe orientation80x00000100150x00008000(>= 37 && <= 64)
ClearType BGR LCD stripe order90x00000200160x00010000(>= 37 && <= 64)
ClearType sub-pixel positioned text enabled100x00000400170x00020000(>= 39 && <= 64)
ClearType symmetric rendering enabled110x00000800180x00040000(>= 40 && <= 64)
ClearType Gray rendering enabled120x00001000190x00080000(>= 40 && <= 64)

The version information is as follows:

GETINFO Version Microsoft Rasterizer Version Notes
1 Macintosh System 6 INIT
2 Macintosh System 7
3 1.0 16-bit Windows 3.1.
4 Macintosh System 6.2
5 Kirin Printer
6 Macintosh System 7.1
7 Macintosh QuickDraw GX
33 1.5 32-bit version, new scan-convertor
34 1.6 Font smoothing, new SCANTYPE
35 1.7 Composite scaling changes
36 1.6+ “Classic” ClearType (Windows CE)
37 1.8 ClearType
38 1.9 Subpixel Positioned ClearType
39 2.0 Subpixel Positioned ClearType flag
40 2.1 Symmetric ClearType flag, ClearType Gray (and flag)
41 2.2 OpenType Font Variations
42 2.3 GETVARIATION support
A selector value is popped from the stack, and a result is pushed onto the stack.

GET VARIATION

GETVARIATION[ ]
Code Range0x91
PushesNormalized axes coordinates, one for each axis in the font. (Values are 2.14 fixed-point numbers padded with zeroes in the upper 16 bits.)

GETVARIATION is used to obtain the current normalized variation coordinates for each axis. The coordinate for the first axis, as defined in the 'fvar' table, is pushed first on the stack, followed by each consecutive axis until the coordinate for the last axis is on the stack.

Since this instruction is not supported in every environment, it is required that an IDEF, in either the 'fpgm' or 'prep' table, be provided for the GETVARIATION OpCode of 145 (0x91). Here is an example:

PUSHB[000] 145 /* OpCode 0x91, GetVariation */
IDEF[]
NPUSHB[] 2 /* Number of axes in this font */, 0, 0
ENDF[]

This program returns two zeroes on the stack, indicating the default values for each of the two axes. Zeroes will be interpreted as the default values for this font. The 'maxp' table should properly reflect the usage of the IDEF.

Notes:

In order to properly handle an instance font that is generated from a variable font, yet still have the instructions provide the same behavior between the variable font and the instance font, the following setup in the instance font is recommended.

Either identify and modify the existing, active IDEF for OpCode 0x91, or else add a new IDEF for OpCode 0x91 at the end of the 'prep' table. Multiple IDEFs for the same OpCode are valid, and the last one executed will be used. By placing a new IDEF at the end of the 'prep' it is easier to dynamically update, and reduces the likelihood of another IDEF overriding this one.

The default IDEF for OpCode 0x91, as noted above, usually returns zeroes on the stack, indicating the default values. In the case of an instance font generated from a variable font, the values to be returned must match the normalized values for the particular instance, with the coordinate value for the first axis pushed first on the stack followed by each consecutive axis in the order listed in the 'fvar' table. Caution should be made that the 'maxp' table properly reflects the maxInstructionDefs and maxStackElements added by this modification.

The following is an example of a replaced IDEF 145 (0x91) added for an instance:

PUSHB[000] 145 /* OpCode 0x91, GetVariation */
IDEF[]
NPUSHB[]   2 /* Number of axes in this font */, -16384, 0
ENDF[]

In this case, it provides the equivalent of GETVARIATION returning -1.0 for the first axis and 0.0 for the second axis.