/* * $Copyright: copyright (c) 2003-2008, e.e d3si9n $ * $License: * This source code is part of DoubleType. * DoubleType is a graphical typeface designer. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This Program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * In addition, as a special exception, e.e d3si9n gives permission to * link the code of this program with any Java Platform that is available * to public with free of charge, including but not limited to * Sun Microsystem's JAVA(TM) 2 RUNTIME ENVIRONMENT (J2RE), * and distribute linked combinations including the two. * You must obey the GNU General Public License in all respects for all * of the code used other than Java Platform. If you modify this file, * you may extend this exception to your version of the file, but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. * $ */ package org.doubletype.ossa.truetype; import java.awt.Point; import java.util.ArrayList; /** * @author e.e */ public class TTGlyph { // -------------------------------------------------------------- public static final int k_onCurve = 0x1; public static final int ARG_1_AND_2_ARE_WORDS = 0x1; public static final int ARGS_ARE_XY_VALUES = 0x2; public static final int ROUND_XY_TO_GRID = 0x4; public static final int WE_HAVE_A_SCALE = 0x8; // 0x10 is obsolete public static final int MORE_COMPONENTS = 0x20; public static final int WE_HAVE_AN_X_AND_Y_SCALE = 0x40; public static final int WE_HAVE_A_TWO_BY_TWO = 0x80; public static final int WE_HAVE_INSTRUCTIONS = 0x100; public static final int USE_MY_METRICS = 0x200; public static final int OVERLAP_COMPOUND = 0x400; /** * Move Direct Absolute Point - do not round */ public static final int MDAP0 = 0x2E; /** * Move Direct Absolute Point - round the value */ public static final int MDAP1 = 0x2F; /** * Interpolate Untouched Points through the outline - y-direction */ public static final int IUP0 = 0x30; /** * Interpolate Untouched Points through the outline - x-direction */ public static final int IUP1 = 0x31; /** * push one byte */ public static final int PUSHB000 = 0xB0; /** * push two bytes */ public static final int PUSHB001 = 0xB1; /** * push three bytes */ public static final int PUSHB010 = 0xB2; public static final int PUSHB011 = 0xB3; public static final int PUSHB100 = 0xB4; public static final int PUSHB101 = 0xB5; public static final int PUSHB110 = 0xB6; public static final int PUSHB111 = 0xB7; /** * set vector to y-axis. */ public static final int SVTCA0 = 0x00; /** * set vector to x-axis. */ public static final int SVTCA1 = 0x01; public static final int SPVFS = 0x0A; // set projection vector public static final int SFVFS = 0x0B; // set freedom vector public static final int SFVTPV = 0x0E; public static final int DELTAP1 = 0x5D; public static final int DELTAP2 = 0x71; public static final int DELTAP3 = 0x72; /** * set delta base */ public static final int SDB = 0x5E; // -------------------------------------------------------------- /** * converts double into F2Dot14, 16 bit fixed point format. * * @param a_value * @return */ public static int toF2Dot14(double a_value) { int retval = 0; if (a_value >= 2.0 || a_value < -2.0) { throw new RuntimeException(Double.toString(a_value) + " out of range"); } int mantissa = (int) Math.floor(a_value); int fraction = (int) Math.floor((a_value - mantissa) * 16384); int twoBitPart = mantissa; if (mantissa < 0) { twoBitPart = 4 + mantissa; } retval = (twoBitPart << 14) | fraction; return retval; } public static int toDeltaArg(int a_relativePpem, int a_step) { int retval = 0; if (a_step < -8 || a_step > 8 || a_step == 0) { throw new RuntimeException("Out of range"); } int selector = 0; if (a_step > 0) { selector = a_step + 7; } else { selector = a_step + 8; } retval = (a_relativePpem << 4) | (selector); return retval; } // -------------------------------------------------------------- private ArrayList<Point> m_points = new ArrayList<>(); private ArrayList<Integer> m_endPtsOfContours = new ArrayList<>(); private ArrayList<Integer> m_instructions = new ArrayList<>(); private ArrayList<Integer> m_flags = new ArrayList<>(); private ArrayList<Integer> m_glyfIndeces = new ArrayList<>(); private ArrayList<Integer> m_arg1s = new ArrayList<>(); private ArrayList<Integer> m_arg2s = new ArrayList<>(); private boolean m_isSimple = true; private int m_advanceWidth = 512; private int m_numOfCompositePoints = 0; private int m_numOfCompositeContours = 0; private int m_componentDepth = 0; private Point m_min = null; private Point m_max = null; // -------------------------------------------------------------- public TTGlyph() { init(); } public void init() { m_isSimple = true; m_points.clear(); m_endPtsOfContours.clear(); m_instructions.clear(); m_flags.clear(); m_glyfIndeces.clear(); m_arg1s.clear(); m_arg2s.clear(); m_advanceWidth = 512; } public void buildCompound() { init(); m_isSimple = false; addFlag(ARG_1_AND_2_ARE_WORDS | ARGS_ARE_XY_VALUES | ROUND_XY_TO_GRID | MORE_COMPONENTS); addFlag(ARG_1_AND_2_ARE_WORDS | ARGS_ARE_XY_VALUES | ROUND_XY_TO_GRID); addGlyfIndex(3); addGlyfIndex(3); addArg1(0); addArg2(0); addArg1(0); addArg2(500); } /** * add the index of the last point in the contour * * @param a_index */ public void addEndPoint(int a_value) { m_endPtsOfContours.add(a_value); } public int getNumOfContours() { if (isSimple()) { return m_endPtsOfContours.size(); } else { return -1; } } public int getEndPoint(int a_index) { return m_endPtsOfContours.get(a_index); } public int getAdvanceWidth() { return m_advanceWidth; } public void setAdvanceWidth(int a_value) { m_advanceWidth = a_value; } public Point getMax() { if (m_max == null) { m_max = new Point(0, 0); } return m_max; } public Point getMin() { if (m_min == null) { m_min = new Point(0, 0); } return m_min; } public boolean isSimple() { return m_isSimple; } public void setSimple(boolean a_isSimple) { m_isSimple = a_isSimple; } public void addInstruction(int a_value) { m_instructions.add(a_value); } public int getInstruction(int a_index) { return m_instructions.get(a_index); } public int getNumOfInstructions() { return m_instructions.size(); } public void addFlag(int a_value) { m_flags.add(a_value); } public int getFlag(int a_index) { return m_flags.get(a_index); } public int getNumOfFlags() { return m_flags.size(); } public void addPoint(Point a_value) { m_points.add(a_value); updateMinMax(a_value); } private void updateMinMax(Point a_value) { if (m_max == null) { m_max = new Point(a_value); } if (m_min == null) { m_min = new Point(a_value); } if (a_value.x > m_max.x) { m_max.x = a_value.x; } if (a_value.x < m_min.x) { m_min.x = a_value.x; } if (a_value.y > m_max.y) { m_max.y = a_value.y; } if (a_value.y < m_min.y) { m_min.y = a_value.y; } } public Point getPoint(int a_index) { return m_points.get(a_index); } public int getNumOfPoints() { return m_points.size(); } public int getLastIndex() { return m_points.size() - 1; } public void addGlyfIndex(int a_value) { m_glyfIndeces.add(a_value); } public int getGlyfIndex(int a_index) { return m_glyfIndeces.get(a_index); } public void addArg1(int a_value) { m_arg1s.add(a_value); } public int getArg1(int a_index) { return m_arg1s.get(a_index); } public void addArg2(int a_value) { m_arg2s.add(a_value); } public int getArg2(int a_index) { return m_arg2s.get(a_index); } public int getNumOfCompositePoints() { if (isSimple()) { return getNumOfPoints(); } else { return m_numOfCompositePoints; } } public void setNumOfCompositePoints(int a_value) { m_numOfCompositePoints = a_value; } public int getNumOfCompositeContours() { if (isSimple()) { return getNumOfContours(); } else { return m_numOfCompositeContours; } } public void setNumOfCompositeContours(int a_value) { m_numOfCompositeContours = a_value; } public int getComponentDepth() { if (isSimple()) { return 0; } else { return m_componentDepth; } } public void setComponentDepth(int a_value) { m_componentDepth = a_value; } public int getLeftSideBearing() { return getMin().x; } public int getRightSideBearing() { return getAdvanceWidth() - getMax().x; } }