org.jpedal.fonts.tt.hinting.TTGraphicsState Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of OpenViewerFX Show documentation
Show all versions of OpenViewerFX Show documentation
An Open Source JavaFX PDF Viewer
/*
* ===========================================
* 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-2015 IDRsolutions and Contributors.
*
* This file is part of JPedal/JPDF2HTML5
*
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* ---------------
* 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;
if (p==0) {
phase = 0;
} else if (p==1) {
phase = period / 4;
} else if (p==2) {
phase = period / 2;
} else {
phase = (3 * period) / 4;
}
//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 = (long)pv[0] * (long)x;
final long yProj = (long)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;
if (p==0) {
phase = "Phase:0";
} else if (p==1) {
phase = "Phase:Period/4";
} else if (p==2) {
phase = "Phase:Period/2";
} else {
phase = "Phase:Period*(3/4)";
}
//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 + ']';
}
}