/* * $Id: Parser.java,v 1.1.1.1 2004-12-05 23:15:06 davidsch Exp $ * * Typecast - The Font Development Environment * * Copyright (c) 2004 David Schweinsberg * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jogamp.graph.font.typecast.tt.engine; import jogamp.graph.font.typecast.ot.Mnemonic; /** * @author <a href="mailto:davidsch@dev.java.net">David Schweinsberg</a> * @version $Id: Parser.java,v 1.1.1.1 2004-12-05 23:15:06 davidsch Exp $ */ public class Parser { private final short[][] instructions = new short[3][]; /** * Advance the instruction pointer to the next executable opcode. * This will be the next byte, unless the current opcode is a push * instruction, in which case it will be the byte immediately beyond * the last data byte. * @param ip The current instruction pointer * @return The new instruction pointer */ public int advanceIP(int ip) { // The high word specifies font, cvt, or glyph program final int prog = ip >> 16; int i = ip & 0xffff; int dataCount; ip++; if (Mnemonic.NPUSHB == instructions[prog][i]) { // Next byte is the data byte count dataCount = instructions[prog][++i]; ip += dataCount + 1; } else if (Mnemonic.NPUSHW == instructions[prog][i]) { // Next byte is the data word count dataCount = instructions[prog][++i]; ip += dataCount*2 + 1; } else if (Mnemonic.PUSHB == (instructions[prog][i] & 0xf8)) { dataCount = (short)((instructions[prog][i] & 0x07) + 1); ip += dataCount; } else if (Mnemonic.PUSHW == (instructions[prog][i] & 0xf8)) { dataCount = (short)((instructions[prog][i] & 0x07) + 1); ip += dataCount*2; } return ip; } public int getISLength(final int prog) { return instructions[prog].length; } public short getOpcode(final int ip) { return instructions[ip >> 16][ip & 0xffff]; } public short getPushCount(final int ip) { final short instr = instructions[ip >> 16][ip & 0xffff]; if ((Mnemonic.NPUSHB == instr) || (Mnemonic.NPUSHW == instr)) { return instructions[ip >> 16][(ip & 0xffff) + 1]; } else if ((Mnemonic.PUSHB == (instr & 0xf8)) || (Mnemonic.PUSHW == (instr & 0xf8))) { return (short)((instr & 0x07) + 1); } return 0; } public int[] getPushData(final int ip) { final int count = getPushCount(ip); final int[] data = new int[count]; final int prog = ip >> 16; final int i = ip & 0xffff; final short instr = instructions[prog][i]; if (Mnemonic.NPUSHB == instr) { for (int j = 0; j < count; j++) { data[j] = instructions[prog][i + j + 2]; } } else if (Mnemonic.PUSHB == (instr & 0xf8)) { for (int j = 0; j < count; j++) { data[j] = instructions[prog][i + j + 1]; } } else if (Mnemonic.NPUSHW == instr) { for (int j = 0; j < count; j++) { data[j] = (instructions[prog][i + j*2 + 2] << 8) | instructions[prog][i + j*2 + 3]; } } else if (Mnemonic.PUSHW == (instr & 0xf8)) { for (int j = 0; j < count; j++) { data[j] = (instructions[prog][i + j*2 + 1] << 8) | instructions[prog][i + j*2 + 2]; } } return data; } public int handleElse(int ip) { while (instructions[ip >> 16][ip & 0xffff] != Mnemonic.EIF) { ip = advanceIP(ip); } return ip; } public int handleIf(final boolean test, int ip) { if (test == false) { // The TrueType spec says that we merely jump to the *next* ELSE or EIF // instruction in the instruction stream. So therefore no nesting! // Looking at actual code, IF-ELSE-EIF can be nested! while ((instructions[ip >> 16][ip & 0xffff] != Mnemonic.ELSE) && (instructions[ip >> 16][ip & 0xffff] != Mnemonic.EIF)) { ip = advanceIP(ip); } } return ip; } /** * This program is run everytime we scale the font */ public void setCvtProgram(final short[] program) { instructions[1] = program; } /** * This program is only run once */ public void setFontProgram(final short[] program) { instructions[0] = program; } /** * This program is run everytime we scale the glyph */ public void setGlyphProgram(final short[] program) { instructions[2] = program; } @Override public String toString() { final StringBuilder sb = new StringBuilder(); int ip = 0; while (ip < instructions[0].length) { sb.append(Mnemonic.getMnemonic(getOpcode(ip))); if (getPushCount(ip) > 0) { final int[] data = getPushData(ip); for(int j = 0; j < data.length; j++) sb.append(" ").append(data[j]); } sb.append("\n"); ip = advanceIP(ip); } sb.append("\n"); ip = 0x10000; while (ip < (0x10000 | instructions[1].length)) { sb.append(Mnemonic.getMnemonic(getOpcode(ip))); if(getPushCount(ip) > 0) { final int[] data = getPushData(ip); for (int j = 0; j < data.length; j++) { sb.append(" ").append(data[j]); } } sb.append("\n"); ip = advanceIP(ip); } sb.append("\n"); ip = 0x20000; while (ip < (0x20000 | instructions[2].length)) { sb.append(Mnemonic.getMnemonic(getOpcode(ip))); if (getPushCount(ip) > 0) { final int[] data = getPushData(ip); for (int j = 0; j < data.length; j++) { sb.append(" ").append(data[j]); } } sb.append("\n"); ip = advanceIP(ip); } return sb.toString(); } }