All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jpedal.fonts.tt.hinting.TTGraphicsState Maven / Gradle / Ivy

There is a newer version: 7.15.25
Show newest version
/*
 * ===========================================
 * Java Pdf Extraction Decoding Access Library
 * ===========================================
 *
 * Project Info:  http://www.idrsolutions.com
 * Help section for developers at http://www.idrsolutions.com/support/
 *
 * (C) Copyright 1997-2017 IDRsolutions and Contributors.
 *
 * This file is part of JPedal/JPDF2HTML5
 *
 @LICENSE@
 *
 * ---------------
 * TTGraphicsState.java
 * ---------------
 */
package org.jpedal.fonts.tt.hinting;

import java.io.Serializable;

/**
 * holds the graphics state variables
 */
public class TTGraphicsState implements Cloneable, Serializable {

    /**
     * Preset vectors -
     * 

* Vectors are stored as two F2Dot14 numbers stored in an int, with the x component taking up the high 16 bits and * the y component taking up the bottom 16. The hypotenuse must be 1 in length. (0x4000 in F2Dot14) */ public static final int x_axis = 0x40000000; public static final int y_axis = 0x00004000; /** * Preset round states - *

* The spec defines a way of interpreting an item from the stack to form a round state consisting of period, phase * and threshold for use in the SROUND instruction. This format is used instead of storing each aspect of the round * state individually. */ public static final int hg = 0x68; //Half Grid public static final int g = 0x48; //Grid public static final int dg = 0x08; //Double Grid public static final int dtg = 0x44; //Down to Grid public static final int utg = 0x40; //Up to Grid public static final int off = -1; //None //Controls whether MIRP will flip CVT entries to match the actual distance public boolean autoFlip = true; //The maximum difference between the measured distance and the cvt entry if the entry is to be used for MIRP public int controlValueTableCutIn = 68; //Lowest number in relative numbering system used by DELTA instructions public int deltaBase = 9; //Determines the magnitude of movements by DELTA instructions public int deltaShift = 3; //Vector which defines the direction of movement (for almost all instructions) public int freedomVector = x_axis; //Vector which defines the direction of measurement (usually) public int projectionVector = x_axis; //Vector which defines the direction of measurement when dealing with points original positions in GC, MD, MDRP and MIRP public int dualProjectionVector = x_axis; //Allows you to disable instructions entirely for glyph programs. public int instructControl; //Scan conversion not implemented - using java for anti aliased rendering instead // public boolean scanControl=false; //Used by some functions to repeat actions. It's always reset to 1 after it's used. public int loop = 1; //Sets the minimum distance to which a value will be rounded in MIRP and MDRP public int minimumDistance = 1; //Contains the components required to round variables public int roundState = g; //Grid period for rounding - 1 usually, sqrt(2)/2 for 45 degrees public double gridPeriod = 1.0; //Reference points public int rp0; public int rp1; public int rp2; //The cutIn is the difference below which a distance will be replaced with the widthValue in MDRP and MIRP public int singleWidthCutIn; public int singleWidthValue; //Zone pointers public int zp0 = TTVM.GLYPH_ZONE; public int zp1 = TTVM.GLYPH_ZONE; public int zp2 = TTVM.GLYPH_ZONE; /** * Create a copy of this object. * * @return Copy reference * @throws CloneNotSupportedException */ @Override public Object clone() throws CloneNotSupportedException { return super.clone(); } /** * Rounds a double according to the round state variable. * * @param n Number to round * @return Rounded number */ public double round(double n) { if (roundState == off) { return n; } final boolean isPositive = n > 0; //Get period int p = (roundState >> 6) & 3; final double period; if (p == 0) { period = gridPeriod / 2; } else if (p == 1) { period = gridPeriod; } else { period = gridPeriod * 2; } //Get phase p = (roundState >> 4) & 3; final double phase; switch (p) { case 0: phase = 0; break; case 1: phase = period / 4; break; case 2: phase = period / 2; break; default: phase = (3 * period) / 4; break; } //Get threshold p = roundState & 15; //special case - use largest number smaller than period if (p == 0) { double result = phase; while (result < n) { result += period; } return result; } final double threshold = ((p - 4) * period) / 8; //Round n -= phase; double lower = 0; if (n > 0) { n += threshold; while (lower + period <= n) { lower += period; } } else { n -= threshold; while (lower - period >= n) { lower -= period; } } n = lower; n += phase; //Make sure number doesn't flip from pos to neg/neg to pos if (isPositive && n < 0) { n = phase % period; } if (!isPositive && n > 0) { n = (phase - (10 * period)) % period; } return n; } /** * Rounds a F26Dot6 number according to the round state variable. * * @param f26dot6 Number to round * @return Rounded number */ public int round(final int f26dot6) { double d = TTVM.getDoubleFromF26Dot6(f26dot6); d = round(d); return TTVM.storeDoubleAsF26Dot6(d); } /** * Takes an F26Dot6 distance along the projection vector and calculates the shift along the freedom vector IN ACTUAL * SPACE required. * * @param distance Move required along PV * @return F26Dot6 shifts needed in x and y */ public int[] getFVMoveforPVDistance(final int distance) { if (distance == 0) { return new int[]{0, 0}; } final int[] fv = getVectorComponents(freedomVector); fv[0] = TTVM.storeDoubleAsF26Dot6(TTVM.getDoubleFromF2Dot14(fv[0])); fv[1] = TTVM.storeDoubleAsF26Dot6(TTVM.getDoubleFromF2Dot14(fv[1])); final double fvWorth = TTVM.getDoubleFromF26Dot6(getCoordsOnVector(projectionVector, fv[0], fv[1])); if (fvWorth != 0) { final double mul = TTVM.getDoubleFromF26Dot6(distance); fv[0] = (int) ((fv[0] * mul) / fvWorth); fv[1] = (int) ((fv[1] * mul) / fvWorth); } else { fv[0] = 0; fv[1] = 0; } return fv; } /** * Get the F2Dot14 components of a vector. * * @param vector vector to get * @return array of x and y components */ static int[] getVectorComponents(final int vector) { return new int[]{(vector >> 16), ((vector << 16) >> 16)}; } /** * Create a vector from two F2Dot14 numbers. * * @param x x component * @param y y component * @return newly created vector */ static int createVector(final int x, final int y) { return ((x & 0xFFFF) << 16) + (y & 0xFFFF); } /** * Get the coordinates of a point on a vector. * * @param vector Vector to measure against * @param x F26Dot6 x coordinate * @param y F26Dot6 y coordinate * @return F26Dot6 coordinate on vector */ static int getCoordsOnVector(final int vector, final int x, final int y) { final int[] pv = getVectorComponents(vector); // double xProj = TTVM.getDoubleFromF2Dot14(pv[0]) * TTVM.getDoubleFromF26Dot6(x); // double yProj = TTVM.getDoubleFromF2Dot14(pv[1]) * TTVM.getDoubleFromF26Dot6(y); // return TTVM.storeDoubleAsF26Dot6(xProj + yProj); final long xProj = pv[0] * (long) x; final long yProj = pv[1] * (long) y; long bigResult = xProj + yProj; final boolean roundUp = (bigResult & 0x3FFF) >= 0x7F; bigResult >>= 14; if (roundUp) { bigResult++; } return (int) bigResult; } /** * Resets various variables for each glyph. */ public void resetForGlyph() { zp0 = TTVM.GLYPH_ZONE; zp1 = TTVM.GLYPH_ZONE; zp2 = TTVM.GLYPH_ZONE; projectionVector = x_axis; dualProjectionVector = x_axis; freedomVector = x_axis; roundState = g; loop = 1; controlValueTableCutIn = 68; } private static String getVectorAsString(final int vector) { final int[] v = getVectorComponents(vector); return TTVM.getDoubleFromF2Dot14(v[0]) + ", " + TTVM.getDoubleFromF2Dot14(v[1]); } public String getRoundStateAsString() { switch (roundState) { case g: return "Grid"; case hg: return "HalfGrid"; case dg: return "DoubleGrid"; case dtg: return "DownToGrid"; case utg: return "UpToGrid"; case off: return "Off"; } //Get period int p = (roundState >> 6) & 3; final String period; if (p == 0) { period = "Period:HalfPixel"; } else if (p == 1) { period = "Period:OnePixel"; } else { period = "Period:TwoPixels"; } //Get phase p = (roundState >> 4) & 3; final String phase; switch (p) { case 0: phase = "Phase:0"; break; case 1: phase = "Phase:Period/4"; break; case 2: phase = "Phase:Period/2"; break; default: phase = "Phase:Period*(3/4)"; break; } //Get threshold p = roundState & 15; final String threshold; if (p == 0) { threshold = "Threshold:Period-1"; } else { threshold = "(" + (p - 4) + "/8)" + "*Period"; } return '(' + period + ',' + phase + ',' + threshold + ')'; } /** * Returns a string containing details of the graphics state. * * @return TTGraphicsState details */ @Override public String toString() { return "org.jpedal.fonts.tt.hinting.TTGraphicsState[" + "zp0=" + (zp0 == TTVM.GLYPH_ZONE ? "GLYPH" : "TWILIGHT") + ",zp1=" + (zp1 == TTVM.GLYPH_ZONE ? "GLYPH" : "TWILIGHT") + ",zp2=" + (zp2 == TTVM.GLYPH_ZONE ? "GLYPH" : "TWILIGHT") + ",rp0=" + rp0 + ",rp1=" + rp1 + ",rp2=" + rp2 + ",freedomVector=(" + getVectorAsString(freedomVector) + ')' + ",projectionVector=(" + getVectorAsString(projectionVector) + ')' + ",dualProjectionVector=(" + getVectorAsString(dualProjectionVector) + ')' + ",instructControl=" + instructControl + ",autoFlip=" + autoFlip + ",deltaBase=" + deltaBase + ",deltaShift=" + deltaShift + ",loop=" + loop + ",roundState=" + getRoundStateAsString() + ",minimumDistance=" + minimumDistance + ",controlValueTableCutIn=" + controlValueTableCutIn + ",singleWidthCutIn=" + singleWidthCutIn + ",singleWidthValue=" + singleWidthValue + ']'; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy