com.sun.pdfview.font.ttf.GlyfCompound Maven / Gradle / Ivy
/*
* $Id: GlyfCompound.java,v 1.3 2009/02/12 13:53:57 tomoke Exp $
*
* Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
* Santa Clara, California 95054, U.S.A. All rights reserved.
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
package com.sun.pdfview.font.ttf;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
/**
* A single simple glyph in a pdf font.
*/
public class GlyfCompound extends Glyf {
/** flags */
private static final int ARG_1_AND_2_ARE_WORDS = 0x1;
private static final int ARGS_ARE_XY_VALUES = 0x2;
private static final int ROUND_XY_TO_GRID = 0x4;
private static final int WE_HAVE_A_SCALE = 0x8;
private static final int MORE_COMPONENTS = 0x20;
private static final int WE_HAVE_AN_X_AND_Y_SCALE = 0x40;
private static final int WE_HAVE_A_TWO_BY_TWO = 0x80;
private static final int WE_HAVE_INSTRUCTIONS = 0x100;
private static final int USE_MY_METRICS = 0x200;
private static final int OVERLAP_COMPOUND = 0x400;
/** the flags for each compound glyph */
private GlyfComponent[] components;
/** the instructions for the compound as a whole */
private byte[] instructions;
/**
* Creates a new instance of a simple glyf
*/
protected GlyfCompound() {
}
/**
* Set the data for this glyf.
*/
@Override public void setData(ByteBuffer data) {
// int pos = data.position();
// byte[] prdata = new byte[data.remaining()];
// data.get(prdata);
// HexDump.printData(prdata);
// data.position(pos);
// read the contour end points
List comps = new ArrayList();
GlyfComponent cur = null;
boolean hasInstructions = false;
do {
cur = new GlyfComponent();
cur.flags = data.getShort();
cur.glyphIndex = data.getShort();
// read either e/f or matching points, as shorts or bytes...
if (((cur.flags & ARG_1_AND_2_ARE_WORDS) != 0) &&
((cur.flags & ARGS_ARE_XY_VALUES) != 0)) {
cur.e = data.getShort();
cur.f = data.getShort();
} else if (!((cur.flags & ARG_1_AND_2_ARE_WORDS) != 0) &&
((cur.flags & ARGS_ARE_XY_VALUES) != 0)) {
cur.e = (float) data.get();
cur.f = (float) data.get();
} else if ( ((cur.flags & ARG_1_AND_2_ARE_WORDS) != 0) &&
!((cur.flags & ARGS_ARE_XY_VALUES) != 0)) {
cur.compoundPoint = data.getShort();
cur.componentPoint = data.getShort();
} else {
cur.compoundPoint = data.get();
cur.componentPoint = data.get();
}
// read the linear transform
if ((cur.flags & WE_HAVE_A_SCALE) != 0) {
cur.a = (float) data.getShort() / (float) (1 << 14);
cur.d = cur.a;
} else if ((cur.flags & WE_HAVE_AN_X_AND_Y_SCALE) != 0) {
cur.a = (float) data.getShort() / (float) (1 << 14);
cur.d = (float) data.getShort() / (float) (1 << 14);
} else if ((cur.flags & WE_HAVE_A_TWO_BY_TWO) != 0) {
cur.a = (float) data.getShort() / (float) (1 << 14);
cur.b = (float) data.getShort() / (float) (1 << 14);
cur.c = (float) data.getShort() / (float) (1 << 14);
cur.d = (float) data.getShort() / (float) (1 << 14);
}
if ((cur.flags & WE_HAVE_INSTRUCTIONS) != 0) {
hasInstructions = true;
}
comps.add(cur);
} while ((cur.flags & MORE_COMPONENTS) != 0);
GlyfComponent[] componentArray = new GlyfComponent[comps.size()];
comps.toArray(componentArray);
setComponents(componentArray);
byte[] instr = null;
if (hasInstructions) {
// read the instructions
short numInstructions = data.getShort();
instr = new byte[numInstructions];
for (int i = 0; i < instr.length; i++) {
instr[i] = data.get();
}
} else {
instr = new byte[0];
}
setInstructions(instr);
}
/**
* Get the data in this glyf as a byte buffer. Not implemented.
*/
@Override public ByteBuffer getData() {
ByteBuffer buf = super.getData();
// don't flip the buffer, since it may be used by subclasses
return buf;
}
/**
* Get the length of this glyf. Not implemented.
*/
@Override public short getLength() {
// start with the length of the superclass
short length = super.getLength();
return length;
}
/**
* Get the number of components in this compound
*/
public int getNumComponents() {
return components.length;
}
/**
* Get a given flag
*/
public short getFlag(int index) {
return components[index].flags;
}
/**
* Get the glyf index for a given glyf
*/
public short getGlyphIndex(int index) {
return components[index].glyphIndex;
}
/**
* Get the base affine transform. This is based on a whacy formula
* defined in the true type font spec.
*/
public double[] getTransform(int index) {
GlyfComponent gc = components[index];
float m = (float) Math.max(Math.abs(gc.a), Math.abs(gc.b));
if (Math.abs(Math.abs(gc.a) - Math.abs(gc.c)) < (33 / 65536)) {
m *= 2;
}
float n = (float) Math.max(Math.abs(gc.c), Math.abs(gc.d));
if (Math.abs(Math.abs(gc.c) - Math.abs(gc.d)) < (33 / 65536)) {
n *= 2;
}
float e = m * gc.e;
float f = n * gc.f;
return new double[] { gc.a, gc.b, gc.c, gc.d, e, f };
}
/**
* Get the point in the compound glyph to match
*/
public int getCompoundPoint(int index) {
return components[index].compoundPoint;
}
/**
* Get the point in the component glyph to match
*/
public int getComponentPoint(int index) {
return components[index].componentPoint;
}
/**
* Determine whether args 1 and 2 are words or bytes
*/
public boolean argsAreWords(int index) {
return ((getFlag(index) & ARG_1_AND_2_ARE_WORDS) != 0);
}
/**
* Determine whether args 1 and 2 are xy values or point indices
*/
public boolean argsAreXYValues(int index) {
return ((getFlag(index) & ARGS_ARE_XY_VALUES) != 0);
}
/**
* Determine whether to round XY values to the grid
*/
public boolean roundXYToGrid(int index) {
return ((getFlag(index) & ROUND_XY_TO_GRID) != 0);
}
/**
* Determine whether there is a simple scale
*/
public boolean hasAScale(int index) {
return ((getFlag(index) & WE_HAVE_A_SCALE) != 0);
}
/**
* Determine whether there are more components left to read
*/
protected boolean moreComponents(int index) {
return ((getFlag(index) & MORE_COMPONENTS) != 0);
}
/**
* Determine whether there are separate scales on X and Y
*/
protected boolean hasXYScale(int index) {
return ((getFlag(index) & WE_HAVE_AN_X_AND_Y_SCALE) != 0);
}
/**
* Determine whether there is a 2x2 transform
*/
protected boolean hasTwoByTwo(int index) {
return ((getFlag(index) & WE_HAVE_A_TWO_BY_TWO) != 0);
}
/**
* Determine whether there are instructions
*/
protected boolean hasInstructions(int index) {
return ((getFlag(index) & WE_HAVE_INSTRUCTIONS) != 0);
}
/**
* Use the metrics of this component for the compound
*/
public boolean useMetrics(int index) {
return ((getFlag(index) & USE_MY_METRICS) != 0);
}
/**
* This component overlaps the existing compound
*/
public boolean overlapCompound(int index) {
return ((getFlag(index) & OVERLAP_COMPOUND) != 0);
}
/**
* Set the components
*/
void setComponents(GlyfComponent[] components) {
this.components = components;
}
/**
* Get the number of instructions
*/
public short getNumInstructions() {
return (short) instructions.length;
}
/**
* Get a given instruction
*/
public byte getInstruction(int index) {
return instructions[index];
}
/**
* Set the instructions
*/
protected void setInstructions(byte[] instructions) {
this.instructions = instructions;
}
/**
* The record for a single component of this compound glyph
*/
class GlyfComponent {
/** flags */
short flags;
/** the index of the component glyf */
short glyphIndex;
/** the points to match */
int compoundPoint;
int componentPoint;
/** affine transform of this component */
float a = 1.0f;
float b = 0.0f;
float c = 0.0f;
float d = 1.0f;
float e = 0.0f;
float f = 0.0f;
}
}