//! TrueType hinting opcodes. /// Operation code for a TrueType instruction. /// /// See [the TrueType instruction set](https://learn.microsoft.com/en-us/typography/opentype/spec/tt_instructions) /// from the OpenType specification for more detail. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] #[repr(u8)] pub enum Opcode { SVTCA0 = 0x00, SVTCA1 = 0x01, SPVTCA0 = 0x02, SPVTCA1 = 0x03, SFVTCA0 = 0x04, SFVTCA1 = 0x05, SPVTL0 = 0x06, SPVTL1 = 0x07, SFVTL0 = 0x08, SFVTL1 = 0x09, SPVFS = 0x0A, SFVFS = 0x0B, GPV = 0x0C, GFV = 0x0D, SFVTPV = 0x0E, ISECT = 0x0F, SRP0 = 0x10, SRP1 = 0x11, SRP2 = 0x12, SZP0 = 0x13, SZP1 = 0x14, SZP2 = 0x15, SZPS = 0x16, SLOOP = 0x17, RTG = 0x18, RTHG = 0x19, SMD = 0x1A, ELSE = 0x1B, JMPR = 0x1C, SCVTCI = 0x1D, SSWCI = 0x1E, SSW = 0x1F, DUP = 0x20, POP = 0x21, CLEAR = 0x22, SWAP = 0x23, DEPTH = 0x24, CINDEX = 0x25, MINDEX = 0x26, ALIGNPTS = 0x27, INS28 = 0x28, UTP = 0x29, LOOPCALL = 0x2A, CALL = 0x2B, FDEF = 0x2C, ENDF = 0x2D, MDAP0 = 0x2E, MDAP1 = 0x2F, IUP0 = 0x30, IUP1 = 0x31, SHP0 = 0x32, SHP1 = 0x33, SHC0 = 0x34, SHC1 = 0x35, SHZ0 = 0x36, SHZ1 = 0x37, SHPIX = 0x38, IP = 0x39, MSIRP0 = 0x3A, MSIRP1 = 0x3B, ALIGNRP = 0x3C, RTDG = 0x3D, MIAP0 = 0x3E, MIAP1 = 0x3F, NPUSHB = 0x40, NPUSHW = 0x41, WS = 0x42, RS = 0x43, WCVTP = 0x44, RCVT = 0x45, GC0 = 0x46, GC1 = 0x47, SCFS = 0x48, MD0 = 0x49, MD1 = 0x4A, MPPEM = 0x4B, MPS = 0x4C, FLIPON = 0x4D, FLIPOFF = 0x4E, DEBUG = 0x4F, LT = 0x50, LTEQ = 0x51, GT = 0x52, GTEQ = 0x53, EQ = 0x54, NEQ = 0x55, ODD = 0x56, EVEN = 0x57, IF = 0x58, EIF = 0x59, AND = 0x5A, OR = 0x5B, NOT = 0x5C, DELTAP1 = 0x5D, SDB = 0x5E, SDS = 0x5F, ADD = 0x60, SUB = 0x61, DIV = 0x62, MUL = 0x63, ABS = 0x64, NEG = 0x65, FLOOR = 0x66, CEILING = 0x67, ROUND00 = 0x68, ROUND01 = 0x69, ROUND10 = 0x6A, ROUND11 = 0x6B, NROUND00 = 0x6C, NROUND01 = 0x6D, NROUND10 = 0x6E, NROUND11 = 0x6F, WCVTF = 0x70, DELTAP2 = 0x71, DELTAP3 = 0x72, DELTAC1 = 0x73, DELTAC2 = 0x74, DELTAC3 = 0x75, SROUND = 0x76, S45ROUND = 0x77, JROT = 0x78, JROF = 0x79, ROFF = 0x7A, INS7B = 0x7B, RUTG = 0x7C, RDTG = 0x7D, SANGW = 0x7E, AA = 0x7F, FLIPPT = 0x80, FLIPRGON = 0x81, FLIPRGOFF = 0x82, INS83 = 0x83, INS84 = 0x84, SCANCTRL = 0x85, SDPVTL0 = 0x86, SDPVTL1 = 0x87, GETINFO = 0x88, IDEF = 0x89, ROLL = 0x8A, MAX = 0x8B, MIN = 0x8C, SCANTYPE = 0x8D, INSTCTRL = 0x8E, INS8F = 0x8F, INS90 = 0x90, GETVARIATION = 0x91, GETDATA = 0x92, INS93 = 0x93, INS94 = 0x94, INS95 = 0x95, INS96 = 0x96, INS97 = 0x97, INS98 = 0x98, INS99 = 0x99, INS9A = 0x9A, INS9B = 0x9B, INS9C = 0x9C, INS9D = 0x9D, INS9E = 0x9E, INS9F = 0x9F, INSA0 = 0xA0, INSA1 = 0xA1, INSA2 = 0xA2, INSA3 = 0xA3, INSA4 = 0xA4, INSA5 = 0xA5, INSA6 = 0xA6, INSA7 = 0xA7, INSA8 = 0xA8, INSA9 = 0xA9, INSAA = 0xAA, INSAB = 0xAB, INSAC = 0xAC, INSAD = 0xAD, INSAE = 0xAE, INSAF = 0xAF, PUSHB000 = 0xB0, PUSHB001 = 0xB1, PUSHB010 = 0xB2, PUSHB011 = 0xB3, PUSHB100 = 0xB4, PUSHB101 = 0xB5, PUSHB110 = 0xB6, PUSHB111 = 0xB7, PUSHW000 = 0xB8, PUSHW001 = 0xB9, PUSHW010 = 0xBA, PUSHW011 = 0xBB, PUSHW100 = 0xBC, PUSHW101 = 0xBD, PUSHW110 = 0xBE, PUSHW111 = 0xBF, MDRP00000 = 0xC0, MDRP00001 = 0xC1, MDRP00010 = 0xC2, MDRP00011 = 0xC3, MDRP00100 = 0xC4, MDRP00101 = 0xC5, MDRP00110 = 0xC6, MDRP00111 = 0xC7, MDRP01000 = 0xC8, MDRP01001 = 0xC9, MDRP01010 = 0xCA, MDRP01011 = 0xCB, MDRP01100 = 0xCC, MDRP01101 = 0xCD, MDRP01110 = 0xCE, MDRP01111 = 0xCF, MDRP10000 = 0xD0, MDRP10001 = 0xD1, MDRP10010 = 0xD2, MDRP10011 = 0xD3, MDRP10100 = 0xD4, MDRP10101 = 0xD5, MDRP10110 = 0xD6, MDRP10111 = 0xD7, MDRP11000 = 0xD8, MDRP11001 = 0xD9, MDRP11010 = 0xDA, MDRP11011 = 0xDB, MDRP11100 = 0xDC, MDRP11101 = 0xDD, MDRP11110 = 0xDE, MDRP11111 = 0xDF, MIRP00000 = 0xE0, MIRP00001 = 0xE1, MIRP00010 = 0xE2, MIRP00011 = 0xE3, MIRP00100 = 0xE4, MIRP00101 = 0xE5, MIRP00110 = 0xE6, MIRP00111 = 0xE7, MIRP01000 = 0xE8, MIRP01001 = 0xE9, MIRP01010 = 0xEA, MIRP01011 = 0xEB, MIRP01100 = 0xEC, MIRP01101 = 0xED, MIRP01110 = 0xEE, MIRP01111 = 0xEF, MIRP10000 = 0xF0, MIRP10001 = 0xF1, MIRP10010 = 0xF2, MIRP10011 = 0xF3, MIRP10100 = 0xF4, MIRP10101 = 0xF5, MIRP10110 = 0xF6, MIRP10111 = 0xF7, MIRP11000 = 0xF8, MIRP11001 = 0xF9, MIRP11010 = 0xFA, MIRP11011 = 0xFB, MIRP11100 = 0xFC, MIRP11101 = 0xFD, MIRP11110 = 0xFE, MIRP11111 = 0xFF, } impl Opcode { /// Creates an opcode from the given byte. /// /// There is a 1:1 mapping between bytes and opcodes. #[inline] pub fn from_byte(byte: u8) -> Self { use Opcode::*; match byte { 0x00 => SVTCA0, 0x01 => SVTCA1, 0x02 => SPVTCA0, 0x03 => SPVTCA1, 0x04 => SFVTCA0, 0x05 => SFVTCA1, 0x06 => SPVTL0, 0x07 => SPVTL1, 0x08 => SFVTL0, 0x09 => SFVTL1, 0x0A => SPVFS, 0x0B => SFVFS, 0x0C => GPV, 0x0D => GFV, 0x0E => SFVTPV, 0x0F => ISECT, 0x10 => SRP0, 0x11 => SRP1, 0x12 => SRP2, 0x13 => SZP0, 0x14 => SZP1, 0x15 => SZP2, 0x16 => SZPS, 0x17 => SLOOP, 0x18 => RTG, 0x19 => RTHG, 0x1A => SMD, 0x1B => ELSE, 0x1C => JMPR, 0x1D => SCVTCI, 0x1E => SSWCI, 0x1F => SSW, 0x20 => DUP, 0x21 => POP, 0x22 => CLEAR, 0x23 => SWAP, 0x24 => DEPTH, 0x25 => CINDEX, 0x26 => MINDEX, 0x27 => ALIGNPTS, 0x28 => INS28, 0x29 => UTP, 0x2A => LOOPCALL, 0x2B => CALL, 0x2C => FDEF, 0x2D => ENDF, 0x2E => MDAP0, 0x2F => MDAP1, 0x30 => IUP0, 0x31 => IUP1, 0x32 => SHP0, 0x33 => SHP1, 0x34 => SHC0, 0x35 => SHC1, 0x36 => SHZ0, 0x37 => SHZ1, 0x38 => SHPIX, 0x39 => IP, 0x3A => MSIRP0, 0x3B => MSIRP1, 0x3C => ALIGNRP, 0x3D => RTDG, 0x3E => MIAP0, 0x3F => MIAP1, 0x40 => NPUSHB, 0x41 => NPUSHW, 0x42 => WS, 0x43 => RS, 0x44 => WCVTP, 0x45 => RCVT, 0x46 => GC0, 0x47 => GC1, 0x48 => SCFS, 0x49 => MD0, 0x4A => MD1, 0x4B => MPPEM, 0x4C => MPS, 0x4D => FLIPON, 0x4E => FLIPOFF, 0x4F => DEBUG, 0x50 => LT, 0x51 => LTEQ, 0x52 => GT, 0x53 => GTEQ, 0x54 => EQ, 0x55 => NEQ, 0x56 => ODD, 0x57 => EVEN, 0x58 => IF, 0x59 => EIF, 0x5A => AND, 0x5B => OR, 0x5C => NOT, 0x5D => DELTAP1, 0x5E => SDB, 0x5F => SDS, 0x60 => ADD, 0x61 => SUB, 0x62 => DIV, 0x63 => MUL, 0x64 => ABS, 0x65 => NEG, 0x66 => FLOOR, 0x67 => CEILING, 0x68 => ROUND00, 0x69 => ROUND01, 0x6A => ROUND10, 0x6B => ROUND11, 0x6C => NROUND00, 0x6D => NROUND01, 0x6E => NROUND10, 0x6F => NROUND11, 0x70 => WCVTF, 0x71 => DELTAP2, 0x72 => DELTAP3, 0x73 => DELTAC1, 0x74 => DELTAC2, 0x75 => DELTAC3, 0x76 => SROUND, 0x77 => S45ROUND, 0x78 => JROT, 0x79 => JROF, 0x7A => ROFF, 0x7B => INS7B, 0x7C => RUTG, 0x7D => RDTG, 0x7E => SANGW, 0x7F => AA, 0x80 => FLIPPT, 0x81 => FLIPRGON, 0x82 => FLIPRGOFF, 0x83 => INS83, 0x84 => INS84, 0x85 => SCANCTRL, 0x86 => SDPVTL0, 0x87 => SDPVTL1, 0x88 => GETINFO, 0x89 => IDEF, 0x8A => ROLL, 0x8B => MAX, 0x8C => MIN, 0x8D => SCANTYPE, 0x8E => INSTCTRL, 0x8F => INS8F, 0x90 => INS90, 0x91 => GETVARIATION, 0x92 => GETDATA, 0x93 => INS93, 0x94 => INS94, 0x95 => INS95, 0x96 => INS96, 0x97 => INS97, 0x98 => INS98, 0x99 => INS99, 0x9A => INS9A, 0x9B => INS9B, 0x9C => INS9C, 0x9D => INS9D, 0x9E => INS9E, 0x9F => INS9F, 0xA0 => INSA0, 0xA1 => INSA1, 0xA2 => INSA2, 0xA3 => INSA3, 0xA4 => INSA4, 0xA5 => INSA5, 0xA6 => INSA6, 0xA7 => INSA7, 0xA8 => INSA8, 0xA9 => INSA9, 0xAA => INSAA, 0xAB => INSAB, 0xAC => INSAC, 0xAD => INSAD, 0xAE => INSAE, 0xAF => INSAF, 0xB0 => PUSHB000, 0xB1 => PUSHB001, 0xB2 => PUSHB010, 0xB3 => PUSHB011, 0xB4 => PUSHB100, 0xB5 => PUSHB101, 0xB6 => PUSHB110, 0xB7 => PUSHB111, 0xB8 => PUSHW000, 0xB9 => PUSHW001, 0xBA => PUSHW010, 0xBB => PUSHW011, 0xBC => PUSHW100, 0xBD => PUSHW101, 0xBE => PUSHW110, 0xBF => PUSHW111, 0xC0 => MDRP00000, 0xC1 => MDRP00001, 0xC2 => MDRP00010, 0xC3 => MDRP00011, 0xC4 => MDRP00100, 0xC5 => MDRP00101, 0xC6 => MDRP00110, 0xC7 => MDRP00111, 0xC8 => MDRP01000, 0xC9 => MDRP01001, 0xCA => MDRP01010, 0xCB => MDRP01011, 0xCC => MDRP01100, 0xCD => MDRP01101, 0xCE => MDRP01110, 0xCF => MDRP01111, 0xD0 => MDRP10000, 0xD1 => MDRP10001, 0xD2 => MDRP10010, 0xD3 => MDRP10011, 0xD4 => MDRP10100, 0xD5 => MDRP10101, 0xD6 => MDRP10110, 0xD7 => MDRP10111, 0xD8 => MDRP11000, 0xD9 => MDRP11001, 0xDA => MDRP11010, 0xDB => MDRP11011, 0xDC => MDRP11100, 0xDD => MDRP11101, 0xDE => MDRP11110, 0xDF => MDRP11111, 0xE0 => MIRP00000, 0xE1 => MIRP00001, 0xE2 => MIRP00010, 0xE3 => MIRP00011, 0xE4 => MIRP00100, 0xE5 => MIRP00101, 0xE6 => MIRP00110, 0xE7 => MIRP00111, 0xE8 => MIRP01000, 0xE9 => MIRP01001, 0xEA => MIRP01010, 0xEB => MIRP01011, 0xEC => MIRP01100, 0xED => MIRP01101, 0xEE => MIRP01110, 0xEF => MIRP01111, 0xF0 => MIRP10000, 0xF1 => MIRP10001, 0xF2 => MIRP10010, 0xF3 => MIRP10011, 0xF4 => MIRP10100, 0xF5 => MIRP10101, 0xF6 => MIRP10110, 0xF7 => MIRP10111, 0xF8 => MIRP11000, 0xF9 => MIRP11001, 0xFA => MIRP11010, 0xFB => MIRP11011, 0xFC => MIRP11100, 0xFD => MIRP11101, 0xFE => MIRP11110, 0xFF => MIRP11111, } } /// Returns a more descriptive name for the opcode. pub fn name(self) -> &'static str { OPCODE_NAMES[self as usize] } /// Returns true if this is an instruction that pushes values onto the /// stack. #[inline] pub fn is_push(self) -> bool { (self >= Self::PUSHB000 && self <= Self::PUSHW111) || self == Self::NPUSHB || self == Self::NPUSHW } pub(super) fn is_push_words(self) -> bool { (self >= Self::PUSHW000 && self <= Self::PUSHW111) || self == Self::NPUSHW } pub(super) fn len(self) -> i32 { OPCODE_LENGTHS[self as usize] as i32 } } impl std::fmt::Display for Opcode { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "{}", self.name()) } } /// There doesn't seem to be any prevailing set of mnemonics for these /// instructions. These are pulled from FreeType with the justification /// that diffing FreeType hinting traces with our own is the most /// efficient way to track down discrepancies. /// const OPCODE_NAMES: [&str; 256] = [ "SVTCA[y]", "SVTCA[x]", "SPVTCA[y]", "SPVTCA[x]", "SFVTCA[y]", "SFVTCA[x]", "SPVTL[||]", "SPVTL[+]", "SFVTL[||]", "SFVTL[+]", "SPVFS", "SFVFS", "GPV", "GFV", "SFVTPV", "ISECT", "SRP0", "SRP1", "SRP2", "SZP0", "SZP1", "SZP2", "SZPS", "SLOOP", "RTG", "RTHG", "SMD", "ELSE", "JMPR", "SCVTCI", "SSWCI", "SSW", "DUP", "POP", "CLEAR", "SWAP", "DEPTH", "CINDEX", "MINDEX", "ALIGNPTS", "INS_$28", "UTP", "LOOPCALL", "CALL", "FDEF", "ENDF", "MDAP[]", "MDAP[rnd]", "IUP[y]", "IUP[x]", "SHP[rp2]", "SHP[rp1]", "SHC[rp2]", "SHC[rp1]", "SHZ[rp2]", "SHZ[rp1]", "SHPIX", "IP", "MSIRP[]", "MSIRP[rp0]", "ALIGNRP", "RTDG", "MIAP[]", "MIAP[rnd]", "NPUSHB", "NPUSHW", "WS", "RS", "WCVTP", "RCVT", "GC[curr]", "GC[orig]", "SCFS", "MD[curr]", "MD[orig]", "MPPEM", "MPS", "FLIPON", "FLIPOFF", "DEBUG", "LT", "LTEQ", "GT", "GTEQ", "EQ", "NEQ", "ODD", "EVEN", "IF", "EIF", "AND", "OR", "NOT", "DELTAP1", "SDB", "SDS", "ADD", "SUB", "DIV", "MUL", "ABS", "NEG", "FLOOR", "CEILING", "ROUND[G]", "ROUND[B]", "ROUND[W]", "ROUND[]", "NROUND[G]", "NROUND[B]", "NROUND[W]", "NROUND[]", "WCVTF", "DELTAP2", "DELTAP3", "DELTAC1", "DELTAC2", "DELTAC3", "SROUND", "S45ROUND", "JROT", "JROF", "ROFF", "INS_$7B", "RUTG", "RDTG", "SANGW", "AA", "FLIPPT", "FLIPRGON", "FLIPRGOFF", "INS_$83", "INS_$84", "SCANCTRL", "SDPVTL[||]", "SDPVTL[+]", "GETINFO", "IDEF", "ROLL", "MAX", "MIN", "SCANTYPE", "INSTCTRL", "INS_$8F", "INS_$90", "GETVARIATION", "GETDATA", "INS_$93", "INS_$94", "INS_$95", "INS_$96", "INS_$97", "INS_$98", "INS_$99", "INS_$9A", "INS_$9B", "INS_$9C", "INS_$9D", "INS_$9E", "INS_$9F", "INS_$A0", "INS_$A1", "INS_$A2", "INS_$A3", "INS_$A4", "INS_$A5", "INS_$A6", "INS_$A7", "INS_$A8", "INS_$A9", "INS_$AA", "INS_$AB", "INS_$AC", "INS_$AD", "INS_$AE", "INS_$AF", "PUSHB[0]", "PUSHB[1]", "PUSHB[2]", "PUSHB[3]", "PUSHB[4]", "PUSHB[5]", "PUSHB[6]", "PUSHB[7]", "PUSHW[0]", "PUSHW[1]", "PUSHW[2]", "PUSHW[3]", "PUSHW[4]", "PUSHW[5]", "PUSHW[6]", "PUSHW[7]", "MDRP[G]", "MDRP[B]", "MDRP[W]", "MDRP[]", "MDRP[rG]", "MDRP[rB]", "MDRP[rW]", "MDRP[r]", "MDRP[mG]", "MDRP[mB]", "MDRP[mW]", "MDRP[m]", "MDRP[mrG]", "MDRP[mrB]", "MDRP[mrW]", "MDRP[mr]", "MDRP[pG]", "MDRP[pB]", "MDRP[pW]", "MDRP[p]", "MDRP[prG]", "MDRP[prB]", "MDRP[prW]", "MDRP[pr]", "MDRP[pmG]", "MDRP[pmB]", "MDRP[pmW]", "MDRP[pm]", "MDRP[pmrG]", "MDRP[pmrB]", "MDRP[pmrW]", "MDRP[pmr]", "MIRP[G]", "MIRP[B]", "MIRP[W]", "MIRP[]", "MIRP[rG]", "MIRP[rB]", "MIRP[rW]", "MIRP[r]", "MIRP[mG]", "MIRP[mB]", "MIRP[mW]", "MIRP[m]", "MIRP[mrG]", "MIRP[mrB]", "MIRP[mrW]", "MIRP[mr]", "MIRP[pG]", "MIRP[pB]", "MIRP[pW]", "MIRP[p]", "MIRP[prG]", "MIRP[prB]", "MIRP[prW]", "MIRP[pr]", "MIRP[pmG]", "MIRP[pmB]", "MIRP[pmW]", "MIRP[pm]", "MIRP[pmrG]", "MIRP[pmrB]", "MIRP[pmrW]", "MIRP[pmr]", ]; /// Size in bytes of an instruction. /// /// The negative values represent variable length instructions where the /// next byte in the stream is the count of following operands and the /// absolute value of the length in this table is the size in bytes of /// each operand. These are just the NPUSHB and NPUSHW instructions. /// const OPCODE_LENGTHS: [i8; 256] = [ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 3, 5, 7, 9, 11, 13, 15, 17, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ];